<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE TIP SYSTEM "http://tcl.activestate.com/cgi-bin/tct/tip/tipxml.dtd">
<!-- Converted at Thu Feb 09 08:23:49 GMT 2012 -->
<!-- TIP AutoGenerator - written by Donal K. Fellows -->

<TIP number='74'>
<header><title>wm stackorder command</title><author address="mailto:mdejong@users.sourceforge.net">Mo DeJong</author><status type='project' state='final' tclversion="8.4" vote='after'>$Revision: 1.6 $</status><history></history><created day='12' month='nov' year='2001' /></header>
<abstract>Tk provides no means to query the stacking order of toplevel windows. This functionality would be useful to applications that wished to save and restore the state and relative order of each toplevel. This functionality would also make it possible to write test cases for window manager related commands like focus, raise, and lower. This document suggests a new <emph style="italic">wm stackorder</emph> command to address this deficiency.</abstract>
<body><section title="Specification">
<verbatim><vline encoding='base64'>d20gc3RhY2tvcmRlciB3aW5kb3cgP2lzYWJvdmV8aXNiZWxvdz8gP3dpbmRvdz8=</vline></verbatim>
<para>The following would return a list of all the toplevels on the display:</para>
<verbatim><vline encoding='base64'>JSB3bSBzdGFja29yZGVyIC4=</vline></verbatim>
<para>The returned list would include the passed in window and its children. Only those toplevel windows that are mapped would be returned. The stacking order is from lowest to highest, so the last element in the list is the window on top of the display.</para>
<para>The <emph style="italic">wm stackorder</emph> command could also be used to compare the relative position in the stackorder. The following command would return true if <emph style="italic">.a</emph> was higher in the stacking order compared to <emph style="italic">.b</emph>.</para>
<verbatim><vline encoding='base64'>JSB3bSBzdGFja29yZGVyIC5hIGlzYWJvdmUgLmI=</vline></verbatim>
<para>The <emph style="italic">isbelow</emph> usage is analogous:</para>
<verbatim><vline encoding='base64'>JSB3bSBzdGFja29yZGVyIC5iIGlzYmVsb3cgLmE=</vline></verbatim>
<para>One additional C API would be added. It would accept a Tk window and return an array of Tk windows in stacking order. This function would be implemented in the platform specific window manager code, such as <emph style="italic">tkUnixWm.c</emph>. This function signature is subject to change.</para>
<verbatim><vline encoding='base64'>VGtXaW5kb3cgKiogVGtXbVN0YWNrb3JkZXJUb3BsZXZlbChUa1dpbmRvdyAqcGFyZW50UHRyKTs=</vline></verbatim>
</section>
<section title="Rationale">
<para>Tk exposes a number of features related to toplevel windows through the <emph style="italic">wm</emph> command. While a user can set the relative position of a toplevel in the stacking order, it is not currently possible to query the stacking order for toplevel windows.</para>
<para>Users are frustrated by the lack of access to this information. This is a posting to <url ref="news:comp.lang.tcl"/> by Jim Ingham is typical:</para>
<quote><emph style="italic">This seems pretty basic, but for the life of me I can&apos;t figure out how to determine the stacking order of Tk toplevels. I want to save away the currently open windows in my application, and I would like to preserve both positions </emph>and<emph style="italic"> window stacking order. I know how to get the positions of toplevels, but I can&apos;t figure out how to get the window manager&apos;s stacking order. Should be in the </emph>wm<emph style="italic"> commands, but nothing leaps out at me. What am I missing?</emph></quote>
<para>It is simply not logical to provide a means to manipulate the stacking order of toplevel windows without also providing a way to query the stacking order. This functionality is needed, if only to help with the authoring of test cases. For example, one could verify that a call to <emph style="italic">wm raise</emph> actually worked by checking to see if the stacking order was changed.</para>
<para>The second form of the wm stackorder command provides an easy way to compare the relative position of windows in the stacking order. This sort of boolean check is commonly needed in test cases. One could implement the same logic by querying the whole list, searching it twice to find the indices, and then comparing the indices, but the code would not be as easy to understand and it would not be as efficient.</para>
<para>The <emph style="italic">wm stackorder</emph> command also has an extra benefit, it provides an easy way to query the currently mapped toplevel windows. It is not difficult to write a procedure that recursively descends through each window and filters out those windows that are not mapped toplevels. This <emph style="italic">wm stackorder</emph> command would just make it easier to query this list.</para>
</section>
<section title="Reference Implementation">
<para>A reference implementation has been created for X windows and Win32 systems. The X version makes us of the <emph style="italic">XQueryTree()</emph> function while the Windows version depends on the <emph style="italic">EnumWindows()</emph> Win32 API. Both implementations query the stacking order of toplevel windows in the root window. The patch, test cases, and documentation changes can be found in Tk patch 481148 at SourceForge. Porting to MacOS and MacOS X will require assistance from area maintainers.</para>
</section>
<section title="Alternatives">
<para>Instead of adding a new <emph style="italic">wm stackorder</emph> command, one could adjust the behavior of <emph style="italic">winfo children</emph>. The documentation currently reads:</para>
<describe><item.d name='winfo children window'><para> Returns a list containing the path names of all the children of window. The list is in stacking order, with the lowest window first. Top-level windows are returned as children of their logical parents.</para></item.d></describe>
<para>A user would no doubt conclude that the stacking order was maintained for both toplevels and contained widgets. Unfortunately, the implementation only tracks the stacking order for contained widgets.</para>
<verbatim><vline encoding='base64'>JSB0b3BsZXZlbCAudA==</vline><vline encoding='base64'>JSBwYWNrIFtidXR0b24gLnQuYjFd</vline><vline encoding='base64'>JSBwYWNrIFtidXR0b24gLnQuYjJd</vline><vline encoding='base64'>JSB3aW5mbyBjaGlsZHJlbiAudA==</vline><vline encoding='base64'>LnQuYjEgLnQuYjI=</vline><vline encoding='base64'>JSByYWlzZSAudC5iMQ==</vline><vline encoding='base64'>JSB3aW5mbyBjaGlsZHJlbiAudA==</vline><vline encoding='base64'>LnQuYjIgLnQuYjE=</vline></verbatim>
<para>Tk does not track stacking order changes for toplevels.</para>
<verbatim><vline encoding='base64'>JSB0b3BsZXZlbCAudDI=</vline><vline encoding='base64'>JSB3aW5mbyBjaGlsZHJlbiAu</vline><vline encoding='base64'>LnQgLnQy</vline><vline encoding='base64'>JSByYWlzZSAudA==</vline><vline encoding='base64'>JSB3aW5mbyBjaGlsZHJlbiAu</vline><vline encoding='base64'>LnQgLnQy</vline></verbatim>
<para>There are two possible ways to &quot;fix&quot; the <emph style="italic">winfo children</emph> command so that it would return toplevels in stacking order. One could call the <emph style="italic">TkWmStackorderToplevel()</emph> function and use the results to sort any toplevels that would be returned by <emph style="italic">winfo children</emph>. The other option would be to resort the <emph style="italic">TkWindow-&gt;childList</emph> as toplevels are moved up and down in the stacking order.</para>
<para>Both of these alternatives have some serious implementation issues. The <emph style="italic">TkWmStackorderToplevel()</emph> function is very slow. The X based implementation recurses through each window in the Tk hierarchy to create a mapping of wrapper window ids to <emph style="italic">TkWindow</emph>s. The function then queries the X server to find each X window that is a child of the root screen and checks to see if the window exists in the mapping. When compared to <emph style="italic">winfo children</emph>, which just loops over an in-memory list, it is easy to see why <emph style="italic">wm stackorder</emph> is so much slower.</para>
<verbatim><vline encoding='base64'>JSBmb3Ige3NldCBpIDB9IHskaSA8IDEwfSB7aW5jciBpfSB7dG9wbGV2ZWwgLnQkaX0=</vline><vline encoding='base64'>JSB0aW1lIHt3aW5mbyBjaGlsZHJlbiAufSAxMDA=</vline><vline encoding='base64'>MzQgbWljcm9zZWNvbmRzIHBlciBpdGVyYXRpb24=</vline><vline encoding='base64'>JSB0aW1lIHt3bSBzdGFja29yZGVyIC59IDEwMA==</vline><vline encoding='base64'>Mzk0IG1pY3Jvc2Vjb25kcyBwZXIgaXRlcmF0aW9u</vline></verbatim>
<para>It would not be wise to make the <emph style="italic">winfo children</emph> command an order of magnitude slower just to add a new capability. One also needs to remember that the <emph style="italic">winfo children</emph> command is often used recursively, so any slowdown would be multiplied by the depth of the window hierarchy.</para>
<para>The second option would be to keep the <emph style="italic">TkWindow-&gt;childList</emph> sorted as toplevels are raised and lowered either by the application or the window manager. This would imply binding to the &lt;Circulate&gt; event under X. While the &lt;Circulate&gt; event is defined in Tk, it does not seem to actually be delivered by the window manager. In any event, this seems like an area ripe for incompatibility and error.</para>
<para>Even if one of the above fixes for the <emph style="italic">winfo children</emph> command was doable, it still would not satisfy user&apos;s needs. One would be able to compare the relative stacking order of two toplevels that have the same parent.</para>
<verbatim><vline encoding='base64'>JSB0b3BsZXZlbCAudDE=</vline><vline encoding='base64'>JSB0b3BsZXZlbCAudDI=</vline><vline encoding='base64'>JSB3aW5mbyBjaGlsZHJlbiAu</vline><vline encoding='base64'>ey50MSAudDJ9</vline></verbatim>
<para>Unfortunately, it would not be possible to compare the stacking order of two toplevel windows that have different parents.</para>
<verbatim><vline encoding='base64'>JSB0b3BsZXZlbCAudDE=</vline><vline encoding='base64'>JSB0b3BsZXZlbCAudDEudDI=</vline><vline encoding='base64'>IyBObyBoZWxwIGhlcmUh</vline><vline encoding='base64'>JSB3aW5mbyBjaGlsZHJlbiAu</vline><vline encoding='base64'>LnQx</vline><vline encoding='base64'>JSB3aW5mbyBjaGlsZHJlbiAudDE=</vline><vline encoding='base64'>LnQxLnQy</vline></verbatim>
<para>It would not even be possible to query the position of the . window in the stacking order since it does not have a parent window that can be passed to <emph style="italic">winfo children</emph>.</para>
<para>Since modifying <emph style="italic">winfo children</emph> could cause some serious problems and would ultimately be ineffective, this alternative was rejected. Instead, the documentation for the <emph style="italic">winfo children</emph> command should be updated to indicate that toplevel windows are not returned in stacking order.</para>
</section>
<section title="Risks">
<para>It is not entirely clear what risks would be associated with this TIP. The logic of the <emph style="italic">wm stackorder</emph> command is rather insulated from the rest of the Tk core. Changing the implementation of <emph style="italic">Tk_RestackWindow()</emph> and keeping the <emph style="italic">TkWindow-&gt;childList</emph> up to date w.r.t. external changes would be more risky since it could affect other parts of the core. Doing an explicit query to find the stacking order seems a lot less error prone when compared to monitoring events from the window manager. We might speed things up by also storing wrapper pointers in the map table so that a call to <emph style="italic">Tk_IdToWindow()</emph> with a wrapper id would work, but it is not clear that would help since the <emph style="italic">XQueryTree()</emph> likely takes up most of the function processing time.</para>
<para>It is also not known how difficult or costly this functionality will be to implement on Mac OS, or Mac OS X.</para>
</section>
<section title="Copyright">
<para>This document has been placed in the public domain.</para>
</section>
</body></TIP>

