awesomeWM / awesome

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

Mouse input lockdown when using keygrabber in client button action #2398

Open M4he opened 6 years ago

M4he commented 6 years ago

System Information

Output of awesome --version:

awesome v4.2 (Human after all)
 • Compiled against Lua 5.1.5 (running with Lua 5.1)
 • D-Bus support: ✔
 • execinfo support: ✔
 • xcb-randr version: 1.5
 • LGI version: 0.9.1

OS:

Distributor ID: Debian
Description:    Debian GNU/Linux 9.5 (stretch)
Release:    9.5
Codename:   stretch

Running awesome standalone using LightDM.

How to reproduce the issue

Use the default config template (/etc/xdg/awesome/rc.lua) but adjust the clientbuttons definition to the following:

clientbuttons = gears.table.join(
    awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
    awful.button({ modkey }, 1, awful.mouse.client.move),
    awful.button({ modkey }, 3, awful.mouse.client.resize),
    awful.button({ modkey }, 2, function (c)
      local grabber
      grabber = awful.keygrabber.run(function(mod, key, event)
        naughty.notify({title= event,text= key })
        awful.keygrabber.stop(grabber)
      end)
    end)
)

Actual result

Expected result

Remarks

Above quoted code is a heavily simplified use case. Original motivation is an issue with my personal awesome config which uses custom menu popup widgets that register a keygrabber for menu navigation and closing actions, which will also suffer from the mouse input lockdown when called that way. I tracked down the cause of the issue to the constellation shown above which represents the core mechanism of my config that originally made this issue appear.

If reproduced as described above, the issue with the mouse event lockdown does occur only occasionally. It seems to be related to the timing of pressing and releasing the modkey and mouse button. In my (much larger) awesome configuration however, the issue is happening every single time.

Note: the mechanism works fine on any awful.button definition anywhere else (titlebars, widgets etc.), only when used in client.buttons the issue appears.

Elv13 commented 6 years ago

First, thanks for the detailed and clear bug report. It's too bad nobody had time to reproduce yet. Can you try with git-master? I fixed one of the reason why this could happen. My guts tell me there is more and I have seen some myself in the past when I wrote a macro module.

The API for keygrabbing is still compatible, but a new, higher level, one is preferred:

https://awesomewm.org/apidoc/classes/awful.keygrabber.html

M4he commented 5 years ago

Thanks for the response and sorry for the late reply. I tried with the current git master now. Still the same issue.

psychon commented 5 years ago

Since I haven't written here anything yet: I reproduced a couple of times already, but I haven't managed to debug this in any useful way yet.

Just now I had a new idea on what could be going on: Some race/desynchronisation between AwesomeWM and the X11 server. The server could freeze input processing, because it waits for an AllowEvents from AwesomeWM (yes, that's a thing). AwesomeWM could "mis-handle" the button release, because the keygrabber is already running and so a different code path handles the event. (While from the point of view of the server, the release occurred before the key grab was activated.)

All of this is just a theory and it could be checked by making awesome print sequence numbers of input events and (some of) the requests it sends. However, I do not have time for this right now, so I am just leaving this theory here for future-me.

Again, sorry that I never answered before.

M4he commented 4 years ago

Workaround

So since this was a long-standing issue in my config and I finally got around to revamping and polishing it recently, I finally took the time to tackle this again and seem to have found a workaround:

clientbuttons = gears.table.join(
    awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
    awful.button({ modkey }, 1, awful.mouse.client.move),
    awful.button({ modkey }, 3, awful.mouse.client.resize),
    awful.button({ modkey }, 2, function (c)

      gears.timer.start_new(0.1, function() -- timer wrap begin

        grabber = awful.keygrabber.run(function(mod, key, event)
          naughty.notify({title= event,text= key })
          awful.keygrabber.stop(grabber)
        end)

      end) -- timer wrap end

    end)
)

Using this small trick to wrap the keygrabber execution in a timer callback seems to enable it to break free from whatever event/execution context that would occasionally misbehave and freeze the input.