Last active
March 24, 2024 09:22
-
-
Save gitaarik/c28511f0a7a94a2b23d6b64a306584c9 to your computer and use it in GitHub Desktop.
Awesome WM script that restores floating clients geometry (width / height / position) when switching layouts or unmaximizing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Restore last used floating client geometry (with / height / position) when | |
-- switching layouts and unmaximizing clients. | |
-- | |
-- When unmaximizing a never-before floating client, it will nicely center the | |
-- client in the middle of the screen. | |
-- | |
-- To use, just `require('restore_floating_clients')` in your `awesome/lua.rc` | |
-- Somewhere where you have your other signal callbacks. | |
local awful = require("awful") | |
-- The following variables contain different states of clients, with the | |
-- `client.window` in the key and the relevant state in the value. | |
-- Store the floating clients geometries (with / height / position), so we can | |
-- restore the clients when the layout changes. | |
local floating_client_geometries = {} | |
-- Store the previous floating clients geometries. We need this to restore from | |
-- maximized, because the maximized signal happens after the geometry signal. | |
-- So the state we want to revert to gets overridden before we can restore it. | |
-- Therefore we also store the previous floating client geometries. | |
local prev_floating_client_geometries = {} | |
-- Store whether a client was NOT maximized in the last used floating layout. | |
-- We use this to determin whether a client should become maximized or floating | |
-- when switching to floating layout. | |
local unmaximized_state = {} | |
-- Store on which screen a client is. This is needed because when setting the | |
-- geometry of a client, the client seems to get moved to the first screen | |
-- regardless of which screen it was on. | |
local clients_screens = {} | |
-- When the geometry of a client changes, and the layout is floating, then | |
-- store the client's maximized state. And if the client is also not maximized, | |
-- then also store the client's geometry. This will be used to restore the | |
-- client's geometry when they become floating again. | |
client.connect_signal("property::geometry", function(c) | |
clients_screens[c.window] = c.screen | |
if ( | |
awesome.startup | |
or awful.layout.get(awful.screen.focused()) ~= awful.layout.suit.floating | |
) then | |
-- Don't store anything during startup, or when we're not in a floating | |
-- layout. | |
return | |
end | |
-- Store the unmaximized state | |
unmaximized_state[c.window] = not c.maximized | |
if c.maximized then | |
-- Don't store geometry for maximized clients | |
return | |
end | |
if floating_client_geometries[c.window] then | |
-- Store the previous client geometry, before saving new one, for | |
-- the unmaximize trigger. | |
prev_floating_client_geometries[c.window] = floating_client_geometries[c.window] | |
end | |
-- Store client geometry | |
floating_client_geometries[c.window] = c:geometry() | |
end) | |
-- When the layout changes, then if the layout is floating, restore the | |
-- geometry of clients that were not maximized the last time the floating | |
-- layout was used, if there is any previously stored geometry to restore. | |
tag.connect_signal("property::layout", function(t) | |
if t.layout == awful.layout.suit.floating then | |
for k, c in ipairs(t:clients()) do | |
if ( | |
floating_client_geometries and unmaximized_state | |
and floating_client_geometries[c.window] | |
and unmaximized_state[c.window] | |
) then | |
-- Restore client geometry | |
c:geometry(floating_client_geometries[c.window]) | |
else | |
-- If the client was maximized in the last used floating layout, | |
-- or if there's no geometry to restore, just set the client to | |
-- maximized. | |
c.maximized = true | |
end | |
end | |
else | |
-- If the layout is not floating, then remove the maximized state from | |
-- all clients, otherwise those layouts don't work properly. | |
for k, c in ipairs(t:clients()) do c.maximized = false end | |
end | |
end) | |
-- When changing a maximized client to unmaximized in a floating layout, then | |
-- restore the floating client geometry to what it was in the previous floating | |
-- state. | |
client.connect_signal("property::maximized", function(c) | |
if ( | |
c.maximized | |
or awful.layout.get(awful.screen.focused()) ~= awful.layout.suit.floating | |
) then | |
-- If the client is maximized, or the layout is not floating, don't | |
-- restore anything. | |
return | |
end | |
if prev_floating_client_geometries[c.window] then | |
-- Restore client geometry | |
c:geometry(prev_floating_client_geometries[c.window]) | |
else | |
-- If there is no previous geometry state, then center the client nicely in the | |
-- middle of the screen, so that it's not off bounds or in a corner or | |
-- extremely small or anything. Then it's easy to move / resize the floating | |
-- client to your wish. | |
local g = c.screen.geometry | |
c:geometry({ | |
x = g.width / 6, | |
y = g.height / 6, | |
width = g.width / 1.5, | |
height = g.height / 1.5 | |
}) | |
-- Restore the client screen, because this seems to get lost due to the | |
-- `c:geometry()` call. This issue only occurs when you have multiple | |
-- screens in use. | |
c.screen = clients_screens[c.window] | |
end | |
end) | |
-- When a new client appears, reset the geometry states. Because this signal | |
-- comes after the geometry signal, and the geometry signal in this case stores | |
-- incorrect geometries for a new client. So since this signal comes after the | |
-- geometry signal, we can reset it, so a new client starts with a blank slate. | |
client.connect_signal("manage", function (c) | |
floating_client_geometries[c.window] = nil | |
prev_floating_client_geometries[c.window] = nil | |
end) |
@guidipolito I'm actually using this now to center a client, which takes into account multi-display setups. At least horizontally, multi-display.
local center_client = function(_client)
_client.maximized = false
_client.maximized_horizontal = false
_client.maximized_vertical = false
_client.floating = true
local total_screens_left_width = 0
for s in screen do
if s == _client.screen then
break
end
total_screens_left_width = total_screens_left_width + s.geometry.width
end
local g = _client.screen.geometry
_client:geometry({
x = total_screens_left_width + (g.width / 6),
y = g.height / 6,
width = g.width / 1.5,
height = g.height / 1.5
})
end
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you 🤝