ch11ng / exwm

Emacs X Window Manager
2.85k stars 135 forks source link

Helm find files loses focus #575

Open RidaAyed opened 5 years ago

RidaAyed commented 5 years ago

While browsing with firefox (tridactyl for vim motions), I often need to switch to some file buffer using s-<Space> helm-find-files or M-x helm-find-files

In helm, hitting <tab> to complete the filepath in the helm-find-files buffer, changes the focus back to firefox and I'm forced to move the mouse, click around, hit esc since the remaining helm buffer becomes unusable.

Do I need to change something related to this 1line?

System Info :computer:

Footnotes

1 https://github.com/emacs-helm/helm-exwm/blob/master/helm-exwm.el#L191

ch11ng commented 5 years ago

Perhaps pressing tab should not select a window displaying a exwm-mode buffer.

There is a valid use case where users can activate the minibuffer and navigate to other windows (including those displaying exwm-mode buffers) to for example copy something back to the minibuffer. So for this use case to work, instead of forwarding keys to Emacs whenever the minibuffer window is active we also check if the minibuffer window is currently selected.

setzer22 commented 5 years ago

@ch11ng Indeed, pressing (helm-execute-persistent-action) in helm should not switch to exwm-mode buffers. As the documentation for the function indicates:

Perform the associated action ATTR without quitting helm.

If helm does not quit, but the exwm-mode buffer gets focus, the helm window will get in a broken state from which the only way to recover consistently for me is to click the modeline for the helm buffer and kill it manually with a keybinding. In this state, the helm buffer will treat input as if it were a regular buffer (I can edit/delete text in it, for example). Note that this does not happen with regular emacs buffers.

Having this working would allow to set helm-follow-mode. I think this would be an awesome feature to use helm as a window switcher, because we'd be able to see the window contents, not just the title!

Do you have any directions as to where this should be implemented? I'm willing to take a look at it myself!

ch11ng commented 5 years ago

Strangely I can't seem to reproduce the problem with @RidaAyed 's recipe ATM. Am I missing something?

Having this working would allow to set helm-follow-mode.

@setzer22 I'm quite new to helm. Could you elaborate it?

RidaAyed commented 5 years ago

Avoiding tab and to continue typing (including space) to narrow down to the desired result in helm-mini-buffer works.

setzer22 commented 5 years ago

@ch11ng Helm can act as a buffer "finder", and has a nice feature called helm-follow-mode. In this mode, when the cursor is over a buffer inside helm, the contents of the buffer will be shown in a temporary window. The underlying mechanism for this is the helm-execute-persistent-action, which for buffers, shows the contents of the buffer without changing focus, so helm can still be used. In helm-follow-mode, the helm-execute-persistent-action function is executed every time the cursor moves. Also, in spacemacs pressing <tab> executes the same function.

The nice thing about this feature with exwm-buffers is that you can see the contents of a buffer before you switch to it. A very good use-case for this is when you have multiple windows from the same program and they are not easily distinguishable by its title (e.g. multiple terminal emulator windows).

The problem is that when helm-execute-persistent-action is run on an exwm-buffer, the helm window looses focus, and enters in a broken state from where the only way to recover is to kill it. What I expect should happen is helm keeping focus, and the exwm buffer just being displayed.

I first reported this in here because I thought the two issues were closely related. But if you think I'm mistaken, please let me know and I'll submit a new one.

ch11ng commented 5 years ago

@setzer22 So here is what I did:

  1. M-x helm-buffers-list RET
  2. Press C-c C-f to enable helm-follow-mode
  3. Use either up or down arrow to preview all buffers

What I found is when an exwm-mode buffer is highlighted the minibuffer frame did lose focus. But up/down arrow keys still worked so it's possible to preview other buffers afterwards.

I've installed the helm and helm-exwm packages.

RidaAyed commented 5 years ago

I've made a 16 sec screencast https://imgur.com/a/EqaBfmQ about the issue. Helm focus is lost at 00:00:12 (imgur position 0:05) after hitting TAB. The subsequent keystrokes (up and down arrows) are sent to the other buffer (Firefox) instead.

