EVALUATION
I've found that the undecorated style of the warning icon window
somehow affects Metacity behavior. Not setting the warning icon
undecorated makes the problem disappear. And here's a native
testcase that 100% reproduces the issue with Metacity 2.16.0:
----------------------------------------------------------------
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
Display *display;
int screen_num;
Window create_window(char *name, Window parent, int x, int y, int width, int height)
{
XSizeHints sh;
XWMHints wmh;
Window win = XCreateSimpleWindow(display, parent, x, y, width, height,
2, // border width
BlackPixel(display, screen_num),
WhitePixel(display, screen_num));
XStoreName(display, win, name);
XSelectInput(display, win, FocusChangeMask | ButtonPressMask | ButtonReleaseMask | StructureNotifyMask );
sh.width = width;
sh.height = height;
sh.x = x;
sh.y = y;
sh.flags = USPosition | USSize;
XSetWMNormalHints(display, win, &sh);
wmh.input = False;
wmh.flags = InputHint;
XSetWMHints(display, win, &wmh);
return win;
}
int main(int argc, char **argv)
{
Atom protocols[1];
Atom XA_WM_TAKE_FOCUS;
Window root;
Window win[2], window;
XEvent ev;
char *win_name;
char *display_name = NULL;
if ((display = XOpenDisplay(display_name)) == NULL)
{
fprintf(stderr, "Couldn't open %s\n", XDisplayName(display_name));
return -1;
}
screen_num = DefaultScreen(display);
root = RootWindow(display, screen_num);
win[0] = create_window("Frame 0", root, 100, 100, 200, 100);
win[1] = create_window("Frame 1", root, 200, 200, 200, 100);
win[2] = create_window("Transient", root, 450, 200, 50, 50);
protocols[0] = XA_WM_TAKE_FOCUS = XInternAtom(display, "WM_TAKE_FOCUS", True);
XSetWMProtocols(display, win[0], protocols, 1);
XSetWMProtocols(display, win[1], protocols, 1);
XSetWMProtocols(display, win[2], NULL, 0);
typedef long CARD32;
typedef struct _mwmhints
{
CARD32 flags;
CARD32 functions;
CARD32 decorations;
CARD32 inputMode;
CARD32 status;
} MWMHints;
long MWM_HINTS_DECORATIONS = (1 << 1);
long PROP_MWM_HINTS_ELEMENTS = 5;
MWMHints mwmhints;
Atom XA_MOTIF_WM_HINTS = XInternAtom(display, "_MOTIF_WM_HINTS", False);
memset(&mwmhints, 0, sizeof(mwmhints));
mwmhints.flags = MWM_HINTS_DECORATIONS;
mwmhints.decorations = 0;
XChangeProperty(display, win[2], XA_MOTIF_WM_HINTS, XA_MOTIF_WM_HINTS, 32,
PropModeReplace, (unsigned char *)&mwmhints,
PROP_MWM_HINTS_ELEMENTS);
XSetTransientForHint(display, win[2], win[1]);
XMapWindow(display, win[0]);
XFlush(display);
XSync(display, False);
while (1)
{
XNextEvent(display, &ev);
window = ev.xany.window;
XFetchName(display, window, &win_name);
if (win_name != 0)
fprintf(stderr, "event on %s: ", win_name);
switch(ev.xany.type)
{
case ClientMessage:
fprintf(stderr, "ClientMessage\n");
if (ev.xclient.data.l[0] == XA_WM_TAKE_FOCUS) {
fprintf(stderr, " WM_TAKE_FOCUS\n");
XSetInputFocus(display, window, RevertToPointerRoot, CurrentTime);
}
break;
case FocusIn:
fprintf(stderr, "FocusIn\n");
break;
case FocusOut:
fprintf(stderr, "FocusOut\n");
break;
case ButtonPress:
fprintf(stderr, "ButtonPress\n");
if (window == win[0]) {
XMapWindow(display, win[1]);
XMapWindow(display, win[2]);
XSetTransientForHint(display, win[2], win[1]);
} else if (window == win[1]) {
XUnmapWindow(display, win[1]);
}
case UnmapNotify:
fprintf(stderr, "UnmapNotify\n");
if (window == win[1]) {
XSetTransientForHint(display, win[2], 0);
XUnmapWindow(display, win[2]);
}
default:
fprintf(stderr, "%d\n", ev.xany.type);
}
}
return 0;
}
----------------------------------------------------------------
To compile it (native.c):
$ gcc native.c -lX11 -o native
By the way, the problem doesn't appear on KWM with this testcase.
|