diff --git a/objects/client.c b/objects/client.c index ac3c9cc2b..309d021e8 100644 --- a/objects/client.c +++ b/objects/client.c @@ -1176,12 +1176,33 @@ client_geometry_refresh(void) area_t real_geometry = c->geometry; if (!c->fullscreen) { + if ((real_geometry.width < c->titlebar[CLIENT_TITLEBAR_LEFT].size + + c->titlebar[CLIENT_TITLEBAR_RIGHT].size) || + (real_geometry.height < c->titlebar[CLIENT_TITLEBAR_TOP].size + + c->titlebar[CLIENT_TITLEBAR_BOTTOM].size)) + warn("Resizing a window to a negative size!? Have width %d-%d-%d=%d" + " and height %d-%d-%d=%d", real_geometry.width, + c->titlebar[CLIENT_TITLEBAR_LEFT].size, + c->titlebar[CLIENT_TITLEBAR_RIGHT].size, + real_geometry.width - + c->titlebar[CLIENT_TITLEBAR_LEFT].size - + c->titlebar[CLIENT_TITLEBAR_RIGHT].size, + real_geometry.height, + c->titlebar[CLIENT_TITLEBAR_TOP].size, + c->titlebar[CLIENT_TITLEBAR_BOTTOM].size, + real_geometry.height - + c->titlebar[CLIENT_TITLEBAR_TOP].size - + c->titlebar[CLIENT_TITLEBAR_BOTTOM].size); + real_geometry.x = c->titlebar[CLIENT_TITLEBAR_LEFT].size; real_geometry.y = c->titlebar[CLIENT_TITLEBAR_TOP].size; real_geometry.width -= c->titlebar[CLIENT_TITLEBAR_LEFT].size; real_geometry.width -= c->titlebar[CLIENT_TITLEBAR_RIGHT].size; real_geometry.height -= c->titlebar[CLIENT_TITLEBAR_TOP].size; real_geometry.height -= c->titlebar[CLIENT_TITLEBAR_BOTTOM].size; + + if (real_geometry.width == 0 || real_geometry.height == 0) + warn("Resizing a window to size zero!?"); } else { real_geometry.x = 0; real_geometry.y = 0; @@ -1678,6 +1699,17 @@ client_resize(client_t *c, area_t geometry, bool honor_hints) if(geometry.y + geometry.height < 0) geometry.y = 0; + if (honor_hints) { + /* We could get integer underflows in client_remove_titlebar_geometry() + * without these checks here. + */ + if(geometry.width < c->titlebar[CLIENT_TITLEBAR_LEFT].size + c->titlebar[CLIENT_TITLEBAR_RIGHT].size) + return false; + if(geometry.height < c->titlebar[CLIENT_TITLEBAR_TOP].size + c->titlebar[CLIENT_TITLEBAR_BOTTOM].size) + return false; + geometry = client_apply_size_hints(c, geometry); + } + if(geometry.width < c->titlebar[CLIENT_TITLEBAR_LEFT].size + c->titlebar[CLIENT_TITLEBAR_RIGHT].size) return false; if(geometry.height < c->titlebar[CLIENT_TITLEBAR_TOP].size + c->titlebar[CLIENT_TITLEBAR_BOTTOM].size) @@ -1686,9 +1718,6 @@ client_resize(client_t *c, area_t geometry, bool honor_hints) if(geometry.width == 0 || geometry.height == 0) return false; - if (honor_hints) - geometry = client_apply_size_hints(c, geometry); - if(!AREA_EQUAL(c->geometry, geometry)) { client_resize_do(c, geometry); diff --git a/tests/_client.lua b/tests/_client.lua index 18435527c..f6b839a80 100644 --- a/tests/_client.lua +++ b/tests/_client.lua @@ -5,30 +5,47 @@ local spawn = require("awful.spawn") local test_client_source = [[ local lgi = require 'lgi' +local Gdk = lgi.require('Gdk') local Gtk = lgi.require('Gtk') local Gio = lgi.require('Gio') Gtk.init() -local function open_window(class, title, snid) +local function open_window(class, title, options) local window = Gtk.Window { default_width = 100, default_height = 100, title = title } - if snid ~= "" then - window:set_startup_id(snid) + if options.snid and options.snid ~= "" then + window:set_startup_id(options.snid) + end + if options.resize_increment then + local geom = Gdk.Geometry { + width_inc = 200, + height_inc = 200, + } + window:set_geometry_hints(nil, geom, Gdk.WindowHints.RESIZE_INC) end window:set_wmclass(class, class) window:show_all() end +local function parse_options(options) + local result = {} + for word in string.gmatch(options, "([^,]+)") do + local key, value = string.match(word, "([^=]+)=?(.*)") + result[key] = value + end + return result +end + -- Start a coroutine for nicer input handling local coro = coroutine.wrap(function() while true do local class = coroutine.yield() local title = coroutine.yield() - local snid = coroutine.yield() - open_window(class, title, snid) + local options = coroutine.yield() + open_window(class, title, parse_options(options)) end end) coro() @@ -86,13 +103,21 @@ local function get_snid(sn_rules, callback) return snid end -return function(class, title, sn_rules, callback) +return function(class, title, sn_rules, callback, resize_increment) class = class or "test_app" title = title or "Awesome test client" init() - local snid = (sn_rules or callback) and get_snid(sn_rules, callback) or "" - local data = class .. "\n" .. title .. "\n" .. snid .. "\n" + local options = "" + local snid + if sn_rules or callback then + snid = get_snid(sn_rules, callback) + options = options .. "snid=" .. snid .. "," + end + if resize_increment then + options = options .. "resize_increment," + end + local data = class .. "\n" .. title .. "\n" .. options .. "\n" local success, msg = pipe:write_all(data) assert(success, tostring(msg)) diff --git a/tests/test-resize.lua b/tests/test-resize.lua index 298323efb..67a75d9c8 100644 --- a/tests/test-resize.lua +++ b/tests/test-resize.lua @@ -439,6 +439,37 @@ table.insert(steps, function() return true end) +table.insert(steps, function() + for _, c in pairs(client.get()) do + c:kill() + end + if #client.get() == 0 then + test_client(nil, nil, nil, nil, true) + return true + end +end) + +table.insert(steps, function() + if #client.get() ~= 1 then + return + end + + local c = client.get()[1] + local geo = c:geometry() + local hints = c.size_hints + assert(hints.height_inc == 200) + assert(hints.width_inc == 200) + assert(c:apply_size_hints(1, 1) == 0) + + c:geometry { width = 1, height = 50 } + + -- The above should be rejected, because it would make us resize the + -- window size 0x0. + assert(c:geometry().width == geo.width) + assert(c:geometry().height == geo.height) + return true +end) + require("_runner").run_steps(steps) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80