c++x11xcb

Programmatically minimise window with XCB


I'm currently writing the linux-side windowing for my game engine, and I wanted to have an option to programmatically minimise/restore the window.

I decided to use XCB and not Xlib, and since I have wrote almost the entire thing now, I don't want to back. What I tried (based on the successful maximising implementation) is to send a client event with _NET_WM_STATE set to _NET_WM_STATE_HIDDEN. The code looks like so:

xcb_intern_atom_reply_t* _net_wm_state = xcb_intern_atom_reply(connection, xcb_intern_atom(connection, true, strlen("_NET_WM_STATE"), "_NET_WM_STATE"), nullptr);
xcb_intern_atom_reply_t* _net_wm_state_hidden = xcb_intern_atom_reply(connection, xcb_intern_atom(connection, true, strlen("_NET_WM_STATE_HIDDEN"), "_NET_WM_STATE_HIDDEN"), nullptr);

// Some code here...

xcb_client_message_data_t data{};
data.data32[0] = true; // yes, I want to minimise the window
data.data32[1] = _net_wm_state_hidden->atom;

xcb_client_message_event_t event{};
event.response_type = XCB_CLIENT_MESSAGE;
event.format = 32;
event.window = windowHandle;
event.type = _net_wm_state;
event.data = data;

xcb_send_event(connection, true, windowHandle, XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (char*)&event);
xcb_flush(connection);

For maximising and entering/exiting fullscreen I used basically the same code just with different atoms. Those work, but this does not.


Solution

  • In X11, minimizing a window has nothing to do with _NET_WM_STATE_HIDDEN. Instead, you need to send XCB_ICCCM_WM_STATE_ICONIC.

    It should be something like this:

    xcb_intern_atom_reply_t* wm_change_state = xcb_intern_atom_reply(connection, xcb_intern_atom(connection, true, strlen("WM_CHANGE_STATE"), "WM_CHANGE_STATE"), nullptr);
    
    xcb_client_message_data_t data{};
    data.data32[0] = XCB_ICCCM_WM_STATE_ICONIC;
    
    xcb_client_message_event_t event{};
    event.response_type = XCB_CLIENT_MESSAGE;
    event.format = 32;
    event.window = windowHandle;
    event.type = wm_change_state->atom;
    event.data = data;
    
    xcb_send_event(connection, false, windowHandle, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (char*)&event);
    xcb_flush(connection);
    
    free(wm_change_state);