TIP 107: Fix the 2-second "raise delay" in Tk

Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2017 Conference, Houston/TX, US, Oct 16-20
Send your abstracts to tclconference@googlegroups.com
by Aug 21.
Author:		Joe English <jenglish@flightlab.com>
State:		Final
Type:		Project
Created:	28-Aug-2002
Tcl-Version:	8.4
Vote:		Done


This TIP explains the genesis of the long delays often associated with the [raise] and [lower] commands under Unix/X with some window managers, as well as describing the solution.


Currently, Tk's [raise] and [lower] commands do not return to the caller until the operation has completed. Under Unix, the window manager is responsible for changing the stacking order of toplevel windows, so [raise] and [lower] must wait for a notification from the WM before returning. Not all window managers are ICCCM-compliant in this regard, however, so the operation may time out instead.

This two-second "raise delay" has been a longstanding, persistent problem in Tk. It has supposedly been fixed several times, but the problem keeps reoccurring under new window managers and new environments. At present, the problem is most noticeable under KDE 2 and KDE 3.


Change Tk so that [raise] and [lower] return immediately, without waiting for a notification that may not be forthcoming.

This should not be be a controversial change. This behaviour is not documented anywhere, and is not observable by Tk programs except via [wm stackorder] (see [74]).

Moreover, the guarantee is largely meaningless. After [raise] returns, the window contents may still not be visible (there may be pending events, for example), and the actual position in the stacking order is still subject to window manager intervention.

Compatibility Issues

The only Tk programs that would break with this change are ones which expect the return value of [wm stackorder] to reflect the results of any immediately-preceding [raise] and [lower] commands. (The Tk test suite is one such program, and would need to be modified).

Unfortunately there is no reliable way to fix such programs - [update] will not work, and the ICCCM does not, to the author's knowledge, provide a way to synchronize with the window manager to make sure it has processed all outstanding client requests. Even if it did, this wouldn't help - the raise delay problem only occurs under non-compliant window managers to begin with!

Since the stacking order is not observable except through [wm stackorder] - that was the whole point of [74] - no other programs will be affected. (Note that [wm stackorder] will still work: the only difference is that it may return soon-to-be out-of-date information. Since this is the case already - the user may restack or iconify windows at any time - this change should be low-impact.)

Reference Implementation

See Sourceforge Tk Patch #601518. http://sourceforge.net/tracker/index.php?func=detail&aid=601518&group\_id=12997&atid=312997

Author's Note

Could we fast-track this? It's a longstanding problem with a simple fix and ought to make it in before 8.4 goes final.

Detailed Analysis

First, some terminology:

*	_toplevel_: a Tk [toplevel] window.

*	_wrapper_: an auxiliary window created by Tk to hold the
toplevel and its \(optional\) menubar.  Initially created as a
child of the root window.

*	_client window_: From the window manager's perspective, any
window created as a child of the root window by an X client.
Tk wrapper windows are client windows.  Most window managers
reparent client windows under a new frame window which holds
window manager decorations.

*	_reparent_: Used as a noun, the immediate parent of a
wrapper which has been reparented by a window manager.

*	_frame_: The immediate child of the root window \(or virtual
root window\) created by the window manager to hold a client
window and its decorations.  May or may not be the same as the
reparent window.

Next, some methodology:

The correct way to change the stacking order of a client window is to make a ConfigureRequest on the client window with stack_mode set appropriately. If the client has not been reparented, then the X server performs the operation directly, and will send a ConfigureNotify back to the client if, and only if, the actual stacking order has changed. (Raising a window which is already at the top of the stacking order will not result in a ConfigureNotify, for example).

If the client window has been reparented (which is usually the case), then the window manager intercepts the request and, at its discretion, restacks the frame window instead. It then sends a synthetic ConfigureNotify back to the client, regardless of whether or not it honored the request.

If the stacking order is to be changed relative to some other window - that is, if the sibling field is also set - and the client has been reparented, then the ConfigureRequest will fail with a BadMatch error before it gets to the WM. Clients must be prepared to handle this case by catching the error and re-sending a synthetic ConfigureRequest to the root window, which the WM receives and handles as above.

See ICCCM section 4.1.5 "Configuring the Window" for the full specification. The Xlib function XReconfigureWMWindow() takes care of all these details.

Now, some archaeology:

Tk 4.0 did not do this: instead, it called XConfigureWindow() on the reparent window, then waited for a ConfigureNotify on that window.

This was wrong on at least two counts. First, the reparent window might not be the same as the frame window, in which case this would have no effect at all. (In 4DWm and Sawfish, for example, the reparent window is a child of an outer frame window). Second, it's not ICCCM-compliant (Tk doesn't own the reparent window and shouldn't be mucking with it).

Tk 4.0 also included several heuristics that attempted to determine when the operation was unnecessary, to avoid waiting for a ConfigureNotify on the reparent that was not forthcoming.

In Tk 4.1, the (incorrect) call to XConfigureWindow() on the reparent was changed to a (correct) call to XReconfigureWMWindow() on the wrapper, but the old heuristic code was left mostly intact.

Browsing the CVS logs and the older Tk Changelog, we see that this code has been updated several times to account for new conditions, but ultimately without success: the problem persists.

These heuristics are not needed at all under WMs which send a synthetic ConfigureNotify in response to client window stacking order changes. On some non-compliant WMs, however, they may help lessen the problem - more by accident than by design - if the reparent is the same as the frame window then the Tk 4.0 heuristics sometimes still work. But even then the heuristics are not reliable. For instance under KDE 2.2 and KDE 3, calling [raise] twice in succession always results in a 2-second delay.

It is the author's opinion that the only way forward is to let [raise] and [lower] run asynchronously, and fix the two-second raise delay once and for all.


This document is hereby placed in the public domain.