[comp.windows.x] Pseudoroots & Window Managers

ken@richsun.UUCP (Ken Marks) (12/15/88)

Before I start, I know pseudoroot support is not a very popular issue with the
Consortium and Yes, I have read the source which is peppered with warnings.
Yet, the fact remains the company I work for needs to run sub-window managers.
While the underlying mechanisms and even the public interface to pseudoroots
may (and most likely will) change, the decision has been made to use/test the
pseudoroot support and update as the mechanism changes.  With this disclaimer
out of the way, I would like to point out some of the interesting consequences
of using pseudoroots in real-world cases.

So far as I have tested, virtually all R3 clients will run as expected within a
pseudoroot by by simply specifying the pseudoroot in the display parameter,
such as:

	xpseudoroot psroot1 &
	xclock -display unix:0.0.psroot1 &

The interesting stuff happens when you start running clients which tend to be
much more aware of the root they are running on.  The largest single class of
these clients are window managers.  (Slight irony here since pseudoroots are 
most useful when they are running sub-window managers.)  I have spent some time
modifying the RTL window manager so that it will run under a pseudoroot.  The
following is a list of the things a window manager (or any client, really) 
might do that will cause problems.  I have not included actual source code
diffs since they are only hacks to RTL which might not be necessary in later
releases of the pseudoroot implementation.

1) One of the things that every reparenting window manager will do is to to 
call XQueryTree on the root window so that it may reparent the top level 
windows (children of the root).  RTL stores the window which it believes to be 
the root in a global variable called "root".  The following call to XQueryTree 
trashes the variable "root" leaving it pointing to the real root window:

XQueryTree(dpy, root, &root, &parent, &children, &nchildren)
		      ^^^^^

Creating a separate Window variable to store the return value of the real root 
fixes this for pseudoroots.

XQueryTree(dpy, root, &real_root, &parent, &children, &nchildren)
		      ^^^^^^^^^^
Any function such as XQueryTree or XGetGeometry which passes back the value
of the real root should be checked to make sure it does not inadvertently use
the value returned for the root.


2) Window managers which do such things as pop-up menus, will generally make
use of the XQueryPointer function.  RTL calls this function with the pseudoroot
as the window used to report coordinated relative to.  The return values are
the pointer location relative to this window and relative to the root (the
real root).  The window relative coordinates should be used here.  This was
kludged in RTL by simply reversing the sets of return coordinates. This 
kludge still allows RTL to run on the real root since both sets of coords
returned are identical in that case.

3) One of the more interesting problems lies with events such as ButtonPress
which report back the pointer location relative to the root (x_root & y_root).
Generally clients are more interested in the window relative coordinates.
Window managers, however, might use this (as does RTL) to determine where to
pop-up a menu.  This is in many respects similar to (2) above.  The best 
client-size fix (kludge) is to detect the case where the root coordinates are
not being reported relative to what you consider to be the root and translate
the coordinates using XTranslateCoordinates as in the following code exerpt:

#ifdef OLD_WAY
	current_pos.x = ev->xbutton.x_root;
	current_pos.y = ev->xbutton.y_root;
#else
        if (ev->xbutton.root != root)
            XTranslateCoordinates(dpy, ev->xbutton.root, root,
                                  ev->xbutton.x_root, ev->xbutton.y_root,
                                  &(current_pos.x), &(current_pos.y), &child);
#endif

Since this involves server round trips on every button/key press, a nicer
method (from the client's point of view) would be to have the events sent to
the client with the root set to the pseudoroot and the root coords relative to
this window.  Admittedly, we're talking server hacking here, but if pseudoroots
are ever to gain equal status with other "real" roots, changes would be needed
in this area.

4) While digging through the server code to see where changes would have to be
made to better fix the above kludge, I came across the function 
FixUpEventFromWindow in server/dix/events.c.  This function fills in the root
field as well as the window relative coordinates.  It seemed to me that if
I could tell that the root of the window that this event was going to be sent 
to was a pseudoroot, then the value filled in for the root field could be
the pseudoroot and the root relative coordinates could be adjusted.  This
turned out not to be possible since the window believes its root to be the
real root.  This can be shown by doing an XQueryTree from a top level window 
being run under a pseudoroot.  This is the result of an assumption made when
the window was first created.  In function CreateWindow of server/dix/window.c,
the child's drawable is copied from the parent's drawable.  This assumes, the
child window must be on the same root as the parent.  Normally a valid 
assumption, but not so in the case of children of a pseudoroot.  The root of
the pseudoroot window is the real root - but the root of its children should
be the pseudoroot itself.  At this point I gave up.

