Version 3 of Catching window managed events

Updated 2002-04-03 21:29:49

Toplevels may be closed by several means, including with the X button on top or Alt-F4. Here's example code how to react to this event and have it confirmed. Code for saving files, status, etc. could also go in there (before the exit, of course ;-)

    wm protocol . WM_DELETE_WINDOW {
        if {[tk_messageBox \
                    -icon    question \
                    -type    yesno \
                    -default no \
                    -message "Do you want to go?" \
                    -title   "Quit Application?"] == "yes"} {
            exit
        }
    } ;# DKF - brought here by RS.

Jeffrey Hobbs writes: However, you can do the usual:

    bind . <Destroy> { puts "away I go" }

The advantage with the first (wm protocol .. [L1 ]) is just that you get it before the window goes away (in fact, you have to explicitly have that destroy or it will stay), which means it still exists and you can save info that might still be in the widgets. With the latter, you are already on the way down, but it still works. In the latter you also have to ensure you check on the %W, because <Destroy> will otherwise trigger for all the widgets in .top (bindtags).

DKF - This illustrates quite nicely the difference between trapping a request (what [wm protocol] handles) and a notification (what <Destroy> notices.) By the time the <Destroy> arrives it is too late to veto it - the window in question has already gone the way of the dodo - whereas WM_DELETE_WINDOW is really the window manager saying "Would you mind deleting this window, please?" and as such you can do whatever you want with it. Making it pop up 30 new windows in response is probably not a good move though... :^)

NEM - One point to remember with WM_DELETE_WINDOW though, is to make certain that your code for the handler is completely bug free (or you catch all errors). Otherwise, you can be left with a window that is impossible to close, without forcibly killing the process.


Donal explain that, in such usages as

      wm protocol <window> WM_DELETE_WINDOW {#}

"An empty string is taken as asking for the default behaviour (to destroy the appropriate toplevel.) Workaround is to set the protocol handler to a non-empty do-nothing script (comments are a favourite...)"


The syntax is

      wm protocol window ?name? ?command?

?name? here names "an atom corresponding to a window manager protocol ..." These atoms therefore are dependent on the governing window managers. Among those generally available are

  • WM_SAVE_YOURSELF
  • WM_DELETE_WINDOW
  • WM_TAKE_FOCUS
  • ...

The first three have a historical association with Motif, or ICCCM more specifically.

Note that Tk applications should not register protocol handlers for WM_TAKE_FOCUS or WM_SAVE_YOURSELF. The ICCCM says that clients must respond to WM_SAVE_YOURSELF by updating the WM_COMMAND property on the top-level client window, and Tk does not provide a way to do that. The proper handling of WM_TAKE_FOCUS is very complicated and should be left to the toolkit (it's there to support a seldom-used keyboard focus model; it doesn't apply to Tk programs).

There apparently are not recognized WM_ICONIFY and such; instead, management of iconification is done with the <Map> and <Unmap> events:

    bind . <Unmap> {puts "It was just iconified."}

"wm transientfor ..." can also help with some window managers ...


Also see the FAQ [L2 ].