/* 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);
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.
/* 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);
-
- if (!EQ (frame, frame1)
- && !FRAME_TOOLTIP_P (f1)
- && FRAME_TERMINAL (f) == FRAME_TERMINAL (f1)
- && FRAME_VISIBLE_P (f1))
- break;
- }
+ Lisp_Object tail;
+ Lisp_Object frame1 UNINIT; /* This line works around GCC bug 85563. */
+ eassume (CONSP (Vframe_list));
- /* 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))
+ && !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))
+ {
+ FOR_EACH_FRAME (tail, frame1)
{
- if (FRAME_TERMCAP_P (f1) || FRAME_MSDOS_P (f1))
- {
- Lisp_Object top_frame = FRAME_TTY (f1)->top_frame;
+ struct frame *f1 = XFRAME (frame1);
- if (!EQ (top_frame, frame))
- frame1 = top_frame;
+ 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
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.
defsubr (&Sframe_list);
defsubr (&Sframe_parent);
defsubr (&Sframe_ancestor_p);
+ defsubr (&Sframe_root_frame);
defsubr (&Snext_frame);
defsubr (&Sprevious_frame);
defsubr (&Slast_nonminibuf_frame);
/* 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)
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,
? 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;
+}
\f
/***********************************************************************
Display-related Macros