<?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 07:50:07 GMT 2012 -->
<!-- TIP AutoGenerator - written by Donal K. Fellows -->

<TIP number='47'>
<header><title>Modifying Tk to Allow Writing X Window managers</title><author address="mailto:mckay@eecs.umich.edu">Neil McKay</author><author address="mailto:andreas_kupries@users.sourceforge.net">Andreas Kupries</author><author address="mailto:fellowsd@cs.man.ac.uk">Donal K. Fellows</author><status type='project' state='final' tclversion="8.4" vote='after'>$Revision: 1.9 $</status><history></history><created day='19' month='jul' year='2001' /></header>
<abstract>With a few modifications to the Tk core, extensions could be written that would allow X window managers to be implemented as Tcl/Tk scripts.</abstract>
<body><section title="Requirements">
<para>Writing X window managers in Tk requires some facilities that the current Tk core doesn&apos;t provide. A window manager must be able to:</para>
<itemize><item.i><para>draw to, and handle events on, the display&apos;s root window (including <emph style="italic">&lt;Create&gt;</emph>, <emph style="italic">&lt;MapRequest&gt;</emph>, <emph style="italic">&lt;ResizeRequest&gt;</emph>, <emph style="italic">&lt;CirculateRequest&gt;</emph>, and <emph style="italic">&lt;ConfigureRequest&gt;</emph> events, which are currently ignored)</para></item.i><item.i><para>embed arbitrary windows inside Tk windows</para></item.i><item.i><para>receive <emph style="italic">&lt;PropertyNotify&gt;</emph> events from embedded windows</para></item.i><item.i><para>perform a variety of other X-specific operations</para></item.i></itemize>
<para>Window embedding can be handled by an extension, if it is not incorporated into the Tk frame widget at some later time. Likewise, the X-specific operations can be handled by an extension. However, Tk as it currently stands cannot access the display&apos;s root window, nor can <emph style="italic">&lt;PropertyNotify&gt;</emph> events be received from embedded windows; doing these things requires core modifications.</para>
</section>
<section title="Root Window Access">
<para>The root window is special in many ways:</para>
<itemize><item.i><para>It does not need to be created</para></item.i><item.i><para>It cannot be destroyed, moved, or resized</para></item.i><item.i><para>Only one process can receive <emph style="italic">&lt;ButtonPress&gt;</emph> and <emph style="italic">&lt;ButtonRelease&gt;</emph> events from it, and only one process can have the <emph style="italic">SubstructureRedirect</emph> and <emph style="italic">ResizeRedirect</emph> masks set</para></item.i><item.i><para>It has no physical parent window</para></item.i></itemize>
<para>Because of these properties, access to the root window via a Tk widget presents some difficulties. First, the widget&apos;s window cannot be created in the standard way; however, this problem may be solved by providing a non-standard creation routine via the <emph style="italic">Tk_SetClassProcs</emph> procedure described in <tipref type="text" tip="5"/>. Likewise, the event handling required by the root window can be enabled in an extension, although some care is required when enabling <emph style="italic">&lt;ButtonPress&gt;</emph> and certain other events. What really causes problems is the lack of a physical parent. There are many places in Tk where it is assumed that only toplevel widgets have no physical parent within the application; this is reflected in the Tk source by the use of the <emph style="italic">TK_TOP_LEVEL</emph> flag. This flag is used to mean different things in different places. In particular, the <emph style="italic">TK_TOP_LEVEL</emph> flag may mean:</para>
<itemize><item.i><para>This window is a toplevel widget</para></item.i><item.i><para>This widget has a wrapper window</para></item.i><item.i><para>This widget&apos;s window is controlled by the window manager</para></item.i><item.i><para>This window is at the top of a physical window hierarchy within the current application</para></item.i></itemize>
<para>In the current version of Tk, toplevel widgets have all of these properties, and no other widgets have any of these properties; hence a single flag suffices. If we create a widget whose window is the display&apos;s root, then this is no longer the case; a root window has the last property, but not the first three. For this reason, it is necessary to replace the <emph style="italic">TK_TOP_LEVEL</emph> flag with at least two distinct flags. A better idea is to replace the <emph style="italic">TK_TOP_LEVEL</emph> flag with four flags, one for each of the properties listed above. (Even in a standard Tk distribution, this replacement is desirable for documentation reasons, since it will indicate what property of a toplevel widget is important in the current circumstances.) We must also replace the <emph style="italic">Tk_IsTopLevel</emph> macro with several macros, or just eliminate it entirely.</para>
<para>One possible set of flag names is:</para>
<describe><item.d name='TK_TOP_LEVEL'><para>this is a toplevel widget</para></item.d><item.d name='TK_HAS_WRAPPER'><para>this window has a wrapper window</para></item.d><item.d name='TK_WIN_MANAGED'><para>this window is controlled by the window manager</para></item.d><item.d name='TK_TOP_HIERARCHY'><para>this window is at the top of a physical window hierarchy</para></item.d></describe>
</section>
<section title="New Event Bindings and Substitutions">
<para>A window manager must be able to intercept certain events on the root window that the standard Tk distribution doesn&apos;t recognize, and it must be able to obtain information about those events. In particular, it needs to respond to <emph style="italic">&lt;CirculateRequest&gt;</emph>, <emph style="italic">&lt;ConfigureRequest&gt;</emph>, <emph style="italic">&lt;CreateNotify&gt;</emph>, <emph style="italic">&lt;MapRequest&gt;</emph>, and <emph style="italic">&lt;ResizeRequest&gt;</emph> events. These events are ignored by standard Tk, and need not be enabled by default; however, they need to be included in the list of events recognized by the Tk <emph style="italic">[bind]</emph> command. Adding this facility is very simple.</para>
<para>Obtaining information about these events is also necessary. This is usually done via %-substitutions in the <emph style="italic">[bind]</emph> command; however, there are two pieces of information that are necessary for implementing a window manager that cannot be obtained via the current %-substitution mechanism: the numerical X window ID, required to handle <emph style="italic">&lt;CreateNotify&gt;</emph> events, and the property name, for handling <emph style="italic">&lt;PropertyNotify&gt;</emph> events. This information could be obtained by adding two new %-substitutions:</para>
<describe><item.d name='%i'><para>substitute the numerical window ID for the event</para></item.d><item.d name='%P'><para>substitute the atom name for the property being changed</para></item.d></describe>
</section>
<section title="Propagating &lt;PropertyNotify&gt; Events">
<para>In order to receive <emph style="italic">&lt;PropertyNotify&gt;</emph> events from embedded windows, the Tk event loop must handle events not just for windows that are represented by <emph style="italic">Tk_Window</emph> structures, but also for their children. One way to accomplish this is to add another flag for the <emph style="italic">Tk_Window</emph> struct, and alter the event loop so that it will also look at a window&apos;s parent, if the event is a <emph style="italic">&lt;PropertyNotify&gt;</emph> event. The relevant part of the Tk event loop currently looks like this:</para>
<verbatim><vline encoding='base64'></vline><vline encoding='base64'>d2luUHRyID0gKFRrV2luZG93ICopIFRrX0lkVG9XaW5kb3coZXZlbnRQdHItPnhhbnkuZGlzcGxheSwgaGFuZGxlcldpbmRvdyk7</vline><vline encoding='base64'>aWYgKHdpblB0ciA9PSBOVUxMKSB7</vline><vline encoding='base64'>ICAgIGlmIChldmVudFB0ci0+dHlwZSA9PSBQcm9wZXJ0eU5vdGlmeSkgew==</vline><vline encoding='base64'>CVRrU2VsUHJvcFByb2MoZXZlbnRQdHIpOw==</vline><vline encoding='base64'>ICAgIH0=</vline><vline encoding='base64'>ICAgIHJldHVybjs=</vline><vline encoding='base64'>fQ==</vline><vline encoding='base64'></vline></verbatim>
<para>If the flag for propagating <emph style="italic">&lt;PropertyNotify&gt;</emph> events is <emph style="italic">TK_PROP_PROPCHANGE</emph>, then the code above must be modified to look approximately like this:</para>
<verbatim><vline encoding='base64'></vline><vline encoding='base64'>d2luUHRyID0gKFRrV2luZG93ICopIFRrX0lkVG9XaW5kb3coZXZlbnRQdHItPnhhbnkuZGlzcGxheSwgaGFuZGxlcldpbmRvdyk7</vline><vline encoding='base64'>aWYgKHdpblB0ciA9PSBOVUxMKSB7</vline><vline encoding='base64'>ICAgIGlmIChldmVudFB0ci0+dHlwZSAhPSBQcm9wZXJ0eU5vdGlmeSkgew==</vline><vline encoding='base64'>CXJldHVybjs=</vline><vline encoding='base64'>ICAgIH0=</vline><vline encoding='base64'>ICAgIFRrU2VsUHJvcFByb2MoZXZlbnRQdHIpOw==</vline><vline encoding='base64'>ICAgIHBhcmVudFhJZCA9IChwYXJlbnQgb2YgaGFuZGxlcldpbmRvdyk7</vline><vline encoding='base64'>ICAgIHdpblB0ciA9IChUa1dpbmRvdyAqKSBUa19JZFRvV2luZG93KGV2ZW50UHRyLT54YW55LmRpc3BsYXksIHBhcmVudFhJZCk7</vline><vline encoding='base64'>ICAgIGlmICh3aW5QdHIgPT0gTlVMTCkgew==</vline><vline encoding='base64'>CXJldHVybjs=</vline><vline encoding='base64'>ICAgIH0=</vline><vline encoding='base64'>ICAgIGlmICghKHdpblB0ci0+ZmxhZ3MgJiBUS19QUk9QX1BST1BDSEFOR0UpKSB7</vline><vline encoding='base64'>CXJldHVybjs=</vline><vline encoding='base64'>ICAgIH0=</vline><vline encoding='base64'>ICAgIGhhbmRsZXJXaW5kb3cgPSBwYXJlbnRYSWQ7</vline><vline encoding='base64'>ICAgIHJldHVybjs=</vline><vline encoding='base64'>fQ==</vline><vline encoding='base64'></vline></verbatim>
</section>
<section title="Patches">
<para>A patch (against tk8.4a2) that implements the changes described above is available [<url ref="http://www.eecs.umich.edu/~mckay/computer/wmenablers.84a3.patch.gz"/>].</para>
</section>
<section title="Notes">
<para><emph style="italic">Andreas Kupries.</emph> There was a &apos;&apos;tkwm&apos; patch once. [<url ref="http://www.neosoft.com/tcl/ftparchive/sorted/x11/tkwm/"/>] [<url ref="http://www.ensta.fr/internet/unix/window_managers/tkwm.html"/>]</para>
</section>
<section title="Copyright">
<para>This document is in the public domain.</para>
</section>
</body></TIP>

