ch11ng / exwm

Emacs X Window Manager
2.85k stars 134 forks source link

Screen flickering on Input #435

Closed guskovd closed 6 years ago

guskovd commented 6 years ago

Archlinux Emacs 25.3.4

After updating to version 25.3.4, exwm began to behave strangely. In firefox (line-mode), when you type text, the screen flickers. In char-mode, everything is fine

guskovd commented 6 years ago

I understand that this is not related specifically to the new version of emacs.

Rollback to the previous version did not solve the problem. Apparently, I need to roll back some other package. But I do not know what

dakra commented 6 years ago

I have the same since some time. I don't even think exwm got updated when it first appeared so I thought it has something to do with gtk or firefox.

One way where it is annoying is when you type in the address bar and then press DOWN to select a suggestions, this doesn't work anymore.

pestctrl commented 6 years ago

I have this issue on arch linux as well. The breaking change for me has been updating the X server from version 1.19.6 to 1.20.0.

ch11ng commented 6 years ago

I can confirm this. Many changes have landed in the Xserver 1.20 release. Still digging through its source.

Stebalien commented 6 years ago

It looks like windows aren't being properly focused, or something like that...

  1. If I run xdo activate -N Firefox, it'll correctly activate my firefox window but won't give it keyboard focus.
  2. If I then click on the Firefox window, it will gain full focus and doesn't flicker on input.
  3. This window appears to retain this property. If I switch to a different window and back, I again won't get keyboard focus until I click and again typing doesn't cause any focus flicker (once I click).
Stebalien commented 6 years ago

So, always using WM_TAKE_FOCUS in exwm-input--set-focus appears to fix this. ~Is the exwm--hints-input conditional backwards (and did xorg fix a bug?)?~

tohojo commented 6 years ago

Steven Allen notifications@github.com writes:

So, always using WM_TAKE_FOCUS in exwm-input--set-focus appears to fix this. Is the exwm--hints-input conditional backwards (and did xorg fix a bug?)?

This does help the behaviour on Firefox for me as well, but only on the machine where exwm is working (i.e., no cursor issues). On the other machine, it makes no difference.

Another weird thing on the broken machine: When I run a terminal (uxrvt in exwm char mode), I cannot type in it; instead, I get 'buffer is read-only' errors in the Emacs modeline. However, if I mash a bunch of keys at once (i.e., if input happens really quickly), some of the characters are passed through to the terminal...

tohojo commented 6 years ago

Toke Høiland-Jørgensen toke@toke.dk writes:

Steven Allen notifications@github.com writes:

So, always using WM_TAKE_FOCUS in exwm-input--set-focus appears to fix this. Is the exwm--hints-input conditional backwards (and did xorg fix a bug?)?

This does help the behaviour on Firefox for me as well, but only on the machine where exwm is working (i.e., no cursor issues). On the other machine, it makes no difference.

Another weird thing on the broken machine: When I run a terminal (uxrvt in exwm char mode), I cannot type in it; instead, I get 'buffer is read-only' errors in the Emacs modeline. However, if I mash a bunch of keys at once (i.e., if input happens really quickly), some of the characters are passed through to the terminal...

Aha! I did some more investigation, and tracked the weird behaviour to this line in my .Xmodmap:

keycode 233 = XF86Forward

which for the life of me I can't remember why I put there. I have another one mapping keycode 234 to XF86Back, which does not seem to give any problems...

Anyway, removing that line causes exwm to work again, and the WM_TAKE_FOCUS now also improves firefox behaviour in line mode on this machine :)

tohojo commented 6 years ago

Toke Høiland-Jørgensen toke@toke.dk writes:

Toke Høiland-Jørgensen toke@toke.dk writes:

Steven Allen notifications@github.com writes:

So, always using WM_TAKE_FOCUS in exwm-input--set-focus appears to fix this. Is the exwm--hints-input conditional backwards (and did xorg fix a bug?)?

This does help the behaviour on Firefox for me as well, but only on the machine where exwm is working (i.e., no cursor issues). On the other machine, it makes no difference.

