awesomeWM / awesome

awesome window manager
https://awesomewm.org/
GNU General Public License v2.0
6.41k stars 598 forks source link

Handle refocusing the same client with mod-j/k #182

Open blueyed opened 9 years ago

blueyed commented 9 years ago

[This was originally reported in the old bugtracker (FS#1284).]

  1. HeidiSQL (download at http://www.heidisql.com/download.php) breaks Mod+J: the focus cannot be moved away from the HeidiSQL window. The taskbar entry flashes, but does not move to the next client.
  2. When moving to the HeidiSQL client with Mod+K, the client window does not get raised properly: it gets the focus, but stays in the background.

This requires you to use combinations of mod+j and mod+k to move away or select the client window.

The relevant properties of the dialog ("Session manager") are:

WM_STATE(WM_STATE):
                window state: Normal
                icon window: 0x0
_NET_WM_STATE(ATOM) = _NET_WM_STATE_SKIP_TASKBAR
_NET_WM_NAME(UTF8_STRING) = "Session manager"
WM_ICON_NAME(STRING) = "Session manager"
WM_NAME(STRING) = "Session manager"
WM_HINTS(WM_HINTS):
                Client accepts input or input focus: False
                Initial state is Normal State.
                bitmap id # to use for icon: 0x58009dc
                bitmap id # of mask for icon: 0x58009de
                window id # of group leader: 0x5a00003
_NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_NORMAL
WM_TRANSIENT_FOR(WINDOW): window id # 0x5a00003
_MOTIF_WM_HINTS(_MOTIF_WM_HINTS) = 0x3, 0x26, 0x1e, 0x114400, 0x10500
WM_NORMAL_HINTS(WM_SIZE_HINTS):
                program specified location: 371, 154
                window gravity: Static
_NET_WM_USER_TIME_WINDOW(WINDOW): window id # 0x5800030
XdndAware(ATOM) = ATOM
_NET_WM_PID(CARDINAL) = 15842
WM_LOCALE_NAME(STRING) = "en_US.UTF-8"
WM_CLIENT_MACHINE(STRING) = "lenny.thequod.de"
WM_CLASS(STRING) = "heidisql.exe", "Wine"
WM_PROTOCOLS(ATOM): protocols  WM_DELETE_WINDOW, _NET_WM_PING, WM_TAKE_FOCUS

And the main window:

WM_STATE(WM_STATE):
                window state: Normal
                icon window: 0x0
_NET_WM_NAME(UTF8_STRING) = "HeidiSQL"
WM_ICON_NAME(STRING) = "HeidiSQL"
WM_NAME(STRING) = "HeidiSQL"
WM_HINTS(WM_HINTS):
                Client accepts input or input focus: False
                Initial state is Normal State.
                bitmap id # to use for icon: 0x5800056
                bitmap id # of mask for icon: 0x5800058
                window id # of group leader: 0x5a00003
_NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_NORMAL
_MOTIF_WM_HINTS(_MOTIF_WM_HINTS) = 0x3, 0x2c, 0x0, 0x67c10, 0x40100
WM_NORMAL_HINTS(WM_SIZE_HINTS):
                program specified location: 684, 385
                program specified minimum size: 1 by 1
                program specified maximum size: 1 by 1
                window gravity: Static
_NET_WM_USER_TIME_WINDOW(WINDOW): window id # 0x5800030
XdndAware(ATOM) = ATOM
_NET_WM_PID(CARDINAL) = 15842
WM_CLASS(STRING) = "heidisql.exe", "Wine"
WM_PROTOCOLS(ATOM): protocols  WM_DELETE_WINDOW, _NET_WM_PING, WM_TAKE_FOCUS

So the actual window ("Session manager") has skip_taskbar and the main window has a size of 1x1.

This works, because transient windows are stacked above their parents.

btw: c.focusable is True for both windows, despite the "Client accepts input or input focus: False" for the dialog. But that may be something different then?!

There are two issues here:

  1. The parent window should be highlighted in the taskbar. This can be fixed in the tasklist module.
  2. client.next() needs to handle this special case.

Re 2: when the main window is focused, it appears to send an event to focus the "dialog". The following is the output from some added print/printf statements:

== mod-j pressed
== focus.byidx: 1 c=nil ==
INSERT: window/client(Session manager): 0x1dbf198
INSERT: window/client(HeidiSQL): 0x2222518
sel: window/client(Session manager): 0x1dbf198
cycle: 2
focus.byidx: window/client(HeidiSQL): 0x2222518
client_focus: HeidiSQL
globalconf.focus.client: HeidiSQL
== mod-j end
client_focus_refresh: HeidiSQL (win: 148)
event_handle_focusin: Session manager
client_focus_update: Session manager
client_unfocus_internal: HeidiSQL
globalconf.focus.client: Session manager

I am not sure about how this should get handled. client.focus.byidx is not able to check if the focus was changed back, because this happens later (after client_focus_refresh).

Reported for HeidiSQL at: https://sourceforge.net/p/heidisql/tickets/3688/

psychon commented 9 years ago

btw: c.focusable is True for both windows, despite the "Client accepts input or input focus: False" for the dialog. But that may be something different then?!

Yeah, for c.focusable to be true, it is enough to either have the "accepts focus" hint or to implement the WM_TAKE_FOCUS protocol.

HeidiSQL seems to use the globally active input focus model and awesome only supports that partly. No idea why it does this (the 1x1 window seems quite useless), but let's look closely at what I guess happens:

This window is the window that we started with and thus trying to move the focus away failed.

I don't see what we can do to handle this besides ugly hacks. And especially in this case, I don't have much motivation for working around this, because the 1x1 window seems like a really, really bad hack on their end.

blueyed commented 9 years ago

I agree that this is a bad corner case, but I think we can improve awesome to handle it.

This window is the window that we started with and thus trying to move the focus away failed.

I think awesome could handle the case where the focus from the root window got taken by the same window, and skip it for focus selection, by focusing the next client in the mod-j list.

I would say that it currently cannot be implemented on the Lua level, and maybe shouldn't, because it's the deal of the WM_TAKE_FOKUS handler, I suppose?

I don't have much motivation for working around this

It's a little detail, yes, but can be maybe fixed with a few lines of code, and would make awesome more robust to this behavior in general.