toml@ninja.Solbourne.COM (Tom LaStrange) (04/11/90)
How's this for fun. The following code fails to work with reparenting window managers, it will work fine with uwm or no window manager. Here's what happens: client wm -------- ----- Create two windows, w1 and w2 Map w1 get MapRequest for w1 reparent w1 Map w2 get MapRequest for w2 reparent w2 reparent w1 to w2 server unmaps w1 then reparents get UnmapNotify for w1 typically will reparent w1 to root The net effect is that w1 ends up on the root window someplace rather than as a child of w2. I've verified this problem with the following window managers: swm (was broken, is now fixed) mwm (1.0) olwm twm (R4) I thought all I would have to do is unmap the window before making the reparent request. This would allow the window manager to complete the transition to Withdrawn state before the reparent request is issued. That was the theory, in practice though, the window manager gets around to handling the UnmapNotify event whenever it wakes up, and by then the reparent could have already taken place. Here's the real solution. I think it's something that every reparenting window manager is going to have to do. When you get the UnmapNotify event, do an XQueryTree on whatever window (typically your frame) you think should be the parent. If you don't find the window in the list of children, the window has been reparented someplace else and you shouldn't do an explicit reparent back to the root. I just have one question about all this: Is the reparent guaranteed to have taken place by the time the window manager gets the UnmapNotify? If not, I'm not sure this problem can be reliably solved. Below is an example Xlib program that exhibits the problem. If someone has better solution, or if I'm just missing something, I would love to hear about it. -- Tom LaStrange Solbourne Computer Inc. ARPA: toml@Solbourne.COM 1900 Pike Rd. UUCP: ...!{boulder,sun}!stan!toml Longmont, CO 80501 --------------------------------------------------------------------- #include <stdio.h> #include <signal.h> #include <fcntl.h> #include <X11/Xlib.h> main(argc, argv) int argc; char *argv[]; { Display *dpy; /* which display are we talking to */ int screen; /* the default screen */ Window w1, w2; Window root; long foreground, background; XEvent event; if ((dpy = XOpenDisplay("")) == NULL) { fprintf(stderr, "can't open the display\n"); exit(1); } screen = DefaultScreen(dpy); root = RootWindow(dpy, screen); foreground = BlackPixel(dpy, screen); background = WhitePixel(dpy, screen); w1 = XCreateSimpleWindow(dpy, root, 100, 100, 50, 50, 2, foreground, background); w2 = XCreateSimpleWindow(dpy, root, 100, 100, 100, 100, 2, foreground, background); XSelectInput(dpy, w1, ButtonPressMask); XSelectInput(dpy, w2, ButtonPressMask); XMapWindow(dpy, w1); XMapWindow(dpy, w2); while (True) { XNextEvent(dpy, &event); if (event.type == ButtonPress) { XReparentWindow(dpy, w1, w2, 25, 25); } } }
colas@avahi.inria.fr (Colas Nahaboo) (04/12/90)
In article <1990Apr10.203116.25044@Solbourne.COM>, toml@ninja.Solbourne.COM (Tom LaStrange) writes: |> I've verified this problem with the following window managers: Just for showing off, gwm works. I think the real solution is not to do a costly QueryTree but listen to ReparentNotify events and act sensibly on them. Colas Nahaboo, Bull Research France -- Koala Project -- GWM X11 Window Manager colas@avahi.inria.fr Phone: (33) 93.65.77.70, Fax: (33) 93 65 77 66 INRIA - Sophia Antipolis, 2004, rte des Lucioles, 06565 Valbonne Cedex, FRANCE
rws@EXPO.LCS.MIT.EDU (Bob Scheifler) (04/13/90)
Here's the real solution. I think it's something that every reparenting window manager is going to have to do. When you get the UnmapNotify event, do an XQueryTree on whatever window (typically your frame) you think should be the parent. If you don't find the window in the list of children, the window has been reparented someplace else and you shouldn't do an explicit reparent back to the root. There's a race condition unless the WM does a GrabServer for this. An alternative is that the client is required to notice that the window was reparented by the WM, and when it wants to know the window has been withdrawn, it must wait for the unmap notify and a subsequent reparent notify back to the root, before itself attempting to reparent.