Updated 2014-01-25 15:24:05 by dkf
wm protocol window ?name? ?command?

This command is used to manage window manager protocols such as WM_DELETE_WINDOW. Name is the name of an atom corresponding to a window manager protocol, such as WM_DELETE_WINDOW or WM_SAVE_YOURSELF or WM_TAKE_FOCUS. If both name and command are specified, then command is associated with the protocol specified by name. Name will be added to window 's WM_PROTOCOLS property to tell the window manager that the application has a protocol handler for name, and command will be invoked in the future whenever the window manager sends a message to the client for that protocol. In this case the command returns an empty string. If name is specified but command isn't, then the current command for name is returned, or an empty string if there is no handler defined for name. If command is specified as an empty string then the current handler for name is deleted and it is removed from the WM_PROTOCOLS property on window; an empty string is returned. Lastly, if neither name nor command is specified, the command returns a list of all the protocols for which handlers are currently defined for window.

Tk always defines a protocol handler for WM_DELETE_WINDOW, even if you haven't asked for one with wm protocol. If a WM_DELETE_WINDOW message arrives when you haven't defined a handler, then Tk handles the message by destroying the window for which it was received.

Use:
   wm protocol <window> WM_DELETE_WINDOW {#}

to prevent your window from closing when the [X] button is clicked.

More on this subject appears under the title "Catching window managed events".

Joe English wrote in c.l.t:

Q. Is there a way of getting a list of available protocols for wm protocol? The man pages only list the obvious / common ones (WM_DELETE_WINDOW, WM_SAVE_YOURSELF, and WM_TAKE_FOCUS).

A. Those are the only three defined by the ICCCM; the freedesktop.org [EWMH] spec also defines _NET_WM_PING.

Note that WM_SAVE_YOURSELF is deprecated, and Tk apps can't implement WM_TAKE_FOCUS or _NET_WM_PING correctly, so WM_DELETE_WINDOW is the only one that should be used.

DKF: Tk now handles _NET_WM_PING for you by itself in the correct way; you'll never see this one at the script level. (The purpose of the protocol is to let other clients — especially a window manager or session manager — determine positively whether the application is processing events. That puts its implementation correctly buried in the guts of Tk.)

An example of use of WM_DELETE_WINDOW and chk_exit (thanks MG!)
wm protocol . WM_DELETE_WINDOW chk_exit

MG 16th Feb 2005 - What this actually does, as far as I understand it, is set the command that's run when the operating system/window manager asks your Tcl program to destroy the window . (with the default being to just destroy the window and, if the window is . (the main toplevel) and you're running wish not tclsh, to exit the app). This means that you can do something like...
  wm protocol . WM_DELETE_WINDOW chk_exit
  proc chk_exit {} {
    set ans [tk_messageBox -type yesno -icon question -message "Are you sure you want to quit?"]
    if { $ans != "no" } {
         exit
       }
  };# chk_exit

You do need to be careful with this, however; if your chk_exit proc (or whatever you call it) never runs the exit command, either because you don't tell it to or because it encounters an error before it reaches it, you cannot exit your app without killing the process.

(As for actually making a command/proc behave like another, interp alias {} function {} proc will create an alias called function for the proc command (as long as there isn't a command called function already). And rename proc function will simply change the name of the command, so 'proc' will no longer exist.)

MHo 12-Nov-2008: What if I start a long loop including updates inside the chk_exit (or whatever name), and I want to prevent the user from closing the window (=interrupting the loop)? If I use wm protocol . WM_DELETE_WINDOW {#} inside the handler, it seems that the first few clicks on the magic X are ignored, but Pressing Alt+F4 or other methods or further clicks on X do end the program... MHo Solved. Using update instead of update idletasks a little more often leads to the expected behaviour.