mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-04-27 08:43:40 -07:00
Add frame-use-time, get-mru-frame, use mru frame in delete-frame (bug#80397)
* lisp/frame.el (get-mru-frame): New defun. * src/frame.c (delete_frame): Call 'get-mru-frame' (when force is not Qnoelisp) to select the most recently used frame that is not the deleted frame as the candidate to select. (syms_of_frame): Qget_mru_frame new DEFSYM. * doc/lispref/frames.texi: Document the new functions. * etc/NEWS: Announce the new functions.
This commit is contained in:
parent
f31c61a9aa
commit
54d0764665
4 changed files with 181 additions and 36 deletions
|
|
@ -3188,6 +3188,55 @@ 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
|
||||
|
||||
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 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.
|
||||
|
||||
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.
|
||||
|
||||
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}'s terminal.
|
||||
|
||||
@item 0
|
||||
means to consider all visible or iconified frames on the current
|
||||
terminal or @var{exclude}'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
|
||||
|
||||
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})
|
||||
@end defun
|
||||
|
||||
@deffn Command select-frame-by-id id &optional noerror
|
||||
This function searches open and undeletable frames for a matching frame
|
||||
identifier @var{id} (@pxref{Frames}). If found, its frame is undeleted,
|
||||
|
|
|
|||
21
etc/NEWS
21
etc/NEWS
|
|
@ -494,6 +494,27 @@ fail to delete its argument FRAME or might signal an error. It is
|
|||
therefore advisable to use this function as part of a condition that
|
||||
determines whether to call 'delete-frame'.
|
||||
|
||||
+++
|
||||
*** New function 'frame-use-time'.
|
||||
This function is the frame equivalent of the function 'window-use-time'
|
||||
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.
|
||||
|
||||
---
|
||||
*** After deleting, 'delete-frame' now selects the most recently used frame.
|
||||
Previously, after deleting a specified frame, 'delete-frame' would
|
||||
select the next eligible frame in the order of the frame list. This is
|
||||
often unrelated to frames' recent use and can appear somewhat random to
|
||||
users.
|
||||
|
||||
+++
|
||||
*** New value 'force' for user option 'frame-inhibit-implied-resize'.
|
||||
This will inhibit implied resizing while a new frame is made and can be
|
||||
|
|
|
|||
|
|
@ -2610,6 +2610,60 @@ for FRAME."
|
|||
(or (/= (window-old-pixel-width root) (window-pixel-width root))
|
||||
(/= (+ (window-old-pixel-height root) mini-old-height)
|
||||
(+ (window-pixel-height root) mini-height)))))
|
||||
|
||||
(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)))
|
||||
|
||||
(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.
|
||||
|
||||
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.
|
||||
|
||||
- 0 (the number zero) means consider all all visible and iconified
|
||||
frames on the current terminal or EXCLUDE's terminal if 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))))
|
||||
(frame-list
|
||||
(seq-remove (lambda (frame)
|
||||
(or (eq frame exclude)
|
||||
(eq (frame-parameter frame 'minibuffer) 'only)
|
||||
(frame-parent frame)))
|
||||
(cond
|
||||
((eq all-frames 'visible)
|
||||
(seq-filter (lambda (frame)
|
||||
(eq (frame-terminal frame) terminal))
|
||||
(visible-frame-list)))
|
||||
((eq all-frames 0)
|
||||
(seq-filter (lambda (frame)
|
||||
(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))
|
||||
|
||||
;;;; Frame/display capabilities.
|
||||
|
||||
|
|
|
|||
93
src/frame.c
93
src/frame.c
|
|
@ -2748,57 +2748,77 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
|
|||
do_switch_frame (mru_rooted_frame (f), 0, 1, Qnil);
|
||||
else
|
||||
{
|
||||
Lisp_Object tail;
|
||||
eassume (CONSP (Vframe_list));
|
||||
|
||||
/* Look for another visible frame on the same terminal.
|
||||
Do not call next_frame here because it may loop forever.
|
||||
See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=15025. */
|
||||
FOR_EACH_FRAME (tail, frame1)
|
||||
frame1 = Qnil;
|
||||
if (!EQ (force, Qnoelisp))
|
||||
{
|
||||
struct frame *f1 = XFRAME (frame1);
|
||||
|
||||
if (!EQ (frame, frame1)
|
||||
&& !FRAME_TOOLTIP_P (f1)
|
||||
&& FRAME_TERMINAL (f) == FRAME_TERMINAL (f1)
|
||||
&& FRAME_VISIBLE_P (f1))
|
||||
break;
|
||||
/* Find the most recently used visible frame among all
|
||||
frames on the same terminal as FRAME, excluding FRAME
|
||||
which we are about to delete. */
|
||||
frame1 = calln (Qget_mru_frame, Qvisible, frame);
|
||||
if (!NILP (frame1))
|
||||
{
|
||||
struct frame *f1 = XFRAME (frame1);
|
||||
if (FRAME_TOOLTIP_P (f1)
|
||||
|| FRAME_TERMINAL (f) != FRAME_TERMINAL (f1)
|
||||
|| !FRAME_VISIBLE_P (f1))
|
||||
frame1 = Qnil;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is none, find *some* other frame. */
|
||||
if (NILP (frame1) || EQ (frame1, frame))
|
||||
if (NILP (frame1))
|
||||
{
|
||||
Lisp_Object tail;
|
||||
eassume (CONSP (Vframe_list));
|
||||
|
||||
/* Look for another visible frame on the same terminal.
|
||||
Do not call next_frame here because it may loop forever.
|
||||
See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=15025. */
|
||||
FOR_EACH_FRAME (tail, frame1)
|
||||
{
|
||||
struct frame *f1 = XFRAME (frame1);
|
||||
|
||||
if (!EQ (frame, frame1)
|
||||
&& FRAME_LIVE_P (f1)
|
||||
&& !FRAME_TOOLTIP_P (f1))
|
||||
{
|
||||
if (FRAME_TERMCAP_P (f1) || FRAME_MSDOS_P (f1))
|
||||
{
|
||||
Lisp_Object top_frame = FRAME_TTY (f1)->top_frame;
|
||||
&& !FRAME_TOOLTIP_P (f1)
|
||||
&& FRAME_TERMINAL (f) == FRAME_TERMINAL (f1)
|
||||
&& FRAME_VISIBLE_P (f1))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!EQ (top_frame, frame))
|
||||
frame1 = top_frame;
|
||||
/* If there is none, find *some* other frame. */
|
||||
if (NILP (frame1) || EQ (frame1, frame))
|
||||
{
|
||||
FOR_EACH_FRAME (tail, frame1)
|
||||
{
|
||||
struct frame *f1 = XFRAME (frame1);
|
||||
|
||||
if (!EQ (frame, frame1)
|
||||
&& FRAME_LIVE_P (f1)
|
||||
&& !FRAME_TOOLTIP_P (f1))
|
||||
{
|
||||
if (FRAME_TERMCAP_P (f1) || FRAME_MSDOS_P (f1))
|
||||
{
|
||||
Lisp_Object top_frame = FRAME_TTY (f1)->top_frame;
|
||||
|
||||
if (!EQ (top_frame, frame))
|
||||
frame1 = top_frame;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef NS_IMPL_COCOA
|
||||
else
|
||||
{
|
||||
/* Under NS, there is no system mechanism for choosing a new
|
||||
window to get focus -- it is left to application code.
|
||||
So the portion of THIS application interfacing with NS
|
||||
needs to make the frame we switch to the key window. */
|
||||
struct frame *f1 = XFRAME (frame1);
|
||||
if (FRAME_NS_P (f1))
|
||||
ns_make_frame_key_window (f1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Under NS, there is no system mechanism for choosing a new
|
||||
window to get focus -- it is left to application code.
|
||||
So the portion of THIS application interfacing with NS
|
||||
needs to make the frame we switch to the key window. */
|
||||
struct frame *f1 = XFRAME (frame1);
|
||||
if (FRAME_NS_P (f1))
|
||||
ns_make_frame_key_window (f1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
do_switch_frame (frame1, 0, 1, Qnil);
|
||||
sf = SELECTED_FRAME ();
|
||||
|
|
@ -7185,6 +7205,7 @@ syms_of_frame (void)
|
|||
DEFSYM (Qframe_monitor_attributes, "frame-monitor-attributes");
|
||||
DEFSYM (Qwindow__pixel_to_total, "window--pixel-to-total");
|
||||
DEFSYM (Qmake_initial_minibuffer_frame, "make-initial-minibuffer-frame");
|
||||
DEFSYM (Qget_mru_frame, "get-mru-frame");
|
||||
DEFSYM (Qexplicit_name, "explicit-name");
|
||||
DEFSYM (Qheight, "height");
|
||||
DEFSYM (Qicon, "icon");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue