source: branches/1.3/gui/scripts/grab.tcl @ 5045

Last change on this file since 5045 was 4570, checked in by gah, 10 years ago

fix sticky global grab

File size: 4.4 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2# ----------------------------------------------------------------------
3#  COMPONENT: grab - improved version of the Tk grab command
4#
5#  This version of "grab" keeps a stack of grab windows, so one
6#  window can steal and release the grab, and the grab will revert
7#  to the previous window.  If things get jammed up, you can press
8#  <Escape> three times to release the grab.
9# ======================================================================
10#  AUTHOR:  Michael McLennan, Purdue University
11#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
12#
13#  See the file "license.terms" for information on usage and
14#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15# ======================================================================
16package require BLT
17
18namespace eval Rappture { # forward declaration }
19namespace eval Rappture::grab {
20    variable state ""  ;# local ("") or global ("-global") grab
21    variable stack ""  ;# stack of grab windows
22}
23
24proc Rappture::grab::init {} { # used for autoloading this module }
25
26bind all <Escape><Escape><Escape> Rappture::grab::reset
27
28# ----------------------------------------------------------------------
29# USAGE: grab ?-global? <window>
30# USAGE: grab set ?-global? <window>
31# USAGE: grab release <window>
32# USAGE: grab current ?<window>?
33# USAGE: grab status <window>
34#
35# This is a replacement for the usual Tk grab command.  It works
36# exactly the same way, but supports a stack of grab windows, so
37# one window can steal grab from another, and then give it back
38# later.
39# ----------------------------------------------------------------------
40rename grab _tk_grab
41proc grab { args } {
42    set op [lindex $args 0]
43    if {[winfo exists $op]} {
44        set op "set"
45    } elseif {$op == "-global" && [winfo exists [lindex $args end]]} {
46        set op "set"
47    }
48
49    if {$op == "set"} {
50        #
51        # Handle GRAB SET specially.
52        # Add the new grab window to the grab stack.
53        #
54        set state $::Rappture::grab::state
55        set window [lindex $args end]
56
57        if {[lsearch -exact $args -global] >= 0} {
58            set state "-global"
59        }
60
61        if {"" != $state} {
62            # if it's a global grab, store the -global flag away for later
63            set window [linsert $window 0 $state]
64
65            # all grabs from now on are global
66            set ::Rappture::grab::state "-global"
67        }
68
69        # if the window is already on the stack, then skip it
70        if {[string equal [lindex $::Rappture::grab::stack 0] $window]} {
71            return $window
72        }
73
74        # add the current configuration to the grab stack
75        set ::Rappture::grab::stack \
76            [linsert $::Rappture::grab::stack 0 $window]
77
78        return [eval _grabset $window]
79
80    } elseif {$op == "release"} {
81        #
82        # Handle GRAB RELEASE specially.
83        # Release the current grab and grab the next window on the stack.
84        # Note that the current grab is on the top of the stack.  The
85        # next one down is the one we want to revert to.
86        #
87        set window [lindex $::Rappture::grab::stack 1]
88        set ::Rappture::grab::stack [lrange $::Rappture::grab::stack 1 end]
89
90        # release the current grab
91        eval _tk_grab $args
92
93        # and set the next one
94        if {[lindex $window 0] != "-global"} {
95            # no more global grabs -- resume local grabs
96            set ::Rappture::grab::state ""
97        }
98        if { $window != "" } {
99            eval _grabset $window
100        }
101        return ""
102    }
103
104    # perform any other grab operation as usual...
105    return [eval _tk_grab $args]
106}
107
108proc _grabset {args} {
109    # give it 3 tries, if necessary
110    for {set i 0} {$i < 3} {incr i} {
111        set status [catch {eval _tk_grab set $args} result]
112        if {$status == 0} {
113            return $result
114        }
115        after 100; update
116    }
117    # oh well, we tried...
118    return ""
119}
120
121# ----------------------------------------------------------------------
122# USAGE: Rappture::grab::reset
123#
124# Used internally to reset the grab whenever the user presses
125# Escape a bunch of times to break out of the grab.
126# ----------------------------------------------------------------------
127proc Rappture::grab::reset {} {
128    set w [_tk_grab current]
129    if {"" != $w} {
130        _tk_grab release $w
131    }
132    set Rappture::grab::stack ""
133    set Rappture::grab::state ""
134
135    foreach win [blt::busy windows] {
136        blt::busy release $win
137    }
138}
Note: See TracBrowser for help on using the repository browser.