tumashu / ivy-posframe

ivy-posframe is a ivy extension, which let ivy use posframe to show its candidate menu, ivy-posframe is a **GNU ELPA** package.
414 stars 26 forks source link

Ivy-posframe loses focus on second frame when terminal is open #112

Open tefkah opened 3 years ago

tefkah commented 3 years ago

So this is a bit of a strange bug. When I am running emacs as a daemon, whenever I open a second frame and try to do something Ivy-y, say M-x, or find-file, the frame somehow "loses focus" and I end up typing/selecting things in the buffer behind the frame.

I have no idea what could be the cause of this, all I know is that it only happens on the second/third/... emacsclient instance, and that it has something to do with ivy-posframe, as disabling it fixes the issue.

I am running doom-emacs, so their configuration could play a role as well.

BlueDrink9 commented 3 years ago

I wonder if this is related to #88

clonex10100 commented 3 years ago

I'm getting a similar issue on emacs 28.0.50 (9c1bbad907575987054b8d81ac2d09bfabe6214b)

It happens when counsel, ivy-ich, and ivy-posframe modes are on, I'm in a created frame (not necessarily with emacsclient), and there is some kind of terminal/repl buffer showing in a window (vterm, ielm, python-repl, geiser, etc.)

Here is an emacs -Q, just eval it and try "M-x" in the created frame.

(require 'ivy)
(require 'counsel)
(require 'ivy-rich)
(require 'ivy-posframe)

(counsel-mode 1)
(ivy-rich-mode 1)
(ivy-posframe-mode 1)

(ielm)
(make-frame-command)
tefkah commented 3 years ago

I'v narrowed it down somewhat, thanks to @clonex10100. This seems to only happen when vterm is open in the second frame. It does not need to have focus. No idea why though!

Happens with or without ivy-rich

fw623 commented 3 years ago

This behaviour seems to occur whenever an ivy-posframe is used on a different frame than the one it was created for and that frame has a buffer in e.g. shell-mode (at least according to my testing). Though it works on its original frame just fine -- even after having lost focus in another frame.

My current (certainly suboptimal) workaround is (add-function :after after-focus-change-function (lambda () (posframe-delete-all))).

Edit: It doesn't seem to work how I thought, thus my workaround also doesn't fix it. Edit2: maybe it does -- see https://github.com/tumashu/ivy-posframe/issues/112#issuecomment-980818069

CarlQLange commented 2 years ago

I just hit the exact same bug on emacs master (as of today). vterm open in one frame, anything open in another, and when I invoke ivy in the vterm frame, it disappears and doesn't seem to gain focus.

Edit: I also seem to get "Attempt to delete a surrogate minibuffer frame" after this issue, when trying to delete the non-vterm frame. No idea if it is related.

tumashu commented 2 years ago

I have try in my machine, but can not find this bug, I use emacs28+debian

fw623 commented 2 years ago

How I can reproduce it

  1. (posframe-delete-all)
  2. open prompt and quit
  3. switch to other frame with a window in shell-mode (vterm-mode does the same)
  4. open prompt
  5. now input goes to the shell-buffer and after a short while the posframe disappears

"Fix"

Adding (add-function :after after-focus-change-function #'posframe-delete-all) actually does fix this for me (contrary to what I had thought earlier).

A new problem (EXWM)

But this "fix" causes an issue for me with counsel-switch-buffer (I use EXWM). Note that counsel-switch-buffer previews (i.e. switches to) the currently highlighted buffer. When the EXWM buffer

Funnily, this did not happen when the profiler was active, so this smells a lot like a race condition.

My current workaround is the following, which mostly works.

(defun fw/exwm-input--update-focus-commit (origfn window)
  "`exwm-input--update-focus-commit' but with attempted fixes for `ivy-posframe-mode'."
  (if (and
       (minibufferp nil t)
       (not (eq window (selected-window))))
      (select-window (selected-window))
    (if (equal " *ivy-posframe-buffer*" (buffer-name (window-buffer window)))
        (select-window (minibuffer-window))
      (funcall origfn window))))
(advice-add #'exwm-input--update-focus-commit :around #'fw/exwm-input--update-focus-commit)

I suspect this problem stems from EXWM using a timer to update the focus in exwm-input--update-focus-defer.

I hope this somehow helps with understanding this issue.

Edit1: corrected the EXWM fix and clarified EXWM problem Edit2: improved EXWM fix further