Xlib and Firefox behavior

This question is ancient but for the benefit of anyone who stumbles across it looking for an answer to this, here’s an edited (chopped to bits) sample of how I solved this based on the hints above:

while (event = xcb_poll_for_event(connection)) {
    uint8_t actual_event = event->response_type & 127;
    switch (actual_event) {
        case XCB_MAP_NOTIFY: ;
            xcb_map_notify_event_t *map_evt = (xcb_map_notify_event_t *)event;
            if (map_evt->override_redirect) {
                xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_transient_for(connection, map_evt->window);
                xcb_window_t transient_for = 0;
                xcb_icccm_get_wm_transient_for_reply(connection, cookie, &transient_for, NULL);
                if (transient_for) {
                    xcb_set_input_focus(connection, XCB_INPUT_FOCUS_POINTER_ROOT, transient_for, XCB_CURRENT_TIME);
                }
                xcb_flush(connection);
            }
            break;
        case XCB_CLIENT_MESSAGE: ;
            xcb_client_message_event_t *message_evt = (xcb_client_message_event_t *)event;
            xcb_get_atom_name_cookie_t name_cookie = xcb_get_atom_name(connection, message_evt->type);
            xcb_get_atom_name_reply_t *name_reply = xcb_get_atom_name_reply(connection, name_cookie, NULL);
            int length = xcb_get_atom_name_name_length(name_reply);
            char *atom_name = malloc(length + 1);
            strncpy(atom_name, xcb_get_atom_name_name(name_reply), length);
            atom_name[length] = '\0';
            free(atom_name);
            free(name_reply);

            if (message_evt->type == ewmh->_NET_WM_STATE) {
                xcb_atom_t atom = message_evt->data.data32[1];
                unsigned int action = message_evt->data.data32[0];
                xcb_get_atom_name_cookie_t name_cookie = xcb_get_atom_name(connection, atom);
                xcb_get_atom_name_reply_t *name_reply = xcb_get_atom_name_reply(connection, name_cookie, NULL);
                int length = xcb_get_atom_name_name_length(name_reply);
                char *atom_name = malloc(length + 1);
                strncpy(atom_name, xcb_get_atom_name_name(name_reply), length);
                atom_name[length] = '\0';
                if (action == XCB_EWMH_WM_STATE_REMOVE) {
                    if (atom == ewmh->_NET_WM_STATE_HIDDEN) {
                        xcb_delete_property(connection, message_evt->window, ewmh->_NET_WM_STATE_HIDDEN);
                    }
                }
                free(atom_name);
                free(name_reply);
            }
            break;
    }
}

By way of explanation, the important events to handle are MapNotify and ClientMessage because there’s two main things that have to be taken care of, the window has to have its hidden state removed on request (the xcb_delete_property call) and the parent window of the transient has to gain input focus (the xcb_set_input_focus call; note that the window that the transient is a transient for gains focus, not the transient itself) or Firefox will immediately hide the transient again.

It also seems to be important for the transients to be stacked above their parent so a WM should respect the ConfigureRequest events.

PS Even if this is the accepted answer, the code of it is for xcb, if you need the code for xlib check my answer below, with the code adapted for xlib, it does cover only the MapNotify event

Leave a Comment