source: trunk/gui/scripts/grab.tcl @ 2586

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