figenc

[RADIOACTIVE] rsa and symmetric key encryption scripts and executables
git clone git://git.figbert.com/figenc.git
Log | Files | Refs | README

menu.tcl (38077B)


      1 # menu.tcl --
      2 #
      3 # This file defines the default bindings for Tk menus and menubuttons.
      4 # It also implements keyboard traversal of menus and implements a few
      5 # other utility procedures related to menus.
      6 #
      7 # Copyright (c) 1992-1994 The Regents of the University of California.
      8 # Copyright (c) 1994-1997 Sun Microsystems, Inc.
      9 # Copyright (c) 1998-1999 by Scriptics Corporation.
     10 # Copyright (c) 2007 Daniel A. Steffen <das@users.sourceforge.net>
     11 #
     12 # See the file "license.terms" for information on usage and redistribution
     13 # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
     14 #
     15 
     16 #-------------------------------------------------------------------------
     17 # Elements of tk::Priv that are used in this file:
     18 #
     19 # cursor -		Saves the -cursor option for the posted menubutton.
     20 # focus -		Saves the focus during a menu selection operation.
     21 #			Focus gets restored here when the menu is unposted.
     22 # grabGlobal -		Used in conjunction with tk::Priv(oldGrab):  if
     23 #			tk::Priv(oldGrab) is non-empty, then tk::Priv(grabGlobal)
     24 #			contains either an empty string or "-global" to
     25 #			indicate whether the old grab was a local one or
     26 #			a global one.
     27 # inMenubutton -	The name of the menubutton widget containing
     28 #			the mouse, or an empty string if the mouse is
     29 #			not over any menubutton.
     30 # menuBar -		The name of the menubar that is the root
     31 #			of the cascade hierarchy which is currently
     32 #			posted. This is null when there is no menu currently
     33 #			being pulled down from a menu bar.
     34 # oldGrab -		Window that had the grab before a menu was posted.
     35 #			Used to restore the grab state after the menu
     36 #			is unposted.  Empty string means there was no
     37 #			grab previously set.
     38 # popup -		If a menu has been popped up via tk_popup, this
     39 #			gives the name of the menu.  Otherwise this
     40 #			value is empty.
     41 # postedMb -		Name of the menubutton whose menu is currently
     42 #			posted, or an empty string if nothing is posted
     43 #			A grab is set on this widget.
     44 # relief -		Used to save the original relief of the current
     45 #			menubutton.
     46 # window -		When the mouse is over a menu, this holds the
     47 #			name of the menu;  it's cleared when the mouse
     48 #			leaves the menu.
     49 # tearoff -		Whether the last menu posted was a tearoff or not.
     50 #			This is true always for unix, for tearoffs for Mac
     51 #			and Windows.
     52 # activeMenu -		This is the last active menu for use
     53 #			with the <<MenuSelect>> virtual event.
     54 # activeItem -		This is the last active menu item for
     55 #			use with the <<MenuSelect>> virtual event.
     56 #-------------------------------------------------------------------------
     57 
     58 #-------------------------------------------------------------------------
     59 # Overall note:
     60 # This file is tricky because there are five different ways that menus
     61 # can be used:
     62 #
     63 # 1. As a pulldown from a menubutton. In this style, the variable
     64 #    tk::Priv(postedMb) identifies the posted menubutton.
     65 # 2. As a torn-off menu copied from some other menu.  In this style
     66 #    tk::Priv(postedMb) is empty, and menu's type is "tearoff".
     67 # 3. As an option menu, triggered from an option menubutton.  In this
     68 #    style tk::Priv(postedMb) identifies the posted menubutton.
     69 # 4. As a popup menu.  In this style tk::Priv(postedMb) is empty and
     70 #    the top-level menu's type is "normal".
     71 # 5. As a pulldown from a menubar. The variable tk::Priv(menubar) has
     72 #    the owning menubar, and the menu itself is of type "normal".
     73 #
     74 # The various binding procedures use the  state described above to
     75 # distinguish the various cases and take different actions in each
     76 # case.
     77 #-------------------------------------------------------------------------
     78 
     79 #-------------------------------------------------------------------------
     80 # The code below creates the default class bindings for menus
     81 # and menubuttons.
     82 #-------------------------------------------------------------------------
     83 
     84 bind Menubutton <FocusIn> {}
     85 bind Menubutton <Enter> {
     86     tk::MbEnter %W
     87 }
     88 bind Menubutton <Leave> {
     89     tk::MbLeave %W
     90 }
     91 bind Menubutton <1> {
     92     if {$tk::Priv(inMenubutton) ne ""} {
     93 	tk::MbPost $tk::Priv(inMenubutton) %X %Y
     94     }
     95 }
     96 bind Menubutton <Motion> {
     97     tk::MbMotion %W up %X %Y
     98 }
     99 bind Menubutton <B1-Motion> {
    100     tk::MbMotion %W down %X %Y
    101 }
    102 bind Menubutton <ButtonRelease-1> {
    103     tk::MbButtonUp %W
    104 }
    105 bind Menubutton <space> {
    106     tk::MbPost %W
    107     tk::MenuFirstEntry [%W cget -menu]
    108 }
    109 bind Menubutton <<Invoke>> {
    110     tk::MbPost %W
    111     tk::MenuFirstEntry [%W cget -menu]
    112 }
    113 
    114 # Must set focus when mouse enters a menu, in order to allow
    115 # mixed-mode processing using both the mouse and the keyboard.
    116 # Don't set the focus if the event comes from a grab release,
    117 # though:  such an event can happen after as part of unposting
    118 # a cascaded chain of menus, after the focus has already been
    119 # restored to wherever it was before menu selection started.
    120 
    121 bind Menu <FocusIn> {}
    122 
    123 bind Menu <Enter> {
    124     set tk::Priv(window) %W
    125     if {[%W cget -type] eq "tearoff"} {
    126 	if {"%m" ne "NotifyUngrab"} {
    127 	    if {[tk windowingsystem] eq "x11"} {
    128 		tk_menuSetFocus %W
    129 	    }
    130 	}
    131     }
    132     tk::MenuMotion %W %x %y %s
    133 }
    134 
    135 bind Menu <Leave> {
    136     tk::MenuLeave %W %X %Y %s
    137 }
    138 bind Menu <Motion> {
    139     tk::MenuMotion %W %x %y %s
    140 }
    141 bind Menu <ButtonPress> {
    142     tk::MenuButtonDown %W
    143 }
    144 bind Menu <ButtonRelease> {
    145    tk::MenuInvoke %W 1
    146 }
    147 bind Menu <space> {
    148     tk::MenuInvoke %W 0
    149 }
    150 bind Menu <<Invoke>> {
    151     tk::MenuInvoke %W 0
    152 }
    153 bind Menu <Return> {
    154     tk::MenuInvoke %W 0
    155 }
    156 bind Menu <Escape> {
    157     tk::MenuEscape %W
    158 }
    159 bind Menu <<PrevChar>> {
    160     tk::MenuLeftArrow %W
    161 }
    162 bind Menu <<NextChar>> {
    163     tk::MenuRightArrow %W
    164 }
    165 bind Menu <<PrevLine>> {
    166     tk::MenuUpArrow %W
    167 }
    168 bind Menu <<NextLine>> {
    169     tk::MenuDownArrow %W
    170 }
    171 bind Menu <KeyPress> {
    172     tk::TraverseWithinMenu %W %A
    173     break
    174 }
    175 
    176 # The following bindings apply to all windows, and are used to
    177 # implement keyboard menu traversal.
    178 
    179 if {[tk windowingsystem] eq "x11"} {
    180     bind all <Alt-KeyPress> {
    181 	tk::TraverseToMenu %W %A
    182     }
    183 
    184     bind all <F10> {
    185 	tk::FirstMenu %W
    186     }
    187 } else {
    188     bind Menubutton <Alt-KeyPress> {
    189 	tk::TraverseToMenu %W %A
    190     }
    191 
    192     bind Menubutton <F10> {
    193 	tk::FirstMenu %W
    194     }
    195 }
    196 
    197 # ::tk::MbEnter --
    198 # This procedure is invoked when the mouse enters a menubutton
    199 # widget.  It activates the widget unless it is disabled.  Note:
    200 # this procedure is only invoked when mouse button 1 is *not* down.
    201 # The procedure ::tk::MbB1Enter is invoked if the button is down.
    202 #
    203 # Arguments:
    204 # w -			The  name of the widget.
    205 
    206 proc ::tk::MbEnter w {
    207     variable ::tk::Priv
    208 
    209     if {$Priv(inMenubutton) ne ""} {
    210 	MbLeave $Priv(inMenubutton)
    211     }
    212     set Priv(inMenubutton) $w
    213     if {[$w cget -state] ne "disabled" && [tk windowingsystem] ne "aqua"} {
    214 	$w configure -state active
    215     }
    216 }
    217 
    218 # ::tk::MbLeave --
    219 # This procedure is invoked when the mouse leaves a menubutton widget.
    220 # It de-activates the widget, if the widget still exists.
    221 #
    222 # Arguments:
    223 # w -			The  name of the widget.
    224 
    225 proc ::tk::MbLeave w {
    226     variable ::tk::Priv
    227 
    228     set Priv(inMenubutton) {}
    229     if {![winfo exists $w]} {
    230 	return
    231     }
    232     if {[$w cget -state] eq "active" && [tk windowingsystem] ne "aqua"} {
    233 	$w configure -state normal
    234     }
    235 }
    236 
    237 # ::tk::MbPost --
    238 # Given a menubutton, this procedure does all the work of posting
    239 # its associated menu and unposting any other menu that is currently
    240 # posted.
    241 #
    242 # Arguments:
    243 # w -			The name of the menubutton widget whose menu
    244 #			is to be posted.
    245 # x, y -		Root coordinates of cursor, used for positioning
    246 #			option menus.  If not specified, then the center
    247 #			of the menubutton is used for an option menu.
    248 
    249 proc ::tk::MbPost {w {x {}} {y {}}} {
    250     global errorInfo
    251     variable ::tk::Priv
    252 
    253     if {[$w cget -state] eq "disabled" || $w eq $Priv(postedMb)} {
    254 	return
    255     }
    256     set menu [$w cget -menu]
    257     if {$menu eq ""} {
    258 	return
    259     }
    260     set tearoff [expr {[tk windowingsystem] eq "x11" \
    261 	    || [$menu cget -type] eq "tearoff"}]
    262     if {[string first $w $menu] != 0} {
    263 	return -code error -errorcode {TK MENUBUTTON POST_NONCHILD} \
    264 	    "can't post $menu: it isn't a descendant of $w"
    265     }
    266     set cur $Priv(postedMb)
    267     if {$cur ne ""} {
    268 	MenuUnpost {}
    269     }
    270     if {$::tk_strictMotif} {
    271         set Priv(cursor) [$w cget -cursor]
    272         $w configure -cursor arrow
    273     }
    274     if {[tk windowingsystem] ne "aqua"} {
    275 	set Priv(relief) [$w cget -relief]
    276 	$w configure -relief raised
    277     } else {
    278 	$w configure -state active
    279     }
    280 
    281     set Priv(postedMb) $w
    282     set Priv(focus) [focus]
    283     $menu activate none
    284     GenerateMenuSelect $menu
    285 
    286     # If this looks like an option menubutton then post the menu so
    287     # that the current entry is on top of the mouse.  Otherwise post
    288     # the menu just below the menubutton, as for a pull-down.
    289 
    290     update idletasks
    291     if {[catch {
    292 	switch [$w cget -direction] {
    293 	    above {
    294 		set x [winfo rootx $w]
    295 		set y [expr {[winfo rooty $w] - [winfo reqheight $menu]}]
    296 		# if we go offscreen to the top, show as 'below'
    297 		if {$y < [winfo vrooty $w]} {
    298 		    set y [expr {[winfo vrooty $w] + [winfo rooty $w] + [winfo reqheight $w]}]
    299 		}
    300 		PostOverPoint $menu $x $y
    301 	    }
    302 	    below {
    303 		set x [winfo rootx $w]
    304 		set y [expr {[winfo rooty $w] + [winfo height $w]}]
    305 		# if we go offscreen to the bottom, show as 'above'
    306 		set mh [winfo reqheight $menu]
    307 		if {($y + $mh) > ([winfo vrooty $w] + [winfo vrootheight $w])} {
    308 		    set y [expr {[winfo vrooty $w] + [winfo vrootheight $w] + [winfo rooty $w] - $mh}]
    309 		}
    310 		PostOverPoint $menu $x $y
    311 	    }
    312 	    left {
    313 		set x [expr {[winfo rootx $w] - [winfo reqwidth $menu]}]
    314 		set y [expr {(2 * [winfo rooty $w] + [winfo height $w]) / 2}]
    315 		set entry [MenuFindName $menu [$w cget -text]]
    316 		if {$entry eq ""} {
    317                     set entry 0
    318 		}
    319 		if {[$w cget -indicatoron]} {
    320 		    if {$entry == [$menu index last]} {
    321 			incr y [expr {-([$menu yposition $entry] \
    322 				+ [winfo reqheight $menu])/2}]
    323 		    } else {
    324 			incr y [expr {-([$menu yposition $entry] \
    325 			        + [$menu yposition [expr {$entry+1}]])/2}]
    326 		    }
    327 		}
    328 		PostOverPoint $menu $x $y
    329 		if {$entry ne "" \
    330 			&& [$menu entrycget $entry -state] ne "disabled"} {
    331 		    $menu activate $entry
    332 		    GenerateMenuSelect $menu
    333 		}
    334 	    }
    335 	    right {
    336 		set x [expr {[winfo rootx $w] + [winfo width $w]}]
    337 		set y [expr {(2 * [winfo rooty $w] + [winfo height $w]) / 2}]
    338 		set entry [MenuFindName $menu [$w cget -text]]
    339 		if {$entry eq ""} {
    340                     set entry 0
    341 		}
    342 		if {[$w cget -indicatoron]} {
    343 		    if {$entry == [$menu index last]} {
    344 			incr y [expr {-([$menu yposition $entry] \
    345 				+ [winfo reqheight $menu])/2}]
    346 		    } else {
    347 			incr y [expr {-([$menu yposition $entry] \
    348 			        + [$menu yposition [expr {$entry+1}]])/2}]
    349 		    }
    350 		}
    351 		PostOverPoint $menu $x $y
    352 		if {$entry ne "" \
    353 			&& [$menu entrycget $entry -state] ne "disabled"} {
    354 		    $menu activate $entry
    355 		    GenerateMenuSelect $menu
    356 		}
    357 	    }
    358 	    default {
    359 		if {[$w cget -indicatoron]} {
    360 		    if {$y eq ""} {
    361 			set x [expr {[winfo rootx $w] + [winfo width $w]/2}]
    362 			set y [expr {[winfo rooty $w] + [winfo height $w]/2}]
    363 		    }
    364 	            PostOverPoint $menu $x $y [MenuFindName $menu [$w cget -text]]
    365 		} else {
    366 		    PostOverPoint $menu [winfo rootx $w] [expr {[winfo rooty $w]+[winfo height $w]}]
    367 		}
    368 	    }
    369 	}
    370     } msg opt]} {
    371 	# Error posting menu (e.g. bogus -postcommand). Unpost it and
    372 	# reflect the error.
    373 
    374 	MenuUnpost {}
    375 	return -options $opt $msg
    376     }
    377 
    378     set Priv(tearoff) $tearoff
    379     if {$tearoff != 0} {
    380 	focus $menu
    381 	if {[winfo viewable $w]} {
    382 	    SaveGrabInfo $w
    383 	    grab -global $w
    384 	}
    385     }
    386 }
    387 
    388 # ::tk::MenuUnpost --
    389 # This procedure unposts a given menu, plus all of its ancestors up
    390 # to (and including) a menubutton, if any.  It also restores various
    391 # values to what they were before the menu was posted, and releases
    392 # a grab if there's a menubutton involved.  Special notes:
    393 # 1. It's important to unpost all menus before releasing the grab, so
    394 #    that any Enter-Leave events (e.g. from menu back to main
    395 #    application) have mode NotifyGrab.
    396 # 2. Be sure to enclose various groups of commands in "catch" so that
    397 #    the procedure will complete even if the menubutton or the menu
    398 #    or the grab window has been deleted.
    399 #
    400 # Arguments:
    401 # menu -		Name of a menu to unpost.  Ignored if there
    402 #			is a posted menubutton.
    403 
    404 proc ::tk::MenuUnpost menu {
    405     variable ::tk::Priv
    406     set mb $Priv(postedMb)
    407 
    408     # Restore focus right away (otherwise X will take focus away when
    409     # the menu is unmapped and under some window managers (e.g. olvwm)
    410     # we'll lose the focus completely).
    411 
    412     catch {focus $Priv(focus)}
    413     set Priv(focus) ""
    414 
    415     # Unpost menu(s) and restore some stuff that's dependent on
    416     # what was posted.
    417 
    418     after cancel [array get Priv menuActivatedTimer]
    419     unset -nocomplain Priv(menuActivated)
    420     after cancel [array get Priv menuDeactivatedTimer]
    421     unset -nocomplain Priv(menuDeactivated)
    422 
    423     catch {
    424 	if {$mb ne ""} {
    425 	    set menu [$mb cget -menu]
    426 	    $menu unpost
    427 	    set Priv(postedMb) {}
    428 	    if {$::tk_strictMotif} {
    429 	        $mb configure -cursor $Priv(cursor)
    430 	    }
    431 	    if {[tk windowingsystem] ne "aqua"} {
    432 		$mb configure -relief $Priv(relief)
    433 	    } else {
    434 		$mb configure -state normal
    435 	    }
    436 	} elseif {$Priv(popup) ne ""} {
    437 	    $Priv(popup) unpost
    438 	    set Priv(popup) {}
    439 	} elseif {[$menu cget -type] ne "menubar" && [$menu cget -type] ne "tearoff"} {
    440 	    # We're in a cascaded sub-menu from a torn-off menu or popup.
    441 	    # Unpost all the menus up to the toplevel one (but not
    442 	    # including the top-level torn-off one) and deactivate the
    443 	    # top-level torn off menu if there is one.
    444 
    445 	    while {1} {
    446 		set parent [winfo parent $menu]
    447 		if {[winfo class $parent] ne "Menu" || ![winfo ismapped $parent]} {
    448 		    break
    449 		}
    450 		$parent activate none
    451 		$parent postcascade none
    452 		GenerateMenuSelect $parent
    453 		set type [$parent cget -type]
    454 		if {$type eq "menubar" || $type eq "tearoff"} {
    455 		    break
    456 		}
    457 		set menu $parent
    458 	    }
    459 	    if {[$menu cget -type] ne "menubar"} {
    460 		$menu unpost
    461 	    }
    462 	}
    463     }
    464 
    465     if {($Priv(tearoff) != 0) || $Priv(menuBar) ne ""} {
    466 	# Release grab, if any, and restore the previous grab, if there
    467 	# was one.
    468 	if {$menu ne ""} {
    469 	    set grab [grab current $menu]
    470 	    if {$grab ne ""} {
    471 		grab release $grab
    472 	    }
    473 	}
    474 	RestoreOldGrab
    475 	if {$Priv(menuBar) ne ""} {
    476 	    if {$::tk_strictMotif} {
    477 		$Priv(menuBar) configure -cursor $Priv(cursor)
    478 	    }
    479 	    set Priv(menuBar) {}
    480 	}
    481 	if {[tk windowingsystem] ne "x11"} {
    482 	    set Priv(tearoff) 0
    483 	}
    484     }
    485 }
    486 
    487 # ::tk::MbMotion --
    488 # This procedure handles mouse motion events inside menubuttons, and
    489 # also outside menubuttons when a menubutton has a grab (e.g. when a
    490 # menu selection operation is in progress).
    491 #
    492 # Arguments:
    493 # w -			The name of the menubutton widget.
    494 # upDown - 		"down" means button 1 is pressed, "up" means
    495 #			it isn't.
    496 # rootx, rooty -	Coordinates of mouse, in (virtual?) root window.
    497 
    498 proc ::tk::MbMotion {w upDown rootx rooty} {
    499     variable ::tk::Priv
    500 
    501     if {$Priv(inMenubutton) eq $w} {
    502 	return
    503     }
    504     set new [winfo containing $rootx $rooty]
    505     if {$new ne $Priv(inMenubutton) \
    506 	    && ($new eq "" || [winfo toplevel $new] eq [winfo toplevel $w])} {
    507 	if {$Priv(inMenubutton) ne ""} {
    508 	    MbLeave $Priv(inMenubutton)
    509 	}
    510 	if {$new ne "" \
    511 		&& [winfo class $new] eq "Menubutton" \
    512 		&& ([$new cget -indicatoron] == 0) \
    513 		&& ([$w cget -indicatoron] == 0)} {
    514 	    if {$upDown eq "down"} {
    515 		MbPost $new $rootx $rooty
    516 	    } else {
    517 		MbEnter $new
    518 	    }
    519 	}
    520     }
    521 }
    522 
    523 # ::tk::MbButtonUp --
    524 # This procedure is invoked to handle button 1 releases for menubuttons.
    525 # If the release happens inside the menubutton then leave its menu
    526 # posted with element 0 activated.  Otherwise, unpost the menu.
    527 #
    528 # Arguments:
    529 # w -			The name of the menubutton widget.
    530 
    531 proc ::tk::MbButtonUp w {
    532     variable ::tk::Priv
    533 
    534     set menu [$w cget -menu]
    535     set tearoff [expr {[tk windowingsystem] eq "x11" || \
    536 	    ($menu ne "" && [$menu cget -type] eq "tearoff")}]
    537     if {($tearoff != 0) && $Priv(postedMb) eq $w \
    538 	    && $Priv(inMenubutton) eq $w} {
    539 	MenuFirstEntry [$Priv(postedMb) cget -menu]
    540     } else {
    541 	MenuUnpost {}
    542     }
    543 }
    544 
    545 # ::tk::MenuMotion --
    546 # This procedure is called to handle mouse motion events for menus.
    547 # It does two things.  First, it resets the active element in the
    548 # menu, if the mouse is over the menu.  Second, if a mouse button
    549 # is down, it posts and unposts cascade entries to match the mouse
    550 # position.
    551 #
    552 # Arguments:
    553 # menu -		The menu window.
    554 # x -			The x position of the mouse.
    555 # y -			The y position of the mouse.
    556 # state -		Modifier state (tells whether buttons are down).
    557 
    558 proc ::tk::MenuMotion {menu x y state} {
    559     variable ::tk::Priv
    560     if {$menu eq $Priv(window)} {
    561         set activeindex [$menu index active]
    562 	if {[$menu cget -type] eq "menubar"} {
    563 	    if {[info exists Priv(focus)] && $menu ne $Priv(focus)} {
    564 		$menu activate @$x,$y
    565 		GenerateMenuSelect $menu
    566 	    }
    567 	} else {
    568 	    $menu activate @$x,$y
    569 	    GenerateMenuSelect $menu
    570 	}
    571         set index [$menu index @$x,$y]
    572         if {[info exists Priv(menuActivated)] \
    573                 && $index ne "none" \
    574                 && $index ne $activeindex} {
    575             set mode [option get $menu clickToFocus ClickToFocus]
    576             if {[string is false $mode]} {
    577                 set delay [expr {[$menu cget -type] eq "menubar" ? 0 : 50}]
    578                 if {[$menu type $index] eq "cascade"} {
    579                     set Priv(menuActivatedTimer) \
    580                         [after $delay [list $menu postcascade active]]
    581                 } else {
    582                     set Priv(menuDeactivatedTimer) \
    583                         [after $delay [list $menu postcascade none]]
    584                 }
    585             }
    586         }
    587     }
    588 }
    589 
    590 # ::tk::MenuButtonDown --
    591 # Handles button presses in menus.  There are a couple of tricky things
    592 # here:
    593 # 1. Change the posted cascade entry (if any) to match the mouse position.
    594 # 2. If there is a posted menubutton, must grab to the menubutton;  this
    595 #    overrrides the implicit grab on button press, so that the menu
    596 #    button can track mouse motions over other menubuttons and change
    597 #    the posted menu.
    598 # 3. If there's no posted menubutton (e.g. because we're a torn-off menu
    599 #    or one of its descendants) must grab to the top-level menu so that
    600 #    we can track mouse motions across the entire menu hierarchy.
    601 #
    602 # Arguments:
    603 # menu -		The menu window.
    604 
    605 proc ::tk::MenuButtonDown menu {
    606     variable ::tk::Priv
    607 
    608     if {![winfo viewable $menu]} {
    609         return
    610     }
    611     if {[$menu index active] eq "none"} {
    612         if {[$menu cget -type] ne "menubar" } {
    613             set Priv(window) {}
    614         }
    615         return
    616     }
    617     $menu postcascade active
    618     if {$Priv(postedMb) ne "" && [winfo viewable $Priv(postedMb)]} {
    619 	grab -global $Priv(postedMb)
    620     } else {
    621 	while {[$menu cget -type] eq "normal" \
    622 		&& [winfo class [winfo parent $menu]] eq "Menu" \
    623 		&& [winfo ismapped [winfo parent $menu]]} {
    624 	    set menu [winfo parent $menu]
    625 	}
    626 
    627 	if {$Priv(menuBar) eq {}} {
    628 	    set Priv(menuBar) $menu
    629 	    if {$::tk_strictMotif} {
    630 		set Priv(cursor) [$menu cget -cursor]
    631 		$menu configure -cursor arrow
    632 	    }
    633 	    if {[$menu type active] eq "cascade"} {
    634 		set Priv(menuActivated) 1
    635 	    }
    636         }
    637 
    638 	# Don't update grab information if the grab window isn't changing.
    639 	# Otherwise, we'll get an error when we unpost the menus and
    640 	# restore the grab, since the old grab window will not be viewable
    641 	# anymore.
    642 
    643 	if {$menu ne [grab current $menu]} {
    644 	    SaveGrabInfo $menu
    645 	}
    646 
    647 	# Must re-grab even if the grab window hasn't changed, in order
    648 	# to release the implicit grab from the button press.
    649 
    650 	if {[tk windowingsystem] eq "x11"} {
    651 	    grab -global $menu
    652 	}
    653     }
    654 }
    655 
    656 # ::tk::MenuLeave --
    657 # This procedure is invoked to handle Leave events for a menu.  It
    658 # deactivates everything unless the active element is a cascade element
    659 # and the mouse is now over the submenu.
    660 #
    661 # Arguments:
    662 # menu -		The menu window.
    663 # rootx, rooty -	Root coordinates of mouse.
    664 # state -		Modifier state.
    665 
    666 proc ::tk::MenuLeave {menu rootx rooty state} {
    667     variable ::tk::Priv
    668     set Priv(window) {}
    669     if {[$menu index active] eq "none"} {
    670 	return
    671     }
    672     if {[$menu type active] eq "cascade" \
    673 	    && [winfo containing $rootx $rooty] eq \
    674 		[$menu entrycget active -menu]} {
    675 	return
    676     }
    677     $menu activate none
    678     GenerateMenuSelect $menu
    679 }
    680 
    681 # ::tk::MenuInvoke --
    682 # This procedure is invoked when button 1 is released over a menu.
    683 # It invokes the appropriate menu action and unposts the menu if
    684 # it came from a menubutton.
    685 #
    686 # Arguments:
    687 # w -			Name of the menu widget.
    688 # buttonRelease -	1 means this procedure is called because of
    689 #			a button release;  0 means because of keystroke.
    690 
    691 proc ::tk::MenuInvoke {w buttonRelease} {
    692     variable ::tk::Priv
    693 
    694     if {$buttonRelease && $Priv(window) eq ""} {
    695 	# Mouse was pressed over a menu without a menu button, then
    696 	# dragged off the menu (possibly with a cascade posted) and
    697 	# released.  Unpost everything and quit.
    698 
    699 	$w postcascade none
    700 	$w activate none
    701 	event generate $w <<MenuSelect>>
    702 	MenuUnpost $w
    703 	return
    704     }
    705     if {[$w type active] eq "cascade"} {
    706 	$w postcascade active
    707 	set menu [$w entrycget active -menu]
    708 	MenuFirstEntry $menu
    709     } elseif {[$w type active] eq "tearoff"} {
    710 	::tk::TearOffMenu $w
    711 	MenuUnpost $w
    712     } elseif {[$w cget -type] eq "menubar"} {
    713 	$w postcascade none
    714 	set active [$w index active]
    715 	set isCascade [string equal [$w type $active] "cascade"]
    716 
    717 	# Only de-activate the active item if it's a cascade; this prevents
    718 	# the annoying "activation flicker" you otherwise get with
    719 	# checkbuttons/commands/etc. on menubars
    720 
    721 	if { $isCascade } {
    722 	    $w activate none
    723 	    event generate $w <<MenuSelect>>
    724 	}
    725 
    726 	MenuUnpost $w
    727 
    728 	# If the active item is not a cascade, invoke it.  This enables
    729 	# the use of checkbuttons/commands/etc. on menubars (which is legal,
    730 	# but not recommended)
    731 
    732 	if { !$isCascade } {
    733 	    uplevel #0 [list $w invoke $active]
    734 	}
    735     } else {
    736 	set active [$w index active]
    737 	if {$Priv(popup) eq "" || $active ne "none"} {
    738 	    MenuUnpost $w
    739 	}
    740 	uplevel #0 [list $w invoke active]
    741     }
    742 }
    743 
    744 # ::tk::MenuEscape --
    745 # This procedure is invoked for the Cancel (or Escape) key.  It unposts
    746 # the given menu and, if it is the top-level menu for a menu button,
    747 # unposts the menu button as well.
    748 #
    749 # Arguments:
    750 # menu -		Name of the menu window.
    751 
    752 proc ::tk::MenuEscape menu {
    753     set parent [winfo parent $menu]
    754     if {[winfo class $parent] ne "Menu"} {
    755 	MenuUnpost $menu
    756     } elseif {[$parent cget -type] eq "menubar"} {
    757 	MenuUnpost $menu
    758 	RestoreOldGrab
    759     } else {
    760 	MenuNextMenu $menu left
    761     }
    762 }
    763 
    764 # The following routines handle arrow keys. Arrow keys behave
    765 # differently depending on whether the menu is a menu bar or not.
    766 
    767 proc ::tk::MenuUpArrow {menu} {
    768     if {[$menu cget -type] eq "menubar"} {
    769 	MenuNextMenu $menu left
    770     } else {
    771 	MenuNextEntry $menu -1
    772     }
    773 }
    774 
    775 proc ::tk::MenuDownArrow {menu} {
    776     if {[$menu cget -type] eq "menubar"} {
    777 	MenuNextMenu $menu right
    778     } else {
    779 	MenuNextEntry $menu 1
    780     }
    781 }
    782 
    783 proc ::tk::MenuLeftArrow {menu} {
    784     if {[$menu cget -type] eq "menubar"} {
    785 	MenuNextEntry $menu -1
    786     } else {
    787 	MenuNextMenu $menu left
    788     }
    789 }
    790 
    791 proc ::tk::MenuRightArrow {menu} {
    792     if {[$menu cget -type] eq "menubar"} {
    793 	MenuNextEntry $menu 1
    794     } else {
    795 	MenuNextMenu $menu right
    796     }
    797 }
    798 
    799 # ::tk::MenuNextMenu --
    800 # This procedure is invoked to handle "left" and "right" traversal
    801 # motions in menus.  It traverses to the next menu in a menu bar,
    802 # or into or out of a cascaded menu.
    803 #
    804 # Arguments:
    805 # menu -		The menu that received the keyboard
    806 #			event.
    807 # direction -		Direction in which to move: "left" or "right"
    808 
    809 proc ::tk::MenuNextMenu {menu direction} {
    810     variable ::tk::Priv
    811 
    812     # First handle traversals into and out of cascaded menus.
    813 
    814     if {$direction eq "right"} {
    815 	set count 1
    816 	set parent [winfo parent $menu]
    817 	set class [winfo class $parent]
    818 	if {[$menu type active] eq "cascade"} {
    819 	    $menu postcascade active
    820 	    set m2 [$menu entrycget active -menu]
    821 	    if {$m2 ne ""} {
    822 		MenuFirstEntry $m2
    823 	    }
    824 	    return
    825 	} else {
    826 	    set parent [winfo parent $menu]
    827 	    while {$parent ne "."} {
    828 		if {[winfo class $parent] eq "Menu" \
    829 			&& [$parent cget -type] eq "menubar"} {
    830 		    tk_menuSetFocus $parent
    831 		    MenuNextEntry $parent 1
    832 		    return
    833 		}
    834 		set parent [winfo parent $parent]
    835 	    }
    836 	}
    837     } else {
    838 	set count -1
    839 	set m2 [winfo parent $menu]
    840 	if {[winfo class $m2] eq "Menu"} {
    841 	    $menu activate none
    842 	    GenerateMenuSelect $menu
    843 	    tk_menuSetFocus $m2
    844 
    845 	    $m2 postcascade none
    846 
    847 	    if {[$m2 cget -type] ne "menubar"} {
    848 		return
    849 	    }
    850 	}
    851     }
    852 
    853     # Can't traverse into or out of a cascaded menu. Go to the next
    854     # or previous menubutton, if that makes sense.
    855 
    856     set m2 [winfo parent $menu]
    857     if {[winfo class $m2] eq "Menu" && [$m2 cget -type] eq "menubar"} {
    858 	tk_menuSetFocus $m2
    859 	MenuNextEntry $m2 -1
    860 	return
    861     }
    862 
    863     set w $Priv(postedMb)
    864     if {$w eq ""} {
    865 	return
    866     }
    867     set buttons [winfo children [winfo parent $w]]
    868     set length [llength $buttons]
    869     set i [expr {[lsearch -exact $buttons $w] + $count}]
    870     while {1} {
    871 	while {$i < 0} {
    872 	    incr i $length
    873 	}
    874 	while {$i >= $length} {
    875 	    incr i -$length
    876 	}
    877 	set mb [lindex $buttons $i]
    878 	if {[winfo class $mb] eq "Menubutton" \
    879 		&& [$mb cget -state] ne "disabled" \
    880 		&& [$mb cget -menu] ne "" \
    881 		&& [[$mb cget -menu] index last] ne "none"} {
    882 	    break
    883 	}
    884 	if {$mb eq $w} {
    885 	    return
    886 	}
    887 	incr i $count
    888     }
    889     MbPost $mb
    890     MenuFirstEntry [$mb cget -menu]
    891 }
    892 
    893 # ::tk::MenuNextEntry --
    894 # Activate the next higher or lower entry in the posted menu,
    895 # wrapping around at the ends.  Disabled entries are skipped.
    896 #
    897 # Arguments:
    898 # menu -			Menu window that received the keystroke.
    899 # count -			1 means go to the next lower entry,
    900 #				-1 means go to the next higher entry.
    901 
    902 proc ::tk::MenuNextEntry {menu count} {
    903     if {[$menu index last] eq "none"} {
    904 	return
    905     }
    906     set length [expr {[$menu index last]+1}]
    907     set quitAfter $length
    908     set active [$menu index active]
    909     if {$active eq "none"} {
    910 	set i 0
    911     } else {
    912 	set i [expr {$active + $count}]
    913     }
    914     while {1} {
    915 	if {$quitAfter <= 0} {
    916 	    # We've tried every entry in the menu.  Either there are
    917 	    # none, or they're all disabled.  Just give up.
    918 
    919 	    return
    920 	}
    921 	while {$i < 0} {
    922 	    incr i $length
    923 	}
    924 	while {$i >= $length} {
    925 	    incr i -$length
    926 	}
    927 	if {[catch {$menu entrycget $i -state} state] == 0} {
    928 	    if {$state ne "disabled" && \
    929 		    ($i!=0 || [$menu cget -type] ne "tearoff" \
    930 		    || [$menu type 0] ne "tearoff")} {
    931 		break
    932 	    }
    933 	}
    934 	if {$i == $active} {
    935 	    return
    936 	}
    937 	incr i $count
    938 	incr quitAfter -1
    939     }
    940     $menu activate $i
    941     GenerateMenuSelect $menu
    942 
    943     if {[$menu type $i] eq "cascade" && [$menu cget -type] eq "menubar"} {
    944 	set cascade [$menu entrycget $i -menu]
    945 	if {$cascade ne ""} {
    946 	    # Here we auto-post a cascade.  This is necessary when
    947 	    # we traverse left/right in the menubar, but undesirable when
    948 	    # we traverse up/down in a menu.
    949 	    $menu postcascade $i
    950 	    MenuFirstEntry $cascade
    951 	}
    952     }
    953 }
    954 
    955 # ::tk::MenuFind --
    956 # This procedure searches the entire window hierarchy under w for
    957 # a menubutton that isn't disabled and whose underlined character
    958 # is "char" or an entry in a menubar that isn't disabled and whose
    959 # underlined character is "char".
    960 # It returns the name of that window, if found, or an
    961 # empty string if no matching window was found.  If "char" is an
    962 # empty string then the procedure returns the name of the first
    963 # menubutton found that isn't disabled.
    964 #
    965 # Arguments:
    966 # w -				Name of window where key was typed.
    967 # char -			Underlined character to search for;
    968 #				may be either upper or lower case, and
    969 #				will match either upper or lower case.
    970 
    971 proc ::tk::MenuFind {w char} {
    972     set char [string tolower $char]
    973     set windowlist [winfo child $w]
    974 
    975     foreach child $windowlist {
    976 	# Don't descend into other toplevels.
    977         if {[winfo toplevel $w] ne [winfo toplevel $child]} {
    978 	    continue
    979 	}
    980 	if {[winfo class $child] eq "Menu" && \
    981 		[$child cget -type] eq "menubar"} {
    982 	    if {$char eq ""} {
    983 		return $child
    984 	    }
    985 	    set last [$child index last]
    986 	    for {set i [$child cget -tearoff]} {$i <= $last} {incr i} {
    987 		if {[$child type $i] eq "separator"} {
    988 		    continue
    989 		}
    990 		set char2 [string index [$child entrycget $i -label] \
    991 			[$child entrycget $i -underline]]
    992 		if {$char eq [string tolower $char2] || $char eq ""} {
    993 		    if {[$child entrycget $i -state] ne "disabled"} {
    994 			return $child
    995 		    }
    996 		}
    997 	    }
    998 	}
    999     }
   1000 
   1001     foreach child $windowlist {
   1002 	# Don't descend into other toplevels.
   1003         if {[winfo toplevel $w] ne [winfo toplevel $child]} {
   1004 	    continue
   1005 	}
   1006 	switch -- [winfo class $child] {
   1007 	    Menubutton {
   1008 		set char2 [string index [$child cget -text] \
   1009 			[$child cget -underline]]
   1010 		if {$char eq [string tolower $char2] || $char eq ""} {
   1011 		    if {[$child cget -state] ne "disabled"} {
   1012 			return $child
   1013 		    }
   1014 		}
   1015 	    }
   1016 
   1017 	    default {
   1018 		set match [MenuFind $child $char]
   1019 		if {$match ne ""} {
   1020 		    return $match
   1021 		}
   1022 	    }
   1023 	}
   1024     }
   1025     return {}
   1026 }
   1027 
   1028 # ::tk::TraverseToMenu --
   1029 # This procedure implements keyboard traversal of menus.  Given an
   1030 # ASCII character "char", it looks for a menubutton with that character
   1031 # underlined.  If one is found, it posts the menubutton's menu
   1032 #
   1033 # Arguments:
   1034 # w -				Window in which the key was typed (selects
   1035 #				a toplevel window).
   1036 # char -			Character that selects a menu.  The case
   1037 #				is ignored.  If an empty string, nothing
   1038 #				happens.
   1039 
   1040 proc ::tk::TraverseToMenu {w char} {
   1041     variable ::tk::Priv
   1042     if {![winfo exists $w] || $char eq ""} {
   1043 	return
   1044     }
   1045     while {[winfo class $w] eq "Menu"} {
   1046 	if {[$w cget -type] eq "menubar"} {
   1047 	    break
   1048 	} elseif {$Priv(postedMb) eq ""} {
   1049 	    return
   1050 	}
   1051 	set w [winfo parent $w]
   1052     }
   1053     set w [MenuFind [winfo toplevel $w] $char]
   1054     if {$w ne ""} {
   1055 	if {[winfo class $w] eq "Menu"} {
   1056 	    tk_menuSetFocus $w
   1057 	    set Priv(window) $w
   1058 	    SaveGrabInfo $w
   1059 	    grab -global $w
   1060 	    TraverseWithinMenu $w $char
   1061 	} else {
   1062 	    MbPost $w
   1063 	    MenuFirstEntry [$w cget -menu]
   1064 	}
   1065     }
   1066 }
   1067 
   1068 # ::tk::FirstMenu --
   1069 # This procedure traverses to the first menubutton in the toplevel
   1070 # for a given window, and posts that menubutton's menu.
   1071 #
   1072 # Arguments:
   1073 # w -				Name of a window.  Selects which toplevel
   1074 #				to search for menubuttons.
   1075 
   1076 proc ::tk::FirstMenu w {
   1077     variable ::tk::Priv
   1078     set w [MenuFind [winfo toplevel $w] ""]
   1079     if {$w ne ""} {
   1080 	if {[winfo class $w] eq "Menu"} {
   1081 	    tk_menuSetFocus $w
   1082 	    set Priv(window) $w
   1083 	    SaveGrabInfo $w
   1084 	    grab -global $w
   1085 	    MenuFirstEntry $w
   1086 	} else {
   1087 	    MbPost $w
   1088 	    MenuFirstEntry [$w cget -menu]
   1089 	}
   1090     }
   1091 }
   1092 
   1093 # ::tk::TraverseWithinMenu
   1094 # This procedure implements keyboard traversal within a menu.  It
   1095 # searches for an entry in the menu that has "char" underlined.  If
   1096 # such an entry is found, it is invoked and the menu is unposted.
   1097 #
   1098 # Arguments:
   1099 # w -				The name of the menu widget.
   1100 # char -			The character to look for;  case is
   1101 #				ignored.  If the string is empty then
   1102 #				nothing happens.
   1103 
   1104 proc ::tk::TraverseWithinMenu {w char} {
   1105     if {$char eq ""} {
   1106 	return
   1107     }
   1108     set char [string tolower $char]
   1109     set last [$w index last]
   1110     if {$last eq "none"} {
   1111 	return
   1112     }
   1113     for {set i 0} {$i <= $last} {incr i} {
   1114 	if {[catch {set char2 [string index \
   1115 		[$w entrycget $i -label] [$w entrycget $i -underline]]}]} {
   1116 	    continue
   1117 	}
   1118 	if {$char eq [string tolower $char2]} {
   1119 	    if {[$w type $i] eq "cascade"} {
   1120 		$w activate $i
   1121 		$w postcascade active
   1122 		event generate $w <<MenuSelect>>
   1123 		set m2 [$w entrycget $i -menu]
   1124 		if {$m2 ne ""} {
   1125 		    MenuFirstEntry $m2
   1126 		}
   1127 	    } else {
   1128 		MenuUnpost $w
   1129 		uplevel #0 [list $w invoke $i]
   1130 	    }
   1131 	    return
   1132 	}
   1133     }
   1134 }
   1135 
   1136 # ::tk::MenuFirstEntry --
   1137 # Given a menu, this procedure finds the first entry that isn't
   1138 # disabled or a tear-off or separator, and activates that entry.
   1139 # However, if there is already an active entry in the menu (e.g.,
   1140 # because of a previous call to tk::PostOverPoint) then the active
   1141 # entry isn't changed.  This procedure also sets the input focus
   1142 # to the menu.
   1143 #
   1144 # Arguments:
   1145 # menu -		Name of the menu window (possibly empty).
   1146 
   1147 proc ::tk::MenuFirstEntry menu {
   1148     if {$menu eq ""} {
   1149 	return
   1150     }
   1151     tk_menuSetFocus $menu
   1152     if {[$menu index active] ne "none"} {
   1153 	return
   1154     }
   1155     set last [$menu index last]
   1156     if {$last eq "none"} {
   1157 	return
   1158     }
   1159     for {set i 0} {$i <= $last} {incr i} {
   1160 	if {([catch {set state [$menu entrycget $i -state]}] == 0) \
   1161 		&& $state ne "disabled" && [$menu type $i] ne "tearoff"} {
   1162 	    $menu activate $i
   1163 	    GenerateMenuSelect $menu
   1164 	    # Only post the cascade if the current menu is a menubar;
   1165 	    # otherwise, if the first entry of the cascade is a cascade,
   1166 	    # we can get an annoying cascading effect resulting in a bunch of
   1167 	    # menus getting posted (bug 676)
   1168 	    if {[$menu type $i] eq "cascade" && [$menu cget -type] eq "menubar"} {
   1169 		set cascade [$menu entrycget $i -menu]
   1170 		if {$cascade ne ""} {
   1171 		    $menu postcascade $i
   1172 		    MenuFirstEntry $cascade
   1173 		}
   1174 	    }
   1175 	    return
   1176 	}
   1177     }
   1178 }
   1179 
   1180 # ::tk::MenuFindName --
   1181 # Given a menu and a text string, return the index of the menu entry
   1182 # that displays the string as its label.  If there is no such entry,
   1183 # return an empty string.  This procedure is tricky because some names
   1184 # like "active" have a special meaning in menu commands, so we can't
   1185 # always use the "index" widget command.
   1186 #
   1187 # Arguments:
   1188 # menu -		Name of the menu widget.
   1189 # s -			String to look for.
   1190 
   1191 proc ::tk::MenuFindName {menu s} {
   1192     set i ""
   1193     if {![regexp {^active$|^last$|^none$|^[0-9]|^@} $s]} {
   1194 	catch {set i [$menu index $s]}
   1195 	return $i
   1196     }
   1197     set last [$menu index last]
   1198     if {$last eq "none"} {
   1199 	return
   1200     }
   1201     for {set i 0} {$i <= $last} {incr i} {
   1202 	if {![catch {$menu entrycget $i -label} label]} {
   1203 	    if {$label eq $s} {
   1204 		return $i
   1205 	    }
   1206 	}
   1207     }
   1208     return ""
   1209 }
   1210 
   1211 # ::tk::PostOverPoint --
   1212 # This procedure posts a given menu such that a given entry in the
   1213 # menu is centered over a given point in the root window.  It also
   1214 # activates the given entry.
   1215 #
   1216 # Arguments:
   1217 # menu -		Menu to post.
   1218 # x, y -		Root coordinates of point.
   1219 # entry -		Index of entry within menu to center over (x,y).
   1220 #			If omitted or specified as {}, then the menu's
   1221 #			upper-left corner goes at (x,y).
   1222 
   1223 proc ::tk::PostOverPoint {menu x y {entry {}}}  {
   1224     if {$entry ne ""} {
   1225 	if {$entry == [$menu index last]} {
   1226 	    incr y [expr {-([$menu yposition $entry] \
   1227 		    + [winfo reqheight $menu])/2}]
   1228 	} else {
   1229 	    incr y [expr {-([$menu yposition $entry] \
   1230 		    + [$menu yposition [expr {$entry+1}]])/2}]
   1231 	}
   1232 	incr x [expr {-[winfo reqwidth $menu]/2}]
   1233     }
   1234 
   1235     if {[tk windowingsystem] eq "win32"} {
   1236 	# osVersion is not available in safe interps
   1237 	set ver 5
   1238 	if {[info exists ::tcl_platform(osVersion)]} {
   1239 	    scan $::tcl_platform(osVersion) %d ver
   1240 	}
   1241 
   1242 	# We need to fix some problems with menu posting on Windows,
   1243 	# where, if the menu would overlap top or bottom of screen,
   1244 	# Windows puts it in the wrong place for us.  We must also
   1245 	# subtract an extra amount for half the height of the current
   1246 	# entry.  To be safe we subtract an extra 10.
   1247 	# NOTE: this issue appears to have been resolved in the Window
   1248 	# manager provided with Vista and Windows 7.
   1249 	if {$ver < 6} {
   1250 	    set yoffset [expr {[winfo screenheight $menu] \
   1251 		    - $y - [winfo reqheight $menu] - 10}]
   1252 	    if {$yoffset < [winfo vrooty $menu]} {
   1253 		# The bottom of the menu is offscreen, so adjust upwards
   1254 		incr y [expr {$yoffset - [winfo vrooty $menu]}]
   1255 	    }
   1256 	    # If we're off the top of the screen (either because we were
   1257 	    # originally or because we just adjusted too far upwards),
   1258 	    # then make the menu popup on the top edge.
   1259 	    if {$y < [winfo vrooty $menu]} {
   1260 		set y [winfo vrooty $menu]
   1261 	    }
   1262 	}
   1263     }
   1264     $menu post $x $y
   1265     if {$entry ne "" && [$menu entrycget $entry -state] ne "disabled"} {
   1266 	$menu activate $entry
   1267 	GenerateMenuSelect $menu
   1268     }
   1269 }
   1270 
   1271 # ::tk::SaveGrabInfo --
   1272 # Sets the variables tk::Priv(oldGrab) and tk::Priv(grabStatus) to record
   1273 # the state of any existing grab on the w's display.
   1274 #
   1275 # Arguments:
   1276 # w -			Name of a window;  used to select the display
   1277 #			whose grab information is to be recorded.
   1278 
   1279 proc tk::SaveGrabInfo w {
   1280     variable ::tk::Priv
   1281     set Priv(oldGrab) [grab current $w]
   1282     if {$Priv(oldGrab) ne ""} {
   1283 	set Priv(grabStatus) [grab status $Priv(oldGrab)]
   1284     }
   1285 }
   1286 
   1287 # ::tk::RestoreOldGrab --
   1288 # Restores the grab to what it was before TkSaveGrabInfo was called.
   1289 #
   1290 
   1291 proc ::tk::RestoreOldGrab {} {
   1292     variable ::tk::Priv
   1293 
   1294     if {$Priv(oldGrab) ne ""} {
   1295 	# Be careful restoring the old grab, since it's window may not
   1296 	# be visible anymore.
   1297 
   1298 	catch {
   1299 	    if {$Priv(grabStatus) eq "global"} {
   1300 		grab set -global $Priv(oldGrab)
   1301 	    } else {
   1302 		grab set $Priv(oldGrab)
   1303 	    }
   1304 	}
   1305 	set Priv(oldGrab) ""
   1306     }
   1307 }
   1308 
   1309 proc ::tk_menuSetFocus {menu} {
   1310     variable ::tk::Priv
   1311     if {![info exists Priv(focus)] || $Priv(focus) eq ""} {
   1312 	set Priv(focus) [focus]
   1313     }
   1314     focus $menu
   1315 }
   1316 
   1317 proc ::tk::GenerateMenuSelect {menu} {
   1318     variable ::tk::Priv
   1319 
   1320     if {$Priv(activeMenu) eq $menu \
   1321 	    && $Priv(activeItem) eq [$menu index active]} {
   1322 	return
   1323     }
   1324 
   1325     set Priv(activeMenu) $menu
   1326     set Priv(activeItem) [$menu index active]
   1327     event generate $menu <<MenuSelect>>
   1328 }
   1329 
   1330 # ::tk_popup --
   1331 # This procedure pops up a menu and sets things up for traversing
   1332 # the menu and its submenus.
   1333 #
   1334 # Arguments:
   1335 # menu -		Name of the menu to be popped up.
   1336 # x, y -		Root coordinates at which to pop up the
   1337 #			menu.
   1338 # entry -		Index of a menu entry to center over (x,y).
   1339 #			If omitted or specified as {}, then menu's
   1340 #			upper-left corner goes at (x,y).
   1341 
   1342 proc ::tk_popup {menu x y {entry {}}} {
   1343     variable ::tk::Priv
   1344     if {$Priv(popup) ne "" || $Priv(postedMb) ne ""} {
   1345 	tk::MenuUnpost {}
   1346     }
   1347     tk::PostOverPoint $menu $x $y $entry
   1348     if {[tk windowingsystem] eq "x11" && [winfo viewable $menu]} {
   1349         tk::SaveGrabInfo $menu
   1350 	grab -global $menu
   1351 	set Priv(popup) $menu
   1352 	set Priv(window) $menu
   1353 	set Priv(menuActivated) 1
   1354 	tk_menuSetFocus $menu
   1355     }
   1356 }