setzer22 commented 5 years ago

@ch11ng Doing the exact same thing as you suggest in my machine won't work. The arrow keys are sent to the exwm-mode buffer and helm is frozen until killed. The behaviour I'm experiencing is consistent with the screencast from @RidaAyed.

The fact that both me and @RidaAyed are using spacemacs makes me think that this may have something to do with either spacemacs or its unofficial exwm layer (https://github.com/timor/spacemacsOS). @RidaAyed, are those two also part of your setup? Maybe that's part of the issue...

RidaAyed commented 5 years ago

@setzer22

are those two also part of your setup?

Indeed. I'm using spacemacs and https://github.com/timor/spacemacsOS

ch11ng commented 5 years ago

Could you enable debug mode (M-x exwm-debug RET) to prepare a log? Spacemacs makes so many tweaks that it's hard to guess by reviewing configs.

setzer22 commented 5 years ago

I finally had some time to look into this. I generated the log as requested. This is the sequence of steps that I recorded:

  1. In the initial state, I was in the XELB-DEBUG buffer
  2. At this point, I pressed SPC-b-b which is bound to helm-mini
  3. In helm-mini I highlighted an exwm-mode buffer (the Gpick application).
  4. I pressed TAB to run helm-execute-persistent-action. NOTE: Spacemacs rebinds the default for the TAB key in helm.
  5. The Gpick buffer was shown. Neither window had focus at this point.
  6. Using my mouse, I manually focused and closed Gpick. During this whole time, helm was unresponsive.
  7. After closing the window, helm was closed as well and I was brought back to XELB-DEBUG, where I copied the log.

And here's the resulting log: https://pastebin.com/AnEWpeL6

Hope it helps!

ch11ng commented 5 years ago

@setzer22 The debug log says Gpick got the input focus. The only key EXWM received was (65307 . 0) (a keysym) which is likely an escape and it was followed by exwm-reset (perhaps you bind exwm-reset to escape?). I'm not sure if the input focus was elsewhere. Could you execute export DISPLAY=:0; xwininfo -tree -root; xdotool getwindowfocus (you'll need to install xdotool and xwininfo) between Step 5 & 6 and see which X window gets the focus? You may either run it from Linux console, or make a new global key binding for it. Also, when reproducing this issue, try typing something after the input focus is lost.

setzer22 commented 5 years ago

@ch11ng Just a quick reply (will check with xwininfo later!). But indeed, Gpick or whatever window I try to show gets the input from my keyboard. By "no focus", I actually meant that neither emacs window appeared to be selected.

Anyway, to clarify things, the issue is precisely Gpick getting input focus. The method is supposed to show the buffer but not switch to it. That way you can "peek" a buffer before switching to it. When helm looses focus it becomes impossible to continue browsing buffers.

EDIT: I keep thinking this may be caused by the behaviour described in https://github.com/timor/spacemacsOS#window-behaviour-regarding-char-and-line-mode. It seems they change some things to synchronise the spacemacs insert/normal states and exwm-input-grab. But I really don't understand enough about exwm to check this...

ch11ng commented 5 years ago

I figured it out: that X window got input focus but was in char-mode so only global keys worked. But I'm not sure why it was put into char-mode.

setzer22 commented 5 years ago

All my X windows spawn in char-mode. Isn't that the mode where all input is forwarded to the application?

Anyway, I think it may be the code I posted above, which definitely messes with char/line modes. I will test with those changes disabled and see what happens.

setzer22 commented 5 years ago

EDIT I'm leaving the old post, but now that I have a clearer picture of the issue, let me clarify things:

This issue can be consistently reproduced when running helm-execute-persistent-action on a buffer that's in line-mode. Me and @RidaAyed encountered the issue because the spacemacs configuration layer in https://github.com/timor/spacemacsOS changes the default behaviour of char/line mode, and all exwm windows are opened in char-mode by default. This is probably why @ch11ng was not able to replicate the issue (please, could you try to reproduce the issue with a char-mode buffer to verify my theory?).

