diff --git a/event.c b/event.c index a8928519..73748f64 100644 --- a/event.c +++ b/event.c @@ -287,7 +287,7 @@ event_handle_configurerequest(xcb_configure_request_event_t *ev) lua_pop(globalconf.L, 1); } - if(!client_resize(c, geometry, false)) + if(!client_resize(c, geometry)) /* ICCCM 4.1.5 / 4.2.3, if nothing was changed, send an event saying so */ xwindow_configure(c->window, geometry, c->border_width); } diff --git a/lib/awful/icccm.lua.in b/lib/awful/icccm.lua.in new file mode 100644 index 00000000..1d1998fd --- /dev/null +++ b/lib/awful/icccm.lua.in @@ -0,0 +1,123 @@ +--------------------------------------------------------------------------- +-- @author Uli Schlachter +-- @copyright 2011 Uli Schlachter +-- @release @AWESOME_VERSION@ +--------------------------------------------------------------------------- + +local client = client +local math = math + +--- Implements ICCCM handling. +module("awful.icccm") + +-- Make sure we don't get into an endless loop +local size_hints_lock = false + +function apply_size_hints(c) + if size_hints_lock then return end + if not c.size_hints_honor then return end + -- Fullscreen clients don't get size hints applied! + if c.fullscreen then return end + + size_hints_lock = true + + local geom = c:geometry() + local hints = c.size_hints + + local basew, baseh + local real_basew, real_baseh = 0, 0 + if hints.base_width then + basew, baseh = hints.base_width, hints.base_height + real_basew, real_baseh = basew, baseh + elseif hints.min_width then + -- Base size is substituted with min size if not specified + basew, baseh = hints.min_width, hints.min_height + else + basew, baseh = 0, 0 + end + + -- Handle the size aspect ratio + + if hints.min_aspect_den then + -- Apply the size aspect + if hints.min_aspect_den > 0 and hints.max_aspect_den > 0 and + geom.height > real_baseh and geom.width > real_basew then + -- ICCCM mandates: + -- If a base size is provided along with the aspect ratio fields, the + -- base size should be subtracted from the window size prior to checking + -- that the aspect ratio falls in range. If a base size is not provided, + -- nothing should be subtracted from the window size. (The minimum size + -- is not to be used in place of the base size for this purpose.) + local dx = geom.width - real_basew + local dy = geom.height - real_baseh + local ratio = dx / dy + local min = hints.min_aspect_num / hints.min_aspect_den + local max = hints.max_aspect_num / hints.max_aspect_den + + if max > 0 and min > 0 and ratio > 0 then + if ratio < min then + -- dx is lower than allowed, make dy lower to compensate this + -- (+ 0.5 to force proper rounding). + dy = dx / min + 0.5 + geom.width = dx + real_basew + geom.height = dy + real_baseh + elseif ratio > max then + -- dx is too high, lower it (+0.5 for proper rounding) + dx = dy * max + 0.5 + geom.width = dx + real_basew + geom.height = dy + real_baseh; + end + -- Make sure these are integers + geom.width = math.floor(geom.width) + geom.height = math.floor(geom.height) + end + end + end + + -- Handle the minimum size + local minw, minh + if hints.min_width then + minw, minh = hints.min_width, hints.min_height + elseif hints.base_width then + -- min size is substituted with base size if not specified + minw, minh = hints.base_width, hints.base_height + else + minw, minh = 0, 0 + end + + if minw ~= nil and minw > 0 and geom.width < minw then + geom.width = minw + end + if minh ~= nil and minh > 0 and geom.height < minh then + geom.height = minh + end + + -- Handle the maximum size + if hints.max_width ~= nil and hints.max_width > 0 and hints.max_width < geom.width then + geom.width = hints.max_width + end + if hints.max_height ~= nil and hints.max_height > 0 and hints.max_height < geom.height then + geom.height = hints.max_height + end + + -- Handle the size increment + if hints.width_inc and hints.width_inc > 0 then + function apply_inc(size, inc, base) + local i = size - base + if i < 0 then i = 0 end + -- Round size down to a multiple of inc, ignoring the base size + return size - math.fmod(i, inc) + end + geom.width = apply_inc(geom.width, hints.width_inc, basew) + geom.height = apply_inc(geom.height, hints.height_inc, baseh) + end + + c:geometry(geom) + + size_hints_lock = false +end + +client.connect_signal("property::width", apply_size_hints) +client.connect_signal("property::height", apply_size_hints) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/lib/awful/init.lua.in b/lib/awful/init.lua.in index 9f4e1732..c16a02e9 100644 --- a/lib/awful/init.lua.in +++ b/lib/awful/init.lua.in @@ -22,6 +22,7 @@ require("awful.wibox") require("awful.startup_notification") require("awful.tooltip") require("awful.ewmh") +require("awful.icccm") --- AWesome Functions very UsefuL module("awful") diff --git a/objects/client.c b/objects/client.c index 5934822f..f568a285 100644 --- a/objects/client.c +++ b/objects/client.c @@ -533,110 +533,6 @@ HANDLE_GEOM(height) lua_pop(globalconf.L, 1); } -/** Compute client geometry with respect to its geometry hints. - * \param c The client. - * \param geometry The geometry that the client might receive. - * \return The geometry the client must take respecting its hints. - */ -area_t -client_geometry_hints(client_t *c, area_t geometry) -{ - int32_t basew, baseh, minw, minh; - int32_t real_basew = 0, real_baseh = 0; - - /* base size is substituted with min size if not specified */ - if(c->size_hints.flags & XCB_SIZE_HINT_P_SIZE) - { - basew = c->size_hints.base_width; - baseh = c->size_hints.base_height; - real_basew = basew; - real_baseh = baseh; - } - else if(c->size_hints.flags & XCB_SIZE_HINT_P_MIN_SIZE) - { - basew = c->size_hints.min_width; - baseh = c->size_hints.min_height; - } - else - basew = baseh = 0; - - /* min size is substituted with base size if not specified */ - if(c->size_hints.flags & XCB_SIZE_HINT_P_MIN_SIZE) - { - minw = c->size_hints.min_width; - minh = c->size_hints.min_height; - } - else if(c->size_hints.flags & XCB_SIZE_HINT_P_SIZE) - { - minw = c->size_hints.base_width; - minh = c->size_hints.base_height; - } - else - minw = minh = 0; - - if(c->size_hints.flags & XCB_SIZE_HINT_P_ASPECT - && c->size_hints.min_aspect_den > 0 - && c->size_hints.max_aspect_den > 0 - && geometry.height - real_baseh > 0 - && geometry.width - real_basew > 0) - { - /* ICCCM mandates: - * If a base size is provided along with the aspect ratio fields, the - * base size should be subtracted from the window size prior to checking - * that the aspect ratio falls in range. If a base size is not provided, - * nothing should be subtracted from the window size. (The minimum size - * is not to be used in place of the base size for this purpose.) */ - double dx = (double) (geometry.width - real_basew); - double dy = (double) (geometry.height - real_baseh); - double min = (double) c->size_hints.min_aspect_num / (double) c->size_hints.min_aspect_den; - double max = (double) c->size_hints.max_aspect_num / (double) c->size_hints.max_aspect_den; - double ratio = dx / dy; - if(max > 0 && min > 0 && ratio > 0) - { - if(ratio < min) - { - /* dx is lower than allowed, make dy lower to compensate this - * (+ 0.5 to force proper rounding). */ - dy = dx / min + 0.5; - geometry.width = (int) dx + real_basew; - geometry.height = (int) dy + real_baseh; - } - else if(ratio > max) - { - /* dx is too high, lower it (+0.5 for proper rounding) */ - dx = dy * max + 0.5; - geometry.width = (int) dx + real_basew; - geometry.height = (int) dy + real_baseh; - } - } - } - - if(minw) - geometry.width = MAX(geometry.width, minw); - if(minh) - geometry.height = MAX(geometry.height, minh); - - if(c->size_hints.flags & XCB_SIZE_HINT_P_MAX_SIZE) - { - if(c->size_hints.max_width) - geometry.width = MIN(geometry.width, c->size_hints.max_width); - if(c->size_hints.max_height) - geometry.height = MIN(geometry.height, c->size_hints.max_height); - } - - 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) - { - 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; -} - /** Resize client window. * The sizes given as parameters are with borders! * \param c Client to resize. @@ -645,7 +541,7 @@ client_geometry_hints(client_t *c, area_t geometry) * \return true if an actual resize occurred. */ bool -client_resize(client_t *c, area_t geometry, bool hints) +client_resize(client_t *c, area_t geometry) { area_t area; @@ -661,9 +557,6 @@ client_resize(client_t *c, area_t geometry, bool hints) if(geometry.y + geometry.height < 0) geometry.y = 0; - if(hints && !c->fullscreen) - geometry = client_geometry_hints(c, geometry); - if(geometry.width == 0 || geometry.height == 0) return false; @@ -1284,7 +1177,7 @@ luaA_client_geometry(lua_State *L) geometry.height = luaA_getopt_number(L, 2, "height", c->geometry.height); } - client_resize(c, geometry, c->size_hints_honor); + client_resize(c, geometry); } return luaA_pusharea(L, c->geometry); diff --git a/objects/client.h b/objects/client.h index ec63537b..c8636be1 100644 --- a/objects/client.h +++ b/objects/client.h @@ -116,8 +116,7 @@ void client_ban(client_t *); void client_ban_unfocus(client_t *); void client_unban(client_t *); void client_manage(xcb_window_t, xcb_get_geometry_reply_t *, bool); -area_t client_geometry_hints(client_t *, area_t); -bool client_resize(client_t *, area_t, bool); +bool client_resize(client_t *, area_t); void client_unmanage(client_t *, bool); void client_kill(client_t *); void client_set_sticky(lua_State *, int, bool); diff --git a/screen.c b/screen.c index 2c0838f5..a4d7582a 100644 --- a/screen.c +++ b/screen.c @@ -378,7 +378,7 @@ screen_client_moveto(client_t *c, screen_t *new_screen, bool doresize) new_geometry.y = to.y + to.height - new_geometry.height; /* move / resize the client */ - client_resize(c, new_geometry, false); + client_resize(c, new_geometry); luaA_object_push(globalconf.L, c); luaA_object_emit_signal(globalconf.L, -1, "property::screen", 0); lua_pop(globalconf.L, 1);