diff --git a/client.c b/client.c index e0cb2b71..8e0dc107 100644 --- a/client.c +++ b/client.c @@ -34,6 +34,7 @@ #include "lua.h" #include "mouse.h" #include "systray.h" +#include "statusbar.h" #include "layouts/floating.h" #include "common/markup.h" #include "common/atoms.h" @@ -457,6 +458,9 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int screen) /* update window title */ client_updatetitle(c); + /* update strut */ + ewmh_client_strut_update(c); + ewmh_update_net_client_list(c->phys_screen); widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); @@ -668,9 +672,7 @@ client_setfullscreen(client_t *c, bool s) xcb_unmap_window(globalconf.connection, c->titlebar->sw->window); c->titlebar->position = Off; } - geometry = screen_area_get(&globalconf.screens[c->screen].geometry, - NULL, - &globalconf.screens[c->screen].padding); + geometry = screen_area_get(c->screen, NULL, &globalconf.screens[c->screen].padding, false); c->m_geometry = c->geometry; c->oldborder = c->border; client_setborder(c, 0); @@ -826,6 +828,12 @@ client_unmanage(client_t *c) xcb_delete_property(globalconf.connection, c->win, _AWESOME_TAGS); xcb_delete_property(globalconf.connection, c->win, _AWESOME_FLOATING); + if(client_hasstrut(c)) + /* All the statusbars (may) need to be repositioned */ + for(int screen = 0; screen < globalconf.screens_info->nscreen; screen++) + for(statusbar_t *s = globalconf.screens[screen].statusbar; s; s = s->next) + statusbar_position_update(s); + /* set client as invalid */ c->invalid = true; diff --git a/client.h b/client.h index 4618fa7f..58a67116 100644 --- a/client.h +++ b/client.h @@ -100,5 +100,26 @@ client_isfloating(client_t *c) || client_isfixed(c)); } +/** Check if a client has strut information. + * \param c A client. + * \return A boolean value, true if the client has strut information. + */ +static inline bool +client_hasstrut(client_t *c) +{ + return (c->strut.left + || c->strut.right + || c->strut.top + || c->strut.bottom + || c->strut.left_start_y + || c->strut.left_end_y + || c->strut.right_start_y + || c->strut.right_end_y + || c->strut.top_start_x + || c->strut.top_end_x + || c->strut.bottom_start_x + || c->strut.bottom_end_x); +} + #endif // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/common/atoms.list b/common/atoms.list index d29a6b8f..a82dd876 100644 --- a/common/atoms.list +++ b/common/atoms.list @@ -9,6 +9,7 @@ _NET_WORKAREA _NET_SUPPORTING_WM_CHECK _NET_CLOSE_WINDOW _NET_WM_NAME +_NET_WM_STRUT_PARTIAL _NET_WM_VISIBLE_NAME _NET_WM_DESKTOP _NET_WM_ICON_NAME diff --git a/event.c b/event.c index 14d6a753..9ce780eb 100644 --- a/event.c +++ b/event.c @@ -217,6 +217,11 @@ event_handle_configurerequest(void *data __attribute__ ((unused)), { client_resize(c, geometry, false); titlebar_draw(c); + if(client_hasstrut(c)) + /* All the statusbars (may) need to be repositioned */ + for(int screen = 0; screen < globalconf.screens_info->nscreen; screen++) + for(statusbar_t *s = globalconf.screens[screen].statusbar; s; s = s->next) + statusbar_position_update(s); } else { @@ -658,6 +663,8 @@ event_handle_propertynotify(void *data __attribute__ ((unused)), client_updatewmhints(c); else if(ev->atom == WM_NAME || ev->atom == _NET_WM_NAME) client_updatetitle(c); + else if(ev->atom == _NET_WM_STRUT_PARTIAL) + ewmh_client_strut_update(c); else if(ev->atom == _NET_WM_ICON) { xcb_get_property_cookie_t icon_q = ewmh_window_icon_get_unchecked(c->win); diff --git a/ewmh.c b/ewmh.c index 2b267a20..67c73519 100644 --- a/ewmh.c +++ b/ewmh.c @@ -32,6 +32,7 @@ #include "widget.h" #include "cnode.h" #include "titlebar.h" +#include "statusbar.h" #include "common/atoms.h" extern awesome_t globalconf; @@ -58,6 +59,7 @@ ewmh_init(int phys_screen) _NET_WORKAREA, _NET_CLOSE_WINDOW, _NET_WM_NAME, + _NET_WM_STRUT_PARTIAL, _NET_WM_ICON_NAME, _NET_WM_VISIBLE_ICON_NAME, _NET_WM_DESKTOP, @@ -213,9 +215,10 @@ ewmh_update_workarea(int phys_screen) { tag_array_t *tags = &globalconf.screens[phys_screen].tags; uint32_t *area = p_alloca(uint32_t, tags->len * 4); - area_t geom = screen_area_get(&globalconf.screens[phys_screen].geometry, + area_t geom = screen_area_get(phys_screen, globalconf.screens[phys_screen].statusbar, - &globalconf.screens[phys_screen].padding); + &globalconf.screens[phys_screen].padding, + true); for(int i = 0; i < tags->len; i++) @@ -435,6 +438,64 @@ ewmh_check_client_hints(client_t *c) p_delete(&reply); } +/** Update the WM strut of a client. + * \param c The client. + */ +void +ewmh_client_strut_update(client_t *c) +{ + void *data; + xcb_get_property_cookie_t strut_q; + xcb_get_property_reply_t *strut_r; + + strut_q = xcb_get_property_unchecked(globalconf.connection, false, c->win, + _NET_WM_STRUT_PARTIAL, CARDINAL, 0, 12); + + strut_r = xcb_get_property_reply(globalconf.connection, strut_q, NULL); + + if(strut_r + && strut_r->value_len + && (data = xcb_get_property_value(strut_r))) + { + uint32_t *strut = data; + + if(c->strut.left != strut[0] + || c->strut.right != strut[1] + || c->strut.top != strut[2] + || c->strut.bottom != strut[3] + || c->strut.left_start_y != strut[4] + || c->strut.left_end_y != strut[5] + || c->strut.right_start_y != strut[6] + || c->strut.right_end_y != strut[7] + || c->strut.top_start_x != strut[8] + || c->strut.top_end_x != strut[9] + || c->strut.bottom_start_x != strut[10] + || c->strut.bottom_end_x != strut[11]) + { + c->strut.left = strut[0]; + c->strut.right = strut[1]; + c->strut.top = strut[2]; + c->strut.bottom = strut[3]; + c->strut.left_start_y = strut[4]; + c->strut.left_end_y = strut[5]; + c->strut.right_start_y = strut[6]; + c->strut.right_end_y = strut[7]; + c->strut.top_start_x = strut[8]; + c->strut.top_end_x = strut[9]; + c->strut.bottom_start_x = strut[10]; + c->strut.bottom_end_x = strut[11]; + + client_need_arrange(c); + /* All the statusbars (may) need to be repositioned */ + for(int screen = 0; screen < globalconf.screens_info->nscreen; screen++) + for(statusbar_t *s = globalconf.screens[screen].statusbar; s; s = s->next) + statusbar_position_update(s); + } + } + p_delete(&strut_r); +} + + /** Send request to get NET_WM_ICON (EWMH) * \param w The window. * \return The cookie associated with the request. diff --git a/ewmh.h b/ewmh.h index 883c8024..29d82a76 100644 --- a/ewmh.h +++ b/ewmh.h @@ -44,6 +44,7 @@ int ewmh_process_client_message(xcb_client_message_event_t *); void ewmh_update_net_client_list_stacking(int); void ewmh_check_client_hints(client_t *); void ewmh_update_workarea(int); +void ewmh_client_strut_update(client_t *); xcb_get_property_cookie_t ewmh_window_icon_get_unchecked(xcb_window_t); netwm_icon_t *ewmh_window_icon_get_reply(xcb_get_property_cookie_t); diff --git a/layouts/fair.c b/layouts/fair.c index 4ecebb4d..ed0e0d5f 100644 --- a/layouts/fair.c +++ b/layouts/fair.c @@ -41,9 +41,10 @@ layout_fair(int screen, const orientation_t orientation) client_t *c; area_t geometry, area; - area = screen_area_get(&globalconf.screens[screen].geometry, + area = screen_area_get(screen, globalconf.screens[screen].statusbar, - &globalconf.screens[screen].padding); + &globalconf.screens[screen].padding, + true); for(c = globalconf.clients ; c; c = c->next) if(IS_TILED(c, screen)) diff --git a/layouts/fibonacci.c b/layouts/fibonacci.c index a59a91c9..3ffbf28e 100644 --- a/layouts/fibonacci.c +++ b/layouts/fibonacci.c @@ -32,9 +32,10 @@ layout_fibonacci(int screen, int shape) int n = 0, i = 0; client_t *c; area_t geometry, area; - geometry = area = screen_area_get(&globalconf.screens[screen].geometry, + geometry = area = screen_area_get(screen, globalconf.screens[screen].statusbar, - &globalconf.screens[screen].padding); + &globalconf.screens[screen].padding, + true); for(c = globalconf.clients; c; c = c->next) if(IS_TILED(c, screen)) diff --git a/layouts/magnifier.c b/layouts/magnifier.c index 0d6aa71e..c10dd33f 100644 --- a/layouts/magnifier.c +++ b/layouts/magnifier.c @@ -34,9 +34,10 @@ layout_magnifier(int screen) int n = 0; client_t *c, *focus; tag_t **curtags = tags_get_current(screen); - area_t geometry, area = screen_area_get(&globalconf.screens[screen].geometry, + area_t geometry, area = screen_area_get(screen, globalconf.screens[screen].statusbar, - &globalconf.screens[screen].padding); + &globalconf.screens[screen].padding, + true); focus = globalconf.screens[screen].client_focus; diff --git a/layouts/max.c b/layouts/max.c index a26c1e4b..f7be2ebc 100644 --- a/layouts/max.c +++ b/layouts/max.c @@ -30,9 +30,10 @@ void layout_max(int screen) { client_t *c; - area_t area = screen_area_get(&globalconf.screens[screen].geometry, + area_t area = screen_area_get(screen, globalconf.screens[screen].statusbar, - &globalconf.screens[screen].padding); + &globalconf.screens[screen].padding, + true); for(c = globalconf.clients; c; c = c->next) if(IS_TILED(c, screen)) diff --git a/layouts/tile.c b/layouts/tile.c index 9088160b..80870062 100644 --- a/layouts/tile.c +++ b/layouts/tile.c @@ -42,9 +42,10 @@ _tile(int screen, const position_t position) client_t *c; tag_t **curtags = tags_get_current(screen); - area = screen_area_get(&globalconf.screens[screen].geometry, + area = screen_area_get(screen, globalconf.screens[screen].statusbar, - &globalconf.screens[screen].padding); + &globalconf.screens[screen].padding, + true); for(n = 0, c = globalconf.clients; c; c = c->next) if(IS_TILED(c, screen)) diff --git a/mouse.c b/mouse.c index 5d4b4bb3..8a279774 100644 --- a/mouse.c +++ b/mouse.c @@ -130,14 +130,16 @@ mouse_snapclient(client_t *c, area_t geometry, int snap) client_t *snapper; area_t snapper_geometry; area_t screen_geometry = - screen_area_get(&globalconf.screens[c->screen].geometry, + screen_area_get(c->screen, globalconf.screens[c->screen].statusbar, - &globalconf.screens[c->screen].padding); + &globalconf.screens[c->screen].padding, + false); area_t screen_geometry_barless = - screen_area_get(&globalconf.screens[c->screen].geometry, + screen_area_get(c->screen, NULL, - &globalconf.screens[c->screen].padding); + &globalconf.screens[c->screen].padding, + false); geometry = titlebar_geometry_add(c->titlebar, c->border, geometry); @@ -745,9 +747,10 @@ mouse_client_resize_tiled(client_t *c) tag = tags_get_current(c->screen)[0]; layout = tag->layout; - area = screen_area_get(&globalconf.screens[tag->screen].geometry, + area = screen_area_get(tag->screen, globalconf.screens[tag->screen].statusbar, - &globalconf.screens[tag->screen].padding); + &globalconf.screens[tag->screen].padding, + true); mouse_query_pointer(screen->root, &mouse_x, &mouse_y, NULL); @@ -848,9 +851,10 @@ mouse_client_resize_magnified(client_t *c, bool infobox) root = xutil_screen_get(globalconf.connection, c->phys_screen)->root; - area = screen_area_get(&globalconf.screens[tag->screen].geometry, + area = screen_area_get(tag->screen, globalconf.screens[tag->screen].statusbar, - &globalconf.screens[tag->screen].padding); + &globalconf.screens[tag->screen].padding, + true); center_x = area.x + (round(area.width / 2.)); center_y = area.y + (round(area.height / 2.)); diff --git a/screen.c b/screen.c index 17dad32f..01a9e23d 100644 --- a/screen.c +++ b/screen.c @@ -36,13 +36,16 @@ extern awesome_t globalconf; * \param screen Screen number. * \param statusbar Statusbar list to remove. * \param padding Padding. + * \param strut Honor windows strut. * \return The screen area. */ area_t -screen_area_get(area_t *geometry, statusbar_t *statusbar, padding_t *padding) +screen_area_get(int screen, statusbar_t *statusbar, + padding_t *padding, bool strut) { - area_t area = *geometry; + area_t area = globalconf.screens[screen].geometry; statusbar_t *sb; + uint16_t top = 0, bottom = 0, left = 0, right = 0; /* make padding corrections */ if(padding) @@ -53,23 +56,68 @@ screen_area_get(area_t *geometry, statusbar_t *statusbar, padding_t *padding) area.height -= padding->top + padding->bottom; } + if(strut) + { + client_t *c; + for(c = globalconf.clients; c; c = c->next) + if(client_isvisible(c, screen)) + { + if(c->strut.top_start_x || c->strut.top_end_x) + { + if(c->strut.top) + top = MAX(top, c->strut.top); + else + top = MAX(top, (c->geometry.y - area.y) + c->geometry.height); + } + if(c->strut.bottom_start_x || c->strut.bottom_end_x) + { + if(c->strut.bottom) + bottom = MAX(bottom, c->strut.bottom); + else + bottom = MAX(bottom, (area.y + area.height) - c->geometry.y); + } + if(c->strut.left_start_y || c->strut.left_end_y) + { + if(c->strut.left) + left = MAX(left, c->strut.left); + else + left = MAX(left, (c->geometry.x - area.x) + c->geometry.width); + } + if(c->strut.right_start_y || c->strut.right_end_y) + { + if(c->strut.right) + right = MAX(right, c->strut.right); + else + right = MAX(right, (area.x + area.width) - c->geometry.x); + } + } + } + + for(sb = statusbar; sb; sb = sb->next) switch(sb->position) { case Top: - area.y += sb->height; + top = MAX(top, (uint16_t) (sb->sw->geometry.y - area.y) + sb->sw->geometry.height); + break; case Bottom: - area.height -= sb->height; + bottom = MAX(bottom, (uint16_t) (area.y + area.height) - sb->sw->geometry.y); break; case Left: - area.x += sb->height; + left = MAX(left, (uint16_t) (sb->sw->geometry.x - area.x) + sb->sw->geometry.width); + break; case Right: - area.width -= sb->height; + right = MAX(right, (uint16_t) (area.x + area.width) - sb->sw->geometry.x); break; default: break; } + area.x += left; + area.y += top; + area.width -= left + right; + area.height -= top + bottom; + return area; } @@ -151,10 +199,10 @@ screen_client_moveto(client_t *c, int new_screen, bool doresize) area_t new_geometry, new_f_geometry; new_f_geometry = c->f_geometry; - to = screen_area_get(&globalconf.screens[c->screen].geometry, - NULL, NULL); - from = screen_area_get(&globalconf.screens[old_screen].geometry, - NULL, NULL); + to = screen_area_get(c->screen, + NULL, NULL, false); + from = screen_area_get(old_screen, + NULL, NULL, false); /* compute new coords in new screen */ new_f_geometry.x = (c->f_geometry.x - from.x) + to.x; @@ -331,7 +379,7 @@ luaA_screen_index(lua_State *L) lua_setfield(L, -2, "height"); break; case A_TK_WORKAREA: - g = screen_area_get(&s->geometry, s->statusbar, &s->padding); + g = screen_area_get(s->index, s->statusbar, &s->padding, true); lua_newtable(L); lua_pushnumber(L, g.x); lua_setfield(L, -2, "x"); diff --git a/screen.h b/screen.h index bad1b150..6c24aec8 100644 --- a/screen.h +++ b/screen.h @@ -26,7 +26,7 @@ #define SCREEN_UNDEF (-1) -area_t screen_area_get(area_t *, statusbar_t *, padding_t *); +area_t screen_area_get(int, statusbar_t *, padding_t *, bool); area_t display_area_get(int, statusbar_t *, padding_t *); int screen_virttophys(int); void screen_client_moveto(client_t *, int, bool); diff --git a/statusbar.c b/statusbar.c index 5a6e0a7a..2d335ed0 100644 --- a/statusbar.c +++ b/statusbar.c @@ -283,9 +283,8 @@ statusbar_position_update(statusbar_t *statusbar) if(statusbar->position == Off) return; - area = screen_area_get(&globalconf.screens[statusbar->screen].geometry, - NULL, - &globalconf.screens[statusbar->screen].padding); + area = screen_area_get(statusbar->screen, NULL, + &globalconf.screens[statusbar->screen].padding, true); /* Top and Bottom statusbar_t have prio */ for(sb = globalconf.screens[statusbar->screen].statusbar; sb; sb = sb->next) diff --git a/structs.h b/structs.h index 7c2a0f5b..805d816d 100644 --- a/structs.h +++ b/structs.h @@ -261,6 +261,16 @@ typedef struct unsigned char *image; } netwm_icon_t; +/* Strut */ +typedef struct +{ + uint16_t left, right, top, bottom; + uint16_t left_start_y, left_end_y; + uint16_t right_start_y, right_end_y; + uint16_t top_start_x, top_end_x; + uint16_t bottom_start_x, bottom_end_x; +} strut_t; + /** client_t type */ struct client_t { @@ -280,6 +290,8 @@ struct client_t int basew, baseh, incw, inch, maxw, maxh, minw, minh; int minax, maxax, minay, maxay; bool hassizehints; + /** Strut */ + strut_t strut; /** Respect resize hints */ bool honorsizehints; int border, oldborder;