Another weird thing on the broken machine: When I run a terminal (uxrvt in exwm char mode), I cannot type in it; instead, I get 'buffer is read-only' errors in the Emacs modeline. However, if I mash a bunch of keys at once (i.e., if input happens really quickly), some of the characters are passed through to the terminal...

Aha! I did some more investigation, and tracked the weird behaviour to this line in my .Xmodmap:

keycode 233 = XF86Forward

which for the life of me I can't remember why I put there. I have another one mapping keycode 234 to XF86Back, which does not seem to give any problems...

Anyway, removing that line causes exwm to work again, and the WM_TAKE_FOCUS now also improves firefox behaviour in line mode on this machine :)

Another observation: Enabling WM_TAKE_FOCUS breaks pinentry-qt (which tries to globally grab input, I think).

ch11ng commented 6 years ago

@Stebalien Thank you for the finding. I believe according to ICCCM we should not send WM_TAKE_FOCUS but use SetInputFocus directly for the so called 'locally active mode' X windows (I may misunderstand that pedantic spec). Perhaps some relevant change had been made.

ch11ng commented 6 years ago

This change was introduced by https://cgit.freedesktop.org/xorg/xserver/commit/?id=c67f2eac56518163981af59f5accb7c79bc00f6a , with which apps would receive extra FocusIn/FocusOut events when keyboard is grabbed. I can't tell if this change is reasonable, but the problem is:

No idea how to resolve this yet, but it seems little can be done on our side.

tohojo commented 6 years ago

Chris Feng notifications@github.com writes:

This change was introduced by https://cgit.freedesktop.org/xorg/xserver/commit/?id=c67f2eac56518163981af59f5accb7c79bc00f6a , with which apps would receive extra FocusIn/FocusOut events when keyboard is grabbed. I can't tell if this change is reasonable, but the problem is:

  • EXWM would grab keyboard in line-mode in order to intercept key events.

Does this happen on every key press? I'm not too familiar with the X protocol, but is there no way to avoid grab events except when the mode changes?

  • X server would send extra events to notify focus change when keyboard is grabbed (they are notifications only; input focus is not changed actually).
  • Apps like Firefox would 'do something' when there is an input focus change (even if it's not real).

No idea how to resolve this yet, but it seems little can be done on our side.

Well, if nothing can be done, opening a bug against firefox might be the way forward; but that seems like it would be a long game of whack-a-mole with applications that do weird things...

Stebalien commented 6 years ago

@ch11ng one way to handle this would be to be smarter about which keys we grab. That is, grab the line mode prefix keys and then only grab the entire keyboard when one of them has been pressed. This should also improve performance.

ch11ng commented 6 years ago

The problem is what we want to 'grab' are key sequences, so theoretically any key may get checked when necessary. Grabbing dynamically requires constantly issuing grab/ungrab requests, which can result in timing problems.

Stebalien commented 6 years ago

Can't we grab the prefix keys synchronously (aren't we already doing that)? That should block all other key presses until we handle the prefix key giving us time to grab the rest of the keyboard (or am I missing something about how key grabbing works?).

dakra commented 6 years ago

Well, if nothing can be done, opening a bug against firefox might be the way forward

Just want to add that it also happens in the pidgin username dropdown. So in an open pidgin conversation press 'C-m' to start texting a new buddy, add partial name and try selecting it with up/down (C-n/C-p for me) that doesn't work anymore. So it's not only Firefox that's affected.

ch11ng commented 6 years ago

@Stebalien This sounds tricky but I'll give a try.

Stebalien commented 6 years ago

You could also try asking the Xorg devs if there is a better solution. However, I'm pretty sure most key-chord hotkey binding programs (e.g., sxhkd) use this "grab the prefix only" method (for performance reasons).

ch11ng commented 6 years ago

@Stebalien As I tried your suggestion I found it difficult to figure out which keys should be grabbed. Emacs is quite flexible at processing keys: extra-keyboard-modifiers, keyboard-translate-table, input-decode-map, local-function-key-map, key-translation-map, overriding-terminal-local-map ... all can alter the meaning of keys. Besides there are other aspects to take into consideration.

