\documentclass[]{article}
\usepackage{amsmath,graphicx,supertabular,hyperref,tabularx,ifthen}
\title{TIP \#107: Fix the 2-second "raise delay" in Tk}
\date{August 28, 2002}
\author{Joe English}
\urlstyle{sf}
\setlength{\parskip}{1ex}
\setlength{\parindent}{0pt}
\def\tipversion$#1${\texttt{\$#1\$}}
\def\tiplangle#1{\ensuremath{<}}
\def\tiprangle#1{\ensuremath{>}}
\def\tipbar#1{\ensuremath{|}}
\def\tipmail#1#2{\(\langle\){\small\expandafter\url{#1@#2}}\(\rangle\)}
\ifx\pdfoutput\undefined
\newcommand{\tipimage}[2]{\typeout{Make sure you download #1.eps}\ifthenelse{\lengthtest{0.8\textwidth>#2}\and\lengthtest{0pt<#2}}{\includegraphics{#1.eps}}{\includegraphics[width=0.8\textwidth]{#1.eps}}}
\newcommand{\tipxref}[1]{}
\newcommand{\tipxrefend}{}
\else
\newcommand{\tipimage}[2]{\typeout{Make sure you create #1.pdf}\ifthenelse{\lengthtest{0.8\textwidth>#2}\and\lengthtest{0pt<#2}}{\includegraphics{#1.pdf}}{\includegraphics[width=0.8\textwidth]{#1.pdf}}}
\pdfcatalog{/PageMode /UseOutlines}
\newcommand{\tipxref}[1]{\pdfannotlink attr {/C [0.5 0.5 1.0] /Border [0 0 1]} goto name {#1}}
\newcommand{\tipxrefend}{\pdfendlink}
\fi
\newenvironment{tipabstract}{\begin{abstract}}{\end{abstract}}
\begin{document}\maketitle
\begin{center}\begin{tabularx}{\linewidth}{|r@{: }X|}\hline
\textbf{TIP \#107}&\textbf{Fix the 2-second "raise delay" in Tk}\\\hline
Author&

Joe English \tipmail{jenglish}{flightlab.com}
\\
Created&Wednesday, \(\text{28}^{\text{th}}\) August 2002\\
Type&Project\\
Tcl Version&\(8.4\)\\
State&Final\\
Vote&Done\\
Version&\tipversion$Revision: 1.4 $\\
Post History&\\
\hline\end{tabularx}\end{center}
\thispagestyle{empty}\pagestyle{empty}
\begin{tipabstract}

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.
\end{tipabstract}
\tableofcontents\setcounter{page}{0}\clearpage\pagestyle{plain}

\section{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.

\section{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 \cite{tip74}).

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

\section{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 \cite{tip74} --- 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.)

\section{Reference Implementation}

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

\section{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.

\section{Detailed Analysis}

First, some terminology:
\begin{itemize}
\item{}
\textit{toplevel}: a Tk [toplevel] window.
\item{}
\textit{wrapper}: an auxiliary window created by Tk to hold the toplevel and its (optional) menubar. Initially created as a child of the root window.
\item{}
\textit{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.
\item{}
\textit{reparent}: Used as a noun, the immediate parent of a wrapper which has been reparented by a window manager.
\item{}
\textit{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.
\end{itemize}

Next, some methodology:

The correct way to change the stacking order of a client window is to make a \textit{ConfigureRequest} on the client window with \textit{stack\_mode} set appropriately. If the client has not been reparented, then the X server performs the operation directly, and will send a \textit{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 \textit{ConfigureNotify}, for example).

If the client window \textit{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 \textit{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 \textit{sibling} field is also set --- and the client has been reparented, then the \textit{ConfigureRequest} will fail with a \textit{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 \textit{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 \textit{XReconfigureWMWindow()} takes care of all these details.

Now, some archaeology:

Tk 4.0 did not do this: instead, it called \textit{XConfigureWindow()} on the \textit{reparent} window, then waited for a \textit{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 \textit{ConfigureNotify} on the reparent that was not forthcoming.

In Tk 4.1, the (incorrect) call to \textit{XConfigureWindow()} on the reparent was changed to a (correct) call to \textit{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 \textit{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.

\section{Copyright}

This document is hereby placed in the public domain.

\section{Colophon}

\textit{TIP AutoGenerator --- written by Donal K. Fellows}
\begin{thebibliography}{TIP \#1}
\addcontentsline{toc}{section}{References}
\bibitem[TIP \#74]{tip74}
Mo DeJong,
\emph{wm stackorder command},
on-line at \url{http://purl.org/tcl/tip/74.html}
\end{thebibliography}
\end{document}
