Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

With 2 window opening the same file, pressing C-g sometimes scrolls to the position in the other window. #45

Open
AmaiKinono opened this issue Oct 28, 2020 · 7 comments

Comments

@AmaiKinono
Copy link
Contributor

First, I can say this is not a problem of mini-modeline alone. I have an old configuration project that doesn't use mini-modeline and it has exactly the same problem. But vanilla Emacs works well, and the problem appears after enabling mini-modeline-mode, so I'd like to report it here and see if you have any idea. Here is how to reproduce:

  1. $ emacs -Q
(require 'dash)
(require 'mini-modeline)
(mini-modeline-mode)
  1. M-x delete-other-windows to keep only one window.
  2. C-x C-f to open a file. I use https://github.com/lsof-org/lsof/blob/master/main.c when testing, but it should happen with any file that's long enough.
  3. M-x split-window-horizontally, so we have 2 window viewing the same file now.
  4. Scroll one window down to somewhere.
  5. Hold C-g, or maybe press it repeatedly and quickly, then the window may go back to the starting position of the file.

If you scroll the other window to some position, and do the same thing, you'll see it actually goes near the position in the other window. Here's a screen recording:

c-g

It's a problem that confuses me for a year. I said it doesn't only happen when using mini-modeline. I believe mode-line-bell also causes the problem (I didn't use it but has some similar code in my configuration). In my current configuration:

  • I set ring-bell-function to ignore, and don't use mini-modeline, problem gone.
  • I set ring-bell-function to ignore, and use mini-modeline, problem appears.
  • I don't use mini-modeline, and use a ring-bell-function. I've created 3 versions:
    • Blinks the modeline: problem appears.
    • Blinks the current line: problem appears.
    • Blinks the echo area (just like what mini-modeline--set-buffer-face does, but restores it with a timer): problem gone.

I didn't do this experiment with $ emacs -Q yet.

My best guess is:

  • Doing things with the modeline (like in mini-modeline and mode-line-bell) causes the problem.
  • Use a "window-local" visual cue (like blinking the current line) for the visible bell causes the problem.

I'm on GNU/Linux and Emacs 27.1.

@AmaiKinono
Copy link
Contributor Author

AmaiKinono commented Oct 28, 2020

After some experiment I found this line in mini-modeline--enable causes the problem:

(setq mini-modeline--timer (run-with-timer 0 0.1 #'mini-modeline-display))

If change this to

(add-hook 'pre-redisplay-functions #'mini-modeline-display)

The problem is gone.

Now I believe the reason is keyboard-quit, timer and the UI elements interfere with each other. This may be a problem of Emacs itself.

Edit: I found a way to simply reproduce it in $ emacs -Q. Just run this line:

(run-with-timer 0 0.1 (lambda () (setq mode-line-format "hi")))

and open a file and do the test, it will happen. Maybe I should report this in the GNU Emacs issue tracker.

Edit: I reported it here: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=44448.

AmaiKinono added a commit to AmaiKinono/emacs-mini-modeline that referenced this issue Nov 4, 2020
…n in window

See kiennq#45. I found using idle-timer rather than timer fixes the problem.
@Eli-Zaretskii
Copy link

Eli-Zaretskii commented Nov 5, 2020

The subtle bug in Emacs which caused this should be fixed now, thanks.

I must note, though, that updating the mode line with such a high frequency is not a good idea: each mode-line update sets a flag that disables display optimizations of the current buffer. So redisplay of the current buffer will work much harder, and don't be surprised if users come back complaining that your mode makes Emacs less responsive.

@AmaiKinono
Copy link
Contributor Author

@Eli-Zaretskii Actually what mini-modeline-display does is writing things to the minibuffer (not the mode-line, sorry for the inaccuracy in my report). like this:

(run-with-timer
 nil 0.1
 (lambda ()
   (let ((buf (window-buffer (minibuffer-window nil))))
     (with-current-buffer buf
       (erase-buffer)
       (insert "hi")))))

which could also cause this bug in vanilla Emacs. Does writing to minibuffer also has the performance problem you mentioned?

@Eli-Zaretskii
Copy link

It will cause at least part of the problems, yes. What this dies is modify a non-current buffer at high frequency, so the main redisplay optimization of updating only the selected window will be disabled. And when that happens, Emacs examines all the windows on all the frames to see which ones need to be updated, something that takes more cycles.

In general, doing something that updates some stuff on display at very high frequency must cause some degradation of redisplay performance.

(Btw, the above recipe signals an error when the minibuffer is active; e.g., try "C-x C-f" after activating the timer.)

@Eli-Zaretskii
Copy link

Sorry, I meant "does", not "dies".

@AmaiKinono
Copy link
Contributor Author

Thanks!

What this does is modify a non-current buffer at high frequency, so the main redisplay optimization of updating only the selected window will be disabled.

Seems this is unavoidable because the whole idea of this package is to show info in the echo area. I guess what makes mode-line could update itself frequently is it's written in C, and we can't do similar things by elisp. Is that right?

Btw, the above recipe signals an error when the minibuffer is active

Yes, but you can ignore them and do the test. The actual code in this package uses a bunch of predicates to decide whether it should write to the minibuffer so it doesn't has the problem.

@Eli-Zaretskii
Copy link

Seems this is unavoidable because the whole idea of this package is to show info in the echo area.

Does the info change every 100 milliseconds? If not, how about updating the echo-area only when it changes?

Anyway, if that's what the mode needs to do, so be it; I just wanted to point out the price.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants