child frame (@pxref{Child Frames}) whose parent becomes the frame
created. As if specified as @code{nil}, Emacs will set this parameter
to the minibuffer window of the child frame but will not select the
-child frame after its creation.
+child frame after its creation. The value @code{child-frame} has no
+effect on text terminals where you have to create a minibuffer-only
+frame manually (@pxref{Child Frame Peculiarities}).
@vindex buffer-predicate@r{, a frame parameter}
@item buffer-predicate
@deffn Command iconify-frame &optional frame
This function iconifies frame @var{frame}. If you omit @var{frame}, it
-iconifies the selected frame. This will also remove any child frames
-(@pxref{Child Frames}) of @var{frame} from display. On the top frame of
-a text terminal this function has no effect. visible. If @var{frame} is
-a child frame, the behavior depends on the value of the variable
-@code{iconify-child-frame} (@pxref{Child Frames}).
+iconifies the selected frame. This function also removes any child
+frames (@pxref{Child Frames}) of @var{frame} and their descendants from
+display. If @var{frame} is a child frame itself, the behavior depends
+on the value of the variable @code{iconify-child-frame}. If @var{frame}
+is the top frame of a text terminal (@pxref{Frames}), this function has
+no effect.
@end deffn
@deffn Command make-frame-visible &optional frame
@defopt minibuffer-auto-raise
If this is non-@code{nil}, activation of the minibuffer raises the frame
-that the minibuffer window is in. This function has no effect on text
+that the minibuffer window is in. This variable has no effect on text
terminals.
@end defopt
@node Child Frames
@section Child Frames
@cindex child frames
-@cindex parent frames
Child frames are objects halfway between windows (@pxref{Windows}) and
``normal'' frames. Like windows, they are attached to an owning frame.
specialized functions or customizable variables. Child frames
are meaningful on graphical and text terminals.
- To create a new child frame or to convert a normal frame into a child
+@menu
+* Child Frame Operations:: Making and investigating child frames.
+* Child Frame Properties:: Special properties of child frames.
+* Child Frame Peculiarities:: Deviant behaviors of child frames.
+@end menu
+
+@node Child Frame Operations
+@subsection Child Frame Operations
+
+To create a new child frame or to convert a normal frame into a child
frame, set that frame's @code{parent-frame} parameter (@pxref{Frame
Interaction Parameters}) to that of an already existing frame. The
frame specified by that parameter will then be the frame's parent frame
-as long as the parameter is not changed or reset. Technically, this
-makes the child frame's window-system window a child window of the
-parent frame's window-system window.
-
-@cindex reparent frame
-@cindex nest frame
- The @code{parent-frame} parameter can be changed at any time.
-Setting it to another frame @dfn{reparents} the child frame. Setting
-it to another child frame makes the frame a @dfn{nested} child frame.
-Setting it to @code{nil} restores the frame's status as a top-level
-frame---a frame whose window-system window is a child of its display's
-root window.@footnote{On Haiku, child frames are only visible when a
-parent frame is active, owing to a limitation of the Haiku windowing
-system. Owing to the same limitation, child frames are only
-guaranteed to appear above their top-level parent; that is to say, the
-top-most frame in the hierarchy, which does not have a parent frame.}
+as long as the parameter is not changed or reset. Technically, on a GUI
+this makes the child frame's window-system window a child window of the
+parent frame's window-system window. On a text terminal, this makes the
+frame usually appear on the same terminal as its parent frame, obscuring
+some part of it.
+
+@cindex reparenting frames
+@cindex nesting frames
+@cindex top-level frame
+ The @code{parent-frame} parameter can be changed at any time. Setting
+it to another frame @dfn{reparents} the child frame. Setting it to
+another child frame makes the frame a @dfn{nested} child frame. Setting
+it to @code{nil} restores the frame's status as a top-level frame---a
+frame whose window-system window is a child of its display's root
+window.@footnote{On Haiku, child frames are only visible when a parent
+frame is active, owing to a limitation of the Haiku windowing system.
+Owing to the same limitation, child frames are only guaranteed to appear
+above their top-level parent; that is to say, the top-most frame in the
+hierarchy, which does not have a parent frame.} On text terminals,
+top-level frames are called root frames (see below).
Since child frames can be arbitrarily nested, a frame can be both a
child and a parent frame. Also, the relative roles of child and parent
parent). An error will be signaled for the attempt to make a frame an
ancestor of itself.
- Most window-systems clip a child frame at the native edges
-(@pxref{Frame Geometry}) of its parent frame---everything outside these
-edges is usually invisible. A child frame's @code{left} and @code{top}
+ When a parent frame is about to be deleted (@pxref{Deleting Frames}),
+its child frames are recursively deleted before it. There is one
+exception to this rule: When the child frame serves as a surrogate
+minibuffer frame (@pxref{Minibuffers and Frames}) for another frame, it
+is retained until the parent frame has been deleted. If, at this time,
+no remaining frame uses the child frame as its minibuffer frame, Emacs
+will try to delete the child frame too. If that deletion fails for
+whatever reason, the child frame is made a top-level frame. Since on
+text terminals no such conversion is possible, deleting a frame may
+throw an error if a surrogate minibuffer frame to be deleted is used by
+a frame that will not be deleted too.
+
+ The following three functions help to understand how parent and child
+frames related to each other.
+
+@defun frame-parent &optional frame
+This function returns the parent frame of @var{frame}. It returns
+@code{nil} if @var{frame} has no parent frame.
+@end defun
+
+@cindex ancestor frame
+@cindex descendant 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}
+when it is either @var{descendant}'s parent frame or it is an ancestor
+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
+
+On a text terminal, a root frame is always positioned at the top left
+edge of its terminal and always occupies the full size of its terminal.
+
+
+@node Child Frame Properties
+@subsection Child Frame Properties
+
+Most window-systems clip child frames at the native edges (@pxref{Frame
+Geometry}) of their parent frame---everything outside these edges is
+usually invisible. A child frame's @code{left} and @code{top}
parameters specify a position relative to the top-left corner of its
parent's native frame. When the parent frame is resized, this position
remains conceptually unaltered.
- NS builds do not clip child frames at the parent frame's edges,
-allowing them to be positioned so they do not obscure the parent frame
-while still being visible themselves.
+ NS builds and text terminals do not clip child frames at the parent
+frame's edges, allowing them to be positioned so they do not obscure the
+parent frame while still being visible themselves.
+
+ 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
+useful to avoid that a child frame obscures any text shown in that
+window.
Usually, moving a parent frame moves along all its child frames and
their descendants as well, keeping their relative positions unaltered.
beneath the parent. This is comparable to the window-system window of a
top-level frame which also always appears on top of its parent
window---the desktop's root window. When a parent frame is iconified or
-made invisible (@pxref{Visibility of Frames}), its child frames are made
-invisible. When a parent frame is deiconified or made visible, its
-child frames are made visible.
-
- When a parent frame is about to be deleted (@pxref{Deleting
-Frames}), its child frames are recursively deleted before it. There
-is one exception to this rule: When the child frame serves as a
-surrogate minibuffer frame (@pxref{Minibuffers and Frames}) for
-another frame, it is retained until the parent frame has been deleted.
-If, at this time, no remaining frame uses the child frame as its
-minibuffer frame, Emacs will try to delete the child frame too. If
-that deletion fails for whatever reason, the child frame is made a
-top-level frame.
+made invisible (@pxref{Visibility of Frames}), any child frames
+descending from it will not be shown either even if
+@code{frame-visible-p} returns @code{t} for them. When a parent frame
+is deiconified or made visible, any child frames descending from it will
+be shown again (provided they and all their ancestor frames are visible
+too). If a child frame is used as surrogate minibuffer frame
+(@pxref{Minibuffers and Frames}), it's up to the application to
+guarantee the frame's visibility whenever the minibuffer is activated.
Whether a child frame can have a menu or tool bar is window-system or
window manager dependent. Most window-systems explicitly disallow menu
bars for child frames. It seems advisable to disable both, menu and
-tool bars, via the frame's initial parameters settings.
+tool bars, via the frame's initial parameters settings. On a text
+terminal, child frames use the menu bar of their root frame (provided it
+has one).
Usually, child frames do not exhibit window manager decorations like a
title bar or external borders (@pxref{Frame Geometry}). When the child
border width will show a one-pixel wide external border. Under all
window-systems, the internal border can be used. In either case, it's
advisable to disable a child frame's window manager decorations with the
-@code{undecorated} frame parameter (@pxref{Management Parameters}).
+@code{undecorated} frame parameter (@pxref{Management Parameters}). On
+a text terminal, on the other hand, it's better to leave that parameter
+alone so your child frame will be drawn with an outer border.
- To resize or move an undecorated child frame with the mouse, special
+ To resize or move a border-less child frame with the mouse, special
frame parameters (@pxref{Mouse Dragging Parameters}) have to be used.
The internal border of a child frame, if present, can be used to resize
the frame with the mouse, provided that frame has a non-@code{nil}
@code{drag-internal-border} parameter. If set, the @code{snap-width}
parameter indicates the number of pixels where the frame @dfn{snaps} at
-the respective edge or corner of its parent frame.
+the respective edge or corner of its parent frame. On a text terminal,
+the outer border can used for resizing.
There are two ways to drag an entire child frame with the mouse: The
@code{drag-with-mode-line} parameter, if non-@code{nil}, enables
parameter (@pxref{Frame Interaction Parameters}) is useful in order to
deal with the frame when the minibuffer is exited.
- The behavior of child frames deviates from that of top-level frames in
-a number of other ways as well. Here we sketch a few of them:
+
+@node Child Frame Peculiarities
+@subsection Child Frame Peculiarities
+
+The behavior of child frames deviates from that of normal frames in a
+number of peculiar ways. Here we sketch a few of them:
@itemize @bullet
@item
Raising, lowering and restacking child frames (@pxref{Raising and
Lowering}) or changing the @code{z-group} (@pxref{Position Parameters})
of a child frame changes only the stacking order of child frames with
-the same parent.
+the same parent. Restacking has not been implemented on text terminals.
@item
Many window-systems are not able to change the opacity (@pxref{Font and
frame or on some ancestor instead.
@end itemize
- The following three functions can be useful when working with child and
-parent frames:
-
-@defun frame-parent &optional frame
-This function returns the parent frame of @var{frame}. The parent frame
-of @var{frame} is the Emacs frame whose window-system window is the
-parent window of @var{frame}'s window-system window. If such a frame
-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}
-when it is either @var{descendant}'s parent frame or it is an ancestor
-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
-useful to avoid that a child frame obscures any text shown in that
-window.
-
Customizing the following option can be useful to tweak the behavior of
@code{iconify-frame} for child frames.
@code{make-invisible}.
@end defopt
+On text terminals exist a few restrictions with respect to reparenting:
+One is that a top frame (@pxref{Frames}) cannot be directly made a child
+frame---you first have to make another root frame the new top frame of
+its terminal. If, on the other hand, you want a child frame to become
+the new top frame of its terminal, you have to make it a root frame
+first.
+
+ Also, the surrogate minibuffer window of any frame on a text terminal
+must reside on a frame with the same root frame. Reparenting will throw
+an error whenever it violates this restriction. It also means that it's
+more tricky to make a minibuffer-less frame whose minibuffer window
+resides on a minibuffer-only child frame. On a GUI, Emacs proceeds as
+follows when a user has specified the value @code{child-frame} for the
+@code{minibuffer} parameter in @code{initial-frame-alist}
+(@pxref{Initial Parameters}):
+
+@enumerate
+@item
+Create a minibuffer-only frame.
+
+@item
+Create a minibuffer-less frame with its @code{minibuffer} parameter set
+to the window of the minibuffer-only frame.
+
+@item
+Make the minibuffer-less frame the parent frame of the minibuffer-only
+frame.
+
+@item
+Delete the originally selected frame.
+@end enumerate
+
+ On a text terminal you have to perform these operations manually as
+sketched in the following snippet:
+
+@example
+@group
+(let* ((selected (selected-frame))
+ (mini-only
+ (make-frame
+ `((parent-frame . ,selected)
+ (minibuffer . only)
+ (left . 1) (top . -1) (width . 20) (height . 1))))
+ (mini-less
+ (make-frame
+ (append `((parent-frame . ,selected)
+ (minibuffer . ,(minibuffer-window mini-only)))))))
+ (set-frame-parameter mini-only 'parent-frame mini-less)
+ (set-frame-parameter mini-less 'parent-frame nil)
+ (select-frame mini-less)
+ (delete-frame selected))
+@end group
+@end example
+
+ This means that you first have to install the minibuffer-less and the
+minibuffer-only frames both as child frames of the selected frame with
+the @code{minibuffer} parameter of the minibuffer-less frame set to the
+minibuffer window of the minibuffer-only frame. Then make the
+minibuffer-only frame a child frame of the minibuffer-less frame and
+make the minibuffer-less frame a new root frame. Finally, select the
+minibuffer-less frame and delete the originally selected frame.
+
@node Mouse Tracking
@section Mouse Tracking
return Qnil;
}
+/* Return true if frame AF is an ancestor of frame DF. */
bool
frame_ancestor_p (struct frame *af, struct frame *df)
{
return false;
}
+/* A frame AF subsumes a frame DF if AF and DF are the same or AF is an
+ ancestor of DF. */
+static bool
+frame_subsumes_p (struct frame *af, struct frame *df)
+{
+ while (df)
+ {
+ if (df == af)
+ return true;
+ else
+ df = FRAME_PARENT_FRAME (df);
+ }
+
+ return false;
+}
+
DEFUN ("frame-ancestor-p", Fframe_ancestor_p, Sframe_ancestor_p,
2, 2, 0,
doc: /* Return non-nil if ANCESTOR is an ancestor of DESCENDANT.
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. */
XSETFRAME (frame, f);
+ if (is_tty_frame (f) && NILP (force))
+ /* If F is a tty frame, check for surrogate minibuffer frames F
+ subsumes used by a frame that is not subsumed by F. */
+ FOR_EACH_FRAME (frames, frame1)
+ {
+ struct frame *f1 = XFRAME (frame1);
+
+ if (frame_subsumes_p (f, WINDOW_XFRAME (XWINDOW (f1->minibuffer_window)))
+ && !frame_subsumes_p (f, f1))
+ error ("Cannot delete surrogate minibuffer frame");
+ }
+
/* Softly delete all frames with this frame as their parent frame or
as their `delete-before' frame parameter value. */
FOR_EACH_FRAME (frames, frame1)
{
if (WINDOWP (val))
{
- if (!MINI_WINDOW_P (XWINDOW (val)))
+ if (!WINDOW_LIVE_P (val) || !MINI_WINDOW_P (XWINDOW (val)))
error ("The `minibuffer' parameter does not specify a valid minibuffer window");
else if (FRAME_MINIBUF_ONLY_P (f))
{
else
error ("Can't change the minibuffer window of a frame with its own minibuffer");
}
+ else if (is_tty_frame (f)
+ && (root_frame (WINDOW_XFRAME (XWINDOW (val)))
+ != root_frame (f)))
+ error ("A frame and its surrogate minibuffer frame must have the same roots");
else
/* Store the chosen minibuffer window. */
fset_minibuffer_window (f, val);
val = old_val;
}
- /* Re-parenting is currently not implemented when changing a root
- frame to a child frame or vice versa. */
+ /* The parent frame parameter for ttys must be handled specially. */
if (is_tty_frame (f) && EQ (prop, Qparent_frame))
{
- if (NILP (f->parent_frame) != NILP (val))
- error ("Making a root frame a child or vice versa is not supported");
+ /* Invariant: When a frame F1 uses a surrogate minibuffer frame M1
+ on a tty, both F1 and M1 must have the same root frame. */
+ Lisp_Object frames, frame1, old_val = f->parent_frame;
+
+ FOR_EACH_FRAME (frames, frame1)
+ {
+ struct frame *f1 = XFRAME (frame1);
+ struct frame *m1 = WINDOW_XFRAME (XWINDOW (f1->minibuffer_window));
+ bool mismatch = false;
+
+ /* Temporarily install VAL and check whether our invariant
+ above gets violated. */
+ f->parent_frame = val;
+ mismatch = root_frame (f1) != root_frame (m1);
+ f->parent_frame = old_val;
+
+ if (mismatch)
+ error ("Cannot re-root surrogate minibuffer frame");
+ }
+
+ if (f == XFRAME (FRAME_TERMINAL (f)->display_info.tty->top_frame)
+ && !NILP (val))
+ error ("Cannot make tty top frame a child frame");
+ else if (NILP (val))
+ {
+ if (!FRAME_HAS_MINIBUF_P (f)
+ && (!frame_ancestor_p
+ (f, WINDOW_XFRAME (XWINDOW (f->minibuffer_window)))))
+ error ("Cannot make tty root frame without valid minibuffer window");
+ else
+ {
+ /* When making a frame a root frame, expand it to full size,
+ if necessary, and position it at top left corner. */
+ int width, height;
+
+ get_tty_size (fileno (FRAME_TTY (f)->input), &width, &height);
+ adjust_frame_size (f, width, height - FRAME_TOP_MARGIN (f), 5, 0,
+ Qterminal_frame);
+ f->left_pos = 0;
+ f->top_pos = 0;
+ }
+ }
SET_FRAME_GARBAGED (root_frame (f));
f->parent_frame = val;
{
Lisp_Object pos = mouse_position (true);
Lisp_Object frame = XCAR (pos);
- struct frame *f = XFRAME (frame);
- int x = XFIXNUM (XCAR (XCDR (pos))) + f->left_pos;
- int y = XFIXNUM (XCDR (XCDR (pos))) + f->top_pos;
if (!FRAMEP (frame))
return Qnil;
else
{
+ struct frame *f = XFRAME (frame);
+ int x = XFIXNUM (XCAR (XCDR (pos))) + f->left_pos;
+ int y = XFIXNUM (XCDR (XCDR (pos))) + f->top_pos;
+
f = FRAME_PARENT_FRAME (f);
while (f)