A quick workaround I've found for this is to slightly alter the helm persistent action for buffers (defined in helm-buffers-list-persistent-action) to take exwm into account. This elisp snippet will make things work:

(defun helm-buffers-list-persistent-action (candidate)
  (let ((current (window-buffer helm-persistent-action-display-window)))
    (if (or (helm-follow-mode-p)
            (eql current (get-buffer helm-current-buffer))
            (not (eql current (get-buffer candidate))))
        ;; CHANGE STARTS HERE:
        (progn
          (exwm-input-grab-keyboard (exwm--buffer->id candidate))
          (switch-to-buffer candidate))
        ;; CHANGE ENDS HERE
      (if (and helm-persistent-action-display-window
               (window-dedicated-p
                (next-window helm-persistent-action-display-window 1)))
          (delete-window helm-persistent-action-display-window)
        (switch-to-buffer helm-current-buffer)))))

Basically, what I did is set line-mode before helm switches to the exwm buffer. This maintains the original functionality in helm. However, it has the obvious side-effect of putting all buffers you try to show with helm in line-mode, which must be removed later.

As for a more robust fix for this, do you think there's a way to configure exwm so that running switch-buffer from within helm will not steal the input focus when the input is in char-mode?

--- OLD POST --- After some testing, I've managed to isolate the issue, which is caused by the following lines of code:

;; kick all exwm buffers into insert mode per default
(add-hook 'exwm-manage-finish-hook (lambda () (call-interactively #'exwm-input-release-keyboard)))

and

    ;; ensure that when char mode is left, state is restored to normal
    (advice-add 'exwm-input-grab-keyboard :after (lambda (&optional id)
                                                   (evil-normal-state)))
    ;; ensure that when char mode is entered, input state is activated
    (advice-add 'exwm-input-release-keyboard :after (lambda(&optional id)
                                                      (evil-insert-state)))

Disabling all three lines, messes up with spacemacs/exwm in general. However, the related issue seems to be fixed. This led me to investigate further, and I've actually discovered that the issue is only present when the buffer being shown by helm-execute-persistent-action is in char-mode. If I manually put Gpick in line mode, then I can show its contents without helm loosing focus.

@ch11ng I know this is now probably outside of the scope of exwm. However, any guidance on how to fix this would be much appreciated! My best bet is that we should try to modify helm-execute-persistent-action for exwm buffers so that it puts them in line-mode before displaying them. Is there a way to do that in elisp?

EDIT: Typed char when I meant line.

ch11ng commented 5 years ago

please, could you try to reproduce the issue with a char-mode buffer to verify my theory?

That's what I did.

As for a more robust fix for this, do you think there's a way to configure exwm so that running switch-buffer from within helm will not steal the input focus when the input is in char-mode?

In char-mode Emacs is not aware of key events targeting other applications. So to prevent this you have to either use line-mode, or make input focus stay on the minibuffer (avoid selecting other Emacs windows or select the minibuffer window again).

divansantana commented 5 years ago

I have the same issue. Because my X windows are spawned in char-mode. Moreover I had set helm-follow-mode-persistent to true, the default in nil. Setting it back to nil, prevents the helm preview and then the issue goes away.

codygman commented 4 years ago

I think my issue is related, but doesn't require using helm follow mode or anything like that. Apologies since I don't have anything more specific, but hopefully this helps us get closer to the issue with helm and exwm.

I sometimes hit go to switch buffers quickly after exiting back to line-mode from char-mode and two helm windows open, and I'm in the part where results are usually displayed. Then I can only get around it by doing C-x o until I'm in the "correct" helm buffer at the bottom of the screen and hit ctrl-g to exit.

I can then kill all helm related buffers and eventually the correct behavior seems to come back. It's all very odd.

Possibly related to emacs-helm/helm#194.

It only seems to happen when I've been switching between char-mode and line-mode, then quickly switch to a new buffer.

codygman commented 4 years ago

I also noticed there is an issue with company-box where focus is lost while typing normal completions, or the auto-completion window will just disappear. Are the other uses using helm-posframe?

I think company-box also uses a posframe. Does exwm not handle posframe well?