1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-03-11 09:21:23 -07:00

Make 'frame-use-time' more reliable. (bug#80397)

Walking the window tree is more reliable than using the selected
window.  Implement 'get-mru-frame' on top of 'get-mru-frames'
using 'frame-use-time'.

* lisp/frame.el (frame-use-time): Change to walk the window tree
for the specified frame.
(get-mru-frames): New defun.
(get-mru-frame): Change to call 'get-mru-frames'.
* doc/lispref/frames.texi: Update documentation.
* etc/NEWS: Update announcement.
This commit is contained in:
Stéphane Marks 2026-03-05 09:58:03 +01:00 committed by Martin Rudalics
parent d40e5050be
commit 192d4fc1f7
3 changed files with 105 additions and 60 deletions

View file

@ -3188,21 +3188,32 @@ could switch to a different terminal without switching back when
you're done.
@end deffn
@cindex most recently used frame
@defun get-mru-frame &optional all-frames exclude
@cindex frame use time
@cindex use time of frame
@cindex frame order by time of last use
@defun frame-use-time &optional frame
This function is like @code{get-mru-window}, but it returns the most
recently used frame. The @dfn{most recently used frame} is the frame
with the most recently selected window as computed by
@code{get-mru-window}. (@pxref{Selecting Windows})
This function returns the use time of frame @var{frame}. @var{frame}
must be a live frame and defaults to the selected one.
This function will return @code{nil} if no candidate frames are found,
for example, if there is only one frame. Tooltip, minibuffer only, and
child frames are never candidates.
The @dfn{use time of a frame} is the highest use time as reported by
@code{window-use-time} of any window on @var{frame}.
@end defun
Since in practice the most recently used frame is always the selected
one, it usually makes sense to call this function with a non-@code{nil}
@var{exclude} argument with, for example, the selected frame.
@defun get-mru-frame &optional all-frames exclude-child-frames exclude-frame
This function returns the frame with the highest use time as reported by
@code{frame-use-time}. It returns @code{nil} if no candidate frames are
found which usually happens if frames are excluded with the help of the
optional arguments.
By default, tooltip and minibuffer-only frames are never candidates. If
the optional argument @var{exclude-child-frames} is non-nil, child
frames are excluded too. The @var{exclude-frame} argument, if present,
excludes the frame it specifies too. Since in practice the most
recently used frame is always the selected one, it usually makes sense
to call this function with a non-@code{nil} @var{exclude-frame} argument
specifying the selected frame.
The optional argument @var{all-frames} specifies which frames to
consider:
@ -3210,31 +3221,47 @@ consider:
@itemize @bullet
@item @code{visible}
means to consider all visible frames on the current terminal or
@var{exclude}'s terminal.
@var{exclude-frame}'s terminal.
@item 0
means to consider all visible or iconified frames on the current
terminal or @var{exclude}'s terminal.
terminal or @var{exclude-frame}'s terminal.
@item Anything else
means to consider all frames.
@end itemize
If @code{get-mru-frame} is called from within the body of
@code{with-selected-frame}, it may yield unexpected results as the most
recently used window will not necessarily match the selected one in the
temporarily selected frame. (@pxref{Selecting Windows})
@end defun
@cindex frame use time
@cindex use time of frame
@cindex frame order by time of last use
@defun frame-use-time &optional frame
@defun get-mru-frames &optional all-frames exclude-child-frames exclude-frame
This function returns the use time of frame @var{frame}. @var{frame}
must be a live frame and defaults to the selected one. The result is
the @code{window-use-time} of @var{frame}'s most recently used window
computed by @code{get-mru-window}. (@pxref{Selecting Windows})
This function returns a list of frames sorted by highest use time as
reported by @code{frame-use-time} which is computed using each frame's
most recently used window.
By default, tooltip and minibuffer-only frames are never candidates. If
the optional argument @var{exclude-child-frames} is non-nil, child
frames are excluded too. The @var{exclude-frame} argument, if present,
excludes the frame it specifies too.
It can return @code{nil} which can happen if frames are excluded with
the help of the optional arguments, for example, if there is a single
frame and @var{exclude-frame} is the selected frame.
The optional argument @var{all-frames} specifies which frames to
consider:
@itemize @bullet
@item @code{visible}
means to consider all visible frames on the current terminal or
@var{exclude-frame}'s terminal.
@item 0
means to consider all visible or iconified frames on the current
terminal or @var{exclude-frame}'s terminal.
@item Anything else
means to consider all frames.
@end itemize
@end defun
@deffn Command select-frame-by-id id &optional noerror

View file

@ -507,12 +507,12 @@ for a window. The result is the `window-use-time' of a frame's most
recently used window.
+++
*** New function 'get-mru-frame'.
This function returns the most recently used frame from among all
frames, or those visible or iconified on the same terminal as the
selected frame. A frame can be excluded, for example, the selected
frame, as it will always be the most recently used frame on the current
terminal.
*** New functions 'get-mru-frames' and 'get-mru-frame'.
'get-mru-frames' returns a list of frames sorted by their most recent
use time from among all frames, or those visible or iconified on the
same terminal as the selected frame. Child frames can be excluded. A
single frame can be excluded, for example, the selected frame.
'get-mru-frame' returns the single most recently used frame.
---
*** After deleting, 'delete-frame' now selects the most recently used frame.

View file

@ -2615,41 +2615,43 @@ for FRAME."
(defun frame-use-time (&optional frame)
"Return FRAME's last use time.
The result is the `window-use-time' of FRAME's most recently used window
computed by `get-mru-window'. If optional FRAME is nil, use the
selected frame."
(window-use-time
;; Arguments to `get-mru-window' consider all windows.
(get-mru-window (window-normalize-frame frame) t t t)))
The result is the highest `window-use-time' of any window on FRAME. If
optional FRAME is nil, use the selected frame."
(let ((time 0))
(walk-window-tree
(lambda (window)
(setq time (max time (window-use-time window))))
frame)
time))
(defun get-mru-frame (&optional all-frames exclude)
"Return the most recently used frame on frames specified by ALL-FRAMES.
Compute the result from each frame's most recently used window computed
by `get-mru-window', which see. Return nil if no candidate frames are
found, for example, if there is only one frame. Tooltip, minibuffer
only, and child frames are never candidates. Optional argument EXCLUDE,
when non-nil, is a frame to exclude, for example, the selected frame.
(defun get-mru-frames (&optional all-frames
exclude-child-frames
exclude-frame)
"Return a frame list sorted by most recent use and filtered by ALL-FRAMES.
Compute the result using `frame-use-time', which see. Tooltip, and
minibuffer only frames are never candidates. If optional argument
EXCLUDE-CHILD-FRAMES is non-nil, eliminate child frames as candidates.
If EXCLUDE-FRAME is non-nil, it is a frame to exclude, for example, the
selected frame.
The following non-nil values of the optional argument ALL-FRAMES
have special meanings:
- `visible' means consider all visible frames on the current terminal
or EXCLUDE's terminal if non-nil.
or EXCLUDE-FRAME's terminal if EXCLUDE-FRAME is non-nil.
- 0 (the number zero) means consider all all visible and iconified
frames on the current terminal or EXCLUDE's terminal if non-nil.
frames on the current terminal or EXCLUDE-FRAME's terminal if
EXCLUDE-FRAME is non-nil.
Any other value of ALL-FRAMES means consider all frames."
(setq all-frames (or all-frames t))
(let* ((mru-frame)
(time)
(best-time 0)
(terminal (frame-terminal (or exclude (selected-frame))))
(let* ((terminal (frame-terminal (or exclude-frame (selected-frame))))
(frame-list
(seq-remove (lambda (frame)
(or (eq frame exclude)
(or (eq frame exclude-frame)
(eq (frame-parameter frame 'minibuffer) 'only)
(frame-parent frame)))
(and exclude-child-frames (frame-parent frame))))
(cond
((eq all-frames 'visible)
(seq-filter (lambda (frame)
@ -2660,12 +2662,28 @@ Any other value of ALL-FRAMES means consider all frames."
(eq (frame-terminal frame) terminal))
(frame-list)))
(t (frame-list))))))
(dolist (frame frame-list)
(setq time (frame-use-time frame))
(when (> time best-time)
(setq best-time time)
(setq mru-frame frame)))
mru-frame))
(sort frame-list :key #'frame-use-time :reverse t)))
(defun get-mru-frame (&optional all-frames exclude-child-frames exclude-frame)
"Return the most recently used frame on frames specified by ALL-FRAMES.
Compute the result using `frame-use-time', which see. Tooltip, and
minibuffer only frames are never candidates. If optional argument
EXCLUDE-CHILD-FRAMES is non-nil, eliminate child frames as candidates.
If EXCLUDE-FRAME is non-nil, it is a frame to exclude, for example, the
selected frame.
The following non-nil values of the optional argument ALL-FRAMES
have special meanings:
- `visible' means consider all visible frames on the current terminal
or EXCLUDE-FRAME's terminal if EXCLUDE-FRAME is non-nil.
- 0 (the number zero) means consider all all visible and iconified
frames on the current terminal or EXCLUDE-FRAME's terminal if
EXCLUDE-FRAME is non-nil.
Any other value of ALL-FRAMES means consider all frames."
(car (get-mru-frames all-frames exclude-child-frames exclude-frame)))
;;;; Frame/display capabilities.