TIP #47: Modifying Tk to Allow Writing X Window managers


TIP:47
Title:Modifying Tk to Allow Writing X Window managers
Version:$Revision: 1.9 $
Authors: Neil McKay <mckay at eecs dot umich dot edu>
Andreas Kupries <andreas_kupries at users dot sourceforge dot net>
Donal K. Fellows <fellowsd at cs dot man dot ac dot uk>
State:Final
Type:Project
Tcl-Version:8.4
Vote:Done
Created:Thursday, 19 July 2001

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.

Requirements

Writing X window managers in Tk requires some facilities that the current Tk core doesn't provide. A window manager must be able to:

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's root window, nor can <PropertyNotify> events be received from embedded windows; doing these things requires core modifications.

Root Window Access

The root window is special in many ways:

Because of these properties, access to the root window via a Tk widget presents some difficulties. First, the widget's window cannot be created in the standard way; however, this problem may be solved by providing a non-standard creation routine via the Tk_SetClassProcs procedure described in TIP #5. Likewise, the event handling required by the root window can be enabled in an extension, although some care is required when enabling <ButtonPress> 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 TK_TOP_LEVEL flag. This flag is used to mean different things in different places. In particular, the TK_TOP_LEVEL flag may mean:

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'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 TK_TOP_LEVEL flag with at least two distinct flags. A better idea is to replace the TK_TOP_LEVEL 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 Tk_IsTopLevel macro with several macros, or just eliminate it entirely.

One possible set of flag names is:

TK_TOP_LEVEL

this is a toplevel widget

TK_HAS_WRAPPER

this window has a wrapper window

TK_WIN_MANAGED

this window is controlled by the window manager

TK_TOP_HIERARCHY

this window is at the top of a physical window hierarchy

New Event Bindings and Substitutions

A window manager must be able to intercept certain events on the root window that the standard Tk distribution doesn't recognize, and it must be able to obtain information about those events. In particular, it needs to respond to <CirculateRequest>, <ConfigureRequest>, <CreateNotify>, <MapRequest>, and <ResizeRequest> 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 [bind] command. Adding this facility is very simple.

Obtaining information about these events is also necessary. This is usually done via %-substitutions in the [bind] 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 <CreateNotify> events, and the property name, for handling <PropertyNotify> events. This information could be obtained by adding two new %-substitutions:

%i

substitute the numerical window ID for the event

%P

substitute the atom name for the property being changed

Propagating <PropertyNotify> Events

In order to receive <PropertyNotify> events from embedded windows, the Tk event loop must handle events not just for windows that are represented by Tk_Window structures, but also for their children. One way to accomplish this is to add another flag for the Tk_Window struct, and alter the event loop so that it will also look at a window's parent, if the event is a <PropertyNotify> event. The relevant part of the Tk event loop currently looks like this:

winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow);
if (winPtr == NULL) {
    if (eventPtr->type == PropertyNotify) {
	TkSelPropProc(eventPtr);
    }
    return;
}

If the flag for propagating <PropertyNotify> events is TK_PROP_PROPCHANGE, then the code above must be modified to look approximately like this:

winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow);
if (winPtr == NULL) {
    if (eventPtr->type != PropertyNotify) {
	return;
    }
    TkSelPropProc(eventPtr);
    parentXId = (parent of handlerWindow);
    winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, parentXId);
    if (winPtr == NULL) {
	return;
    }
    if (!(winPtr->flags & TK_PROP_PROPCHANGE)) {
	return;
    }
    handlerWindow = parentXId;
    return;
}

Patches

A patch (against tk8.4a2) that implements the changes described above is available [1].

Notes

Andreas Kupries. There was a ''tkwm' patch once. [2] [3]

Copyright

This document is in the public domain.


Powered by Tcl[Index] [History] [HTML Format] [Source Format] [LaTeX Format] [Text Format] [XML Format] [*roff Format (experimental)] [RTF Format (experimental)]

TIP AutoGenerator - written by Donal K. Fellows