TIP:		107
Title:		Fix the 2-second "raise delay" in Tk
Version:	$Revision: 1.4 $
Author:		Joe English <jenglish@flightlab.com>
State:		Final
Type:		Project
Created:	28-Aug-2002
Tcl-Version:	8.4
Vote:		Done
Post-History:	

~ Abstract

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.

~ Rationale

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.

~ Proposal

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 <Expose> 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.

~ Copyright

This document is hereby placed in the public domain.
