focus.global_bydirection does not move from empty screen correctly
Output of awesome --version:
awesome v4.3-1356-g9895aeb0d (Too long) • Compiled against Lua 5.4.4 (running with 0.9.2) • API level: 4 • D-Bus support: yes • xcb-errors support: no • execinfo support: yes • xcb-randr version: 1.6 • LGI version: /usr/share/lua/5.4/lgi/version.lua • Transparency enabled: yes • Custom search paths: no
How to reproduce the issue:
- Copy default config, change the keybindings to use
awful.client.focus.global_bydirection.
awful.keyboard.append_global_keybindings({
-- By direction client focus
awful.key({ modkey }, "j",
function()
awful.client.focus.global_bydirection("down")
if client.focus then client.focus:raise() end
end,
{description = "focus down", group = "client"}),
awful.key({ modkey }, "k",
function()
awful.client.focus.global_bydirection("up")
if client.focus then client.focus:raise() end
end,
{description = "focus up", group = "client"}),
awful.key({ modkey }, "h",
function()
awful.client.focus.global_bydirection("left")
if client.focus then client.focus:raise() end
end,
{description = "focus left", group = "client"}),
awful.key({ modkey }, "l",
function()
awful.client.focus.global_bydirection("right")
if client.focus then client.focus:raise() end
end,
{description = "focus right", group = "client"}),
})
- Open a window on one screen.
- Move to a second screen using the
focus.global_bydirectionkeybinding. - Move back to the first screen (using the same bindings).
Actual result:
The cursor remains on the second screen instead of moving to the first one, resulting in new windows spawned and tags changing on the second screen.
Expected result:
When moving from the second screen back to the first one, I would expect the cursor moving back to the first screen as well, so that new windows are spawned on the first screen.
What I tried:
I tried looking at the code for awful.client.focus.global_bydirection, found out that focus.bydirection is called as expected but due to my beginner level lua and awesomewm knowledge I did not find much more.
More details about what was tried can be found in this reddit post.
Hello @chr-sa,
First, I have successfully reproduced the bug. I have to admit that it was tricky, and I had to try multiple times to get it correctly.
From my quick look-up, in the code, focus.global_bydirection seems to rely on inconsistent sources to find the “focused” screen. It uses a mix of client.focused(.screen) (aka the last known client to be focused), and screen.focused() (that fallbacks to the screen where there is the cursor). Add to this a screen with no clients on, and you have the perfect receipt to break things.
I guess the fix would be to double-check these “focused screen” detection to make them consistent across the function. It would also be nice to have a new test for this behavior. That's however something I'll not be able to do before a few days.
It seems, in my case at least, that the issue begins when moving to a screen that is empty (has 0 clients). When you do that, not the "entire" focus is properly transferred to the destination screen. Specifically, the client focus is left lagging behind. As a workaround, I've found this to work quite well.
local focus_bydirection = function(direction)
awful.client.focus.global_bydirection(direction)
if client.focus then
-- focus on the client
client.focus:raise()
end
-- BUG: focus across screens is wonky when there are no clients on the destination screen
-- https://github.com/awesomeWM/awesome/issues/3638
-- Workaround: manually unfocus client after moving focus to an empty screen
local is_empty_destination = #awful.screen.focused().clients < 1
if is_empty_destination then
-- manually unfocus the current focused client
client.focus = nil
end
end