5

Currently I am in charge of developing a (C++) window class for a little project; the goal is to keep dependencies at a bare minimum. The implementation for Win32/WinAPI works as supposed, however, I am struggling when it comes to Linux/XCB.

I am aware, that I am able to check the "_NET_WM_STATE" property, however, the documentation doesn't specify any event, which would occur when the window is being maximized or minimized. The Extended Window Manager Hints specification doesn't seem to define a event either.

So, how would one intercept the Maximize/Minimize event?

EDIT: My code looks basically like that, but doesn't work: (By doesn't work, I mean the if-condition below is never met.)

// xcb_generic_event_t* msg;
// xcb_intern_atom_reply_t*    wmStateMinimized;   

case XCB_PROPERTY_NOTIFY: {
    xcb_property_notify_event_t* data{reinterpret_cast<xcb_property_notify_event_t*>(msg)};
    if(data->atom == wmStateMinimized->atom)
        eventQueue.emplace(Event::Minimized);

} break;

I have also checked the atoms the event provides me. They differ from the atom provided by 'wmStateMinimized', altough the atom for 'wmStateMinimized' is provided by the window manager.

EDIT 2: Ok, the xcb_property_notify_event_t supplies the atom that has been change, not the value it self. So the if should look like this then:

if(data->atom == wmState->atom)

Gotta figure out, how to retrieve the value properly.

  • 3
    There is no specific event for maximize/minimize. To watch for property changes you need to subscribe to PropertyNotify events. This is controlled by the PropertyChangeMask. – n. m. could be an AI Jun 01 '16 at 12:31
  • Thanks, just figured it out as well, by printing the event codes my application would get. –  Jun 01 '16 at 12:34
  • AFAIK, in X11 the maximizing-minimizing has been handled by the window manager. In a few X11 apps I wrote, I've never handled it explicitly. Yet, this [SO post](http://stackoverflow.com/questions/4530786/xlib-create-window-in-mimized-or-maximized-state) might be of interest for you to read. – user3078414 Jun 01 '16 at 12:36
  • Looks like I don't understand the specs: "Implementation note: if an Application asks to toggle _NET_WM_STATE_HIDDEN the Window Manager should probably just ignore the request, since _NET_WM_STATE_HIDDEN is a function of some other aspect of the window such as minimization, rather than an independent state." - What does it mean? –  Jun 01 '16 at 13:28
  • 2
    @user3078414 This means that _NET_WM_STATE_HIDDEN doesn't *control* the hidden state, it only *reflects* it. – n. m. could be an AI Jun 01 '16 at 16:15

1 Answers1

7

So, after 3 hours I finally figured it out. This solution snippet assumes, that you already have queried the atoms:

  • _NET_WM_STATE
  • _NET_WM_STATE_HIDDEN
  • _NET_WM_STATE_MAXIMIZED_VERT
  • _NET_WM_STATE_MAXIMIZED_HORZ

They are being stored in the following atoms:

xcb_atom_t wmState;
xcb_atom_t wmStateHidden;
xcb_atom_t wmStateMaxVert;
xcb_atom_t wmStateMaxHorz;

This snippet does as well assume, that you have specified

XCB_EVENT_MASK_PROPERTY_CHANGE

for the window, in order to actually get notified about property changes.

So, let's pretend we're in the Event Loop now:

case XCB_PROPERTY_NOTIFY: {
    xcb_property_notify_event_t* data{reinterpret_cast<xcb_property_notify_event_t*>(msg)};
    if(data->atom == wmState){ // the WM_STATE property was changed.
        // Now we need the value.
        // Therefore I implemented an auxiliary function.
        if(internal::getAtomValue(connection, window, wmState) == wmStateHidden)
            // Handle Events here:
            eventQueue.emplace(Event::Minimized);
        else{
            xcb_atom_t value{internal::getAtomValue(connection, window, wmState)};
            if((value == wmStateMaxVert) || (value == wmStateMaxHorz))
            // Handle Event here
            eventQueue.emplace(Event::Maximized);
        }
    }

} break;

The auxiliary function 'internal::getAtomValue' works as following:

xcb_get_property_cookie_t    cookie{xcb_get_property(connection, false, window, atom, XCB_ATOM_ATOM, 0, 32)};
xcb_generic_error_t*         err{nullptr};
xcb_get_property_reply_t     reply{xcb_get_property_reply(connection, cookie, &err);
xcb_atom_t*                  value{reinterpret_cast<xcb_atom_t*>(xcb_get_property_value(reply))};

I hope that this solution concept proof and correct. May it serve as an reference for everyone, who needs to work with XCB.

P.S.: These Snippets were stripped down from my original source. It might contain Typos.

  • 1
    Please, be so kind to double-check against typos. Both your question and reply are important. Someone else will find your research and sharing this helpful. Thanks. – user3078414 Jun 01 '16 at 18:34