emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] Fix display-buffer-use-some-window to honor reusable-frames


From: martin rudalics
Subject: Re: [PATCH] Fix display-buffer-use-some-window to honor reusable-frames
Date: Mon, 6 Feb 2023 11:01:20 +0100

> (2) The current version of 'window-bump-use-time' changes the semantics
> of "least recently used window" without even mentioning that anywhere.
> For example, this code in sql.el
>
>      (let ((one-win (eq (selected-window)
>                         (get-lru-window))))
>
> will conclude that there is only one window even if another window
> recently created by 'display-buffer-use-least-recent-window' exists.  I
> have no idea how 'get-mru-window' could be affected.
>
> This is a grave bug.

This statement is much too harsh.  The "use time" concept is inherently
flawed ever since it was conceived and it's unlikely that we will ever
be able to fix that.

For example, the following form

(with-selected-window (split-window nil nil t)
  (eq (get-lru-window) (selected-window)))

will consider the selected window the least recently used one which
doesn't make sense.  One now might think that the "least recently used
window" is well-defined outside the scope of 'with-selected-window' but
even that is false.  Consider

(let (window)
  (with-selected-window (setq window (split-window nil nil t))
    (select-window (split-window window nil t)))
  (eq (selected-window) (get-mru-window)))

Here the window selected outside the scope of any window excursion is no
more the most recently used one.

This means that any code like the above cited

>      (let ((one-win (eq (selected-window)
>                         (get-lru-window))))

is based on the false assumption that if the selected window is the
least recently used one, this is tantamount to saying that the selected
window is alone on its frame.

Given the number of 'display-buffer' calls that occur within window
excursions like 'save-selected-window', 'with-selected-window' and the
like, there's no wonder that many of them have produced unexpected
results in the past.  To cite but a few, all of ‘next-error-no-select’,
‘xref--show-location’, ‘widget-button--check-and-call-button’,
‘table-generate-source’, ‘mail-recover’, ‘occur-mode-display-occurrence’
cannot hold apart the selected window from the most recently used one
when running 'display-buffer-use-some-window'.

What looks even more disturbing is that these functions are often
supposed to use a window that is not the selected one.  But for
'display-buffer' the selected window is the one temporarily selected by
these functions and not the one that will be selected after the temporal
selection has been left and the final result in form of a displayed
buffer is presented.  Which obviously means that all action functions
called by 'display-buffer' that deal with the selected window and its
avoidance via an 'inhibit-same-window' action alist entry are affected.

Consider

(with-selected-window (split-window)
  (display-buffer "*Messages*"))

*Messages* will be displayed in the upper window and that window will be
the selected one.  Hardly what 'display-buffer' is advertised to do.

But this also means that code bumping a window's use time can do that
any which way it likes.  There is no invariant that code should try to
preserve.  Although it might be a good idea to not bump any window's use
time in a state where the selected window's use time does not equal the
value of window_select_count as in the version below.

DEFUN ("window-bump-use-time", Fwindow_bump_use_time,
       Swindow_bump_use_time, 0, 1, 0,
       doc: /* Mark WINDOW as most recently used after the selected window.
WINDOW must specify a live window.

If WINDOW is not selected and the selected window has the highest use
time of all windows, set the use time of WINDOW to that of the selected
window, increase the use time of the selected window by one and return
the new use time of WINDOW.  Otherwise, do nothing and return nil.  */)
  (Lisp_Object window)
{
  struct window *w = decode_live_window (window);
  struct window *sw = XWINDOW (selected_window);

  if (w != sw && sw->use_time == window_select_count)
    {
      w->use_time = window_select_count;
      sw->use_time = ++window_select_count;

      return make_fixnum (w->use_time);
    }
  else
    return Qnil;
}

martin

reply via email to

[Prev in Thread] Current Thread [Next in Thread]