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.