From 6e199bbd7608a16d563f9174556b317dcb9ca3d6 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 12 Dec 2008 00:01:43 +0100 Subject: [PATCH] client, swindow: switch to a more convient definition of geometry - In many places i see people correcting for border width and titlebars. - This new definition is the equivilant of what used to be fullgeometry. - The internal geometry is now contained to a few functions that few people ever touch. - This should avoid confusion and make code easier. - Also protect against several unsigned overflows. Signed-off-by: Maarten Maathuis Signed-off-by: Julien Danjou --- awesomerc.lua.in | 2 +- client.c | 129 ++++++++++--------------- common/util.h | 8 ++ lib/awful/layout/suit/fair.lua.in | 5 +- lib/awful/layout/suit/magnifier.lua.in | 12 +-- lib/awful/layout/suit/max.lua.in | 6 +- lib/awful/layout/suit/tile.lua.in | 30 +++--- lib/awful/menu.lua.in | 14 +-- lib/awful/mouse.lua.in | 18 ++-- lib/awful/placement.lua.in | 11 +-- lib/awful/titlebar.lua.in | 12 +-- lib/naughty.lua.in | 6 +- structs.h | 2 + swindow.c | 62 ++++++++---- swindow.h | 5 + titlebar.c | 34 +++---- titlebar.h | 28 +++--- wibox.c | 14 +-- 18 files changed, 198 insertions(+), 200 deletions(-) diff --git a/awesomerc.lua.in b/awesomerc.lua.in index 70f834fd..a4086a4b 100644 --- a/awesomerc.lua.in +++ b/awesomerc.lua.in @@ -393,7 +393,7 @@ awful.hooks.arrange.register(function (screen) -- Uncomment if you want mouse warping --[[ if client.focus then - local c_c = client.focus:fullgeometry() + local c_c = client.focus:geometry() local m_c = mouse.coords() if m_c.x < c_c.x or m_c.x >= c_c.x + c_c.width or diff --git a/client.c b/client.c index 029bac19..26d6636d 100644 --- a/client.c +++ b/client.c @@ -174,8 +174,8 @@ client_ban(client_t *c) { /* Move all clients out of the physical viewport into negative coordinate space. */ /* They will all be put on top of each other. */ - uint32_t request[2] = { - (c->geometry.width + 2 * c->border), - - (c->geometry.height + 2 * c->border) }; + uint32_t request[2] = { - (c->geometries.internal.width + 2 * c->border), + - (c->geometries.internal.height + 2 * c->border) }; xcb_configure_window(globalconf.connection, c->win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, @@ -475,8 +475,13 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int phys_screen, c->win = w; c->geometry.x = wgeom->x; c->geometry.y = wgeom->y; - c->geometry.width = wgeom->width; - c->geometry.height = wgeom->height; + c->geometry.width = wgeom->width + 2 * wgeom->border_width; + c->geometry.height = wgeom->height + 2 * wgeom->border_width; + /* Also set internal geometry (client_ban() needs it). */ + c->geometries.internal.x = wgeom->x; + c->geometries.internal.y = wgeom->y; + c->geometries.internal.width = wgeom->width; + c->geometries.internal.height = wgeom->height; client_setborder(c, wgeom->border_width); if((icon = ewmh_window_icon_get_reply(ewmh_icon_cookie))) c->icon = image_ref(&icon); @@ -674,8 +679,11 @@ client_geometry_hints(client_t *c, area_t geometry) if(c->size_hints.flags & (XCB_SIZE_HINT_P_RESIZE_INC | XCB_SIZE_HINT_BASE_SIZE) && c->size_hints.width_inc && c->size_hints.height_inc) { - geometry.width -= (geometry.width - basew) % c->size_hints.width_inc; - geometry.height -= (geometry.height - baseh) % c->size_hints.height_inc; + uint16_t t1 = geometry.width, t2 = geometry.height; + unsigned_subtract(t1, basew); + unsigned_subtract(t2, baseh); + geometry.width -= t1 % c->size_hints.width_inc; + geometry.height -= t2 % c->size_hints.height_inc; } return geometry; @@ -690,42 +698,52 @@ void client_resize(client_t *c, area_t geometry, bool hints) { int new_screen; + area_t geometry_internal; area_t area; - if(hints) - geometry = client_geometry_hints(c, geometry); - - if(geometry.width <= 0 || geometry.height <= 0) - return; - /* offscreen appearance fixes */ area = display_area_get(c->phys_screen, NULL, &globalconf.screens[c->screen].padding); if(geometry.x > area.width) - geometry.x = area.width - geometry.width - 2 * c->border; + geometry.x = area.width - geometry.width; if(geometry.y > area.height) - geometry.y = area.height - geometry.height - 2 * c->border; - if(geometry.x + geometry.width + 2 * c->border < 0) + geometry.y = area.height - geometry.height; + if(geometry.x + geometry.width < 0) geometry.x = 0; - if(geometry.y + geometry.height + 2 * c->border < 0) + if(geometry.y + geometry.height < 0) geometry.y = 0; - if(c->geometry.x != geometry.x - || c->geometry.y != geometry.y - || c->geometry.width != geometry.width - || c->geometry.height != geometry.height) + /* Real client geometry, please keep it contained to C code at the very least. */ + geometry_internal = titlebar_geometry_remove(c->titlebar, c->border, geometry); + + if(hints) + geometry_internal = client_geometry_hints(c, geometry_internal); + + if(geometry_internal.width == 0 || geometry_internal.height == 0) + return; + + /* Also let client hints propegate to the "official" geometry. */ + geometry = titlebar_geometry_add(c->titlebar, c->border, geometry_internal); + + if(c->geometries.internal.x != geometry_internal.x + || c->geometries.internal.y != geometry_internal.y + || c->geometries.internal.width != geometry_internal.width + || c->geometries.internal.height != geometry_internal.height) { - new_screen = screen_getbycoord(c->screen, geometry.x, geometry.y); + new_screen = screen_getbycoord(c->screen, geometry_internal.x, geometry_internal.y); /* Values to configure a window is an array where values are * stored according to 'value_mask' */ uint32_t values[4]; - c->geometry.x = values[0] = geometry.x; - c->geometry.y = values[1] = geometry.y; - c->geometry.width = values[2] = geometry.width; - c->geometry.height = values[3] = geometry.height; + c->geometries.internal.x = values[0] = geometry_internal.x; + c->geometries.internal.y = values[1] = geometry_internal.y; + c->geometries.internal.width = values[2] = geometry_internal.width; + c->geometries.internal.height = values[3] = geometry_internal.height; + + /* Also store geometry including border and titlebar. */ + c->geometry = geometry; titlebar_update_geometry(c); @@ -734,15 +752,15 @@ client_resize(client_t *c, area_t geometry, bool hints) /* This at least doesn't break expectations about events. */ if (c->isbanned) { - geometry.x = values[0] = - (geometry.width + 2 * c->border); - geometry.y = values[1] = - (geometry.height + 2 * c->border); + geometry.x = values[0] = - (geometry_internal.width + 2 * c->border); + geometry.y = values[1] = - (geometry_internal.height + 2 * c->border); } xcb_configure_window(globalconf.connection, c->win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); - window_configure(c->win, geometry, c->border); + window_configure(c->win, geometry_internal, c->border); screen_client_moveto(c, new_screen, true, false); @@ -846,10 +864,6 @@ client_setmaxhoriz(client_t *c, bool s) &globalconf.screens[c->screen].wiboxes, &globalconf.screens[c->screen].padding, true); - /* Remove space needed for titlebar and border. */ - geometry = titlebar_geometry_remove(c->titlebar, - c->border, - geometry); geometry.y = c->geometry.y; geometry.height = c->geometry.height; c->geometries.max.x = c->geometry.x; @@ -890,10 +904,6 @@ client_setmaxvert(client_t *c, bool s) &globalconf.screens[c->screen].wiboxes, &globalconf.screens[c->screen].padding, true); - /* Remove space needed for titlebar and border. */ - geometry = titlebar_geometry_remove(c->titlebar, - c->border, - geometry); geometry.x = c->geometry.x; geometry.width = c->geometry.width; c->geometries.max.y = c->geometry.y; @@ -1006,12 +1016,12 @@ client_unban(client_t *c) if(c->isbanned) { /* Move the client back where it belongs. */ - uint32_t request[2] = { c->geometry.x, c->geometry.y }; + uint32_t request[2] = { c->geometries.internal.x, c->geometries.internal.y }; xcb_configure_window(globalconf.connection, c->win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, request); - window_configure(c->win, c->geometry, c->border); + window_configure(c->win, c->geometries.internal, c->border); /* Do this manually because the system doesn't know we moved the toolbar. * Note that !isvisible titlebars are unmapped and for fullscreen it'll @@ -1347,11 +1357,13 @@ luaA_client_unmanage(lua_State *L) /** Return client geometry. * \param L The Lua VM state. - * \param full Use titlebar also. * \return The number of elements pushed on stack. + * \luastack + * \lparam A table with new coordinates, or none. + * \lreturn A table with client coordinates. */ static int -luaA_client_handlegeom(lua_State *L, bool full) +luaA_client_geometry(lua_State *L) { client_t **c = luaA_checkudata(L, 1, "client"); @@ -1373,48 +1385,12 @@ luaA_client_handlegeom(lua_State *L, bool full) geometry.height = luaA_getopt_number(L, 2, "height", (*c)->geometry.height); } - if(full) - geometry = titlebar_geometry_remove((*c)->titlebar, - (*c)->border, - geometry); - client_resize(*c, geometry, (*c)->size_hints_honor); } - if(full) - return luaA_pusharea(L, titlebar_geometry_add((*c)->titlebar, - (*c)->border, - (*c)->geometry)); - return luaA_pusharea(L, (*c)->geometry); } -/** Return client geometry. - * \param L The Lua VM state. - * \return The number of elements pushed on stack. - * \luastack - * \lparam A table with new coordinates, or none. - * \lreturn A table with client coordinates. - */ -static int -luaA_client_geometry(lua_State *L) -{ - return luaA_client_handlegeom(L, false); -} - -/** Return client geometry, using also titlebar and border width. - * \param L The Lua VM state. - * \return The number of elements pushed on stack. - * \luastack - * \lparam A table with new coordinates, or none. - * \lreturn A table with client coordinates. - */ -static int -luaA_client_fullgeometry(lua_State *L) -{ - return luaA_client_handlegeom(L, true); -} - /** Client newindex. * \param L The Lua VM state. * \return The number of elements pushed on stack. @@ -1955,7 +1931,6 @@ const struct luaL_reg awesome_client_meta[] = { { "isvisible", luaA_client_isvisible }, { "geometry", luaA_client_geometry }, - { "fullgeometry", luaA_client_fullgeometry }, { "buttons", luaA_client_buttons }, { "tags", luaA_client_tags }, { "kill", luaA_client_kill }, diff --git a/common/util.h b/common/util.h index 483c0969..7869a969 100644 --- a/common/util.h +++ b/common/util.h @@ -72,6 +72,14 @@ typedef struct #define MAX(a,b) ((a) < (b) ? (b) : (a)) #define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define unsigned_subtract(a, b) \ + do { \ + if (b > a) \ + a = 0; \ + else \ + a -= b; \ + } while (0) + #define ssizeof(foo) (ssize_t)sizeof(foo) #define countof(foo) (ssizeof(foo) / ssizeof(foo[0])) diff --git a/lib/awful/layout/suit/fair.lua.in b/lib/awful/layout/suit/fair.lua.in index 6b879fb3..9b078e60 100644 --- a/lib/awful/layout/suit/fair.lua.in +++ b/lib/awful/layout/suit/fair.lua.in @@ -52,10 +52,7 @@ local function fair(screen, orientation) g.y = wa.y + cell * g.height end - g.width = g.width - 2 * c.border_width - g.height = g.height - 2 * c.border_width - - c:fullgeometry(g) + c:geometry(g) cell = cell + 1 if cell == cells then diff --git a/lib/awful/layout/suit/magnifier.lua.in b/lib/awful/layout/suit/magnifier.lua.in index 72f2763c..062ac8f2 100644 --- a/lib/awful/layout/suit/magnifier.lua.in +++ b/lib/awful/layout/suit/magnifier.lua.in @@ -55,10 +55,10 @@ local function magnifier(_, screen) else geometry.x = area.x geometry.y = area.y - geometry.width = area.width - 2 * focus.border_width - geometry.height = area.height - 2 * focus.border_width + geometry.width = area.width + geometry.height = area.height end - focus:fullgeometry(geometry) + focus:geometry(geometry) focus:raise() if #cls - 1 > 0 then @@ -69,11 +69,7 @@ local function magnifier(_, screen) for k, c in ipairs(cls) do if c ~= focus then - geometry.height = geometry.height - 2 * c.border_width - geometry.width = geometry.width - 2 * c.border_width - c:fullgeometry(geometry) - geometry.height = geometry.height + 2 * c.border_width - geometry.width = geometry.width + 2 * c.border_width + c:geometry(geometry) geometry.y = geometry.y + geometry.height end end diff --git a/lib/awful/layout/suit/max.lua.in b/lib/awful/layout/suit/max.lua.in index cc95cf58..f3455c76 100644 --- a/lib/awful/layout/suit/max.lua.in +++ b/lib/awful/layout/suit/max.lua.in @@ -27,11 +27,7 @@ local function fmax(screen, fs) for k, c in pairs(client.visible(screen)) do if not client.floating.get(c) then - area.width = area.width - 2 * c.border_width - area.height = area.height - 2 * c.border_width - c:fullgeometry(area) - area.width = area.width + 2 * c.border_width - area.height = area.height + 2 * c.border_width + c:geometry(area) end end end diff --git a/lib/awful/layout/suit/tile.lua.in b/lib/awful/layout/suit/tile.lua.in index e703f100..1d04d3af 100644 --- a/lib/awful/layout/suit/tile.lua.in +++ b/lib/awful/layout/suit/tile.lua.in @@ -87,8 +87,8 @@ local function tile(_, screen, position) geometry.y = wa.y end - geometry.width = mw - 2 * c.border_width - geometry.height = mh - 2 * c.border_width + geometry.width = mw + geometry.height = mh -- Slave windows else @@ -98,52 +98,52 @@ local function tile(_, screen, position) if position == "right" or position == "left" then if otherwin <= real_ncol then - geometry.height = wa.height - 2 * c.border_width + geometry.height = wa.height elseif (otherwin % win_by_col) ~= 0 and (current_col == real_ncol - 1) then - geometry.height = math.floor(wa.height / (otherwin % win_by_col)) - 2 * c.border_width + geometry.height = math.floor(wa.height / (otherwin % win_by_col)) else - geometry.height = math.floor(wa.height / win_by_col) - 2 * c.border_width + geometry.height = math.floor(wa.height / win_by_col) end - geometry.width = math.floor((wa.width - mw) / real_ncol) - 2 * c.border_width + geometry.width = math.floor((wa.width - mw) / real_ncol) if otherwin <= real_ncol then geometry.y = wa.y else geometry.y = wa.y + ((i - 1 - nmaster) % win_by_col) * - (geometry.height + 2 * c.border_width) + geometry.height end - geometry.x = wa.x + current_col * (geometry.width + 2 * c.border_width) + geometry.x = wa.x + current_col * geometry.width if position == "right" then geometry.x = geometry.x + mw end else if otherwin <= real_ncol then - geometry.width = wa.width - 2 * c.border_width + geometry.width = wa.width elseif (otherwin % win_by_col) ~= 0 and (current_col == real_ncol - 1) then - geometry.width = math.floor(wa.width / (otherwin % win_by_col)) - 2 * c.border_width + geometry.width = math.floor(wa.width / (otherwin % win_by_col)) else - geometry.width = math.floor(wa.width / win_by_col) - 2 * c.border_width + geometry.width = math.floor(wa.width / win_by_col) end - geometry.height = math.floor((wa.height - mh) / real_ncol) - 2 * c.border_width + geometry.height = math.floor((wa.height - mh) / real_ncol) if otherwin <= real_ncol then geometry.x = wa.x else geometry.x = wa.x + ((i - 1 - nmaster) % win_by_col) * - (geometry.width + 2 * c.border_width) + geometry.width end - geometry.y = wa.y + current_col * (geometry.height + 2 * c.border_width) + geometry.y = wa.y + current_col * geometry.height if position == "bottom" then geometry.y = geometry.y + mh end end end - c:fullgeometry(geometry) + c:geometry(geometry) end end diff --git a/lib/awful/menu.lua.in b/lib/awful/menu.lua.in index 0949dc5b..6a19df19 100644 --- a/lib/awful/menu.lua.in +++ b/lib/awful/menu.lua.in @@ -199,19 +199,19 @@ local function set_coords(menu, screen_idx) menu.w = menu.parent.w menu.h = menu.parent.h - local p_w = (menu.h + menu.theme.border_width) * (menu.num - 1) - local m_h = menu.theme.border_width + (menu.h + menu.theme.border_width) * #menu.items - local m_w = menu.w + menu.theme.border_width + local p_w = menu.h * (menu.num - 1) + local m_h = menu.h * #menu.items + local m_w = menu.w menu.y = menu.parent.y + p_w + m_h > screen_h and screen_h - m_h or menu.parent.y + p_w - menu.x = menu.parent.x + menu.w*2 + menu.theme.border_width > screen_w and menu.parent.x - m_w or menu.parent.x + m_w + menu.x = menu.parent.x + menu.w > screen_w and menu.parent.x - m_w or menu.parent.x + m_w else local m_coords = capi.mouse.coords() menu.y = m_coords.y < s_geometry.y and s_geometry.y or m_coords.y menu.x = m_coords.x < s_geometry.x and s_geometry.x or m_coords.x - local m_h = menu.theme.border_width + (menu.h + menu.theme.border_width) * #menu.items - local m_w = menu.w + menu.theme.border_width*2 + local m_h = menu.h * #menu.items + local m_w = menu.w menu.y = menu.y + m_h > screen_h and screen_h - m_h or menu.y menu.x = menu.x + m_w > screen_w and screen_w - m_w or menu.x end @@ -227,7 +227,7 @@ function show(menu) width = menu.w, height = menu.h, x = menu.x, - y = menu.y + (num - 1) * (menu.h + menu.theme.border_width) + y = menu.y + (num - 1) * menu.h }) item.screen = screen_index end diff --git a/lib/awful/mouse.lua.in b/lib/awful/mouse.lua.in index 79bb0046..e5c84c07 100644 --- a/lib/awful/mouse.lua.in +++ b/lib/awful/mouse.lua.in @@ -86,8 +86,8 @@ end function client.snap(c, snap, x, y, fixed_x, fixed_y) local snap = snap or 8 local c = c or client.focus - local cur_geom = c:fullgeometry() - local geom = c:fullgeometry() + local cur_geom = c:geometry() + local geom = c:geometry() geom.x = x or geom.x geom.y = y or geom.y @@ -96,7 +96,7 @@ function client.snap(c, snap, x, y, fixed_x, fixed_y) for k, snapper in ipairs(aclient.visible(c.screen)) do if snapper ~= c then - geom = snap_outside(geom, snapper:fullgeometry(), snap) + geom = snap_outside(geom, snapper:geometry(), snap) end end @@ -124,7 +124,7 @@ function client.move(c, snap) c:raise() - local orig = c:fullgeometry() + local orig = c:geometry() local m_c = capi.mouse.coords() local dist_x = m_c.x - orig.x local dist_y = m_c.y - orig.y @@ -134,7 +134,7 @@ function client.move(c, snap) local function ug(c, prop) if prop == "geometry" then - local g = c:fullgeometry() + local g = c:geometry() capi.mouse.coords({ x = g.x + dist_x, y = g.y + dist_y }) end end @@ -147,7 +147,7 @@ function client.move(c, snap) if lay == layout.suit.floating or aclient.floating.get(c) then local x = mouse.x - dist_x local y = mouse.y - dist_y - c:fullgeometry(client.snap(c, snap, x, y, fixed_x, fixed_y)) + c:geometry(client.snap(c, snap, x, y, fixed_x, fixed_y)) if layout.get(c.screen) ~= layout.suit.floating and not aclient.floating.get(c) then hooks.property.register(ug) end @@ -389,9 +389,9 @@ local function client_resize_floating(c, corner, fixed_x, fixed_y) end if ng.width <= 0 then ng.width = nil end if ng.height <= 0 then ng.height = nil end - if fixed_x then ng.width = width end - if fixed_y then ng.height = height end - c:geometry({ width = ng.width, height = ng.height }) + if fixed_x then ng.width = g.width ng.x = g.x end + if fixed_y then ng.height = g.height ng.y = g.y end + c:geometry(ng) -- Get real geometry that has been applied -- in case we honor size hints -- XXX: This should be rewritten when size diff --git a/lib/awful/placement.lua.in b/lib/awful/placement.lua.in index f75fed58..56217f5c 100644 --- a/lib/awful/placement.lua.in +++ b/lib/awful/placement.lua.in @@ -101,7 +101,7 @@ end --- Place the client without it being outside the screen. -- @param c The client. function no_offscreen(c) - local geometry = c:fullgeometry() + local geometry = c:geometry() local screen_geometry = capi.screen[c.screen].workarea if geometry.x + geometry.width > screen_geometry.x + screen_geometry.width then @@ -116,7 +116,7 @@ function no_offscreen(c) geometry.y = screen_geometry.y end - c:fullgeometry(geometry) + c:geometry(geometry) end --- Place the client where there's place available with minimum overlap. @@ -126,10 +126,9 @@ function no_overlap(c) local layout = layout.get() local areas = { capi.screen[c.screen].workarea } local geometry = c:geometry() - local fullgeometry = c:fullgeometry() for i, cl in pairs(cls) do if cl ~= c and (client.get.floating(cl) or layout == layout.suit.floating) then - areas = area_remove(areas, cl:fullgeometry()) + areas = area_remove(areas, cl:geometry()) end end @@ -137,8 +136,8 @@ function no_overlap(c) local found = false local new = { x = geometry.x, y = geometry.y, width = 0, height = 0 } for i, r in ipairs(areas) do - if r.width >= fullgeometry.width - and r.height >= fullgeometry.height + if r.width >= geometry.width + and r.height >= geometry.height and r.width * r.height > new.width * new.height then found = true new = r diff --git a/lib/awful/titlebar.lua.in b/lib/awful/titlebar.lua.in index 93b89270..b2de82d0 100644 --- a/lib/awful/titlebar.lua.in +++ b/lib/awful/titlebar.lua.in @@ -113,12 +113,12 @@ function add(c, args) closef = closef, close = close } -- Store old geometry (including borders) - local old_geom = c:fullgeometry() + local old_geom = c:geometry() c.titlebar = tb -- Resize the client so the same amount of space is occupied as before. - c:fullgeometry(old_geom) + c:geometry(old_geom) update(c) update(c, "geometry") @@ -142,10 +142,10 @@ function update(c, prop) if data[c].width then if c.titlebar.position == "top" or c.titlebar.position == "bottom" then - local w = math.min(data[c].width, c:geometry().width + 2 * c.border_width) + local w = math.min(data[c].width, c:geometry().width) c.titlebar:geometry({ width = w }) else - local w = math.min(data[c].width, c:geometry().height + 2 * c.border_width) + local w = math.min(data[c].width, c:geometry().height) c.titlebar:geometry({ height = w }) end end @@ -167,11 +167,11 @@ end --- Remove a titlebar from a client. -- @param c The client. function remove(c) - local old_geom = c:fullgeometry() + local old_geom = c:geometry() c.titlebar = nil data[c] = nil -- Resize the client so the same amount of space is occupied as before. - c:fullgeometry(old_geom) + c:geometry(old_geom) end -- Register standards hooks diff --git a/lib/naughty.lua.in b/lib/naughty.lua.in index 8ddc3f18..9b62c751 100644 --- a/lib/naughty.lua.in +++ b/lib/naughty.lua.in @@ -159,20 +159,20 @@ local function get_offset(screen, position, idx, width, height) if position:match("left") then v.x = ws.x + config.padding else - v.x = ws.x + ws.width - (width + config.border_width*2 + config.padding) + v.x = ws.x + ws.width - (width + config.padding) end -- calculate existing popups' height local existing = 0 for i = 1, idx-1, 1 do - existing = existing + notifications[screen][position][i].height + config.spacing + config.border_width*2 + existing = existing + notifications[screen][position][i].height + config.spacing end -- calculate y if position:match("top") then v.y = ws.y + config.padding + existing else - v.y = ws.y + ws.height - (config.padding + config.border_width*2 + height + existing) + v.y = ws.y + ws.height - (config.padding + height + existing) end -- if positioned outside workarea, destroy oldest popup and recalculate diff --git a/structs.h b/structs.h index 13ef6dd3..d64e8db6 100644 --- a/structs.h +++ b/structs.h @@ -162,6 +162,8 @@ struct client_t area_t fullscreen; /** Client geometry when (un)-max */ area_t max; + /** Internal geometry (matching X11 protocol) */ + area_t internal; } geometries; /** Strut */ strut_t strut; diff --git a/swindow.c b/swindow.c index 33522594..487ad8eb 100644 --- a/swindow.c +++ b/swindow.c @@ -48,14 +48,14 @@ simplewindow_draw_context_update(simple_window_t *sw, xcb_screen_t *s) xcb_create_pixmap(globalconf.connection, s->root_depth, sw->ctx.pixmap, s->root, - sw->geometry.height, sw->geometry.width); + sw->geometry.height, sw->geometries.internal.width); draw_context_init(&sw->ctx, phys_screen, - sw->geometry.height, sw->geometry.width, + sw->geometry.height, sw->geometries.internal.width, sw->ctx.pixmap, &fg, &bg); break; case East: draw_context_init(&sw->ctx, phys_screen, - sw->geometry.width, sw->geometry.height, + sw->geometries.internal.width, sw->geometries.internal.height, sw->pixmap, &fg, &bg); break; } @@ -88,6 +88,13 @@ simplewindow_init(simple_window_t *sw, sw->geometry.width = geometry.width; sw->geometry.height = geometry.height; sw->border.width = border_width; + + /* The real protocol window. */ + sw->geometries.internal.x = geometry.x; + sw->geometries.internal.y = geometry.y; + sw->geometries.internal.width = geometry.width - 2*border_width; + sw->geometries.internal.height = geometry.height - 2*border_width; + sw->orientation = orientation; sw->ctx.fg = *fg; sw->ctx.bg = *bg; @@ -102,14 +109,14 @@ simplewindow_init(simple_window_t *sw, sw->window = xcb_generate_id(globalconf.connection); xcb_create_window(globalconf.connection, s->root_depth, sw->window, s->root, - geometry.x, geometry.y, geometry.width, geometry.height, + sw->geometries.internal.x, sw->geometries.internal.y, sw->geometries.internal.width, sw->geometries.internal.height, border_width, XCB_COPY_FROM_PARENT, s->root_visual, XCB_CW_BACK_PIXMAP | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK, create_win_val); sw->pixmap = xcb_generate_id(globalconf.connection); xcb_create_pixmap(globalconf.connection, s->root_depth, sw->pixmap, s->root, - geometry.width, geometry.height); + sw->geometries.internal.width, sw->geometries.internal.height); sw->ctx.phys_screen = phys_screen; simplewindow_draw_context_update(sw, s); @@ -153,10 +160,10 @@ simplewindow_move(simple_window_t *sw, int x, int y) { const uint32_t move_win_vals[] = { x, y }; - if(x != sw->geometry.x || y != sw->geometry.y) + if(x != sw->geometries.internal.x || y != sw->geometries.internal.y) { - sw->geometry.x = x; - sw->geometry.y = y; + sw->geometry.x = sw->geometries.internal.x = x; + sw->geometry.y = sw->geometries.internal.y = y; xcb_configure_window(globalconf.connection, sw->window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, move_win_vals); @@ -171,19 +178,25 @@ simplewindow_move(simple_window_t *sw, int x, int y) void simplewindow_resize(simple_window_t *sw, int w, int h) { - if(w > 0 && h > 0 && (sw->geometry.width != w || sw->geometry.height != h)) + int iw = w - 2 * sw->border.width; + int ih = h - 2 * sw->border.width; + + if(iw > 0 && ih > 0 && + (sw->geometries.internal.width != iw || sw->geometries.internal.height != ih)) { xcb_screen_t *s = xutil_screen_get(globalconf.connection, sw->ctx.phys_screen); uint32_t resize_win_vals[2]; - sw->geometry.width = resize_win_vals[0] = w; - sw->geometry.height = resize_win_vals[1] = h; + sw->geometries.internal.width = resize_win_vals[0] = iw; + sw->geometries.internal.height = resize_win_vals[1] = ih; + sw->geometry.width = w; + sw->geometry.height = h; xcb_free_pixmap(globalconf.connection, sw->pixmap); /* orientation != East */ if(sw->pixmap != sw->ctx.pixmap) xcb_free_pixmap(globalconf.connection, sw->ctx.pixmap); sw->pixmap = xcb_generate_id(globalconf.connection); - xcb_create_pixmap(globalconf.connection, s->root_depth, sw->pixmap, s->root, w, h); + xcb_create_pixmap(globalconf.connection, s->root_depth, sw->pixmap, s->root, iw, ih); xcb_configure_window(globalconf.connection, sw->window, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, resize_win_vals); @@ -193,7 +206,7 @@ simplewindow_resize(simple_window_t *sw, int w, int h) /** Move and resize a window in one call. * \param sw The simple window to move and resize. - * \param geom The new gometry. + * \param geom The new geometry. */ void simplewindow_moveresize(simple_window_t *sw, area_t geom) @@ -201,10 +214,14 @@ simplewindow_moveresize(simple_window_t *sw, area_t geom) uint32_t moveresize_win_vals[4], mask_vals = 0; xcb_screen_t *s = xutil_screen_get(globalconf.connection, sw->ctx.phys_screen); - if(sw->geometry.x != geom.x || sw->geometry.y != geom.y) + area_t geom_internal = geom; + geom_internal.width -= 2 * sw->border.width; + geom_internal.height -= 2* sw->border.width; + + if(sw->geometries.internal.x != geom_internal.x || sw->geometries.internal.y != geom_internal.y) { - sw->geometry.x = moveresize_win_vals[0] = geom.x; - sw->geometry.y = moveresize_win_vals[1] = geom.y; + sw->geometries.internal.x = moveresize_win_vals[0] = geom_internal.x; + sw->geometries.internal.y = moveresize_win_vals[1] = geom_internal.y; mask_vals |= XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y; } @@ -212,13 +229,13 @@ simplewindow_moveresize(simple_window_t *sw, area_t geom) { if(mask_vals) { - sw->geometry.width = moveresize_win_vals[2] = geom.width; - sw->geometry.height = moveresize_win_vals[3] = geom.height; + sw->geometries.internal.width = moveresize_win_vals[2] = geom_internal.width; + sw->geometries.internal.height = moveresize_win_vals[3] = geom_internal.height; } else { - sw->geometry.width = moveresize_win_vals[0] = geom.width; - sw->geometry.height = moveresize_win_vals[1] = geom.height; + sw->geometries.internal.width = moveresize_win_vals[0] = geom_internal.width; + sw->geometries.internal.height = moveresize_win_vals[1] = geom_internal.height; } mask_vals |= XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; xcb_free_pixmap(globalconf.connection, sw->pixmap); @@ -226,10 +243,13 @@ simplewindow_moveresize(simple_window_t *sw, area_t geom) if(sw->pixmap != sw->ctx.pixmap) xcb_free_pixmap(globalconf.connection, sw->ctx.pixmap); sw->pixmap = xcb_generate_id(globalconf.connection); - xcb_create_pixmap(globalconf.connection, s->root_depth, sw->pixmap, s->root, geom.width, geom.height); + xcb_create_pixmap(globalconf.connection, s->root_depth, sw->pixmap, s->root, geom_internal.width, geom_internal.height); simplewindow_draw_context_update(sw, s); } + /* Also save geometry including border. */ + sw->geometry = geom; + xcb_configure_window(globalconf.connection, sw->window, mask_vals, moveresize_win_vals); } diff --git a/swindow.h b/swindow.h index 49f142d3..91762004 100644 --- a/swindow.h +++ b/swindow.h @@ -36,6 +36,11 @@ typedef struct simple_window_t xcb_gcontext_t gc; /** The window geometry. */ area_t geometry; + struct + { + /** Internal geometry (matching X11 protocol) */ + area_t internal; + } geometries; /** The window border */ struct { diff --git a/titlebar.c b/titlebar.c index 510b65ed..45b34143 100644 --- a/titlebar.c +++ b/titlebar.c @@ -64,83 +64,83 @@ client_getbytitlebarwin(xcb_window_t win) void titlebar_geometry_compute(client_t *c, area_t geometry, area_t *res) { - int width, x_offset = 0, y_offset = 0; + int height, width, x_offset = 0, y_offset = 0; switch(c->titlebar->position) { default: return; case Top: - width = MAX(1, geometry.width + 2 * c->border - 2 * c->titlebar->sw.border.width); + width = MAX(1, geometry.width); switch(c->titlebar->align) { default: break; case AlignRight: - x_offset = 2 * c->border + geometry.width - width - 2 * c->titlebar->sw.border.width; + x_offset = geometry.width - width; break; case AlignCenter: x_offset = (geometry.width - width) / 2; break; } res->x = geometry.x + x_offset; - res->y = geometry.y - c->titlebar->sw.geometry.height - 2 * c->titlebar->sw.border.width + c->border; + res->y = geometry.y; res->width = width; res->height = c->titlebar->sw.geometry.height; break; case Bottom: - width = MAX(1, geometry.width + 2 * c->border - 2 * c->titlebar->sw.border.width); + width = MAX(1, geometry.width); switch(c->titlebar->align) { default: break; case AlignRight: - x_offset = 2 * c->border + geometry.width - width - 2 * c->titlebar->sw.border.width; + x_offset = geometry.width - width; break; case AlignCenter: x_offset = (geometry.width - width) / 2; break; } res->x = geometry.x + x_offset; - res->y = geometry.y + geometry.height + c->border; + res->y = geometry.y + geometry.height - c->titlebar->sw.geometry.height; res->width = width; res->height = c->titlebar->sw.geometry.height; break; case Left: - width = MAX(1, geometry.height + 2 * c->border - 2 * c->titlebar->sw.border.width); + height = MAX(1, geometry.height); switch(c->titlebar->align) { default: break; case AlignRight: - y_offset = 2 * c->border + geometry.height - width - 2 * c->titlebar->sw.border.width; + y_offset = geometry.height - height; break; case AlignCenter: - y_offset = (geometry.height - width) / 2; + y_offset = (geometry.height - height) / 2; break; } - res->x = geometry.x - c->titlebar->sw.geometry.width + c->border; + res->x = geometry.x; res->y = geometry.y + y_offset; res->width = c->titlebar->sw.geometry.width; - res->height = width; + res->height = height; break; case Right: - width = MAX(1, geometry.height + 2 * c->border - 2 * c->titlebar->sw.border.width); + height = MAX(1, geometry.height); switch(c->titlebar->align) { default: break; case AlignRight: - y_offset = 2 * c->border + geometry.height - width - 2 * c->titlebar->sw.border.width; + y_offset = geometry.height - height; break; case AlignCenter: - y_offset = (geometry.height - width) / 2; + y_offset = (geometry.height - height) / 2; break; } - res->x = geometry.x + geometry.width + c->border; + res->x = geometry.x + geometry.width - c->titlebar->sw.geometry.width; res->y = geometry.y + y_offset; res->width = c->titlebar->sw.geometry.width; - res->height = width; + res->height = height; break; } } diff --git a/titlebar.h b/titlebar.h index 0adbf3d6..dd8e9b99 100644 --- a/titlebar.h +++ b/titlebar.h @@ -51,18 +51,18 @@ titlebar_geometry_add(wibox_t *t, int border, area_t geometry) switch(t->position) { case Top: - geometry.y -= t->sw.geometry.height + 2 * t->sw.border.width; - geometry.height += t->sw.geometry.height + 2 * t->sw.border.width; + geometry.y -= t->sw.geometry.height; + geometry.height += t->sw.geometry.height; break; case Bottom: - geometry.height += t->sw.geometry.height + 2 * t->sw.border.width; + geometry.height += t->sw.geometry.height; break; case Left: - geometry.x -= t->sw.geometry.width + 2 * t->sw.border.width; - geometry.width += t->sw.geometry.width + 2 * t->sw.border.width; + geometry.x -= t->sw.geometry.width; + geometry.width += t->sw.geometry.width; break; case Right: - geometry.width += t->sw.geometry.width + 2 * t->sw.border.width; + geometry.width += t->sw.geometry.width; break; default: break; @@ -92,26 +92,26 @@ titlebar_geometry_remove(wibox_t *t, int border, area_t geometry) switch(t->position) { case Top: - geometry.y += t->sw.geometry.height + 2 * t->sw.border.width; - geometry.height -= t->sw.geometry.height + 2 * t->sw.border.width; + geometry.y += t->sw.geometry.height; + unsigned_subtract(geometry.height, t->sw.geometry.height); break; case Bottom: - geometry.height -= t->sw.geometry.height + 2 * t->sw.border.width; + unsigned_subtract(geometry.height, t->sw.geometry.height); break; case Left: - geometry.x += t->sw.geometry.width + 2 * t->sw.border.width; - geometry.width -= t->sw.geometry.width + 2 * t->sw.border.width; + geometry.x += t->sw.geometry.width; + unsigned_subtract(geometry.width, t->sw.geometry.width); break; case Right: - geometry.width -= t->sw.geometry.width + 2 * t->sw.border.width; + unsigned_subtract(geometry.width, t->sw.geometry.width); break; default: break; } /* Adding a border to a client only changes width and height, x and y are including border. */ - geometry.width -= 2 * border; - geometry.height -= 2 * border; + unsigned_subtract(geometry.width, 2*border); + unsigned_subtract(geometry.height, 2*border); return geometry; } diff --git a/wibox.c b/wibox.c index 9a460deb..9c0f8b57 100644 --- a/wibox.c +++ b/wibox.c @@ -366,9 +366,9 @@ wibox_position_update(wibox_t *wibox) switch(wibox->position) { case Right: - wingeom.height = area.height - 2 * wibox->sw.border.width; + wingeom.height = area.height; wingeom.width = wibox->sw.geometry.width > 0 ? wibox->sw.geometry.width : 1.5 * globalconf.font->height; - wingeom.x = area.x + area.width - wingeom.width - 2 * wibox->sw.border.width; + wingeom.x = area.x + area.width - wingeom.width; switch(wibox->align) { default: @@ -383,13 +383,13 @@ wibox_position_update(wibox_t *wibox) } break; case Left: - wingeom.height = area.height - 2 * wibox->sw.border.width; + wingeom.height = area.height; wingeom.width = wibox->sw.geometry.width > 0 ? wibox->sw.geometry.width : 1.5 * globalconf.font->height; wingeom.x = area.x; switch(wibox->align) { default: - wingeom.y = (area.y + area.height) - wingeom.height - 2 * wibox->sw.border.width; + wingeom.y = (area.y + area.height) - wingeom.height; break; case AlignRight: wingeom.y = area.y; @@ -400,8 +400,8 @@ wibox_position_update(wibox_t *wibox) break; case Bottom: wingeom.height = wibox->sw.geometry.height > 0 ? wibox->sw.geometry.height : 1.5 * globalconf.font->height; - wingeom.width = area.width - 2 * wibox->sw.border.width; - wingeom.y = (area.y + area.height) - wingeom.height - 2 * wibox->sw.border.width; + wingeom.width = area.width; + wingeom.y = (area.y + area.height) - wingeom.height; wingeom.x = area.x; switch(wibox->align) { @@ -417,7 +417,7 @@ wibox_position_update(wibox_t *wibox) break; case Top: wingeom.height = wibox->sw.geometry.height > 0 ? wibox->sw.geometry.height : 1.5 * globalconf.font->height; - wingeom.width = area.width - 2 * wibox->sw.border.width; + wingeom.width = area.width; wingeom.x = area.x; wingeom.y = area.y; switch(wibox->align)