In the meantime I've been trying with the XI2 extension to grab and replay keys. From the source of Xorg server it appears if we grab 'slave devices' those annoying events won't be generated. No much process has been made on this yet but at least XI2 works after some fixes.

Stebalien commented 6 years ago

Can you not grab exwm-input-prefix-keys and then grab everything if one of these are pressed? I may have misunderstood how line-mode works.

FYI, I've found that sending WM_TAKE_FOCUS in addition to SetInputFocus appears to work. That is:

(defun exwm-input--set-focus (id)
  "Set input focus to window ID in a proper way."
  (when (exwm--id->buffer id)
    (with-current-buffer (exwm--id->buffer id)
      (cond
       ((and (not exwm--hints-input)
             (memq xcb:Atom:WM_TAKE_FOCUS exwm--protocols))
        (when (= (frame-parameter nil 'exwm-id)
                 (slot-value (xcb:+request-unchecked+reply exwm--connection
                                 (make-instance 'xcb:GetInputFocus))
                             'focus))
          (exwm--log "Focus on #x%x with WM_TAKE_FOCUS" id)
          (exwm-input--update-timestamp
           (lambda (timestamp id)
             (let ((event (make-instance 'xcb:icccm:WM_TAKE_FOCUS
                                         :window id
                                         :time timestamp)))
               (setq event (xcb:marshal event exwm--connection))
               (xcb:+request exwm--connection
                   (make-instance 'xcb:icccm:SendEvent
                                  :destination id
                                  :event event))
               (exwm-input--set-active-window id)
               (xcb:flush exwm--connection)))
           id)))
       (t
        (exwm--log "Focus on #x%x with SetInputFocus" id)
        (exwm-input--update-timestamp
         (lambda (timestamp id)
           (let ((event (make-instance 'xcb:icccm:WM_TAKE_FOCUS
                                       :window id
                                       :time timestamp)))
             (setq event (xcb:marshal event exwm--connection))
             (xcb:+request exwm--connection
                 (make-instance 'xcb:icccm:SendEvent
                                :destination id
                                :event event)))
           (xcb:+request exwm--connection
               (make-instance 'xcb:SetInputFocus
                              :revert-to xcb:InputFocus:Parent
                              :focus id
                              :time timestamp))
           (exwm-input--set-active-window id)
           (xcb:flush exwm--connection))
         id))))))

I'm not sure if this is the right way to do this, but I haven't had any focus issues since making this change.

dakra commented 6 years ago

@Stebalien thanks. I just evaled your snippet and can confirm that it also solves the focus problem I had (firefox navbar and pidgin new message contact popup) :+1:

tohojo commented 6 years ago

Daniel Kraus notifications@github.com writes:

@Stebalien thanks. I just evaled your snippet and can confirm that it also solves the focus problem I had (firefox navbar and pidgin new message contact popup) :+1:

Yup, seems to work for me as well; thanks! :)

ch11ng commented 6 years ago

@Stebalien I'm not sure how your snippet works around the problem. It worth further investigations of course.

Anyway I've given up replaying key events with the core protocol, but I'm surprised to learn XI2 cannot do replay for slave keyboards (it does work for the master). If someone know how to do that, please tel me. For now I turn to XTEST and it basically works. I'm afraid something may be broken with this change so please give as much test as you can.

Stebalien commented 6 years ago

That change appears to break my electron-based slack. For some reason, exwm doesn't capture any events when I first start it. After some messing around, it started capturing events however, when I tried to close slack, I started running into weird focus issues.

dakra commented 6 years ago

The last xelb and exwm updates break things for me too. Most noticeable is that CapsLock which normally is mapped to Control is really CapsLock but only in X11 buffers.

ch11ng commented 6 years ago

Considering the regressions introduced in by the last change I've replaced it with @Stebalien's solution. Sending an extra WM_TAKE_FOCUS event doesn't seem to cause any side-effect. I have to admit it's a good solution for it does solve the problem, though the theory behind it is not clear.

medranocalvo commented 6 years ago

This seems to be working all right. @ch11ng, shall we close this ticket?

ch11ng commented 6 years ago

@medranocalvo I think so. We ended up with @Stebalien's solution and it works fine. @Stebalien thanks!