Handle removal of selected tty child frame
* src/dispextern.h (root_frame): * src/frame.h (root_frame): Move declaration from dispextern.h to frame.h. (SET_FRAME_VISIBLE): Whend making the selected tty child frame invisible, use mru_rooted_frame to find a frame to switch to. * src/dispnew.c (root_frame): Move root_frame to frame.c. * src/frame.c (do_switch_frame): On ttys don't change the top frame when switching from a child frame to another frame with the same root. (root_frame): Move here from dispnew.c. (Fframe_root_frame): New Lisp function. (delete_frame): Whend deleting the selected tty child frame use, mru_rooted_frame to find a frame to switch to. * src/window.c (mru_rooted_frame): New function. * src/window.h (mru_rooted_frame): Declare it. * doc/lispref/frames.texi (Child Frames): Describe new function 'frame-root-frame'.
This commit is contained in:
parent
0226d35794
commit
d4aeb6bd23
7 changed files with 154 additions and 77 deletions
|
@ -3579,7 +3579,7 @@ work on all window-systems. Some will drop the object on the parent
|
|||
frame or on some ancestor instead.
|
||||
@end itemize
|
||||
|
||||
The following two functions can be useful when working with child and
|
||||
The following three functions can be useful when working with child and
|
||||
parent frames:
|
||||
|
||||
@defun frame-parent &optional frame
|
||||
|
@ -3591,6 +3591,7 @@ exists, @var{frame} is considered a child frame of that frame.
|
|||
This function returns @code{nil} if @var{frame} has no parent frame.
|
||||
@end defun
|
||||
|
||||
@cindex ancestor frame
|
||||
@defun frame-ancestor-p ancestor descendant
|
||||
This functions returns non-@code{nil} if @var{ancestor} is an ancestor
|
||||
of @var{descendant}. @var{ancestor} is an ancestor of @var{descendant}
|
||||
|
@ -3599,6 +3600,16 @@ of @var{descendant}'s parent frame. Both, @var{ancestor} and
|
|||
@var{descendant} must specify live frames.
|
||||
@end defun
|
||||
|
||||
@cindex root frame
|
||||
@defun frame-root-frame &optional frame
|
||||
This function returns the root frame of the specified @var{frame}.
|
||||
@var{frame} must be a live frame and defaults to the selected one. The
|
||||
root frame of @var{frame} is the frame obtained by following the chain
|
||||
of parent frames starting with @var{frame} until a frame is reached that
|
||||
has no parent. If @var{frame} has no parent, its root frame is
|
||||
@var{frame} itself.
|
||||
@end defun
|
||||
|
||||
Note also the function @code{window-largest-empty-rectangle}
|
||||
(@pxref{Coordinates and Windows}) which can be used to inscribe a child
|
||||
frame in the largest empty area of an existing window. This can be
|
||||
|
|
|
@ -3949,7 +3949,6 @@ extern void gui_redo_mouse_highlight (Display_Info *);
|
|||
|
||||
#endif /* HAVE_WINDOW_SYSTEM */
|
||||
|
||||
struct frame *root_frame (struct frame *f);
|
||||
Lisp_Object frames_in_reverse_z_order (struct frame *f, bool visible);
|
||||
bool is_tty_frame (struct frame *f);
|
||||
bool is_tty_child_frame (struct frame *f);
|
||||
|
|
|
@ -3334,18 +3334,6 @@ frame_rect_abs (struct frame *f)
|
|||
|
||||
#endif /* !HAVE_ANDROID */
|
||||
|
||||
/* Return the root frame of frame F. Follow the parent_frame chain
|
||||
until we reach a frame that has no parent. That is the root frame.
|
||||
Note that the root of a root frame is itself. */
|
||||
|
||||
struct frame *
|
||||
root_frame (struct frame *f)
|
||||
{
|
||||
while (FRAME_PARENT_FRAME (f))
|
||||
f = FRAME_PARENT_FRAME (f);
|
||||
return f;
|
||||
}
|
||||
|
||||
int
|
||||
max_child_z_order (struct frame *parent)
|
||||
{
|
||||
|
|
133
src/frame.c
133
src/frame.c
|
@ -1775,7 +1775,7 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor
|
|||
|
||||
/* Don't mark the frame garbaged if we are switching to the frame
|
||||
that is already the top frame of that TTY. */
|
||||
if (!EQ (frame, top_frame))
|
||||
if (!EQ (frame, top_frame) && root_frame (f) != XFRAME (top_frame))
|
||||
{
|
||||
struct frame *new_root = root_frame (f);
|
||||
SET_FRAME_VISIBLE (new_root, true);
|
||||
|
@ -2021,6 +2021,39 @@ frame. */)
|
|||
return frame_ancestor_p (af, df) ? Qt : Qnil;
|
||||
}
|
||||
|
||||
|
||||
/* Return the root frame of frame F. Follow the parent_frame chain
|
||||
until we reach a frame that has no parent. That is the root frame.
|
||||
Note that the root of a root frame is itself. */
|
||||
|
||||
struct frame *
|
||||
root_frame (struct frame *f)
|
||||
{
|
||||
while (FRAME_PARENT_FRAME (f))
|
||||
f = FRAME_PARENT_FRAME (f);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
DEFUN ("frame-root-frame", Fframe_root_frame, Sframe_root_frame,
|
||||
0, 1, 0,
|
||||
doc: /* Return root frame of specified FRAME.
|
||||
FRAME must be a live frame and defaults to the selected one. The root
|
||||
frame of FRAME is the frame obtained by following the chain of parent
|
||||
frames starting with FRAME until a frame is reached that has no parent.
|
||||
If FRAME has no parent, its root frame is FRAME. */)
|
||||
(Lisp_Object frame)
|
||||
{
|
||||
struct frame *f = decode_live_frame (frame);
|
||||
struct frame *r = root_frame (f);
|
||||
Lisp_Object root;
|
||||
|
||||
XSETFRAME (root, r);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
/* Return CANDIDATE if it can be used as 'other-than-FRAME' frame on the
|
||||
same tty (for tty frames) or among frames which uses FRAME's keyboard.
|
||||
If MINIBUF is nil, do not consider minibuffer-only candidate.
|
||||
|
@ -2433,61 +2466,68 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
|
|||
/* Don't let the frame remain selected. */
|
||||
if (f == sf)
|
||||
{
|
||||
Lisp_Object tail;
|
||||
Lisp_Object frame1 UNINIT; /* This line works around GCC bug 85563. */
|
||||
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)
|
||||
if (is_tty_child_frame (f))
|
||||
/* If F is a child frame on a tty and is the selected frame, try
|
||||
to re-select the frame that was selected before F. */
|
||||
do_switch_frame (mru_rooted_frame (f), 0, 1, Qnil);
|
||||
else
|
||||
{
|
||||
struct frame *f1 = XFRAME (frame1);
|
||||
Lisp_Object tail;
|
||||
Lisp_Object frame1 UNINIT; /* This line works around GCC bug 85563. */
|
||||
eassume (CONSP (Vframe_list));
|
||||
|
||||
if (!EQ (frame, frame1)
|
||||
&& !FRAME_TOOLTIP_P (f1)
|
||||
&& FRAME_TERMINAL (f) == FRAME_TERMINAL (f1)
|
||||
&& FRAME_VISIBLE_P (f1))
|
||||
break;
|
||||
}
|
||||
|
||||
/* If there is none, find *some* other frame. */
|
||||
if (NILP (frame1) || EQ (frame1, frame))
|
||||
{
|
||||
/* 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 ();
|
||||
do_switch_frame (frame1, 0, 1, Qnil);
|
||||
sf = SELECTED_FRAME ();
|
||||
}
|
||||
}
|
||||
else
|
||||
/* Ensure any minibuffers on FRAME are moved onto the selected
|
||||
|
@ -2583,11 +2623,11 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
|
|||
f->terminal = 0; /* Now the frame is dead. */
|
||||
unblock_input ();
|
||||
|
||||
/* Clear markers and overlays set by F on behalf of an input
|
||||
method. */
|
||||
/* Clear markers and overlays set by F on behalf of an input
|
||||
method. */
|
||||
#ifdef HAVE_TEXT_CONVERSION
|
||||
if (FRAME_WINDOW_P (f))
|
||||
reset_frame_state (f);
|
||||
if (FRAME_WINDOW_P (f))
|
||||
reset_frame_state (f);
|
||||
#endif
|
||||
|
||||
/* If needed, delete the terminal that this frame was on.
|
||||
|
@ -7146,6 +7186,7 @@ iconify the top level frame instead. */);
|
|||
defsubr (&Sframe_list);
|
||||
defsubr (&Sframe_parent);
|
||||
defsubr (&Sframe_ancestor_p);
|
||||
defsubr (&Sframe_root_frame);
|
||||
defsubr (&Snext_frame);
|
||||
defsubr (&Sprevious_frame);
|
||||
defsubr (&Slast_nonminibuf_frame);
|
||||
|
|
39
src/frame.h
39
src/frame.h
|
@ -1428,23 +1428,6 @@ FRAME_PARENT_FRAME (struct frame *f)
|
|||
/* False means there are no visible garbaged frames. */
|
||||
extern bool frame_garbaged;
|
||||
|
||||
/* Set visibility of frame F.
|
||||
We call redisplay_other_windows to make sure the frame gets redisplayed
|
||||
if some changes were applied to it while it wasn't visible (and hence
|
||||
wasn't redisplayed). */
|
||||
INLINE void
|
||||
SET_FRAME_VISIBLE (struct frame *f, bool v)
|
||||
{
|
||||
if (v)
|
||||
{
|
||||
if (v == 1 && f->visible != 1)
|
||||
redisplay_other_windows ();
|
||||
if (FRAME_GARBAGED_P (f))
|
||||
frame_garbaged = true;
|
||||
}
|
||||
f->visible = v;
|
||||
}
|
||||
|
||||
/* Set iconified status of frame F. */
|
||||
INLINE void
|
||||
SET_FRAME_ICONIFIED (struct frame *f, int i)
|
||||
|
@ -1518,6 +1501,7 @@ void check_tty (struct frame *f);
|
|||
struct frame *decode_tty_frame (Lisp_Object frame);
|
||||
extern void frame_make_pointer_invisible (struct frame *);
|
||||
extern void frame_make_pointer_visible (struct frame *);
|
||||
extern struct frame *root_frame (struct frame *f);
|
||||
extern Lisp_Object delete_frame (Lisp_Object, Lisp_Object);
|
||||
extern bool frame_inhibit_resize (struct frame *, bool, Lisp_Object);
|
||||
extern void adjust_frame_size (struct frame *, int, int, int, bool,
|
||||
|
@ -1541,6 +1525,27 @@ extern Lisp_Object Vframe_list;
|
|||
? XFRAME (selected_frame) \
|
||||
: (emacs_abort (), (struct frame *) 0))
|
||||
|
||||
/* Set visibility of frame F.
|
||||
We call redisplay_other_windows to make sure the frame gets redisplayed
|
||||
if some changes were applied to it while it wasn't visible (and hence
|
||||
wasn't redisplayed). */
|
||||
INLINE void
|
||||
SET_FRAME_VISIBLE (struct frame *f, bool v)
|
||||
{
|
||||
if (v)
|
||||
{
|
||||
if (v == 1 && f->visible != 1)
|
||||
redisplay_other_windows ();
|
||||
if (FRAME_GARBAGED_P (f))
|
||||
frame_garbaged = true;
|
||||
}
|
||||
/* If F is a child frame on a tty and is the selected frame, try to
|
||||
re-select the frame that was selected before F. */
|
||||
else if (is_tty_child_frame (f) && f == XFRAME (selected_frame))
|
||||
do_switch_frame (mru_rooted_frame (f), 0, 0, Qnil);
|
||||
|
||||
f->visible = v;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
Display-related Macros
|
||||
|
|
32
src/window.c
32
src/window.c
|
@ -3097,6 +3097,38 @@ be listed first but no error is signaled. */)
|
|||
{
|
||||
return window_list_1 (window, minibuf, all_frames);
|
||||
}
|
||||
|
||||
/** Return most recently selected frame that has the same root as a
|
||||
given frame. It's defined here because the static window_list_1 is
|
||||
here too but in fact it's only needed in the frame code. */
|
||||
Lisp_Object
|
||||
mru_rooted_frame (struct frame *f)
|
||||
{
|
||||
Lisp_Object windows = window_list_1 (FRAME_SELECTED_WINDOW (f), Qnil, Qt);
|
||||
struct frame *r = root_frame (f);
|
||||
struct window *b = NULL;
|
||||
|
||||
for (; CONSP (windows); windows = XCDR (windows))
|
||||
{
|
||||
struct window *w = XWINDOW (XCAR (windows));
|
||||
struct frame *wf = WINDOW_XFRAME (w);
|
||||
|
||||
if (wf != f && root_frame (wf) == r && FRAME_VISIBLE_P (wf)
|
||||
&& (!b || w->use_time > b->use_time))
|
||||
b = w;
|
||||
}
|
||||
|
||||
if (b)
|
||||
return WINDOW_FRAME (b);
|
||||
else
|
||||
{
|
||||
Lisp_Object root;
|
||||
|
||||
XSETFRAME (root, r);
|
||||
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look at all windows, performing an operation specified by TYPE
|
||||
with argument OBJ.
|
||||
|
|
|
@ -1227,6 +1227,7 @@ extern void wset_buffer (struct window *, Lisp_Object);
|
|||
extern bool window_outdated (struct window *);
|
||||
extern ptrdiff_t window_point (struct window *w);
|
||||
extern void window_discard_buffer_from_dead_windows (Lisp_Object);
|
||||
extern Lisp_Object mru_rooted_frame (struct frame *);
|
||||
extern void init_window_once (void);
|
||||
extern void init_window (void);
|
||||
extern void syms_of_window (void);
|
||||
|
|
Loading…
Add table
Reference in a new issue