5) Window manages will now have to add StructureNotifyMask to the XSelectInput
call for the root (pseudoroot) window.  In the past window managers did not
have to worry about the root window changing size.  Now they have to catch
ConfigureNotify events and determine if the pseudoroot dimensions have changed.
The new dimensions must be copied into any "desktop size" variables that the 
window manager might be keeping.  An interesting kludge was made here.  The RTL
code would use the macros DisplayWidth and DisplayHeight to bounds test during
the placement of a popup menu.  The display structure accessed in the macros
does not get updated when the pseudoroot changes size so it must be updated
manually if the macros are expected to report the correct sizes.  Since the
display macros are indeed macros and not functions, they can conveniently be
used as the lhs of an assignment.  Thus the following code is valid:

	DisplayWidth(dpy, scrn) = ev.xconfigure.width;
        DisplayHeight(dpy, scrn) = ev.xconfigure.height;


6) A stickier problem which I am still fighting with is specific to the
tiling nature of RTL.  Each client may specify max and min window sizes using
profiles.  If not specified for a particular client, these values are taken
from reasonable defaults.  It is reasonable to set the max size to the size
of the root window.  Reasonable, that is, until the root window changes size!


I hope this rather long winded presentation of my work with pseudoroots and
window managers will be of some help to others interested in making window
managers run in pseudoroots and to the Consortium who will be ultimately 
responsible for setting new pseudoroot conventions.

================================================================================
Ken Marks              ken@richsun.UUCP           Rich, inc.  - A REUTER company
================================================================================

jim@EXPO.LCS.MIT.EDU (Jim Fulton) (12/17/88)

> [note on pseudoroots]

It's nice to see that people are experimenting with pseudoroots, but the
warning bears repeating.  Please make sure that you don't count on them.  They
have been removed from the ICCCM and the trial support in Xlib and the
xpseudoroot program will go away in R4.  The eventual goal will be to provide a
server extension that will allow normally-coded clients to work properly in
pseudoroots (but this isn't even in the kitchen yet, let alone on the back
burner). 

							Jim Fulton
							MIT X Consortium

aud%hplaki@HPLABS.HP.COM (audrey ishizaki) (12/17/88)

ken,

I have also successfully implemented pseudo-root functionality (X11R2,
HP machines).

I did not like having to change source code in already written client
programs, so I implemented many of the changes you made in the Xlib
code itself.  This has worked well enough to have twm, wm, uwm and
hpwm run without changes.

One problem I have not been able to overcome (in Xlib) is deciding which
screen (yes, a multi-screen implementation) certain events originated on.
Of course, I also limited myself to changing things ONLY in Xlib.

I'm sure David Rosenthal and Jim Fulton will be interested in your work
(as they were in mine).  I now agree with them that to do a good pseudo
root implementation, one has to have access to the server.  Alternatively,
one can change window managers (the only class of clients, so far, which
is interested in roots, and x and y w/r to root) to understand which sub
window they should be running in (and there seem to be only 5-6 widely
used window managers).

keep in touch; I'm glad you posted your findings.

audrey ishizaki		ishizaki@hplabs.hp.com

rws@EXPO.LCS.MIT.EDU (Bob Scheifler) (12/17/88)

You've managed to point out a number of the problems that
have led us to believe that the current implementation of
Pseudoroots is inadequate, and that server support (perhaps
along the lines of a chroot request) is desirable but somewhat
complex at first glance (we haven't gotten around to a second
glance yet).

    Thus the following code is valid:
    DisplayWidth(dpy, scrn) = ev.xconfigure.width;
    DisplayHeight(dpy, scrn) = ev.xconfigure.height;

No, this code is rather invalid.  There is no guarantee that this
will work in all Xlib implementations.