Relocate a client window as if it is undecorated when reparenting it back. It eliminates the position offset due to re-decorating when a client trys to restore its previous position. (#3253)

Add tests for geometry changes when managing/unmanaging clients. Also verified that it fixed issue #2308.
This commit is contained in:
Xinhao Yuan 2022-02-02 16:59:01 -05:00 committed by GitHub
parent cd4008c249
commit ab6f7e03ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 138 additions and 3 deletions

View File

@ -111,8 +111,9 @@ awesome_atexit(bool restart)
/* Move clients where we want them to be and keep the stacking order intact */
foreach(c, globalconf.stack)
{
area_t geometry = client_get_undecorated_geometry(*c);
xcb_reparent_window(globalconf.connection, (*c)->window, globalconf.screen->root,
(*c)->geometry.x, (*c)->geometry.y);
geometry.x, geometry.y);
}
/* Save the client order. This is useful also for "hard" restarts. */

View File

@ -2267,6 +2267,27 @@ client_add_titlebar_geometry(client_t *c, area_t *geometry)
geometry->height += c->titlebar[CLIENT_TITLEBAR_BOTTOM].size;
}
area_t
client_get_undecorated_geometry(client_t *c)
{
area_t geometry = c->geometry;
if (!c->fullscreen) {
int diff_left = c->titlebar[CLIENT_TITLEBAR_LEFT].size;
int diff_right = c->titlebar[CLIENT_TITLEBAR_RIGHT].size;
int diff_top = c->titlebar[CLIENT_TITLEBAR_TOP].size;
int diff_bottom = c->titlebar[CLIENT_TITLEBAR_BOTTOM].size;
geometry.width -= diff_left + diff_right;
geometry.height -= diff_top + diff_bottom;
if (c->size_hints.flags & XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY) {
xwindow_translate_for_gravity(c->size_hints.win_gravity,
-diff_left - c->border_width, -diff_top - c->border_width,
-diff_right - c->border_width, -diff_bottom - c->border_width,
&geometry.x, &geometry.y);
}
}
return geometry;
}
/** Send a synthetic configure event to a window.
*/
void
@ -2941,9 +2962,10 @@ client_unmanage(client_t *c, client_unmanage_t reason)
if(reason != CLIENT_UNMANAGE_DESTROYED)
{
area_t geometry = client_get_undecorated_geometry(c);
xcb_unmap_window(globalconf.connection, c->window);
xcb_reparent_window(globalconf.connection, c->window, globalconf.screen->root,
c->geometry.x, c->geometry.y);
geometry.x, geometry.y);
}
if (c->nofocus_window != XCB_NONE)

View File

@ -256,6 +256,7 @@ void client_emit_scanned(void);
void client_emit_scanning(void);
drawable_t *client_get_drawable(client_t *, int, int);
drawable_t *client_get_drawable_offset(client_t *, int *, int *);
area_t client_get_undecorated_geometry(client_t *);
/** Put client on top of the stack.
* \param c The client to raise.

View File

@ -6,9 +6,13 @@ local wibox = require( "wibox" )
local beautiful = require( "beautiful" )
local cruled = require("ruled.client")
local gdebug = require("gears.debug")
local test_client = require("_client")
local lgi = require("lgi")
local gears = require("gears")
local w = nil
local w1_draw, w2_draw
local windowid
-- Replacing the rules is not supported anymore.
local dep = gdebug.deprecate
@ -257,6 +261,113 @@ local steps = {
end
}
runner.run_steps(steps)
-- Tests for unmanaged client geometries with different gravity settings.
local test_data = {
-- gravity => expectation of unmanaged x, y, w, h.
["NORTH_WEST"] = {0, 0, 100, 80},
["NORTH"] = {10, 0, 100, 80},
["NORTH_EAST"] = {20, 0, 100, 80},
["WEST"] = {0, 20, 100, 80},
["CENTER"] = {10, 20, 100, 80},
["EAST"] = {20, 20, 100, 80},
["SOUTH_WEST"] = {0, 40, 100, 80},
["SOUTH"] = {10, 40, 100, 80},
["SOUTH_EAST"] = {20, 40, 100, 80},
["STATIC"] = {10, 30, 100, 80}
}
for gravity, expectation in pairs(test_data) do
gears.table.merge(steps, {
function()
set_rules { }
-- Wait for the previous cleanup to be done
if #client.get() == 0 then
return true
end
end,
function(count)
if count == 1 then
print("testing gravity " .. gravity)
test_client(nil,nil,nil,nil,nil,{gravity=lgi.Gdk.Gravity[gravity]})
else
local c = client.get()[1]
if c then
assert(c.size_hints.win_gravity == gravity:lower())
c.border_width = 10
c:titlebar_top(20)
c:geometry({
x = 0,
y = 0,
width = 100,
height = 100
})
windowid = c.window
return true
end
end
end,
-- For some reason unmanage needs to happen in a separate step to pass the tests..
function()
local c = client.get()[1]
c:unmanage()
awesome.sync()
return true
end,
function()
local display = lgi.Gdk.Display.open(os.getenv("DISPLAY"))
local window = lgi.GdkX11.X11Window.foreign_new_for_display(display, windowid)
local x, y, width, height = window:get_geometry()
print(gravity, x, y, width, height)
assert(x == expectation[1])
assert(y == expectation[2])
assert(width == expectation[3])
assert(height == expectation[4])
window:destroy()
return true
end,
function()
local display = lgi.Gdk.Display.open(os.getenv("DISPLAY"))
local window = lgi.GdkX11.X11Window.foreign_new_for_display(display, windowid)
if window then return end
return true
end,
-- Additionally, checks our expectations are correct by adding decoration back.
function(count)
if count == 1 then
test_client(nil,nil,nil,nil,nil,{gravity=lgi.Gdk.Gravity[gravity]})
else
local c = client.get()[1]
if c then
assert(c.size_hints.win_gravity == gravity:lower())
c.border_width = 0
c:titlebar_top(0)
c:geometry({
x = expectation[1],
y = expectation[2],
width = expectation[3],
height = expectation[4]
})
return true
end
end
end,
function()
local c = client.get()[1]
c:titlebar_top(20)
c.border_width = 10
return true
end,
function()
local c = client.get()[1]
assert(c.border_width == 10 )
assert(c:geometry().x == 0 )
assert(c:geometry().y == 0 )
assert(c:geometry().height == 100 )
assert(c:geometry().width == 100 )
c:kill()
return true
end,
})
end
runner.run_steps(steps)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80