tags:

views:

469

answers:

1

So I'm in a situation where I need to know when a top level window gets created. I'm working at the Xlib/Xt level and on a Window Manager that doesn't support the EWMH specification. My idea is to hook into the root window's SubstructureNotify events. But things are not as simple as just that.

The problem is that not every CreateNotify event corresponds to the creation of a [b]top level[/b] window. So what I think I need to do is test the window I get from the event somehow to confirm that it is a top level window. I've got close, but some spurious windows still make it through my net. For example, in a GTK application if you have a dropdown box and you click it, a new window is created that I can't figure out how to catch and ignore. Such a window is troublesomely indistinguishable from a typical top level application window.

Here's what I have so far:

// I am omiting (tons of) cleanup code and where I set the display and toplevel variables.

Display* display;
Widget toplevel;

bool has_name(Window window)
{
    XTextProperty data = XTextProperty ();
    return (!XGetWMName (display, window, &data));
}

bool has_client_leader(Window window)
{
    unsigned long nitems = 0;
    unsigned char* data = 0;
    Atom actual_type;
    int actual_format;
    unsigned long bytes;
    // WM_CLIENT_LEADER is an interned Atom for the WM_CLIENT_LEADER property
    int status = XGetWindowProperty (display, window, WM_CLIENT_LEADER, 0L, (~0L), False,
     AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes, &data);
    if (status != Success || acutal_type == None) return false;
    Window* leader = reinterpret_cast<Window*> (data);
    return (*leader != 0);
}

bool has_class(Window window)
{
    XClassHint data = XClassHint ();
    return (!GetClassHint (display, window, &data));
}

void handle_event(Widget widget, XtPointer, XEvent* event, Boolean*)
{
    if (event->type != CreateNotify) return;

    Window w = event->xcreatewindow.window;

    // confirm window has a name
    if (!has_name (w)) return;

    // confirm window is a client window
    Window client = XmuClientWindow (display, w);
    if (!client || client != w) return;

    // confirm window has a client leader that is not 0x0
    if (!has_client_leader (client)) return;

    // confirm window has a class
    if (!has_class (client)) return;

    // The window has passed all our checks!
    // Go on to do stuff with the window ...
}

int main(int argc, char* argv[])
{
    // ...

    // Setting up the event handler for SubstructureNotify on root window
    Window root_window = XDefaultRootWindow (display);
    Widget dummy = XtCreateWidget ("dummy", coreWidgetClass, toplevel, 0, 0);
    XtRegisterDrawable (display, root_window, dummy);
    XSelectInput (display, root_window, SubstructureNotifyMask);
    XtAddRawEventHandler (dummy, SubstructureNotifyMask, False, handle_event, 0);

// ...
}

A long shot, but does anyone have any ideas I could try? I can't think of much else I can really do here.

+1  A: 

I assume you're familiar with the ICCCM and its long-winded discussion.

Have you checked the WM_TRANSIENT_FOR property?

Kim Reece
+1 for the pertinent link and hint
neuro