Partially support _NET_WM_STRUT_PARTIAL.
authorIain Patterson <wm@iain.cx>
Fri, 26 Oct 2012 18:40:55 +0000 (26 11:40 -0700)
committerCarlos R. Mafra <crmafra@gmail.com>
Sun, 28 Oct 2012 10:58:43 +0000 (28 10:58 +0000)
Window Maker already supports the _NET_WM_STRUT property as described
in the EWMH spec.  We respect client-provided struts and avoid placing
or maximizing windows over those areas.  An example is that we don't
try to place or maximize windows where they would be obscured by an
always-on-top gnome-panel.

_NET_WM_STRUT is now deprecated and redefined as a special case of
_NET_WM_STRUT_PARTIAL, which allows variable strut widths.  A panel at
the bottom of the screen, for example, does not have to reserve the
whole width as a strut if it does not fill 100% of the screen width.
By default the XFCE bottom panel does not extend the whole width of
the screen, for instance.

Our method for restricting parts of the screen from placement doesn't
have a way to account for struts which are not 100% tall or 100% wide,
so until now we have ignored partial struts.  In the case of the XFCE
panel mentioned above, the result is that a window may maximize
underneath the panel and be obscured.

As a partial hackaround we now query windows for _NET_WM_STRUT_PARTIAL
but throw away the start and end co-ordinates, assuming instead that
the struts are full-width/full-height.  This trades off a small amount
of wasted placement space to avoid the case where windows can be
partially obscured by panels, which can be particularly annoying if
the panel is at the top and the victim's titlebar becomes hidden.

src/wmspec.c

index 1e70089..4ca8af4 100644 (file)
@@ -859,10 +859,20 @@ static Bool updateStrut(WWindow *wwin, Bool adding)
                unsigned long nitems_ret, bytes_after_ret;
                long *data = NULL;
 
-               if (XGetWindowProperty(dpy, wwin->client_win, net_wm_strut, 0, 4, False,
+               if ((XGetWindowProperty(dpy, wwin->client_win, net_wm_strut, 0, 4, False,
                                       XA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret,
-                                      &bytes_after_ret, (unsigned char **)&data) == Success && data) {
-
+                                      &bytes_after_ret, (unsigned char **)&data) == Success && data) ||
+                   ((XGetWindowProperty(dpy, wwin->client_win, net_wm_strut_partial, 0, 12, False,
+                                      XA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret,
+                                      &bytes_after_ret, (unsigned char **)&data) == Success && data))) {
+
+                       /* XXX: This is strictly incorrect in the case of net_wm_strut_partial...
+                        * Discard the start and end properties from the partial strut and treat it as
+                        * a (deprecated) strut.
+                        * This means we are marking the whole width or height of the screen as
+                        * reserved, which is not necessarily what the strut defines.  However for the
+                        * purposes of determining placement or maximization it's probably good enough.
+                        */
                        area = (WReservedArea *) wmalloc(sizeof(WReservedArea));
                        area->area.x1 = data[0];
                        area->area.x2 = data[1];
@@ -1448,7 +1458,7 @@ void wNETWMCheckClientHintChange(WWindow *wwin, XPropertyEvent *event)
        wmessage("clientHintChange type %s\n", XGetAtomName(dpy, event->atom));
 #endif
 
-       if (event->atom == net_wm_strut) {
+       if (event->atom == net_wm_strut || event->atom == net_wm_strut_partial) {
                updateStrut(wwin, False);
                updateStrut(wwin, True);
                wScreenUpdateUsableArea(wwin->screen_ptr);