Subject: Re: bug#25408: Remove Decorations Around Emacs Frame (NS port)

From: martin rudalics <[email-masked]>
Date: Thu, 22 Jun 2017 11:10:54 +0200

> Anything else you’d like me to look at here?

Attached find the changes I intend to push in the next few days plus a
ChangeLog.  You will find this particular change there:

+  f->output_data.ns->left_edge_cursor = [NSCursor resizeLeftRightCursor];
+  f->output_data.ns->top_left_corner_cursor = [NSCursor arrowCursor];
+  f->output_data.ns->top_edge_cursor = [NSCursor resizeUpDownCursor];
+  f->output_data.ns->top_right_corner_cursor = [NSCursor arrowCursor];
+  f->output_data.ns->right_edge_cursor = [NSCursor resizeLeftRightCursor];
+  f->output_data.ns->bottom_right_corner_cursor = [NSCursor arrowCursor];
+  f->output_data.ns->bottom_edge_cursor = [NSCursor resizeUpDownCursor];
+  f->output_data.ns->bottom_left_corner_cursor = [NSCursor arrowCursor];

It would be nice to have something better on NS for the
top_left_corner_cursor, top_right_corner_cursor,
bottom_right_corner_cursor and bottom_left_corner_cursor cases.

If you want to play around with child frames, try the attached file
my-child-frame.el.  Any feedback welcome.

Thanks in advance, martin
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 4de55fd..04c5ba2 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -1974,6 +1974,71 @@ Size of Displayed Text
 height of both, if present, in the return value.
 @end defun

+@code{window-text-pixel-size} treats the text displayed in a window as a
+whole and does not care about the size of individual lines.  The
+following function does.
+
+@defun window-lines-pixel-dimensions &optional window first last body inverse
+This function calculates the pixel dimensions of each line displayed in
+the specified @var{window}.  It does so by walking @var{window}'s
+current glyph matrix---a matrix storing the glyph (@pxref{Glyphs}) of
+each buffer character currently displayed in @var{window}.  If
+successful, it returns a list of cons pairs representing the x- and
+y-coordinates of the lower right corner of the last character of each
+line.  Coordinates are measured in pixels from an origin (0, 0) at the
+top-left corner of @var{window}.  @var{window} must be a live window and
+defaults to the selected one.
+
+If the optional argument @var{first} is an integer, it denotes the index
+(starting with 0) of the first line of @var{window}'s glyph matrix to be
+returned.  Note that if @var{window} has a header line, the line with
+index 0 is that header line.  If @var{first} is nil, the first line to
+be considered is determined by the value of the optional argument
+@var{body}: If @var{body} is non-@code{nil}, this means to start with
+the first line of @var{window}'s body, skipping any header line, if
+present.  Otherwise, this function will start with the first line of
+@var{window}'s glyph matrix, possibly the header line.
+
+If the optional argument @var{last} is an integer, it denotes the index
+of the last line of @var{window}'s glyph matrix that shall be returned.
+If @var{last} is nil, the last line to be considered is determined by
+the value of @var{body}: If @var{body} is non-@code{nil}, this means to
+use the last line of @var{window}'s body, omitting @var{window}'s mode
+line, if present.  Otherwise, this means to use the last line of
+@var{window} which may be the mode line.
+
+The optional argument @var{inverse}, if @code{nil}, means that the
+y-pixel value returned for any line specifies the distance in pixels
+from the left edge (body edge if @var{body} is non-@code{nil}) of
+@var{window} to the right edge of the last glyph of that line.
+@var{inverse} non-@code{nil} means that the y-pixel value returned for
+any line specifies the distance in pixels from the right edge of the
+last glyph of that line to the right edge (body edge if @var{body} is
+non-@code{nil}) of @var{window}.  This is useful for determining the
+amount of slack space at the end of each line.
+
+The optional argument @var{left}, if non-@code{nil} means to return the
+x- and y-coordinates of the lower left corner of the leftmost character
+on each line.  This is the value that should be used for windows that
+mostly display text from right to left.
+
+If @var{left} is non-@code{nil} and @var{inverse} is @code{nil}, this
+means that the y-pixel value returned for any line specifies the
+distance in pixels from the left edge of the last (leftmost) glyph of
+that line to the right edge (body edge if @var{body} is non-@code{nil})
+of @var{window}.  If @var{left} and @var{inverse} are both
+non-@code{nil}, the y-pixel value returned for any line specifies the
+distance in pixels from the left edge (body edge if @var{body} is
+non-@code{nil}) of @var{window} to the left edge of the last (leftmost)
+glyph of that line.
+
+This function returns @code{nil} if the current glyph matrix of
+@var{window} is not up-to-date which usually happens when Emacs is busy,
+for example, when processing a command.  The value should be retrievable
+though when this function is run from an idle timer with a delay of zero
+seconds.
+@end defun
+
 @defun line-pixel-height
 This function returns the height in pixels of the line at point in the
 selected window.  The value includes the line spacing of the line
diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi
index 7cc91a8..4bedea3 100644
--- a/doc/lispref/elisp.texi
+++ b/doc/lispref/elisp.texi
@@ -1130,6 +1130,8 @@ Top
 * Buffer Parameters::       Which buffers have been or should be shown.
 * Frame Interaction Parameters::  Parameters for interacting with other
                               frames.
+* Mouse Dragging Parameters::  Parameters for resizing and moving
+                              frames with the mouse.
 * Management Parameters::   Communicating with the window manager.
 * Cursor Parameters::       Controlling the cursor appearance.
 * Font and Color Parameters:: Fonts and colors for the frame text.
diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi
index 50467d1..b430f7c 100644
--- a/doc/lispref/frames.texi
+++ b/doc/lispref/frames.texi
@@ -974,14 +974,7 @@ Frame Size
 the help of an X-style geometry specification.  @xref{Emacs Invocation,,
 Command Line Arguments for Emacs Invocation, emacs, The GNU Emacs
 Manual}.  Below we list some functions to access and set the size of an
-existing, visible frame.
-
-@defun frame-text-height &optional frame
-@defunx frame-text-width &optional frame
-These functions return the height and width of the text area of
-@var{frame} (@pxref{Frame Layout}), measured in pixels.  For a text
-terminal, the results are in characters rather than pixels.
-@end defun
+existing, visible frame, by default the selected one.

 @defun frame-height &optional frame
 @defunx frame-width &optional frame
@@ -997,11 +990,33 @@ Frame Size
 fit into the text area.
 @end defun

-@defun frame-pixel-height &optional frame
-@defunx frame-pixel-width &optional frame
-These functions return the native width and height, see @ref{Frame
-Layout}) of @var{frame} in pixels.  For a text terminal, the results are
-in characters rather than pixels.
+The functions following next return the pixel widths and heights of the
+native, outer and inner frame and the text area (@pxref{Frame Layout})
+of a given frame.  For a text terminal, the results are in characters
+rather than pixels.
+
+@defun frame-outer-width &optional frame
+@defunx frame-outer-height &optional frame
+These functions return the outer width and height of @var{frame} in
+pixels.
+@end defun
+
+@defun frame-native-height &optional frame
+@defunx frame-native-width &optional frame
+These functions return the native width and height of @var{frame} in
+pixels.
+@end defun
+
+@defun frame-inner-width &optional frame
+@defunx frame-inner-height &optional frame
+These functions return the inner width and height of @var{frame} in
+pixels.
+@end defun
+
+@defun frame-text-width &optional frame
+@defunx frame-text-height &optional frame
+These functions return the width and height of the text area of
+@var{frame} in pixels.
 @end defun

 On window systems that support it, Emacs tries by default to make the
@@ -1345,6 +1360,8 @@ Window Frame Parameters
 * Buffer Parameters::           Which buffers have been or should be shown.
 * Frame Interaction Parameters::  Parameters for interacting with other
                                   frames.
+* Mouse Dragging Parameters::   Parameters for resizing and moving
+                                  frames with the mouse.
 * Management Parameters::       Communicating with the window manager.
 * Cursor Parameters::           Controlling the cursor appearance.
 * Font and Color Parameters::   Fonts and colors for the frame text.
@@ -1404,18 +1421,19 @@ Position Parameters
 @cindex frame position

 Parameters describing the X- and Y-offsets of a frame are always
-measured in pixels.  For normal, non-child frames they specify the
-frame's absolute outer position (@pxref{Frame Geometry}) with respect to
-its display's origin.  For a child frame (@pxref{Child Frames}) they
-specify the frame's outer position relative to the native position of
-the frame's parent frame.  (Note that none of these parameters is
-meaningful on TTY frames.)
+measured in pixels.  For a normal, non-child frame they specify the
+frame's outer position (@pxref{Frame Geometry}) relative to its
+display's origin.  For a child frame (@pxref{Child Frames}) they specify
+the frame's outer position relative to the native position of the
+frame's parent frame.  (Note that none of these parameters is meaningful
+on TTY frames.)

 @table @code
 @vindex left, a frame parameter
 @item left
 The position, in pixels, of the left outer edge of the frame with
-respect to the left edge of the frame's display or parent frame.
+respect to the left edge of the frame's display or parent frame.  It can
+be specified in one of the following ways.

 @table @asis
 @item an integer
@@ -1436,6 +1454,30 @@ Position Parameters
 positive or negative; a negative value specifies a position outside the
 screen or parent frame or on a monitor other than the primary one (for
 multi-monitor displays).
+
+@cindex left position ratio
+@cindex top position ratio
+@item a floating-point value
+A floating-point value in the range 0.0 to 1.0 specifies the left edge's
+offset via the @dfn{left position ratio} of the frame---the ratio of the
+left edge of its outer frame to the width of the frame's workarea
+(@pxref{Multiple Terminals}) or its parent's native frame (@pxref{Child
+Frames}) minus the width of the outer frame.  Thus, a left position
+ratio of 0.0 flushes a frame to the left, a ratio of 0.5 centers it and
+a ratio of 1.0 flushes it to the right of its display or parent frame.
+Similarly, the @dfn{top position ratio} of a frame is the ratio of the
+frame's top position to the height of its workarea or parent frame minus
+the height of the frame.
+
+Emacs will try to keep the position ratios of a child frame unaltered if
+that frame has a non-@code{nil} @code{keep-ratio} parameter
+(@pxref{Frame Interaction Parameters}) and its parent frame is resized.
+
+Since the outer size of a frame (@pxref{Frame Geometry}) is usually
+unavailable before a frame has been made visible, it is generally not
+advisable to use floating-point values when creating decorated frames.
+Floating-point values are more suited for ensuring that an (undecorated)
+child frame is positioned nicely within the area of its parent frame.
 @end table

 Some window managers ignore program-specified positions.  If you want to
@@ -1448,17 +1490,19 @@ Position Parameters
   nil '((user-position . t) (left . (+ -4))))
 @end example

-In general, it is not a good idea to specify negative offsets to
-position a frame relative to the right or bottom edge of its display.
-Positioning the initial or a new frame is either not accurate (because
-the size of the outer frame is not yet fully known before the frame has
-been made visible) or will cause additional flicker (if the frame is
-repositioned after becoming visible).
+In general, it is not a good idea to position a frame relative to the
+right or bottom edge of its display.  Positioning the initial or a new
+frame is either not accurate (because the size of the outer frame is not
+yet fully known before the frame has been made visible) or will cause
+additional flicker (if the frame has to be repositioned after becoming
+visible).

-  Note also, that negative offsets are not stored internally and are not
-returned by the function @code{frame-parameters}.  This means that the
-desktop saving routines will restore the frame from the positive offsets
-obtained by that function.
+  Note also, that positions specified relative to the right/bottom edge
+of a display, workarea or parent frame as well as floating-point offsets
+are stored internally as integer offsets relative to the left/top edge
+of the display, workarea or parent frame edge.  They are also returned
+as such by functions like @code{frame-parameters} and restored as such
+by the desktop saving routines.

 @vindex top, a frame parameter
 @item top
@@ -1523,24 +1567,61 @@ Size Parameters
 @subsubsection Size Parameters
 @cindex window size on display

-  Frame parameters specify frame sizes in character units.  On
-graphical displays, the @code{default} face determines the actual
-pixel sizes of these character units (@pxref{Face Attributes}).
+Frame parameters usually specify frame sizes in character units.  On
+graphical displays, the @code{default} face determines the actual pixel
+sizes of these character units (@pxref{Face Attributes}).

 @table @code
 @vindex width, a frame parameter
 @item width
-The width of the frame's text area (@pxref{Frame Geometry}), in
-characters.  The value can be also a cons cell of the symbol
-@code{text-pixels} and an integer denoting the width of the text area in
-pixels.
+This parameter specifies the width of the frame.  It can be specified as
+in the following ways:
+
+@table @asis
+@item an integer
+A positive integer specifies the width of the frame's text area
+(@pxref{Frame Geometry}) in characters.
+
+@item a cons cell
+If this is a cons cell with the symbol @code{text-pixels} in its
+@sc{car}, the @sc{cdr} of that cell specifies the width of the frame's
+text area in pixels.
+
+@cindex frame width ratio
+@cindex frame height ratio
+@item a floating-point value
+A floating-point number between 0.0 and 1.0 can be used to specify the
+width of a frame via its @dfn{width ratio}---the ratio of its outer
+width (@pxref{Frame Geometry}) to the width of the frame's workarea
+(@pxref{Multiple Terminals}) or its parent frame's (@pxref{Child
+Frames}) native frame.  Thus, a value of 0.5 makes the frame occupy half
+of the width of its workarea or parent frame, a value of 1.0 the full
+width.  Similarly, the @dfn{height ratio} of a frame is the ratio of its
+outer height to the height of its workarea or its parent's native frame.
+
+Emacs will try to keep the width and height ratio of a child frame
+unaltered if that frame has a non-@code{nil} @code{keep-ratio} parameter
+(@pxref{Frame Interaction Parameters}) and its parent frame is resized.
+
+Since the outer size of a frame is usually unavailable before a frame
+has been made visible, it is generally not advisable to use
+floating-point values when creating decorated frames.  Floating-point
+values are more suited to ensure that a child frame always fits within
+the area of its parent frame as, for example, when customizing
+@code{display-buffer-alist} (@pxref{Choosing Window}) via
+@code{display-buffer-in-child-frame}.
+@end table
+
+Regardless of how this parameter was specified, functions reporting the
+value of this parameter like @code{frame-parameters} always report the
+width of the frame's text area in characters as an integer rounded, if
+necessary, to a multiple of the frame's default character width.  That
+value is also used by the desktop saving routines.

 @vindex height, a frame parameter
 @item height
-The height of the frame's text area (@pxref{Frame Geometry}), in
-characters.  The value can be also a cons cell of the symbol
-@code{text-pixels} and an integer denoting the height of the text area
-in pixels.
+This parameter specifies the height of the frame.  It works just like
+@code{width}, except vertically instead of horizontally.

 @vindex user-size, a frame parameter
 @item user-size
@@ -1551,25 +1632,25 @@ Size Parameters

 @vindex min-width, a frame parameter
 @item min-width
-This parameter specifies the minimum native width of the frame
-(@pxref{Frame Geometry}), in characters.  Normally, the functions that
+This parameter specifies the minimum native width (@pxref{Frame
+Geometry}) of the frame, in characters.  Normally, the functions that
 establish a frame's initial width or resize a frame horizontally make
 sure that all the frame's windows, vertical scroll bars, fringes,
 margins and vertical dividers can be displayed.  This parameter, if
 non-@code{nil} allows to make a frame narrower than that with the
-consequence that any components that do not fit on the frame will be
-clipped by the window manager.
+consequence that any components that do not fit will be clipped by the
+window manager.

 @vindex min-height, a frame parameter
 @item min-height
-This parameter specifies the minimum height of the native (@pxref{Frame
-Geometry}), in characters.  Normally, the functions that establish a
-frame's initial size or resize a frame make sure that all the frame's
-windows, horizontal scroll bars and dividers, mode and header lines, the
-echo area and the internal menu and tool bar can be displayed.  This
-parameter, if non-@code{nil} allows to make a frame smaller than that
-with the consequence that any components that do not fit on the frame
-will be clipped by the window-system or window manager.
+This parameter specifies the minimum native height (@pxref{Frame
+Geometry}) of the frame, in characters.  Normally, the functions that
+establish a frame's initial size or resize a frame make sure that all
+the frame's windows, horizontal scroll bars and dividers, mode and
+header lines, the echo area and the internal menu and tool bar can be
+displayed.  This parameter, if non-@code{nil} allows to make a frame
+smaller than that with the consequence that any components that do not
+fit will be clipped by the window manager.

 @cindex fullboth frames
 @cindex fullheight frames
@@ -1623,6 +1704,20 @@ Size Parameters

 This will give a new frame full height after typing in it @key{F11} for
 the first time.
+
+@vindex fit-frame-to-buffer-margins, a frame parameter
+@item fit-frame-to-buffer-margins
+This parameter allows to override the value of the option
+@code{fit-frame-to-buffer-margins} when fitting this frame to the buffer
+of its root window with @code{fit-frame-to-buffer} (@pxref{Resizing
+Windows}).
+
+@vindex fit-frame-to-buffer-sizes, a frame parameter
+@item fit-frame-to-buffer-sizes
+This parameter allows to override the value of the option
+@code{fit-frame-to-buffer-sizes} when fitting this frame to the buffer
+of its root window with @code{fit-frame-to-buffer} (@pxref{Resizing
+Windows}).
 @end table

@@ -1646,9 +1741,9 @@ Layout Parameters

 @vindex vertical-scroll-bars, a frame parameter
 @item vertical-scroll-bars
-Whether the frame has scroll bars for vertical scrolling, and which side
-of the frame they should be on.  The possible values are @code{left},
-@code{right}, and @code{nil} for no scroll bars.
+Whether the frame has scroll bars (@pxref{Scroll Bars}) for vertical
+scrolling, and which side of the frame they should be on.  The possible
+values are @code{left}, @code{right}, and @code{nil} for no scroll bars.

 @vindex horizontal-scroll-bars, a frame parameter
 @item horizontal-scroll-bars
@@ -1692,30 +1787,40 @@ Layout Parameters

 @vindex menu-bar-lines frame parameter
 @item menu-bar-lines
-The number of lines to allocate at the top of the frame for a menu bar.
-The default is one if Menu Bar mode is enabled and zero otherwise.
-@xref{Menu Bars,,,emacs, The GNU Emacs Manual}.  For an external menu
-bar, this value remains unchanged even when the menu bar wraps to two or
-more lines.  In that case, the @code{menu-bar-size} value returned by
-@code{frame-geometry} (@pxref{Frame Geometry}) allows to derive whether
-the menu bar actually occupies one or more lines.
+The number of lines to allocate at the top of the frame for a menu bar
+(@pxref{Menu Bar}).  The default is one if Menu Bar mode is enabled and
+zero otherwise.  @xref{Menu Bars,,,emacs, The GNU Emacs Manual}.  For an
+external menu bar (@pxref{Frame Layout}), this value remains unchanged
+even when the menu bar wraps to two or more lines.  In that case, the
+@code{menu-bar-size} value returned by @code{frame-geometry}
+(@pxref{Frame Geometry}) allows to derive whether the menu bar actually
+occupies one or more lines.

 @vindex tool-bar-lines frame parameter
 @item tool-bar-lines
-The number of lines to use for the tool bar.  The default is one if Tool
-Bar mode is enabled and zero otherwise.  @xref{Tool Bars,,,emacs, The
-GNU Emacs Manual}.  This value may change whenever the tool bar wraps.
+The number of lines to use for the tool bar (@pxref{Tool Bar}).  The
+default is one if Tool Bar mode is enabled and zero otherwise.
+@xref{Tool Bars,,,emacs, The GNU Emacs Manual}.  This value may change
+whenever the tool bar wraps (@pxref{Frame Layout}).

 @vindex tool-bar-position frame parameter
 @item tool-bar-position
-The position of the tool bar.  Currently only for the GTK tool bar.
-Value can be one of @code{top}, @code{bottom} @code{left}, @code{right}.
-The default is @code{top}.
+The position of the tool bar when Emacs was built with GTK+.  Its value
+can be one of @code{top}, @code{bottom} @code{left}, @code{right}.  The
+default is @code{top}.

 @vindex line-spacing, a frame parameter
 @item line-spacing
 Additional space to leave below each text line, in pixels (a positive
 integer).  @xref{Line Height}, for more information.
+
+@vindex no-special-glyphs, a frame parameter
+@item no-special-glyphs
+If this is non-@code{nil}, it suppresses the display of any truncation
+and continuation glyphs (@pxref{Truncation}) for all buffers displayed
+by this frame.  This is useful to eliminate such glyphs when fitting a
+frame to its buffer via @code{fit-frame-to-buffer} (@pxref{Resizing
+Windows}).
 @end table

@@ -1781,15 +1886,115 @@ Frame Interaction Parameters
 @item mouse-wheel-frame
 If non-@code{nil}, this parameter specifies the frame whose windows will
 be scrolled whenever the mouse wheel is scrolled with the mouse pointer
-hovering over this frame (@pxref{Mouse Commands,,, emacs, The GNU Emacs
-Manual}).
+hovering over this frame, see @ref{Mouse Commands,,, emacs, The GNU
+Emacs Manual}.

 @vindex no-other-frame, a frame parameter
 @item no-other-frame
 If this is non-@code{nil}, then this frame is not eligible as candidate
 for the functions @code{next-frame}, @code{previous-frame}
-(@pxref{Finding All Frames}) and @code{other-frame} (@pxref{Frame
-Commands,,, emacs, The GNU Emacs Manual}).
+(@pxref{Finding All Frames}) and @code{other-frame}, see @ref{Frame
+Commands,,, emacs, The GNU Emacs Manual}.
+
+@vindex auto-hide-function, a frame parameter
+@item auto-hide-function
+When this parameter specifies a function, that function will be called
+instead of the function specified by the variable
+@code{frame-auto-hide-function} when quitting the frame's only window
+(@pxref{Quitting Windows}) and there are other frames left.
+
+@vindex minibuffer-exit, a frame parameter
+@item minibuffer-exit
+When this parameter is non-@code{nil}, Emacs will by default make this
+frame invisible whenever the minibuffer (@pxref{Minibuffers}) is exited.
+Alternatively, it can specify the functions @code{iconify-frame} and
+@code{delete-frame}.  This parameter is useful to make a child frame
+disappear automatically (similar to how Emacs deals with a window) when
+exiting the minibuffer.
+
+@vindex keep-ratio, a frame parameter
+@item keep-ratio
+This parameter is currently meaningful for child frames (@pxref{Child
+Frames}) only.  If it is non-@code{nil}, then Emacs will try to keep the
+frame's size (width and height) ratios (@pxref{Size Parameters}) as well
+as its left and right position ratios (@pxref{Position Parameters})
+unaltered whenever its parent frame is resized.
+
+If the value of this parameter is @code{nil}, the frame's position and
+size remain unaltered when the parent frame is resized, so the position
+and size ratios may change.  If the value of this parameter is @code{t},
+Emacs will try to preserve the frame's size and position ratios, hence
+the frame's size and position relative to its parent frame may change.
+
+More individual control is possible by using a cons cell: In that case
+the frame's width ratio is preserved if the @sc{car} of the cell is
+either @code{t} or @code{width-only}.  The height ratio is preserved if
+the @sc{car} of the cell is either @code{t} or @code{height-only}.  The
+left position ratio is preserved if the @sc{cdr} of the cell is either
+@code{t} or @code{left-only}.  The top position ratio is preserved if
+the @sc{cdr} of the cell is either @code{t} or @code{top-only}.
+@end table
+
+
+@node Mouse Dragging Parameters
+@subsubsection Mouse Dragging Parameters
+@cindex mouse dragging parameters
+@cindex parameters for resizing frames with the mouse
+@cindex parameters for moving frames with the mouse
+
+The parameters described below provide support for resizing a frame by
+dragging its internal borders with the mouse.  They also allow moving a
+frame with the mouse by dragging the header line of its topmost or the
+mode line of its bottommost window.
+
+These parameters are mostly useful for child frames (@pxref{Child
+Frames}) that come without window manager decorations.  If necessary,
+they can be used for undecorated top-level frames as well.
+
+@table @code
+@vindex drag-internal-border, a frame parameter
+@item drag-internal-border
+If non-@code{nil}, the frame can be resized by dragging its internal
+borders, if present, with the mouse.
+
+@vindex drag-with-header-line, a frame parameter
+@item drag-with-header-line
+If non-@code{nil}, the frame can be moved with the mouse by dragging the
+header line of its topmost window.
+
+@vindex drag-with-mode-line, a frame parameter
+@item drag-with-mode-line
+If non-@code{nil}, the frame can be moved with the mouse by dragging the
+mode line of its bottommost window.  Note that such a frame is not
+allowed to have its own minibuffer window.
+
+@vindex snap-width, a frame parameter
+@item snap-width
+A frame that is moved with the mouse will ``snap'' at the border(s) of
+the display or its parent frame whenever it is dragged as near to such
+an edge as the number of pixels specified by this parameter.
+
+@vindex top-visible, a frame parameter
+@item top-visible
+If this parameter is a number, the top edge of the frame never appears
+above the top edge of its display or parent frame.  Moreover, as many
+pixels of the frame as specified by that number will remain visible when
+the frame is moved against any of the remaining edges of its display or
+parent frame.  Setting this parameter is useful to guard against
+dragging a child frame with a non-@code{nil}
+@code{drag-with-header-line} parameter completely out of the area
+of its parent frame.
+
+@vindex bottom-visible, a frame parameter
+@item bottom-visible
+If this parameter is a number, the bottom edge of the frame never
+appears below the bottom edge of its display or parent frame.  Moreover,
+as many pixels of the frame as specified by that number will remain
+visible when the frame is moved against any of the remaining edges of
+its display or parent frame.  Setting this parameter is useful to guard
+against dragging a child frame with a non-@code{nil}
+@code{drag-with-mode-line} parameter completely out of the area of
+its parent frame.
 @end table

@@ -1797,9 +2002,9 @@ Management Parameters
 @subsubsection Window Management Parameters
 @cindex window manager interaction, and frame parameters

-  The following frame parameters control various aspects of the
-frame's interaction with the window manager.  They have no effect on
-text terminals.
+  The following frame parameters control various aspects of the frame's
+interaction with the window manager or window system.  They have no
+effect on text terminals.

 @table @code
 @vindex visibility, a frame parameter
@@ -1908,7 +2113,8 @@ Management Parameters
 frame---a frame not handled by window managers under X.  Override
 redirect frames have no window manager decorations, can be positioned
 and resized only via Emacs' positioning and resizing functions and are
-usually drawn on top of all other frames.
+usually drawn on top of all other frames.  Setting this parameter has
+no effect on MS-Windows.

 @ignore
 @vindex parent-id, a frame parameter
@@ -2080,6 +2286,9 @@ Font and Color Parameters
 @code{(@var{active} . @var{inactive})}, where @var{active} is the
 opacity of the frame when it is selected, and @var{inactive} is the
 opacity when it is not selected.
+
+Some window systems do not support the @code{alpha} parameter for child
+frames (@pxref{Child Frames}).
 @end table

 The following frame parameters are semi-obsolete in that they are
@@ -2824,57 +3033,78 @@ Child Frames
 @cindex child frames
 @cindex parent frames

-On some window-systems the @code{parent-frame} parameter (@pxref{Frame
-Interaction Parameters}) can be used to make a frame a child of the
-frame specified by that parameter.  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.
+Child frames are objects halfway between windows (@pxref{Windows}) and
+``normal'' frames.  Like windows, they are attached to an owning frame.
+Unlike windows, they may overlap each other---changing the size or
+position of one child frame does not change the size or position of any
+of its sibling child frames.
+
+  By design, operations to make or modify child frames are implemented
+with the help of frame parameters (@pxref{Frame Parameters}) without any
+specialized functions or customizable variables.  Note that child frames
+are meaningful on graphical terminals only.
+
+  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 top-level frame
+@cindex reparent frame
+@cindex nest frame
   The @code{parent-frame} parameter can be changed at any time.  Setting
-it to another frame ``reparents'' the child frame.  Setting it to
-another child frame makes the frame a ``nested'' child frame.  Setting
-it to @code{nil} restores the frame's status as a top-level frame---one
-whose window-system window is a child of its display's root window.
+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 @dfn{top-level
+frame}---a frame whose window-system window is a child of its display's
+root window.

   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
 frame may be reversed at any time (though it's usually a good idea to
-keep the size of child frames sufficiently smaller than that of their
+keep the size of a child frame sufficiently smaller than that of its
 parent).  An error will be signaled for the attempt to make a frame an
 ancestor of itself.

-  A child frame is clipped at the native edges (@pxref{Frame Geometry})
-of its parent frame---everything outside these edges is invisible.  Its
-@code{left} and @code{top} parameters specify positions relative to the
-top-left corner of its parent's native frame.  When either of the frames
-is resized, the relative position of the child frame remains unaltered.
-Hence, resizing either of these frames can hide or reveal parts of the
-child frame.
+   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}
+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.
+allowing them to be positioned so they do not obscure the parent frame
+while still being visible themselves.

   Usually, moving a parent frame moves along all its child frames and
 their descendants as well, keeping their relative positions unaltered.
-The hook @code{move-frame-functions} (@pxref{Frame Position}) is run for
-a child frame only when the position of the child frame relative to its
-parent frame changes.  When a parent frame is resized, the child frame
-retains its position respective to the left and upper native edges of
-its parent.  In this case, the position respective to the lower or right
-native edge of the parent frame is usually lost.
+Note that the hook @code{move-frame-functions} (@pxref{Frame Position})
+is run for a child frame only when the position of the child frame
+relative to its parent frame changes.  It is not run for a child frame
+when the position of the parent frame changes.
+
+  When a parent frame is resized, its child frames conceptually retain
+their previous sizes and their positions relative to the left upper
+corner of the parent.  This means that a child frame may become
+(partially) invisible when its parent frame shrinks.  The parameter
+@code{keep-ratio} (@pxref{Frame Interaction Parameters}) can be used to
+resize and reposition a child frame proportionally whenever its parent
+frame is resized.  This may avoid obscuring parts of a frame when its
+parent frame is shrunk.

   A visible child frame always appears on top of its parent frame thus
 obscuring parts of it, except on NS builds where it may be positioned
-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
+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.

   Whether a child frame can have a menu or tool bar is window-system or
@@ -2892,7 +3122,55 @@ Child Frames
 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}).
+
+  To resize or move an undecorated 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.
+
+  There are two ways to drag an entire child frame with the mouse: The
+@code{drag-with-mode-line} parameter, if non-@code{nil}, allows to drag
+a frame without minibuffer window (@pxref{Minibuffer Windows}) via the
+mode line area of its bottommost window.  The
+@code{drag-with-header-line} parameter, if non-@code{nil}, allows to
+drag the frame via the header line area of its topmost window.
+
+  In order to give a child frame a draggable header or mode line, the
+window parameters @code{mode-line-format} and @code{header-line-format}
+are handy (@pxref{Window Parameters}).  These allow to remove an
+unwanted mode line (when @code{drag-with-header-line} is chosen) and to
+remove mouse-sensitive areas which might interfere with frame dragging.
+
+  To avoid that dragging moves a frame completely out of its parent's
+native frame, something which might happen when the mouse cursor
+overshoots and makes the frame difficult to retrieve once the mouse
+button has been released, it is advisable to set the frame's
+@code{top-visible} or @code{bottom-visible} parameter correspondingly.
+
+  The @code{top-visible} parameter specifies the number of pixels at the
+top of the frame that always remain visible within the parent's native
+frame during dragging and should be set when specifying a non-@code{nil}
+@code{drag-with-header-line} parameter.  The @code{bottom-visible}
+parameter specifies the number of pixels at the bottom of the frame that
+always remain visible within the parent's native frame during dragging
+and should be preferred when specifying a non-@code{nil}
+@code{drag-with-mode-line} parameter.
+
+  When a child frame is used for displaying a buffer via
+@code{display-buffer-in-child-frame} (@pxref{Display Action Functions}),
+the frame's @code{auto-hide-function} parameter (@pxref{Frame
+Interaction Parameters}) can be set to a function, in order to
+appropriately deal with the frame when the window displaying the buffer
+shall be quit.
+
+  When a child frame is used during minibuffer interaction, for example,
+to display completions in a separate window, the @code{minibuffer-exit}
+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:
@@ -2930,7 +3208,7 @@ Child Frames
 frame or on some ancestor instead.
 @end itemize

-  The following two functions may be useful when working with child and
+  The following two functions can be useful when working with child and
 parent frames:

 @defun frame-parent &optional frame
@@ -2951,6 +3229,12 @@ Child Frames
 frame.
 @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.
+

 @node Mouse Tracking
 @section Mouse Tracking
diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi
index 0e476b4..f7013da 100644
--- a/doc/lispref/modes.texi
+++ b/doc/lispref/modes.texi
@@ -1737,7 +1737,9 @@ Mode Line Basics
 displayed on the buffer's mode line.  The value of
 @code{header-line-format} specifies the buffer's header line in the same
 way.  All windows for the same buffer use the same
-@code{mode-line-format} and @code{header-line-format}.
+@code{mode-line-format} and @code{header-line-format} unless a
+@code{mode-line-format} or @code{header-line-format} parameter has been
+specified for that window (@pxref{Window Parameters}).

   For efficiency, Emacs does not continuously recompute each window's
 mode line and header line.  It does so when circumstances appear to call
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index d9b4b74..eb5c2fc 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -752,6 +752,7 @@ Window Sizes
 minimum size of @var{window} counted in pixels.
 @end defun

+
 @node Resizing Windows
 @section Resizing Windows
 @cindex window resizing
@@ -943,7 +944,8 @@ Resizing Windows
 @defopt fit-frame-to-buffer-margins
 This option can be used to specify margins around frames to be fit by
 @code{fit-frame-to-buffer}.  Such margins can be useful to avoid, for
-example, that such frames overlap the taskbar.
+example, that the resized frame overlaps the taskbar or parts of its
+parent frame.

 It specifies the numbers of pixels to be left free on the left, above,
 the right, and below a frame that shall be fit.  The default specifies
@@ -2484,6 +2486,25 @@ Display Action Functions
 is added to the newly created frame's parameters.
 @end defun

+@defun display-buffer-in-child-frame buffer alist
+This function tries to display @var{buffer} in a child frame
+(@pxref{Child Frames}) of the selected frame, either reusing an existing
+child frame or by making a new one.  If @var{alist} has a non-@code{nil}
+@code{child-frame-parameters} entry, the corresponding value is an alist
+of frame parameters to give the new frame.  A @code{parent-frame}
+parameter specifying the selected frame is provided by default.  If the
+child frame should be or become the child of another frame, a
+corresponding entry must be added to @var{alist}.
+
+The appearance of child frames is largely dependent on the parameters
+provided via @var{alist}.  It is advisable to use at least ratios to
+specify the size (@pxref{Size Parameters}) and the position
+(@pxref{Position Parameters}) of the child frame and to add the
+@code{keep-ratio} in order to make sure that the child frame remains
+visible.  For other parameters that should be considered see @ref{Child
+Frames}.
+@end defun
+
 @defun display-buffer-use-some-frame buffer alist
 This function tries to display @var{buffer} by trying to find a
 frame that meets a predicate (by default any frame other than the
@@ -3124,12 +3145,17 @@ Quitting Windows
 The default is to call @code{iconify-frame} (@pxref{Visibility of
 Frames}).  Alternatively, you may specify either @code{delete-frame}
 (@pxref{Deleting Frames}) to remove the frame from its display,
-@code{ignore} to leave the frame unchanged, or any other function that
-can take a frame as its sole argument.
+@code{make-frame-invisible} to make the frame invisible, @code{ignore}
+to leave the frame unchanged, or any other function that can take a
+frame as its sole argument.

 Note that the function specified by this option is called only if the
 specified frame contains just one live window and there is at least one
 other frame on the same terminal.
+
+For a particular frame, the value specified here may be overridden by
+that frame's @code{auto-hide-function} frame parameter (@pxref{Frame
+Interaction Parameters}).
 @end defopt

@@ -4364,13 +4390,12 @@ Coordinates and Windows
 @cindex coordinate, relative to frame
 @cindex window position

-This section describes functions that report the position of a window.
-Most of these functions report positions relative to an origin at the
-native position of the window's frame (@pxref{Frame Geometry}).  Some
-functions report positions relative to the origin of the display of the
-window's frame.  In any case, the origin has the coordinates (0, 0) and
-X and Y coordinates increase rightward and downward
-respectively.
+This section describes functions that report positions of and within a
+window.  Most of these functions report positions relative to an origin
+at the native position of the window's frame (@pxref{Frame Geometry}).
+Some functions report positions relative to the origin of the display of
+the window's frame.  In any case, the origin has the coordinates (0, 0)
+and X and Y coordinates increase rightward and downward respectively.

   For the following functions, X and Y coordinates are reported in
 integer character units, i.e., numbers of lines and columns
@@ -4608,6 +4633,49 @@ Coordinates and Windows
 @end example
 @end defun

+The following function returns the largest rectangle that can be
+inscribed in a window without covering text displayed in that window.
+
+@defun window-largest-empty-rectangle &optional window count min-width min-height positions left
+This function calculates the dimensions of the largest empty rectangle
+that can be inscribed in the specified @var{window}'s text area.
+@var{window} must be a live window and defaults to the selected one.
+
+The return value is a triple of the width and the start and end
+y-coordinates of the largest rectangle that can be inscribed into the
+empty space (space not displaying any text) of the text area of
+@var{window}.  No x-coordinates are returned by this function---any such
+rectangle is assumed to end at the right edge of @var{window}'s text
+area.  If no empty space can be found, the return value is @code{nil}.
+
+The optional argument @var{count}, if non-@code{nil}, specifies a
+maximum number of rectangles to return.  This means that the return
+value is a list of triples specifying rectangles with the largest
+rectangle first.  @var{count} can be also a cons cell whose car
+specifies the number of rectangles to return and whose @sc{cdr}, if
+non-@code{nil}, states that all rectangles returned must be disjoint.
+
+The optional arguments @var{min-width} and @var{min-height}, if
+non-@code{nil}, specify the minimum width and height of any rectangle
+returned.
+
+The optional argument @var{positions}, if non-@code{nil}, is a cons cell
+whose @sc{car} specifies the uppermost and whose @sc{cdr} specifies the
+lowermost pixel position that must be covered by any rectangle returned.
+These positions measure from the start of the text area of @var{window}.
+
+The optional argument @var{left}, if non-@code{nil}, means to return
+values suitable for buffers displaying right to left text.  In that
+case, any rectangle returned is assumed to start at the left edge of
+@var{window}'s text area.
+
+Note that this function has to retrieve the dimensions of each line of
+@var{window}'s glyph matrix via @code{window-lines-pixel-dimensions}
+(@pxref{Size of Displayed Text}).  Hence, this function may also return
+@code{nil} when the current glyph matrix of @var{window} is not
+up-to-date.
+@end defun
+

 @node Mouse Window Auto-selection
 @section Mouse Window Auto-selection
@@ -4911,37 +4979,45 @@ Window Parameters
 The following parameters are currently used by the window management
 code:

-@table @asis
-@item @code{delete-window}
+@table @code
+@item delete-window
+@vindex delete-window, a window parameter
 This parameter affects the execution of @code{delete-window}
 (@pxref{Deleting Windows}).

-@item @code{delete-other-windows}
+@item delete-other-windows
+@vindex delete-other-windows, a window parameter
 This parameter affects the execution of @code{delete-other-windows}
 (@pxref{Deleting Windows}).

-@item @code{no-delete-other-window}
+@item no-delete-other-window
+@vindex no-delete-other-window, a window parameter
 This parameter marks the window as not deletable by
 @code{delete-other-windows} (@pxref{Deleting Windows}).

-@item @code{split-window}
+@item split-window
+@vindex split-window, a window parameter
 This parameter affects the execution of @code{split-window}
 (@pxref{Splitting Windows}).

-@item @code{other-window}
+@item other-window
+@vindex other-window, a window parameter
 This parameter affects the execution of @code{other-window}
 (@pxref{Cyclic Window Ordering}).

-@item @code{no-other-window}
+@item no-other-window
+@vindex no-other-window, a window parameter
 This parameter marks the window as not selectable by @code{other-window}
 (@pxref{Cyclic Window Ordering}).

-@item @code{clone-of}
+@item clone-of
+@vindex clone-of, a window parameter
 This parameter specifies the window that this one has been cloned
 from.  It is installed by @code{window-state-get} (@pxref{Window
 Configurations}).

-@item @code{preserved-size}
+@item preserved-size
+@vindex preserved-size, a window parameter
 This parameter specifies a buffer, a direction where @code{nil} means
 vertical and @code{t} horizontal, and a size in pixels.  If this window
 displays the specified buffer and its size in the indicated direction
@@ -4950,7 +5026,8 @@ Window Parameters
 parameter is installed and updated by the function
 @code{window-preserve-size} (@pxref{Preserving Window Sizes}).

-@item @code{quit-restore}
+@item quit-restore
+@vindex quit-restore, a window parameter
 This parameter is installed by the buffer display functions
 (@pxref{Choosing Window}) and consulted by @code{quit-restore-window}
 (@pxref{Quitting Windows}).  It contains four elements:
@@ -4981,15 +5058,37 @@ Window Parameters
 See the description of @code{quit-restore-window} in @ref{Quitting
 Windows} for details.

-@item @code{window-side} @code{window-slot}
+@item window-side window-slot
+@vindex window-side, a window parameter
+@vindex window-slot, a window parameter
 These parameters are used for implementing side windows (@pxref{Side
 Windows}).

-@item @code{window-atom}
+@item window-atom
+@vindex window-atom, a window parameter
 This parameter is used for implementing atomic windows, see @ref{Atomic
 Windows}.

-@item @code{min-margins}
+@item mode-line-format
+@vindex mode-line-format, a window parameter
+This parameter replaces the value of the buffer-local variable
+@code{mode-line-format} (@pxref{Mode Line Basics}) of this window's
+buffer whenever this window is displayed.  The symbol @code{none} means
+to suppress display of a mode line for this window.  Display and
+contents of the mode line on other windows showing this buffer are not
+affected.
+
+@item header-line-format
+@vindex header-line-format, a window parameter
+This parameter replaces the value of the buffer-local variable
+@code{header-line-format} (@pxref{Mode Line Basics}) of this window's
+buffer whenever this window is displayed.  The symbol @code{none} means
+to suppress display of a header line for this window.  Display and
+contents of the header line on other windows showing this buffer are not
+affected.
+
+@item min-margins
+@vindex min-margins, a window parameter
 The value of this parameter is a cons cell whose @sc{car} and @sc{cdr},
 if non-@code{nil}, specify the minimum values (in columns) for the left
 and right margin of this window.  When present, Emacs will use these
diff --git a/etc/NEWS b/etc/NEWS
index 78d37484..430bab4 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1203,7 +1203,7 @@ run.
 frame's outer border.

 +++
-*** New frame parameters
+*** New frame parameters and changed semantics for older ones

 +++
 **** 'z-group' positions a frame above or below all others.
@@ -1248,10 +1248,32 @@ focus via the mouse.
 frame.

 +++
-*** The 'width' and 'height' frame parameters allow to specify pixel
-values now.
+**** 'width' and 'height' allow to specify pixel values and ratios now.

 +++
+**** 'left' and 'top' allow to specify ratios now.
+
++++
+**** 'keep-ratio' preserves size and position of child frames when their
+parent frame is resized.
+
++++
+**** 'no-special-glyphs' suppresses display of truncation and
+continuation glyphs in a frame.
+
++++
+**** 'auto-hide-function' and 'minibuffer-exit' handle auto hiding of
+frames and exiting from minibuffer individually.
+
++++
+**** 'fit-frame-to-buffer-margins' and 'fit-frame-to-buffer-sizes'
+handle fitting a frame to its buffer individually.
+
++++
+**** 'drag-internal-border', 'drag-with-header-line',
+'drag-with-mode-line', 'snap-width', 'top-visible' and 'bottom-visible'
+allow to drag and resize frames with the mouse.
+
 *** The new function 'frame-list-z-order' returns a list of all frames
 in Z (stacking) order.

@@ -1310,6 +1332,10 @@ a new window when opening man pages when there's already one, use
 its window gets deleted by 'delete-other-windows'.

 +++
+*** New window parameters 'mode-line-format' and 'header-line-format'
+allow to override the buffer-local formats for this window.
+
++++
 *** New command 'window-swap-states' swaps the states of two live
 windows.

@@ -1319,6 +1345,15 @@ windows.
 window changed size when 'window-size-change-functions' are run.

 +++
+*** The new function 'window-lines-pixel-dimensions' returns the pixel
+dimensions of a window's text lines.
+
++++
+*** The new function 'window-largest-empty-rectangle' returns the
+dimensions of the largest rectangular area not occupying any text in a
+window's body.
+
++++
 *** The semantics of 'mouse-autoselect-window' has changed slightly.
 For details see the section "Mouse Window Auto-selection" in the Elisp
 manual.
@@ -1364,7 +1399,7 @@ This is in contrast to the default action on POSIX Systems, where it
 causes the receiving process to terminate with a core dump if no
 debugger has been attached to it.

-** `set-mouse-position' and `set-mouse-absolute-pixel-position' work
+** 'set-mouse-position' and 'set-mouse-absolute-pixel-position' work
 on macOS.

 
diff --git a/lisp/frame.el b/lisp/frame.el
index b7a5516..b54df6f 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -1110,6 +1110,38 @@ frame-width
 If FRAME is omitted, describe the currently selected frame."
   (cdr (assq 'width (frame-parameters frame))))

+(defalias 'frame-border-width 'frame-internal-border-width)
+(defalias 'frame-pixel-width 'frame-native-width)
+(defalias 'frame-pixel-height 'frame-native-height)
+
+(defun frame-inner-width (&optional frame)
+  "Return inner width of FRAME in pixels.
+FRAME defaults to the selected frame."
+  (setq frame (window-normalize-frame frame))
+  (- (frame-native-width frame)
+     (* 2 (frame-internal-border-width frame))))
+
+(defun frame-inner-height (&optional frame)
+  "Return inner height of FRAME in pixels.
+FRAME defaults to the selected frame."
+  (setq frame (window-normalize-frame frame))
+  (- (frame-native-height frame)
+     (* 2 (frame-internal-border-width frame))))
+
+(defun frame-outer-width (&optional frame)
+  "Return outer width of FRAME in pixels.
+FRAME defaults to the selected frame."
+  (setq frame (window-normalize-frame frame))
+  (let ((edges (frame-edges frame 'outer-edges)))
+    (- (nth 2 edges) (nth 0 edges))))
+
+(defun frame-outer-height (&optional frame)
+  "Return outer height of FRAME in pixels.
+FRAME defaults to the selected frame."
+  (setq frame (window-normalize-frame frame))
+  (let ((edges (frame-edges frame 'outer-edges)))
+    (- (nth 3 edges) (nth 1 edges))))
+
 (declare-function x-list-fonts "xfaces.c"
                   (pattern &optional face frame maximum width))

diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index c3480cd..e5b1029 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -746,7 +746,7 @@ completion-show-inline-help

 (defcustom completion-auto-help t
   "Non-nil means automatically provide help for invalid completion input.
-If the value is t the *Completion* buffer is displayed whenever completion
+If the value is t the *Completions* buffer is displayed whenever completion
 is requested but cannot be done.
 If the value is `lazy', the *Completions* buffer is only displayed after
 the second failed attempt to complete."
diff --git a/lisp/mouse.el b/lisp/mouse.el
index 9b6b169..e079443 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -380,7 +380,7 @@ mouse-split-window-horizontally

 (defun mouse-drag-line (start-event line)
   "Drag a mode line, header line, or vertical line with the mouse.
-START-EVENT is the starting mouse-event of the drag action.  LINE
+START-EVENT is the starting mouse event of the drag action.  LINE
 must be one of the symbols `header', `mode', or `vertical'."
   ;; Give temporary modes such as isearch a chance to turn off.
   (run-hooks 'mouse-leave-buffer-hook)
@@ -405,29 +405,15 @@ mouse-drag-line
     ;; window's edge we drag.
     (cond
      ((eq line 'header)
-      (if (window-at-side-p window 'top)
-	  ;; We can't drag the header line of a topmost window.
-	  (setq draggable nil)
-	;; Drag bottom edge of window above the header line.
-	(setq window (window-in-direction 'above window t))))
-     ((eq line 'mode)
-      (if (and (window-at-side-p window 'bottom)
-	       ;; Allow resizing the minibuffer window if it's on the
-	       ;; same frame as and immediately below `window', and it's
-	       ;; either active or `resize-mini-windows' is nil.
-	       (let ((minibuffer-window (minibuffer-window frame)))
-		 (not (and (eq (window-frame minibuffer-window) frame)
-			   (or (not resize-mini-windows)
-			       (eq minibuffer-window
-				   (active-minibuffer-window)))))))
-	  (setq draggable nil)))
+      ;; Drag bottom edge of window above the header line.
+      (setq window (window-in-direction 'above window t)))
+     ((eq line 'mode))
      ((eq line 'vertical)
       (let ((divider-width (frame-right-divider-width frame)))
         (when (and (or (not (numberp divider-width))
                        (zerop divider-width))
                    (eq (frame-parameter frame 'vertical-scroll-bars) 'left))
           (setq window (window-in-direction 'left window t))))))
-
     (let* ((exitfun nil)
            (move
 	    (lambda (event) (interactive "e")
@@ -530,20 +516,405 @@ mouse-drag-line
 	     t (lambda () (setq track-mouse old-track-mouse)))))))

 (defun mouse-drag-mode-line (start-event)
-  "Change the height of a window by dragging on the mode line."
+  "Change the height of a window by dragging on its mode line.
+START-EVENT is the starting mouse event of the drag action.
+
+If the drag happens in a mode line on the bottom of a frame and
+that frame's `drag-with-mode-line' parameter is non-nil, drag the
+frame instead."
   (interactive "e")
-  (mouse-drag-line start-event 'mode))
+  (let* ((start (event-start start-event))
+	 (window (posn-window start))
+         (frame (window-frame window)))
+    (cond
+     ((not (window-live-p window)))
+     ((or (not (window-at-side-p window 'bottom))
+          ;; Allow resizing the minibuffer window if it's on the
+          ;; same frame as and immediately below `window', and it's
+          ;; either active or `resize-mini-windows' is nil.
+          (let ((minibuffer-window (minibuffer-window frame)))
+            (and (eq (window-frame minibuffer-window) frame)
+                 (or (not resize-mini-windows)
+                     (eq minibuffer-window
+                         (active-minibuffer-window))))))
+      (mouse-drag-line start-event 'mode))
+     ((and (frame-parameter frame 'drag-with-mode-line)
+           (window-at-side-p window 'bottom)
+           (let ((minibuffer-window (minibuffer-window frame)))
+             (not (eq (window-frame minibuffer-window) frame))))
+      ;; Drag frame when the window is on the bottom of its frame and
+      ;; there is no minibuffer window below.
+      (mouse-drag-frame start-event 'move)))))

 (defun mouse-drag-header-line (start-event)
-  "Change the height of a window by dragging on the header line."
+  "Change the height of a window by dragging on its header line.
+START-EVENT is the starting mouse event of the drag action.
+
+If the drag happens in a header line on the top of a frame and
+that frame's `drag-with-header-line' parameter is non-nil, drag
+the frame instead."
   (interactive "e")
-  (mouse-drag-line start-event 'header))
+  (let* ((start (event-start start-event))
+	 (window (posn-window start)))
+    (if (and (window-live-p window)
+             (not (window-at-side-p window 'top)))
+        (mouse-drag-line start-event 'header)
+      (let ((frame (window-frame window)))
+        (when (frame-parameter frame 'drag-with-header-line)
+          (mouse-drag-frame start-event 'move))))))

 (defun mouse-drag-vertical-line (start-event)
-  "Change the width of a window by dragging on the vertical line."
+  "Change the width of a window by dragging on a vertical line.
+START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
   (mouse-drag-line start-event 'vertical))
 
+(defun mouse-resize-frame (frame x-diff y-diff &optional x-move y-move)
+  "Helper function for `mouse-drag-frame'."
+  (let* ((frame-x-y (frame-position frame))
+         (frame-x (car frame-x-y))
+         (frame-y (cdr frame-x-y))
+         alist)
+    (if (> x-diff 0)
+        (when x-move
+          (setq x-diff (min x-diff frame-x))
+          (setq x-move (- frame-x x-diff)))
+      (let* ((min-width (frame-windows-min-size frame t nil t))
+             (min-diff (max 0 (- (frame-inner-width frame) min-width))))
+        (setq x-diff (max x-diff (- min-diff)))
+        (when x-move
+          (setq x-move (+ frame-x (- x-diff))))))
+
+    (if (> y-diff 0)
+        (when y-move
+          (setq y-diff (min y-diff frame-y))
+          (setq y-move (- frame-y y-diff)))
+      (let* ((min-height (frame-windows-min-size frame nil nil t))
+             (min-diff (max 0 (- (frame-inner-height frame) min-height))))
+        (setq y-diff (max y-diff (- min-diff)))
+        (when y-move
+          (setq y-move (+ frame-y (- y-diff))))))
+
+    (unless (zerop x-diff)
+      (when x-move
+        (push `(left . ,x-move) alist))
+      (push `(width . (text-pixels . ,(+ (frame-text-width frame) x-diff)))
+            alist))
+    (unless (zerop y-diff)
+      (when y-move
+        (push `(top . ,y-move) alist))
+      (push `(height . (text-pixels . ,(+ (frame-text-height frame) y-diff)))
+            alist))
+    (when alist
+      (modify-frame-parameters frame alist))))
+
+(defun mouse-drag-frame (start-event part)
+  "Drag a frame or one of its edges with the mouse.
+START-EVENT is the starting mouse event of the drag action.  Its
+position window denotes the frame that will be dragged.
+
+PART specifies the part that has been dragged and must be one of
+the symbols 'left', 'top', 'right', 'bottom', 'top-left',
+'top-right', 'bottom-left', 'bottom-right' to drag an internal
+border or edge.  If PART equals 'move', this means to move the
+frame with the mouse."
+  ;; Give temporary modes such as isearch a chance to turn off.
+  (run-hooks 'mouse-leave-buffer-hook)
+  (let* ((echo-keystrokes 0)
+	 (start (event-start start-event))
+         (window (posn-window start))
+         ;; FRAME is the frame to drag.
+         (frame (if (window-live-p window)
+                    (window-frame window)
+                  window))
+         (width (frame-native-width frame))
+         (height (frame-native-height frame))
+         ;; PARENT is the parent frame of FRAME or, if FRAME is a
+         ;; top-level frame, FRAME's workarea.
+         (parent (frame-parent frame))
+         (parent-edges
+          (if parent
+              `(0 0 ,(frame-native-width parent) ,(frame-native-height parent))
+            (let* ((attributes
+                    (car (display-monitor-attributes-list)))
+                   (workarea (assq 'workarea attributes)))
+              (and workarea
+                   `(,(nth 1 workarea) ,(nth 2 workarea)
+                     ,(+ (nth 1 workarea) (nth 3 workarea))
+                     ,(+ (nth 2 workarea) (nth 4 workarea)))))))
+         (parent-left (and parent-edges (nth 0 parent-edges)))
+         (parent-top (and parent-edges (nth 1 parent-edges)))
+         (parent-right (and parent-edges (nth 2 parent-edges)))
+         (parent-bottom (and parent-edges (nth 3 parent-edges)))
+         ;; `pos-x' and `pos-y' record the x- and y-coordinates of the
+	 ;; last sampled mouse position.  Note that we sample absolute
+	 ;; mouse positions to avoid that moving the mouse from one
+	 ;; frame into another gets into our way.  `last-x' and `last-y'
+	 ;; records the x- and y-coordinates of the previously sampled
+	 ;; position.  The differences between `last-x' and `pos-x' as
+	 ;; well as `last-y' and `pos-y' determine the amount the mouse
+	 ;; has been dragged between the last two samples.
+         pos-x-y pos-x pos-y
+         (last-x-y (mouse-absolute-pixel-position))
+         (last-x (car last-x-y))
+         (last-y (cdr last-x-y))
+         ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
+         ;; mouse position when FRAME snapped.  As soon as the
+         ;; difference between `pos-x' and `snap-x' (or `pos-y' and
+         ;; `snap-y') exceeds the value of FRAME's `snap-width'
+         ;; parameter, unsnap FRAME (at the respective side).  `snap-x'
+         ;; and `snap-y' nil mean FRAME is curerntly not snapped.
+         snap-x snap-y
+         (exitfun nil)
+         (move
+          (lambda (event)
+            (interactive "e")
+            (when (consp event)
+              (setq pos-x-y (mouse-absolute-pixel-position))
+              (setq pos-x (car pos-x-y))
+              (setq pos-y (cdr pos-x-y))
+              (cond
+               ((eq part 'left)
+                (mouse-resize-frame frame (- last-x pos-x) 0 t))
+               ((eq part 'top)
+                (mouse-resize-frame frame 0 (- last-y pos-y) nil t))
+               ((eq part 'right)
+                (mouse-resize-frame frame (- pos-x last-x) 0))
+               ((eq part 'bottom)
+                (mouse-resize-frame frame 0 (- pos-y last-y)))
+               ((eq part 'top-left)
+                (mouse-resize-frame
+                 frame (- last-x pos-x) (- last-y pos-y) t t))
+               ((eq part 'top-right)
+                (mouse-resize-frame
+                 frame (- pos-x last-x) (- last-y pos-y) nil t))
+               ((eq part 'bottom-left)
+                (mouse-resize-frame
+                 frame (- last-x pos-x) (- pos-y last-y) t))
+               ((eq part 'bottom-right)
+                (mouse-resize-frame
+                 frame (- pos-x last-x) (- pos-y last-y)))
+               ((eq part 'move)
+                (let* ((old-position (frame-position frame))
+                       (old-left (car old-position))
+                       (old-top (cdr old-position))
+                       (left (+ old-left (- pos-x last-x)))
+                       (top (+ old-top (- pos-y last-y)))
+                       right bottom
+                       ;; `snap-width' (maybe also a yet to be provided
+                       ;; `snap-height') could become floats to handle
+                       ;; proportionality wrt PARENT.  We don't do any
+                       ;; checks on this parameter so far.
+                       (snap-width (frame-parameter frame 'snap-width)))
+                  ;; Docking and constraining.
+                  (when (and (numberp snap-width) parent-edges)
+                    (cond
+                     ;; Docking at the left parent edge.
+                     ((< pos-x last-x)
+                      (cond
+                       ((and (> left parent-left)
+                             (<= (- left parent-left) snap-width))
+                        ;; Snap when the mouse moved leftward and
+                        ;; FRAME's left edge would end up within
+                        ;; `snap-width' pixels from PARENT's left edge.
+                        (setq snap-x pos-x)
+                        (setq left parent-left))
+                       ((and (<= left parent-left)
+                             (<= (- parent-left left) snap-width)
+                             snap-x (<= (- snap-x pos-x) snap-width))
+                        ;; Stay snapped when the mouse moved leftward
+                        ;; but not more than `snap-width' pixels from
+                        ;; the time FRAME snapped.
+                        (setq left parent-left))
+                       (t
+                        ;; Unsnap when the mouse moved more than
+                        ;; `snap-width' pixels leftward from the time
+                        ;; FRAME snapped.
+                        (setq snap-x nil))))
+                     ((> pos-x last-x)
+                      (setq right (+ left width))
+                      (cond
+                       ((and (< right parent-right)
+                             (<= (- parent-right right) snap-width))
+                        ;; Snap when the mouse moved rightward and
+                        ;; FRAME's right edge would end up within
+                        ;; `snap-width' pixels from PARENT's right edge.
+                        (setq snap-x pos-x)
+                        (setq left (- parent-right width)))
+                       ((and (>= right parent-right)
+                             (<= (- right parent-right) snap-width)
+                             snap-x (<= (- pos-x snap-x) snap-width))
+                        ;; Stay snapped when the mouse moved rightward
+                        ;; but not more more than `snap-width' pixels
+                        ;; from the time FRAME snapped.
+                        (setq left (- parent-right width)))
+                       (t
+                        ;; Unsnap when the mouse moved rightward more
+                        ;; than `snap-width' pixels from the time FRAME
+                        ;; snapped.
+                        (setq snap-x nil)))))
+
+                    (cond
+                     ((< pos-y last-y)
+                      (cond
+                       ((and (> top parent-top)
+                             (<= (- top parent-top) snap-width))
+                        ;; Snap when the mouse moved upward and FRAME's
+                        ;; top edge would end up within `snap-width'
+                        ;; pixels from PARENT's top edge.
+                        (setq snap-y pos-y)
+                        (setq top parent-top))
+                       ((and (<= top parent-top)
+                             (<= (- parent-top top) snap-width)
+                             snap-y (<= (- snap-y pos-y) snap-width))
+                        ;; Stay snapped when the mouse moved upward but
+                        ;; not more more than `snap-width' pixels from
+                        ;; the time FRAME snapped.
+                        (setq top parent-top))
+                       (t
+                        ;; Unsnap when the mouse moved upward more than
+                        ;; `snap-width' pixels from the time FRAME
+                        ;; snapped.
+                        (setq snap-y nil))))
+                     ((> pos-y last-y)
+                      (setq bottom (+ top height))
+                      (cond
+                       ((and (< bottom parent-bottom)
+                             (<= (- parent-bottom bottom) snap-width))
+                        ;; Snap when the mouse moved downward and
+                        ;; FRAME's bottom edge would end up within
+                        ;; `snap-width' pixels from PARENT's bottom
+                        ;; edge.
+                        (setq snap-y pos-y)
+                        (setq top (- parent-bottom height)))
+                       ((and (>= bottom parent-bottom)
+                             (<= (- bottom parent-bottom) snap-width)
+                             snap-y (<= (- pos-y snap-y) snap-width))
+                        ;; Stay snapped when the mouse moved downward
+                        ;; but not more more than `snap-width' pixels
+                        ;; from the time FRAME snapped.
+                        (setq top (- parent-bottom height)))
+                       (t
+                        ;; Unsnap when the mouse moved downward more
+                        ;; than `snap-width' pixels from the time FRAME
+                        ;; snapped.
+                        (setq snap-y nil))))))
+
+                  ;; If requested, constrain FRAME's draggable areas to
+                  ;; PARENT's edges.  The `top-visible' parameter should
+                  ;; be set when FRAME has a draggable header-line.  If
+                  ;; set to a number, it ascertains that the top of
+                  ;; FRAME is always constrained to the top of PARENT
+                  ;; and that at least as many pixels of FRAME as
+                  ;; specified by that number are visible on each of the
+                  ;; three remaining sides of PARENT.
+                  ;;
+                  ;; The `bottom-visible' parameter should be set when
+                  ;; FRAME has a draggable mode-line.  If set to a
+                  ;; number, it ascertains that the bottom of FRAME is
+                  ;; always constrained to the bottom of PARENT and that
+                  ;; at least as many pixels of FRAME as specified by
+                  ;; that number are visible on each of the three
+                  ;; remaining sides of PARENT.
+                  (let ((par (frame-parameter frame 'top-visible))
+                        bottom-visible)
+                    (unless par
+                      (setq par (frame-parameter frame 'bottom-visible))
+                      (setq bottom-visible t))
+                    (when (and (numberp par) parent-edges)
+                      (setq left
+                            (max (min (- parent-right par) left)
+                                 (+ (- parent-left width) par)))
+                      (setq top
+                            (if bottom-visible
+                                (min (max top (- parent-top (- height par)))
+                                     (- parent-bottom height))
+                              (min (max top parent-top)
+                                   (- parent-bottom par))))))
+
+                  ;; Use `modify-frame-parameters' since `left' and
+                  ;; `top' may want to move FRAME out of its PARENT.
+                  (modify-frame-parameters
+                   frame
+                   `((left . (+ ,left)) (top . (+ ,top)))))))
+              (setq last-x pos-x)
+              (setq last-y pos-y))))
+         (old-track-mouse track-mouse))
+    ;; Start tracking.  The special value 'dragging' signals the
+    ;; display engine to freeze the mouse pointer shape for as long
+    ;; as we drag.
+    (setq track-mouse 'dragging)
+    ;; Loop reading events and sampling the position of the mouse.
+    (setq exitfun
+          (set-transient-map
+           (let ((map (make-sparse-keymap)))
+             (define-key map [switch-frame] #'ignore)
+             (define-key map [select-window] #'ignore)
+             (define-key map [scroll-bar-movement] #'ignore)
+             (define-key map [mouse-movement] move)
+             ;; Swallow drag-mouse-1 events to avoid selecting some other window.
+             (define-key map [drag-mouse-1]
+               (lambda () (interactive) (funcall exitfun)))
+             ;; Some of the events will of course end up looked up
+             ;; with a mode-line, header-line or vertical-line prefix ...
+             (define-key map [mode-line] map)
+             (define-key map [header-line] map)
+             (define-key map [vertical-line] map)
+             ;; ... and some maybe even with a right- or bottom-divider
+             ;; prefix.
+             (define-key map [right-divider] map)
+             (define-key map [bottom-divider] map)
+             map)
+           t (lambda () (setq track-mouse old-track-mouse))))))
+
+(defun mouse-drag-left-edge (start-event)
+  "Drag left edge of a frame with the mouse.
+START-EVENT is the starting mouse event of the drag action."
+  (interactive "e")
+  (mouse-drag-frame start-event 'left))
+
+(defun mouse-drag-top-left-corner (start-event)
+  "Drag top left corner of a frame with the mouse.
+START-EVENT is the starting mouse event of the drag action."
+  (interactive "e")
+  (mouse-drag-frame start-event 'top-left))
+
+(defun mouse-drag-top-edge (start-event)
+  "Drag top edge of a frame with the mouse.
+START-EVENT is the starting mouse event of the drag action."
+  (interactive "e")
+  (mouse-drag-frame start-event 'top))
+
+(defun mouse-drag-top-right-corner (start-event)
+  "Drag top right corner of a frame with the mouse.
+START-EVENT is the starting mouse event of the drag action."
+  (interactive "e")
+  (mouse-drag-frame start-event 'top-right))
+
+(defun mouse-drag-right-edge (start-event)
+  "Drag right edge of a frame with the mouse.
+START-EVENT is the starting mouse event of the drag action."
+  (interactive "e")
+  (mouse-drag-frame start-event 'right))
+
+(defun mouse-drag-bottom-right-corner (start-event)
+  "Drag bottom right corner of a frame with the mouse.
+START-EVENT is the starting mouse event of the drag action."
+  (interactive "e")
+  (mouse-drag-frame start-event 'bottom-right))
+
+(defun mouse-drag-bottom-edge (start-event)
+  "Drag bottom edge of a frame with the mouse.
+START-EVENT is the starting mouse event of the drag action."
+  (interactive "e")
+  (mouse-drag-frame start-event 'bottom))
+
+(defun mouse-drag-bottom-left-corner (start-event)
+  "Drag bottom left corner of a frame with the mouse.
+START-EVENT is the starting mouse event of the drag action."
+  (interactive "e")
+  (mouse-drag-frame start-event 'bottom-left))
+
 (defcustom mouse-select-region-move-to-beginning nil
   "Effect of selecting a region extending backward from double click.
 Nil means keep point at the position clicked (region end);
@@ -2078,6 +2449,22 @@ function-key-map
 (global-set-key [bottom-divider down-mouse-1] 'mouse-drag-mode-line)
 (global-set-key [bottom-divider mouse-1] 'ignore)
 (global-set-key [bottom-divider C-mouse-2] 'mouse-split-window-horizontally)
+(global-set-key [left-edge down-mouse-1] 'mouse-drag-left-edge)
+(global-set-key [left-edge mouse-1] 'ignore)
+(global-set-key [top-left-corner down-mouse-1] 'mouse-drag-top-left-corner)
+(global-set-key [top-left-corner mouse-1] 'ignore)
+(global-set-key [top-edge down-mouse-1] 'mouse-drag-top-edge)
+(global-set-key [top-edge mouse-1] 'ignore)
+(global-set-key [top-right-corner down-mouse-1] 'mouse-drag-top-right-corner)
+(global-set-key [top-right-corner mouse-1] 'ignore)
+(global-set-key [right-edge down-mouse-1] 'mouse-drag-right-edge)
+(global-set-key [right-edge mouse-1] 'ignore)
+(global-set-key [bottom-right-corner down-mouse-1] 'mouse-drag-bottom-right-corner)
+(global-set-key [bottom-right-corner mouse-1] 'ignore)
+(global-set-key [bottom-edge down-mouse-1] 'mouse-drag-bottom-edge)
+(global-set-key [bottom-edge mouse-1] 'ignore)
+(global-set-key [bottom-left-corner down-mouse-1] 'mouse-drag-bottom-left-corner)
+(global-set-key [bottom-left-corner mouse-1] 'ignore)

 (provide 'mouse)

diff --git a/lisp/tooltip.el b/lisp/tooltip.el
index 367114b..c011f1b 100644
--- a/lisp/tooltip.el
+++ b/lisp/tooltip.el
@@ -119,7 +119,8 @@ tooltip-y-offset
 (defcustom tooltip-frame-parameters
   '((name . "tooltip")
     (internal-border-width . 2)
-    (border-width . 1))
+    (border-width . 1)
+    (no-special-glyphs . t))
   "Frame parameters used for tooltips.

 If `left' or `top' parameters are included, they specify the absolute
@@ -130,7 +131,8 @@ tooltip-frame-parameters
   :type '(repeat (cons :format "%v"
 		       (symbol :tag "Parameter")
 		       (sexp :tag "Value")))
-  :group 'tooltip)
+  :group 'tooltip
+  :version "26.1")

 (defface tooltip
   '((((class color))
diff --git a/lisp/window.el b/lisp/window.el
index 8b07ed4..c933996 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -3703,7 +3703,7 @@ window-edges
 ABSOLUTE is non-nil, PIXELWISE is implicitly non-nil too."
   (let* ((window (window-normalize-window window body))
 	 (frame (window-frame window))
-	 (border-width (frame-border-width frame))
+	 (border-width (frame-internal-border-width frame))
 	 (char-width (frame-char-width frame))
 	 (char-height (frame-char-height frame))
 	 (left (if pixelwise
@@ -4572,12 +4572,13 @@ frame-auto-hide-function
 Functions affected by this option are those that bury a buffer
 shown in a separate frame like `quit-window' and `bury-buffer'."
   :type '(choice (const :tag "Iconify" iconify-frame)
+                 (const :tag "Make invisible" make-frame-invisible)
                  (const :tag "Delete" delete-frame)
                  (const :tag "Do nothing" ignore)
                  function)
   :group 'windows
   :group 'frames
-  :version "24.1")
+  :version "26.1")

 (defun window--delete (&optional window dedicated-only kill)
   "Delete WINDOW if possible.
@@ -4595,7 +4596,9 @@ window--delete
 	  (cond
 	   (kill
 	    (delete-frame frame))
-	   ((functionp frame-auto-hide-function)
+           ((functionp (frame-parameter frame 'auto-hide-function))
+            (funcall (frame-parameter frame 'auto-hide-function)))
+           ((functionp frame-auto-hide-function)
 	    (funcall frame-auto-hide-function frame))))
 	'frame)
        (deletable
@@ -6734,15 +6737,17 @@ window--display-buffer
     window))

 (defun window--maybe-raise-frame (frame)
-  (let ((visible (frame-visible-p frame)))
-    (unless (or (not visible)
-		;; Assume the selected frame is already visible enough.
-		(eq frame (selected-frame))
-		;; Assume the frame from which we invoked the
-		;; minibuffer is visible.
-		(and (minibuffer-window-active-p (selected-window))
-		     (eq frame (window-frame (minibuffer-selected-window)))))
-      (raise-frame frame))))
+  (make-frame-visible frame)
+  (unless (or (frame-parameter frame 'no-focus-on-map)
+              ;; Don't raise frames that should not get focus.
+              (frame-parameter frame 'no-accept-focus)
+              ;; Assume the selected frame is already visible enough.
+	      (eq frame (selected-frame))
+	      ;; Assume the frame from which we invoked the
+	      ;; minibuffer is visible.
+	      (and (minibuffer-window-active-p (selected-window))
+		   (eq frame (window-frame (minibuffer-selected-window)))))
+    (raise-frame frame)))

 ;; FIXME: Not implemented.
 ;; FIXME: By the way, there could be more levels of dedication:
@@ -6762,6 +6767,7 @@ display-buffer--action-function-custom-type
 	   (const display-buffer-pop-up-window)
 	   (const display-buffer-same-window)
 	   (const display-buffer-pop-up-frame)
+	   (const display-buffer-in-child-frame)
 	   (const display-buffer-below-selected)
 	   (const display-buffer-at-bottom)
 	   (const display-buffer-in-previous-window)
@@ -6908,6 +6914,7 @@ display-buffer
  `display-buffer-same-window'
  `display-buffer-reuse-window'
  `display-buffer-pop-up-frame'
+ `display-buffer-in-child-frame'
  `display-buffer-pop-up-window'
  `display-buffer-in-previous-window'
  `display-buffer-use-some-window'
@@ -7239,6 +7246,7 @@ display-buffer-pop-up-window
 				 (get-largest-window frame t) alist)
 				(window--try-to-split-window
 				 (get-lru-window frame t) alist))))
+
       (prog1 (window--display-buffer
 	      buffer window 'window alist display-buffer-mark-dedicated)
 	(unless (cdr (assq 'inhibit-switch-frame alist))
@@ -7258,6 +7266,47 @@ display-buffer--maybe-pop-up-frame-or-window
       (and pop-up-windows
 	   (display-buffer-pop-up-window buffer alist))))

+(defun display-buffer-in-child-frame (buffer alist)
+  "Display BUFFER in a child frame.
+By default, this either reuses a child frame of the selected
+frame or makes a new child frame of the selected frame.  If
+successful, return the window used; otherwise return nil.
+
+If ALIST has a non-nil 'child-frame-parameters' entry, the
+corresponding value is an alist of frame parameters to give the
+new frame.  A 'parent-frame' parameter specifying the selected
+frame is provided by default.  If the child frame should be or
+become the child of any other frame, a corresponding entry must
+be added to ALIST."
+  (let* ((parameters
+          (append
+           (cdr (assq 'child-frame-parameters alist))
+           `((parent-frame . ,(selected-frame)))))
+	 (parent (or (assq 'parent-frame parameters)
+                     (selected-frame)))
+         (share (assq 'share-child-frame parameters))
+         share1 frame window)
+    (with-current-buffer buffer
+      (when (frame-live-p parent)
+        (catch 'frame
+          (dolist (frame1 (frame-list))
+            (when (eq (frame-parent frame1) parent)
+              (setq share1 (assq 'share-child-frame
+                                 (frame-parameters frame1)))
+              (when (eq share share1)
+                (setq frame frame1)
+                (throw 'frame t))))))
+
+      (if frame
+          (setq window (frame-selected-window frame))
+        (setq frame (make-frame parameters))
+        (setq window (frame-selected-window frame))))
+
+    (prog1 (window--display-buffer
+	    buffer window 'frame alist display-buffer-mark-dedicated)
+      (unless (cdr (assq 'inhibit-switch-frame alist))
+	(window--maybe-raise-frame frame)))))
+
 (defun display-buffer-below-selected (buffer alist)
   "Try displaying BUFFER in a window below the selected window.
 If there is a window below the selected one and that window
@@ -7272,7 +7321,8 @@ display-buffer-below-selected
 	(and (not (frame-parameter nil 'unsplittable))
 	     (let ((split-height-threshold 0)
 		   split-width-threshold)
-	       (setq window (window--try-to-split-window (selected-window) alist)))
+	       (setq window (window--try-to-split-window
+                             (selected-window) alist)))
 	     (window--display-buffer
 	      buffer window 'window alist display-buffer-mark-dedicated))
 	(and (setq window (window-in-direction 'below))
@@ -7885,10 +7935,12 @@ fit-frame-to-buffer-sizes
 (declare-function x-display-pixel-height "xfns.c" (&optional terminal))

 (defun window--sanitize-margin (margin left right)
-  "Return MARGIN if it's a number between LEFT and RIGHT."
-  (when (and (numberp margin)
-	     (<= left (- right margin)) (<= margin right))
-    margin))
+  "Return MARGIN if it's a number between LEFT and RIGHT.
+Return 0 otherwise."
+  (if (and (numberp margin)
+           (<= left (- right margin)) (<= margin right))
+      margin
+    0))

 (declare-function tool-bar-height "xdisp.c" (&optional frame pixelwise))

@@ -7906,190 +7958,197 @@ fit-frame-to-buffer

 The new position and size of FRAME can be additionally determined
 by customizing the options `fit-frame-to-buffer-sizes' and
-`fit-frame-to-buffer-margins' or the corresponding parameters of
-FRAME."
+`fit-frame-to-buffer-margins' or setting the corresponding
+parameters of FRAME."
   (interactive)
-  (unless (and (fboundp 'x-display-pixel-height)
-	       ;; We need the respective sizes now.
-	       (fboundp 'display-monitor-attributes-list))
+  (unless (fboundp 'display-monitor-attributes-list)
     (user-error "Cannot resize frame in non-graphic Emacs"))
   (setq frame (window-normalize-frame frame))
   (when (window-live-p (frame-root-window frame))
-    (with-selected-window (frame-root-window frame)
-      (let* ((char-width (frame-char-width))
-	     (char-height (frame-char-height))
-	     (monitor-attributes (car (display-monitor-attributes-list
-				       (frame-parameter frame 'display))))
-	     (geometry (cdr (assq 'geometry monitor-attributes)))
-	     (display-width (- (nth 2 geometry) (nth 0 geometry)))
-	     (display-height (- (nth 3 geometry) (nth 1 geometry)))
-	     (workarea (cdr (assq 'workarea monitor-attributes)))
-	     ;; Handle margins.
-	     (margins (or (frame-parameter frame 'fit-frame-to-buffer-margins)
-			  fit-frame-to-buffer-margins))
-	     (left-margin (if (nth 0 margins)
-			      (or (window--sanitize-margin
-				   (nth 0 margins) 0 display-width)
-				  0)
-			    (nth 0 workarea)))
-	     (top-margin (if (nth 1 margins)
-			     (or (window--sanitize-margin
-				  (nth 1 margins) 0 display-height)
-				 0)
-			   (nth 1 workarea)))
-	     (workarea-width (nth 2 workarea))
-	     (right-margin (if (nth 2 margins)
-			       (- display-width
-				  (or (window--sanitize-margin
-				       (nth 2 margins) left-margin display-width)
-				      0))
-			     (nth 2 workarea)))
-	     (workarea-height (nth 3 workarea))
-	     (bottom-margin (if (nth 3 margins)
-				(- display-height
-				   (or (window--sanitize-margin
-					(nth 3 margins) top-margin display-height)
-				       0))
-			      (nth 3 workarea)))
-	     ;; The pixel width of FRAME (which does not include the
-	     ;; window manager's decorations).
-	     (frame-width (frame-pixel-width))
-	     ;; The pixel width of the body of FRAME's root window.
-	     (window-body-width (window-body-width nil t))
-	     ;; The difference in pixels between total and body width of
-	     ;; FRAME's window.
-	     (window-extra-width (- (window-pixel-width) window-body-width))
-	     ;; The difference in pixels between the frame's pixel width
-	     ;; and the window's body width.  This is the space we can't
-	     ;; use for fitting.
-	     (extra-width (- frame-width window-body-width))
-	     ;; The pixel position of FRAME's left border.  We usually
-	     ;; try to leave this alone.
-	     (left
-	      (let ((left (frame-parameter nil 'left)))
-		(if (consp left)
-		    (funcall (car left) (cadr left))
-		  left)))
-	     ;; The pixel height of FRAME (which does not include title
-	     ;; line, decorations, and sometimes neither the menu nor
-	     ;; the toolbar).
-	     (frame-height (frame-pixel-height))
-	     ;; The pixel height of FRAME's root window (we don't care
-	     ;; about the window's body height since the return value of
-	     ;; `window-text-pixel-size' includes header and mode line).
-	     (window-height (window-pixel-height))
-	     ;; The difference in pixels between the frame's pixel
-	     ;; height and the window's height.
-	     (extra-height (- frame-height window-height))
-	     ;; The pixel position of FRAME's top border.
-	     (top
-	      (let ((top (frame-parameter nil 'top)))
-		(if (consp top)
-		    (funcall (car top) (cadr top))
-		  top)))
-	     ;; Sanitize minimum and maximum sizes.
-	     (sizes (or (frame-parameter frame 'fit-frame-to-buffer-sizes)
-			fit-frame-to-buffer-sizes))
-	     (max-height
-	      (cond
-	       ((numberp (nth 0 sizes)) (* (nth 0 sizes) char-height))
-	       ((numberp max-height) (* max-height char-height))
-	       (t display-height)))
-	     (min-height
-	      (cond
-	       ((numberp (nth 1 sizes)) (* (nth 1 sizes) char-height))
-	       ((numberp min-height) (* min-height char-height))
-	       (t (* window-min-height char-height))))
-	     (max-width
-	      (cond
-	       ((numberp (nth 2 sizes))
-		(- (* (nth 2 sizes) char-width) window-extra-width))
-	       ((numberp max-width)
-		(- (* max-width char-width) window-extra-width))
-	       (t display-width)))
-	     (min-width
-	      (cond
-	       ((numberp (nth 3 sizes))
-		(- (* (nth 3 sizes) char-width) window-extra-width))
-	       ((numberp min-width)
-		(- (* min-width char-width) window-extra-width))
-	       (t (* window-min-width char-width))))
-	     ;; Note: Currently, for a new frame the sizes of the header
-	     ;; and mode line may be estimated incorrectly
-	     (value (window-text-pixel-size
-		     nil t t workarea-width workarea-height t))
-	     (width (+ (car value) (window-right-divider-width)))
-	     (height
-	      (+ (cdr value)
-		 (window-bottom-divider-width)
-		 (window-scroll-bar-height))))
-	;; Don't change height or width when the window's size is fixed
-	;; in either direction or ONLY forbids it.
-	(cond
-	 ((or (eq window-size-fixed 'width) (eq only 'vertically))
-	  (setq width nil))
-	 ((or (eq window-size-fixed 'height) (eq only 'horizontally))
-	  (setq height nil)))
-	;; Fit width to constraints.
-	(when width
-	  (unless frame-resize-pixelwise
-	    ;; Round to character sizes.
-	    (setq width (* (/ (+ width char-width -1) char-width)
-			   char-width)))
-	  ;; Fit to maximum and minimum widths.
-	  (setq width (max (min width max-width) min-width))
-	  ;; Add extra width.
-	  (setq width (+ width extra-width))
-	  ;; Preserve margins.
-	  (let ((right (+ left width)))
-	    (cond
-	     ((> right right-margin)
-	      ;; Move frame to left (we don't know its real width).
-	      (setq left (max left-margin (- left (- right right-margin)))))
-	     ((< left left-margin)
-	      ;; Move frame to right.
-	      (setq left left-margin)))))
-	;; Fit height to constraints.
-	(when height
-	  (unless frame-resize-pixelwise
-	    (setq height (* (/ (+ height char-height -1) char-height)
-			    char-height)))
-	  ;; Fit to maximum and minimum heights.
-	  (setq height (max (min height max-height) min-height))
-	  ;; Add extra height.
-	  (setq height (+ height extra-height))
-	  ;; Preserve margins.
-	  (let ((bottom (+ top height)))
-	    (cond
-	     ((> bottom bottom-margin)
-	      ;; Move frame up (we don't know its real height).
-	      (setq top (max top-margin (- top (- bottom bottom-margin)))))
-	     ((< top top-margin)
-	      ;; Move frame down.
-	      (setq top top-margin)))))
-	;; Apply changes.
-	(set-frame-position frame left top)
-	;; Clumsily try to translate our calculations to what
-	;; `set-frame-size' wants.
-	(when width
-	  (setq width (- (+ (frame-text-width) width)
-			 extra-width window-body-width)))
-	(when height
-	  (setq height (- (+ (frame-text-height) height)
-			  extra-height window-height)))
-	(set-frame-size
-	 frame
-	 (if width
-	     (if frame-resize-pixelwise
-		 width
-	       (/ width char-width))
-	   (frame-text-width))
-	 (if height
-	     (if frame-resize-pixelwise
-		 height
-	       (/ height char-height))
-	   (frame-text-height))
-	 frame-resize-pixelwise)))))
+    (let* ((char-width (frame-char-width frame))
+           (char-height (frame-char-height frame))
+           ;; WINDOW is FRAME's root window.
+           (window (frame-root-window frame))
+           (parent (frame-parent frame))
+           (monitor-attributes
+            (unless parent
+              (car (display-monitor-attributes-list
+                    (frame-parameter frame 'display)))))
+           ;; FRAME'S parent or display sizes.  Used in connection
+           ;; with margins.
+           (geometry
+            (unless parent
+              (cdr (assq 'geometry monitor-attributes))))
+           (parent-or-display-width
+            (if parent
+                (frame-native-width parent)
+              (- (nth 2 geometry) (nth 0 geometry))))
+           (parent-or-display-height
+            (if parent
+                (frame-native-height parent)
+              (- (nth 3 geometry) (nth 1 geometry))))
+           ;; FRAME'S parent or workarea sizes.  Used when no margins
+           ;; are specified.
+           (parent-or-workarea
+            (if parent
+                `(0 0 ,parent-or-display-width ,parent-or-display-height)
+              (cdr (assq 'workarea monitor-attributes))))
+           ;; The outer size of FRAME.  Needed to calculate the
+           ;; margins around the root window's body that have to
+           ;; remain untouched by fitting.
+           (outer-edges (frame-edges frame 'outer-edges))
+           (outer-width (if outer-edges
+                            (- (nth 2 outer-edges) (nth 0 outer-edges))
+                          ;; A poor guess.
+                          (frame-pixel-width frame)))
+           (outer-height (if outer-edges
+                             (- (nth 3 outer-edges) (nth 1 outer-edges))
+                           ;; Another poor guess.
+                           (frame-pixel-height frame)))
+           ;; The text size of of FRAME.  Needed to specify FRAME's
+           ;; text size after the root window's body's new sizes have
+           ;; been calculated.
+           (text-width (frame-text-width frame))
+           (text-height (frame-text-height frame))
+           ;; WINDOW's body size.
+           (body-width (window-body-width window t))
+           (body-height (window-body-height window t))
+           ;; The difference between FRAME's outer size and WINDOW's
+           ;; body size.
+           (outer-minus-body-width (- outer-width body-width))
+           (outer-minus-body-height (- outer-height body-height))
+           ;; The difference between FRAME's text size and WINDOW's
+           ;; body size (these values "should" be positive).
+           (text-minus-body-width (- text-width body-width))
+           (text-minus-body-height (- text-height body-height))
+           ;; The current position of FRAME.
+           (position (frame-position frame))
+           (left (car position))
+           (top (cdr position))
+           ;; The margins specified for FRAME.  These represent pixel
+           ;; offsets from the left, top, right and bottom edge of the
+           ;; display or FRAME's parent's native rectangle and have to
+           ;; take care of the display's taskbar and other obstacles.
+           ;; If they are unspecified, constrain the resulting frame
+           ;; to its workarea or the parent frame's native rectangle.
+           (margins (or (frame-parameter frame 'fit-frame-to-buffer-margins)
+                        fit-frame-to-buffer-margins))
+           ;; Convert margins intto pixel offsets from the left-top
+           ;; corner of FRAME's display or parent.
+           (left-margin (if (nth 0 margins)
+                            (window--sanitize-margin
+                             (nth 0 margins) 0 parent-or-display-width)
+                          (nth 0 parent-or-workarea)))
+           (top-margin (if (nth 1 margins)
+                           (window--sanitize-margin
+                            (nth 1 margins) 0 parent-or-display-height)
+                         (nth 1 parent-or-workarea)))
+           (right-margin (if (nth 2 margins)
+                             (- parent-or-display-width
+                                (window--sanitize-margin
+                                 (nth 2 margins) left-margin
+                                 parent-or-display-width))
+                           (nth 2 parent-or-workarea)))
+           (bottom-margin (if (nth 3 margins)
+                              (- parent-or-display-height
+                                 (window--sanitize-margin
+                                  (nth 3 margins) top-margin
+                                  parent-or-display-height))
+                            (nth 3 parent-or-workarea)))
+           ;; Minimum and maximum sizes specified for FRAME.
+           (sizes (or (frame-parameter frame 'fit-frame-to-buffer-sizes)
+                      fit-frame-to-buffer-sizes))
+           ;; Calculate the minimum and maximum pixel sizes of FRAME
+           ;; from the values provided by the MAX-HEIGHT, MIN-HEIGHT,
+           ;; MAX-WIDTH and MIN-WIDTH arguments or, if these are nil,
+           ;; from those provided by `fit-frame-to-buffer-sizes'.
+           (max-height
+            (min
+             (cond
+              ((numberp max-height) (* max-height char-height))
+              ((numberp (nth 0 sizes)) (* (nth 0 sizes) char-height))
+              (t parent-or-display-height))
+             ;; The following is the maximum height that fits into the
+             ;; top and bottom margins.
+             (max (- bottom-margin top-margin outer-minus-body-height))))
+           (min-height
+            (cond
+             ((numberp min-height) (* min-height char-height))
+             ((numberp (nth 1 sizes)) (* (nth 1 sizes) char-height))
+             (t (window-min-size window nil nil t))))
+           (max-width
+            (min
+             (cond
+              ((numberp max-width) (* max-width char-width))
+              ((numberp (nth 2 sizes)) (* (nth 2 sizes) char-width))
+              (t parent-or-display-width))
+             ;; The following is the maximum width that fits into the
+             ;; left and right margins.
+             (max (- right-margin left-margin outer-minus-body-width))))
+           (min-width
+            (cond
+             ((numberp min-width) (* min-width char-width))
+             ((numberp (nth 3 sizes)) (nth 3 sizes))
+             (t (window-min-size window t nil t))))
+           ;; Note: Currently, for a new frame the sizes of the header
+           ;; and mode line may be estimated incorrectly
+           (size
+            (window-text-pixel-size window t t max-width max-height))
+           (width (max (car size) min-width))
+           (height (max (cdr size) min-height)))
+      ;; Don't change height or width when the window's size is fixed
+      ;; in either direction or ONLY forbids it.
+      (cond
+       ((or (eq window-size-fixed 'width) (eq only 'vertically))
+        (setq width nil))
+       ((or (eq window-size-fixed 'height) (eq only 'horizontally))
+        (setq height nil)))
+      ;; Fit width to constraints.
+      (when width
+        (unless frame-resize-pixelwise
+          ;; Round to character sizes.
+          (setq width (* (/ (+ width char-width -1) char-width)
+                         char-width)))
+        ;; The new outer width (in pixels).
+        (setq outer-width (+ width outer-minus-body-width))
+        ;; Maybe move FRAME to preserve margins.
+        (let ((right (+ left outer-width)))
+          (cond
+           ((> right right-margin)
+            ;; Move frame to left.
+            (setq left (max left-margin (- left (- right right-margin)))))
+           ((< left left-margin)
+            ;; Move frame to right.
+            (setq left left-margin)))))
+      ;; Fit height to constraints.
+      (when height
+        (unless frame-resize-pixelwise
+          (setq height (* (/ (+ height char-height -1) char-height)
+                          char-height)))
+        ;; The new outer height.
+        (setq outer-height (+ height outer-minus-body-height))
+        ;; Preserve margins.
+        (let ((bottom (+ top outer-height)))
+          (cond
+           ((> bottom bottom-margin)
+            ;; Move frame up.
+            (setq top (max top-margin (- top (- bottom bottom-margin)))))
+           ((< top top-margin)
+            ;; Move frame down.
+            (setq top top-margin)))))
+      ;; Apply our changes.
+      (setq text-width
+            (if width
+                (+ width text-minus-body-width)
+              (frame-text-width frame)))
+      (setq text-height
+            (if height
+                (+ height text-minus-body-height)
+              (frame-text-height frame)))
+      (modify-frame-parameters
+       frame `((left . ,left) (top . ,top)
+               (width . (text-pixels . ,text-width))
+               (height . (text-pixels . ,text-height)))))))

 (defun fit-window-to-buffer (&optional window max-height min-height max-width min-width preserve-size)
   "Adjust size of WINDOW to display its buffer's contents exactly.
@@ -8286,6 +8345,168 @@ shrink-window-if-larger-than-buffer
   (when (and (window-combined-p window)
 	     (pos-visible-in-window-p (point-min) window))
     (fit-window-to-buffer window (window-total-height window))))
+
+(defun window-largest-empty-rectangle--maximums-1 (quad maximums)
+  "Support function for `window-largest-empty-rectangle'."
+  (cond
+   ((null maximums)
+    (list quad))
+   ((> (car quad) (caar maximums))
+    (cons quad maximums))
+   (t
+    (cons (car maximums)
+	  (window-largest-empty-rectangle--maximums-1 quad (cdr maximums))))))
+
+(defun window-largest-empty-rectangle--maximums (quad maximums count)
+  "Support function for `window-largest-empty-rectangle'."
+  (setq maximums (window-largest-empty-rectangle--maximums-1 quad maximums))
+  (if (> (length maximums) count)
+      (nbutlast maximums)
+    maximums))
+
+(defun window-largest-empty-rectangle--disjoint-maximums (maximums count)
+  "Support function for `window-largest-empty-rectangle'."
+  (setq maximums (sort maximums (lambda (x y) (> (car x) (car y)))))
+  (let ((new-length 0)
+	new-maximums)
+    (while (and maximums (< new-length count))
+      (let* ((maximum (car maximums))
+	     (at (nth 2 maximum))
+	     (to (nth 3 maximum)))
+	(catch 'drop
+	  (dolist (new-maximum new-maximums)
+	    (let ((new-at (nth 2 new-maximum))
+		  (new-to (nth 3 new-maximum)))
+	      (when (if (< at new-at) (> to new-at) (< at new-to))
+		;; Intersection -> drop.
+		(throw 'drop nil))))
+	  (setq new-maximums (cons maximum new-maximums))
+	  (setq new-length (1+ new-length)))
+	(setq maximums (cdr maximums))))
+
+    (nreverse new-maximums)))
+
+(defun window-largest-empty-rectangle (&optional window count min-width min-height positions left)
+  "Return dimensions of largest empty rectangle in WINDOW.
+WINDOW must be a live window and defaults to the selected one.
+
+The return value is a triple of the width and the start and end
+Y-coordinates of the largest rectangle that can be inscribed into
+the empty space (the space not displaying any text) of WINDOW's
+text area.  The return value is nil if the current glyph matrix
+of WINDOW is not up-to-date.
+
+Optional argument COUNT, if non-nil, specifies the maximum number
+of rectangles to return.  This means that the return value is a
+list of triples specifying rectangles with the largest rectangle
+first.  COUNT can be also a cons cell whose car specifies the
+number of rectangles to return and whose cdr, if non-nil, states
+that all rectangles returned must be disjoint.
+
+Note that the right edge of any rectangle returned by this
+function is the right edge of WINDOW (the left edge if its buffer
+displays RTL text).
+
+Optional arguments MIN-WIDTH and MIN-HEIGHT, if non-nil, specify
+the minimum width and height of any rectangle returned.
+
+Optional argument POSITIONS, if non-nil, is a cons cell whose car
+specifies the uppermost and whose cdr specifies the lowermost
+pixel position that must be covered by any rectangle returned.
+Note that positions are counted from the start of the text area
+of WINDOW.
+
+Optional argument LEFT, if non-nil, means to return values suitable for
+buffers displaying right to left text."
+  ;; Process lines as returned by ‘window-lines-pixel-dimensions’.
+  ;; STACK is a stack that contains rows that have to be processed yet.
+  (let* ((window (window-normalize-window window t))
+	 (disjoint (and (consp count) (cdr count)))
+	 (count (or (and (numberp count) count)
+		    (and (consp count) (numberp (car count)) (car count))))
+	 (rows (window-lines-pixel-dimensions window nil nil t t left))
+	 (rows-at 0)
+	 (max-size 0)
+	 row stack stack-at stack-to
+	 top top-width top-at top-to top-size
+	 max-width max-at max-to maximums)
+    ;; ROWS-AT is the position where the first element of ROWS starts.
+    ;; STACK-AT is the position where the first element of STACK starts.
+    (while rows
+      (setq row (car rows))
+      (if (or (not stack) (>= (car row) (caar stack)))
+	  (progn
+	    (unless stack
+	      (setq stack-at rows-at))
+	    (setq stack (cons row stack))
+	    ;; Set ROWS-AT to where the first element of ROWS ends
+	    ;; which, after popping ROW, makes it the start position of
+	    ;; the next ROW.
+	    (setq rows-at (cdr row))
+	    (setq rows (cdr rows)))
+	(setq top (car stack))
+	(setq stack (cdr stack))
+	(setq top-width (car top))
+	(setq top-at (if stack (cdar stack) stack-at))
+	(setq top-to (cdr top))
+	(setq top-size (* top-width (- top-to top-at)))
+	(unless (or (and min-width (< top-width min-width))
+		    (and min-height (< (- top-to top-at) min-height))
+		    (and positions
+			 (or (> top-at (car positions))
+			     (< top-to (cdr positions)))))
+	  (if count
+	      (if disjoint
+		  (setq maximums (cons (list top-size top-width top-at top-to)
+				       maximums))
+		(setq maximums (window-largest-empty-rectangle--maximums
+				(list top-size top-width top-at top-to)
+				maximums count)))
+	    (when (> top-size max-size)
+	      (setq max-size top-size)
+	      (setq max-width top-width)
+	      (setq max-at top-at)
+	      (setq max-to top-to))))
+	(if (and stack (> (caar stack) (car row)))
+	    ;; Have new top element of stack include old top.
+	    (setq stack (cons (cons (caar stack) (cdr top)) (cdr stack)))
+	  ;; Move rows-at backwards to top-at.
+	  (setq rows-at top-at))))
+
+    (when stack
+      ;; STACK-TO is the position where the stack ends.
+      (setq stack-to (cdar stack))
+      (while stack
+	(setq top (car stack))
+	(setq stack (cdr stack))
+	(setq top-width (car top))
+	(setq top-at (if stack (cdar stack) stack-at))
+	(setq top-size (* top-width (- stack-to top-at)))
+	(unless (or (and min-width (< top-width min-width))
+		    (and min-height (< (- stack-to top-at) min-height))
+		    (and positions
+			 (or (> top-at (car positions))
+			     (< stack-to (cdr positions)))))
+	  (if count
+	      (if disjoint
+		  (setq maximums (cons (list top-size top-width top-at stack-to)
+				       maximums))
+		(setq maximums (window-largest-empty-rectangle--maximums
+				(list top-size top-width top-at stack-to)
+				maximums count)))
+	    (when (> top-size max-size)
+	      (setq max-size top-size)
+	      (setq max-width top-width)
+	      (setq max-at top-at)
+	      (setq max-to stack-to))))))
+
+    (cond
+     (maximums
+      (if disjoint
+	  (window-largest-empty-rectangle--disjoint-maximums maximums count)
+	maximums))
+     ((> max-size 0)
+      (list max-width max-at max-to)))))
 
 (defun kill-buffer-and-window ()
   "Kill the current buffer and delete the selected window."
diff --git a/src/dispextern.h b/src/dispextern.h
index d1e4715..8644ce2 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1106,7 +1106,7 @@ struct glyph_row
 #define MATRIX_BOTTOM_TEXT_ROW(MATRIX, W)		\
      ((MATRIX)->rows					\
       + (MATRIX)->nrows					\
-      - (WINDOW_WANTS_MODELINE_P ((W)) ? 1 : 0))
+      - (window_wants_mode_line ((W)) ? 1 : 0))

 /* Non-zero if the face of the last glyph in ROW's text area has
    to be drawn to the end of the text area.  */
@@ -1469,40 +1469,6 @@ struct glyph_string
 #define DESIRED_HEADER_LINE_HEIGHT(W) \
      MATRIX_HEADER_LINE_HEIGHT ((W)->desired_matrix)

-/* PXW: The height checks below serve to show at least one text line
-   instead of a mode- and/or header line when a window gets very small.
-   But (1) the check fails when the mode- or header-line is taller than
-   the associated frame's line height and (2) we don't care much about
-   text visibility anyway when shrinking a frame containing a toolbar.
-
-   So maybe these checks should be removed and any clipping left to the
-   window manager.  */
-
-/* Value is true if window W wants a mode line and is large enough
-   to accommodate it.  */
-#define WINDOW_WANTS_MODELINE_P(W)					\
-  (BUFFERP ((W)->contents)						\
-   ? (!MINI_WINDOW_P (W)						\
-      && !(W)->pseudo_window_p						\
-      && FRAME_WANTS_MODELINE_P (XFRAME (WINDOW_FRAME (W)))		\
-      && !NILP (BVAR (XBUFFER ((W)->contents), mode_line_format))	\
-      && WINDOW_PIXEL_HEIGHT (W) > WINDOW_FRAME_LINE_HEIGHT (W))	\
-   : false)
-
-/* Value is true if window W wants a header line and is large enough
-   to accommodate it.  */
-#define WINDOW_WANTS_HEADER_LINE_P(W)					\
-     (BUFFERP ((W)->contents)						\
-      ? (!MINI_WINDOW_P (W)						\
-	 && !(W)->pseudo_window_p					\
-	 && FRAME_WANTS_MODELINE_P (XFRAME (WINDOW_FRAME (W)))		\
-	 && !NILP (BVAR (XBUFFER ((W)->contents), header_line_format))	\
-	 && (WINDOW_PIXEL_HEIGHT (W)					\
-	     > (WINDOW_WANTS_MODELINE_P (W)				\
-		? (2 * WINDOW_FRAME_LINE_HEIGHT (W))			\
-		: WINDOW_FRAME_LINE_HEIGHT (W))))			\
-      : false)
-
 /* Return proper value to be used as baseline offset of font that has
    ASCENT and DESCENT to draw characters by the font at the vertical
    center of the line of frame F.
diff --git a/src/dispnew.c b/src/dispnew.c
index 27c69bd..0c1918f 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -377,7 +377,7 @@ struct redisplay_history
     {
       window_box (w, ANY_AREA, 0, 0, &window_width, &window_height);

-      header_line_p = WINDOW_WANTS_HEADER_LINE_P (w);
+      header_line_p = window_wants_header_line (w);
       header_line_changed_p = header_line_p != matrix->header_line_p;
     }
   matrix->header_line_p = header_line_p;
@@ -446,7 +446,7 @@ struct redisplay_history

 	  if (w == NULL
 	      || (row == matrix->rows + dim.height - 1
-		  && WINDOW_WANTS_MODELINE_P (w))
+		  && window_wants_mode_line (w))
 	      || (row == matrix->rows && matrix->header_line_p))
 	    {
 	      row->glyphs[TEXT_AREA]
@@ -491,7 +491,7 @@ struct redisplay_history

 	      /* The mode line, if displayed, never has marginal areas.  */
 	      if ((row == matrix->rows + dim.height - 1
-		   && !(w && WINDOW_WANTS_MODELINE_P (w)))
+		   && !(w && window_wants_mode_line (w)))
 		  || (row == matrix->rows && matrix->header_line_p))
 		{
 		  row->glyphs[TEXT_AREA]
@@ -570,7 +570,7 @@ struct redisplay_history
 	     the mode line, if any, since otherwise it will remain
 	     disabled in the current matrix, and expose events won't
 	     redraw it.  */
-	  if (WINDOW_WANTS_MODELINE_P (w))
+	  if (window_wants_mode_line (w))
 	    w->update_mode_line = 1;
 	}
       else if (matrix == w->desired_matrix)
@@ -5188,7 +5188,7 @@ struct row_entry
      start position, i.e. it excludes the header-line row, but
      MATRIX_ROW includes the header-line row.  Adjust for a possible
      header-line row.  */
-  it_vpos = it.vpos + WINDOW_WANTS_HEADER_LINE_P (w);
+  it_vpos = it.vpos + window_wants_header_line (w);
   if (it_vpos < w->current_matrix->nrows
       && (row = MATRIX_ROW (w->current_matrix, it_vpos),
 	  row->enabled_p))
diff --git a/src/frame.c b/src/frame.c
index 4d17a07..653e44f 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -328,8 +328,8 @@ struct frame *
  * frame_windows_min_size:
  *
  * Return the minimum number of lines (columns if HORIZONTAL is non-nil)
- * of FRAME.  If PIXELWISE is non-nil, return the minimum height (width)
- * in pixels.
+ * of FRAME.  If PIXELWISE is non-nil, return the minimum inner height
+ * (width) of FRAME in pixels.
  *
  * This value is calculated by the function `frame-windows-min-size' in
  * window.el unless the `min-height' (`min-width' if HORIZONTAL is
@@ -341,7 +341,7 @@ struct frame *
  * of `window-min-height' (`window-min-width' if HORIZONTAL is non-nil).
  * With IGNORE non-nil the values of these variables are ignored.
  *
- * In either case never return a value less than 1.
+ * In either case, never return a value less than 1.
  */
 static int
 frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal,
@@ -373,46 +373,179 @@ struct frame *
 }

-/* Make sure windows sizes of frame F are OK.  new_width and new_height
-   are in pixels.  A value of -1 means no change is requested for that
-   size (but the frame may still have to be resized to accommodate
-   windows with their minimum sizes).  This can either issue a request
-   to resize the frame externally (via x_set_window_size), to resize the
-   frame internally (via resize_frame_windows) or do nothing at all.
+#ifdef HAVE_WINDOW_SYSTEM
+/**
+ * keep_ratio:
+ *
+ * Preserve ratios of frame F which usually happens after its parent
+ * frame got resized.  OLD_WIDTH, OLD_HEIGHT specifies the old native
+ * size of F's parent, NEW_WIDTH and NEW_HEIGHT its new size.
+ *
+ * Adjust F's width if F's 'keep_ratio' parameter is non-nil and, if
+ * it is a cons, its car is not 'height-only'.  Adjust F's height if F's
+ * 'keep_ratio' parameter is non-nil and, if it is a cons, its car
+ * is not 'width-only'.
+ *
+ * Adjust F's left position if F's 'keep_ratio' parameter is non-nil
+ * and, if its is a cons, its cdr is non-nil and not 'top-only'.  Adjust
+ * F's top position if F's 'keep_ratio' parameter is non-nil and, if
+ * its is a cons, its cdr is non-nil and not 'left-only'.
+ *
+ * Note that when positional adjustment is requested but the size of F
+ * should remain unaltered in the corresponding direction, this routine
+ * tries to constrain F to its parent frame - something which usually
+ * happens when the parent frame shrinks.  This means, however, that
+ * when the parent frame is re-enlarged later, the child's original
+ * position will not get restored to its pre-shrinking value.
+ *
+ * This routine is currently useful for child frames only.  It might be
+ * eventually useful when moving non-child frames between monitors with
+ * different resolutions.
+ */
+static void
+keep_ratio (struct frame *f, int old_width, int old_height,
+		    int new_width, int new_height)
+{
+  Lisp_Object keep_ratio = get_frame_param (f, Qkeep_ratio);

-   The argument INHIBIT can assume the following values:

-   0 means to unconditionally call x_set_window_size even if sizes
-     apparently do not change.  Fx_create_frame uses this to pass the
-     initial size to the window manager.
+  if (!NILP (keep_ratio))
+    {
+      double width_factor = (double)new_width / (double)old_width;
+      double height_factor = (double)new_height / (double)old_height;
+      int pixel_width, pixel_height, pos_x, pos_y;

-   1 means to call x_set_window_size if the outer frame size really
-     changes.  Fset_frame_size, Fset_frame_height, ... use this.
+      if (!CONSP (keep_ratio) || !NILP (Fcdr (keep_ratio)))
+	{
+	  if (CONSP (keep_ratio) && EQ (Fcdr (keep_ratio), Qtop_only))
+	    pos_x = f->left_pos;
+	  else
+	    {
+	      pos_x = (int)(f->left_pos * width_factor + 0.5);

-   2 means to call x_set_window_size provided frame_inhibit_resize
-     allows it.  The menu and tool bar code use this ("3" won't work
-     here in general because menu and tool bar are often not counted in
-     the frame's text height).
+	      if (CONSP (keep_ratio) &&
+		  (NILP (Fcar (keep_ratio)) || EQ (Fcar (keep_ratio), Qheight_only)))
+		{
+		  struct frame *p = FRAME_PARENT_FRAME (f);

-   3 means call x_set_window_size if window minimum sizes must be
-     preserved or frame_inhibit_resize allows it.  x_set_left_fringe,
-     x_set_scroll_bar_width, x_new_font ... use (or should use) this.
+		  if (pos_x + f->pixel_width > p->pixel_width)
+		    {
+		      int p_f_width = p->pixel_width - f->pixel_width;

-   4 means call x_set_window_size only if window minimum sizes must be
-     preserved.  x_set_right_divider_width, x_set_border_width and the
-     code responsible for wrapping the tool bar use this.
+		      if (p_f_width <= 0)
+			pos_x = 0;
+		      else
+			pos_x = (int)(p_f_width * width_factor * 0.5 + 0.5);
+		    }
+		}
+
+	      f->left_pos = pos_x;
+	    }
+
+	  if (CONSP (keep_ratio) && EQ (Fcdr (keep_ratio), Qleft_only))
+	    pos_y = f->top_pos;
+	  else
+	    {
+	      pos_y = (int)(f->top_pos * height_factor + 0.5);
+
+	      if (CONSP (keep_ratio) &&
+		  (NILP (Fcar (keep_ratio)) || EQ (Fcar (keep_ratio), Qwidth_only)))
+		/* When positional adjustment was requested and the
+		   width of F should remain unaltered, try to constrain
+		   F to its parent.  This means that when the parent
+		   frame is enlarged later the child's original position
+		   won't get restored.  */
+		{
+		  struct frame *p = FRAME_PARENT_FRAME (f);
+
+		  if (pos_y + f->pixel_height > p->pixel_height)
+		    {
+		      int p_f_height = p->pixel_height - f->pixel_height;
+
+		      if (p_f_height <= 0)
+			pos_y = 0;
+		      else
+			pos_y = (int)(p_f_height * height_factor * 0.5 + 0.5);
+		    }
+		}

-   5 means to never call x_set_window_size.  change_frame_size uses
-     this.
+	      f->top_pos = pos_y;
+	    }

-   Note that even when x_set_window_size is not called, individual
-   windows may have to be resized (via `window--sanitize-window-sizes')
-   in order to support minimum size constraints.
+	  x_set_offset (f, pos_x, pos_y, -1);
+	}

-   PRETEND is as for change_frame_size.  PARAMETER, if non-nil, is the
-   symbol of the parameter changed (like `menu-bar-lines', `font', ...).
-   This is passed on to frame_inhibit_resize to let the latter decide on
-   a case-by-case basis whether the frame may be resized externally.  */
+      if (!CONSP (keep_ratio) || !NILP (Fcar (keep_ratio)))
+	{
+	  if (CONSP (keep_ratio) && EQ (Fcar (keep_ratio), Qheight_only))
+	    pixel_width = -1;
+	  else
+	    {
+	      pixel_width = (int)(f->pixel_width * width_factor + 0.5);
+	      pixel_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, pixel_width);
+	    }
+
+	  if (CONSP (keep_ratio) && EQ (Fcar (keep_ratio), Qwidth_only))
+	    pixel_height = -1;
+	  else
+	    {
+	      pixel_height = (int)(f->pixel_height * height_factor + 0.5);
+	      pixel_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixel_height);
+	    }
+
+	  adjust_frame_size (f, pixel_width, pixel_height, 1, 0,
+			     Qkeep_ratio);
+	}
+    }
+}
+#endif
+
+
+/**
+ * adjust_frame_size:
+ *
+ * Adjust size of frame F.  NEW_WIDTH and NEW_HEIGHT specify the new
+ * text size of F in pixels.  A value of -1 means no change is requested
+ * for that direction (but the frame may still have to be resized to
+ * accommodate windows with their minimum sizes).  This can either issue
+ * a request to resize the frame externally (via x_set_window_size), to
+ * resize the frame internally (via resize_frame_windows) or do nothing
+ * at all.
+ *
+ * The argument INHIBIT can assume the following values:
+ *
+ * 0 means to unconditionally call x_set_window_size even if sizes
+ *   apparently do not change.  Fx_create_frame uses this to pass the
+ *   initial size to the window manager.
+ *
+ * 1 means to call x_set_window_size if the native frame size really
+ *   changes.  Fset_frame_size, Fset_frame_height, ... use this.
+ *
+ * 2 means to call x_set_window_size provided frame_inhibit_resize
+ *   allows it.  The menu and tool bar code use this ("3" won't work
+ *   here in general because menu and tool bar are often not counted in
+ *   the frame's text height).
+ *
+ * 3 means call x_set_window_size if window minimum sizes must be
+ *   preserved or frame_inhibit_resize allows it.  x_set_left_fringe,
+ *   x_set_scroll_bar_width, x_new_font ... use (or should use) this.
+ *
+ * 4 means call x_set_window_size only if window minimum sizes must be
+ *   preserved.  x_set_right_divider_width, x_set_border_width and the
+ *   code responsible for wrapping the tool bar use this.
+ *
+ * 5 means to never call x_set_window_size.  change_frame_size uses
+ *   this.
+ *
+ * Note that even when x_set_window_size is not called, individual
+ * windows may have to be resized (via `window--sanitize-window-sizes')
+ * in order to support minimum size constraints.
+ *
+ * PRETEND is as for change_frame_size.  PARAMETER, if non-nil, is the
+ * symbol of the parameter changed (like `menu-bar-lines', `font', ...).
+ * This is passed on to frame_inhibit_resize to let the latter decide on
+ * a case-by-case basis whether the frame may be resized externally.
+ */
 void
 adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit,
 		   bool pretend, Lisp_Object parameter)
@@ -636,6 +769,18 @@ struct frame *
 		  || new_pixel_height != old_pixel_height);

   unblock_input ();
+
+#ifdef HAVE_WINDOW_SYSTEM
+  {
+    /* Adjust size of F's child frames.  */
+    Lisp_Object frames, frame1;
+
+    FOR_EACH_FRAME (frames, frame1)
+      if (FRAME_PARENT_FRAME (XFRAME (frame1)) == f)
+	keep_ratio (XFRAME (frame1), old_pixel_width, old_pixel_height,
+			 new_pixel_width, new_pixel_height);
+  }
+#endif
 }

 /* Allocate basically initialized frame.  */
@@ -684,6 +829,7 @@ struct frame *
   f->horizontal_scroll_bars = false;
   f->want_fullscreen = FULLSCREEN_NONE;
   f->undecorated = false;
+  f->no_special_glyphs = false;
 #ifndef HAVE_NTGUI
   f->override_redirect = false;
 #endif
@@ -2004,8 +2150,101 @@ of them (the selected terminal frame) is actually displayed.
 {
   return delete_frame (frame, !NILP (force) ? Qt : Qnil);
 }
-
 
+#ifdef HAVE_WINDOW_SYSTEM
+/**
+ * frame_internal_border_part:
+ *
+ * Return part of internal border the coordinates X and Y relative to
+ * frame F are on.  Return nil if the coordinates are not on the
+ * internal border of F.
+ *
+ * Return one of INTERNAL_BORDER_LEFT_EDGE, INTERNAL_BORDER_TOP_EDGE,
+ * INTERNAL_BORDER_RIGHT_EDGE or INTERNAL_BORDER_BOTTOM_EDGE when the
+ * mouse cursor is on the corresponding border with an offset of at
+ * least one canonical character height from that border's edges.
+ *
+ * If no border part could be found this way, return one of
+ * INTERNAL_BORDER_TOP_LEFT_CORNER, INTERNAL_BORDER_TOP_RIGHT_CORNER,
+ * INTERNAL_BORDER_BOTTOM_LEFT_CORNER or
+ * INTERNAL_BORDER_BOTTOM_RIGHT_CORNER to indicate that the mouse is in
+ * one of the corresponding corners.  This means that for very small
+ * frames an `edge' return value is preferred.
+ */
+enum internal_border_part
+frame_internal_border_part (struct frame *f, int x, int y)
+{
+  int border = FRAME_INTERNAL_BORDER_WIDTH (f);
+  int offset = FRAME_LINE_HEIGHT (f);
+  int width = FRAME_PIXEL_WIDTH (f);
+  int height = FRAME_PIXEL_HEIGHT (f);
+  enum internal_border_part part = INTERNAL_BORDER_NONE;
+
+  if (offset < border)
+    /* For very wide borders make offset at least as large as
+       border.  */
+    offset = border;
+
+  if (offset < x && x < width - offset)
+    /* Top or bottom border.  */
+    {
+      if (0 <= y && y <= border)
+	part = INTERNAL_BORDER_TOP_EDGE;
+      else if (height - border <= y && y <= height)
+	part = INTERNAL_BORDER_BOTTOM_EDGE;
+    }
+  else if (offset < y && y < height - offset)
+    /* Left or right border.  */
+    {
+      if (0 <= x && x <= border)
+	part = INTERNAL_BORDER_LEFT_EDGE;
+      else if (width - border <= x && x <= width)
+	part = INTERNAL_BORDER_RIGHT_EDGE;
+    }
+  else
+    {
+      /* An edge.  */
+      int half_width = width / 2;
+      int half_height = height / 2;
+
+      if (0 <= x && x <= border)
+	{
+	  /* A left edge.  */
+	  if (0 <= y && y <= half_height)
+	     part = INTERNAL_BORDER_TOP_LEFT_CORNER;
+	  else if (half_height < y && y <= height)
+	     part = INTERNAL_BORDER_BOTTOM_LEFT_CORNER;
+	}
+      else if (width - border <= x && x <= width)
+	{
+	  /* A right edge.  */
+	  if (0 <= y && y <= half_height)
+	     part = INTERNAL_BORDER_TOP_RIGHT_CORNER;
+	  else if (half_height < y && y <= height)
+	     part = INTERNAL_BORDER_BOTTOM_RIGHT_CORNER;
+	}
+      else if (0 <= y && y <= border)
+	{
+	  /* A top edge.  */
+	  if (0 <= x && x <= half_width)
+	     part = INTERNAL_BORDER_TOP_LEFT_CORNER;
+	  else if (half_width < x && x <= width)
+	    part = INTERNAL_BORDER_TOP_RIGHT_CORNER;
+	}
+      else if (height - border <= y && y <= height)
+	{
+	  /* A bottom edge.  */
+	  if (0 <= x && x <= half_width)
+	     part = INTERNAL_BORDER_BOTTOM_LEFT_CORNER;
+	  else if (half_width < x && x <= width)
+	    part = INTERNAL_BORDER_BOTTOM_RIGHT_CORNER;
+	}
+    }
+
+  return part;
+}
+#endif
+
 /* Return mouse position in character cell units.  */

 DEFUN ("mouse-position", Fmouse_position, Smouse_position, 0, 0, 0,
@@ -2962,49 +3201,47 @@ Each element of ALIST has the form (PARM . VALUE), where PARM is a symbol.
     return make_number (1);
 }

-DEFUN ("frame-pixel-height", Fframe_pixel_height,
-       Sframe_pixel_height, 0, 1, 0,
-       doc: /* Return a FRAME's height in pixels.
-If FRAME is omitted or nil, the selected frame is used.  The exact value
-of the result depends on the window-system and toolkit in use:
-
-In the Gtk+ version of Emacs, it includes only any window (including
-the minibuffer or echo area), mode line, and header line.  It does not
-include the tool bar or menu bar.
-
-With other graphical versions, it also includes the tool bar and the
-menu bar.
-
-For a text terminal, it includes the menu bar.  In this case, the
-result is really in characters rather than pixels (i.e., is identical
-to `frame-height'). */)
+DEFUN ("frame-native-width", Fframe_native_width,
+       Sframe_native_width, 0, 1, 0,
+       doc: /* Return FRAME's native width in pixels.
+For a terminal frame, the result really gives the width in characters.
+If FRAME is omitted or nil, the selected frame is used.  */)
   (Lisp_Object frame)
 {
   struct frame *f = decode_any_frame (frame);

 #ifdef HAVE_WINDOW_SYSTEM
   if (FRAME_WINDOW_P (f))
-    return make_number (FRAME_PIXEL_HEIGHT (f));
+    return make_number (FRAME_PIXEL_WIDTH (f));
   else
 #endif
-    return make_number (FRAME_TOTAL_LINES (f));
+    return make_number (FRAME_TOTAL_COLS (f));
 }

-DEFUN ("frame-pixel-width", Fframe_pixel_width,
-       Sframe_pixel_width, 0, 1, 0,
-       doc: /* Return FRAME's width in pixels.
-For a terminal frame, the result really gives the width in characters.
-If FRAME is omitted or nil, the selected frame is used.  */)
+DEFUN ("frame-native-height", Fframe_native_height,
+       Sframe_native_height, 0, 1, 0,
+       doc: /* Return FRAME's native height in pixels.
+If FRAME is omitted or nil, the selected frame is used.  The exact value
+of the result depends on the window-system and toolkit in use:
+
+In the Gtk+ and NS versions, it includes only any window (including the
+minibuffer or echo area), mode line, and header line.  It does not
+include the tool bar or menu bar.  With other graphical versions, it may
+also include the tool bar and the menu bar.
+
+For a text terminal, it includes the menu bar.  In this case, the
+result is really in characters rather than pixels (i.e., is identical
+to `frame-height'). */)
   (Lisp_Object frame)
 {
   struct frame *f = decode_any_frame (frame);

 #ifdef HAVE_WINDOW_SYSTEM
   if (FRAME_WINDOW_P (f))
-    return make_number (FRAME_PIXEL_WIDTH (f));
+    return make_number (FRAME_PIXEL_HEIGHT (f));
   else
 #endif
-    return make_number (FRAME_TOTAL_COLS (f));
+    return make_number (FRAME_TOTAL_LINES (f));
 }

 DEFUN ("tool-bar-pixel-width", Ftool_bar_pixel_width,
@@ -3087,8 +3324,8 @@ result is really in characters rather than pixels (i.e., is identical
   return make_number (FRAME_TOTAL_FRINGE_WIDTH (decode_any_frame (frame)));
 }

-DEFUN ("frame-border-width", Fborder_width, Sborder_width, 0, 1, 0,
-       doc: /* Return border width of FRAME in pixels.  */)
+DEFUN ("frame-internal-border-width", Fframe_internal_border_width, Sframe_internal_border_width, 0, 1, 0,
+       doc: /* Return width of FRAME's internal border in pixels.  */)
   (Lisp_Object frame)
 {
   return make_number (FRAME_INTERNAL_BORDER_WIDTH (decode_any_frame (frame)));
@@ -3224,7 +3461,6 @@ outer frame in pixels relative to an origin (0, 0) of FRAME's display.

   return Qt;
 }
-
 
 /***********************************************************************
 				Frame Parameters
@@ -3289,10 +3525,193 @@ struct frame_parm_table {
   {"no-accept-focus",		SYMBOL_INDEX (Qno_accept_focus)},
   {"z-group",			SYMBOL_INDEX (Qz_group)},
   {"override-redirect",		SYMBOL_INDEX (Qoverride_redirect)},
+  {"no-special-glyphs",		SYMBOL_INDEX (Qno_special_glyphs)},
 };

 #ifdef HAVE_WINDOW_SYSTEM

+/* Enumeration type for switch in frame_float.  */
+enum frame_float_type
+{
+ FRAME_FLOAT_WIDTH,
+ FRAME_FLOAT_HEIGHT,
+ FRAME_FLOAT_LEFT,
+ FRAME_FLOAT_TOP
+};
+
+/**
+ * frame_float:
+ *
+ * Process the value VAL of the float type frame parameter 'width',
+ * 'height', 'left', or 'top' specified via a frame_float_type
+ * enumeration type WHAT for frame F.  Such parameters relate the outer
+ * size or position of F to the size of the F's display or parent frame
+ * which have to be both available in some way.
+ *
+ * The return value is a size or position value in pixels.  VAL must be
+ * in the range 0.0 to 1.0 where a width/height of 0.0 means to return 0
+ * and 1.0 means to return the full width/height of the display/parent.
+ * For positions, 0.0 means position in the left/top corner of the
+ * display/parent while 1.0 means to position at the right/bottom corner
+ * of the display/parent frame.
+ *
+ * Set PARENT_DONE and OUTER_DONE to avoid recalculation of the outer
+ * size or parent or display attributes when more float parameters are
+ * calculated in a row: -1 means not processed yet, 0 means processing
+ * failed, 1 means processing succeeded.
+ *
+ * Return DEFAULT_VALUE when processing fails for whatever reason with
+ * one exception: When calculating F's outer edges fails (probably
+ * because F has not been created yet) return the difference between F's
+ * native and text size.
+ */
+static int
+frame_float (struct frame *f, Lisp_Object val, enum frame_float_type what,
+	     int *parent_done, int *outer_done, int default_value)
+{
+  double d_val = XFLOAT_DATA (val);
+
+  if (d_val < 0.0 || d_val > 1.0)
+    /* Invalid VAL.  */
+    return default_value;
+  else
+    {
+      static unsigned parent_width, parent_height;
+      static int parent_left, parent_top;
+      static unsigned outer_minus_text_width, outer_minus_text_height;
+      struct frame *p = FRAME_PARENT_FRAME (f);
+
+      if (*parent_done == 1)
+	;
+      else if (p)
+	{
+	  parent_width = FRAME_PIXEL_WIDTH (p);
+	  parent_height = FRAME_PIXEL_HEIGHT (p);
+	  *parent_done = 1;
+	}
+      else
+	{
+	  if (*parent_done == 0)
+	    /* No workarea available.  */
+	    return default_value;
+	  else if (*parent_done == -1)
+	    {
+	      Lisp_Object monitor_attributes;
+	      Lisp_Object workarea;
+	      Lisp_Object frame;
+
+	      XSETFRAME (frame, f);
+	      monitor_attributes = Fcar (call1 (Qdisplay_monitor_attributes_list, frame));
+	      if (NILP (monitor_attributes))
+		{
+		  /* No monitor attributes available.  */
+		  *parent_done = 0;
+
+		  return default_value;
+		}
+
+	      workarea = Fcdr (Fassq (Qworkarea, monitor_attributes));
+	      if (NILP (workarea))
+		{
+		  /* No workarea available.  */
+		  *parent_done = 0;
+
+		  return default_value;
+		}
+
+	      /* Workarea available.  */
+	      parent_left = XINT (Fnth (make_number (0), workarea));
+	      parent_top = XINT (Fnth (make_number (1), workarea));
+	      parent_width = XINT (Fnth (make_number (2), workarea));
+	      parent_height = XINT (Fnth (make_number (3), workarea));
+	      *parent_done = 1;
+	    }
+	}
+
+      if (*outer_done == 1)
+	;
+      else if (FRAME_UNDECORATED (f))
+	{
+	  outer_minus_text_width
+	    = FRAME_PIXEL_WIDTH (f) - FRAME_TEXT_WIDTH (f);
+	  outer_minus_text_height
+	    = FRAME_PIXEL_HEIGHT (f) - FRAME_TEXT_HEIGHT (f);
+	  *outer_done = 1;
+	}
+      else if (*outer_done == 0)
+	/* No outer size available.  */
+	return default_value;
+      else if (*outer_done == -1)
+	{
+	  Lisp_Object frame, outer_edges;
+
+	  XSETFRAME (frame, f);
+	  outer_edges = call2 (Qframe_edges, frame, Qouter_edges);
+
+	  if (!NILP (outer_edges))
+	    {
+	      outer_minus_text_width
+		= (XINT (Fnth (make_number (2), outer_edges))
+		   - XINT (Fnth (make_number (0), outer_edges))
+		   - FRAME_TEXT_WIDTH (f));
+	      outer_minus_text_height
+		= (XINT (Fnth (make_number (3), outer_edges))
+		   - XINT (Fnth (make_number (1), outer_edges))
+		   - FRAME_TEXT_HEIGHT (f));
+	    }
+	  else
+	    {
+	      /* If we can't get any outer edges, proceed as if the frame
+		 were undecorated.  */
+	      outer_minus_text_width
+		= FRAME_PIXEL_WIDTH (f) - FRAME_TEXT_WIDTH (f);
+	      outer_minus_text_height
+		= FRAME_PIXEL_HEIGHT (f) - FRAME_TEXT_HEIGHT (f);
+	    }
+
+	  *outer_done = 1;
+	}
+
+      switch (what)
+	{
+	case FRAME_FLOAT_WIDTH:
+	  return parent_width * d_val - outer_minus_text_width;
+
+	case FRAME_FLOAT_HEIGHT:
+	  return parent_height * d_val - outer_minus_text_height;
+
+	case FRAME_FLOAT_LEFT:
+	  {
+	    int rest_width = (parent_width
+			      - FRAME_TEXT_WIDTH (f)
+			      - outer_minus_text_width);
+
+	    if (p)
+	      return (rest_width <= 0 ? 0 : d_val * rest_width);
+	    else
+	      return (rest_width <= 0
+		      ? parent_left
+		      : parent_left + d_val * rest_width);
+	  }
+	case FRAME_FLOAT_TOP:
+	  {
+	    int rest_height = (parent_height
+			       - FRAME_TEXT_HEIGHT (f)
+			       - outer_minus_text_height);
+
+	    if (p)
+	      return (rest_height <= 0 ? 0 : d_val * rest_height);
+	    else
+	      return (rest_height <= 0
+		      ? parent_top
+		      : parent_top + d_val * rest_height);
+	  }
+	default:
+	  emacs_abort ();
+	}
+    }
+}
+
 /* Change the parameters of frame F as specified by ALIST.
    If a parameter is not specially recognized, do nothing special;
    otherwise call the `x_set_...' function for that parameter.
@@ -3302,7 +3721,8 @@ struct frame_parm_table {
 void
 x_set_frame_parameters (struct frame *f, Lisp_Object alist)
 {
-  Lisp_Object tail;
+  Lisp_Object tail, frame;
+

   /* If both of these parameters are present, it's more efficient to
      set them both at once.  So we wait until we've looked at the
@@ -3327,7 +3747,9 @@ struct frame_parm_table {
 #ifdef HAVE_X_WINDOWS
   bool icon_left_no_change = 0, icon_top_no_change = 0;
 #endif
+  int parent_done = -1, outer_done = -1;

+  XSETFRAME (frame, f);
   for (size = 0, tail = alist; CONSP (tail); tail = XCDR (tail))
     size++;
   CHECK_LIST_END (tail, alist);
@@ -3388,6 +3810,9 @@ struct frame_parm_table {
 	  else if (CONSP (val) && EQ (XCAR (val), Qtext_pixels)
 		   && RANGED_INTEGERP (0, XCDR (val), INT_MAX))
 	    width = XFASTINT (XCDR (val));
+	  else if (FLOATP (val))
+	    width = frame_float (f, val, FRAME_FLOAT_WIDTH, &parent_done,
+				 &outer_done, -1);
         }
       else if (EQ (prop, Qheight))
         {
@@ -3396,6 +3821,9 @@ struct frame_parm_table {
 	  else if (CONSP (val) && EQ (XCAR (val), Qtext_pixels)
 		   && RANGED_INTEGERP (0, XCDR (val), INT_MAX))
 	    height = XFASTINT (XCDR (val));
+	  else if (FLOATP (val))
+	    height = frame_float (f, val, FRAME_FLOAT_HEIGHT, &parent_done,
+				 &outer_done, -1);
         }
       else if (EQ (prop, Qtop))
 	top = val;
@@ -3472,105 +3900,100 @@ struct frame_parm_table {
      Don't set these parameters unless they actually differ from the
      window's current parameters; the window may not actually exist
      yet.  */
-  {
-    Lisp_Object frame;
-
-    XSETFRAME (frame, f);
-
-    if ((width != -1 && width != FRAME_TEXT_WIDTH (f))
-	|| (height != -1 && height != FRAME_TEXT_HEIGHT (f)))
-      /* We could consider checking f->after_make_frame here, but I
-	 don't have the faintest idea why the following is needed at
-	 all.  With the old setting it can get a Heisenbug when
-	 EmacsFrameResize intermittently provokes a delayed
-	 change_frame_size in the middle of adjust_frame_size.  */
-      /** 	|| (f->can_x_set_window_size && (f->new_height || f->new_width))) **/
-      adjust_frame_size (f, width, height, 1, 0, Qx_set_frame_parameters);
-
-    if ((!NILP (left) || !NILP (top))
-	&& ! (left_no_change && top_no_change)
-	&& ! (NUMBERP (left) && XINT (left) == f->left_pos
-	      && NUMBERP (top) && XINT (top) == f->top_pos))
-      {
-	int leftpos = 0;
-	int toppos = 0;
+  if ((width != -1 && width != FRAME_TEXT_WIDTH (f))
+      || (height != -1 && height != FRAME_TEXT_HEIGHT (f)))
+    /* We could consider checking f->after_make_frame here, but I
+       don't have the faintest idea why the following is needed at
+       all.  With the old setting it can get a Heisenbug when
+       EmacsFrameResize intermittently provokes a delayed
+       change_frame_size in the middle of adjust_frame_size.  */
+    /** 	|| (f->can_x_set_window_size && (f->new_height || f->new_width))) **/
+    adjust_frame_size (f, width, height, 1, 0, Qx_set_frame_parameters);
+
+  if ((!NILP (left) || !NILP (top))
+      && ! (left_no_change && top_no_change)
+      && ! (NUMBERP (left) && XINT (left) == f->left_pos
+	    && NUMBERP (top) && XINT (top) == f->top_pos))
+    {
+      int leftpos = 0;
+      int toppos = 0;

-	/* Record the signs.  */
-	f->size_hint_flags &= ~ (XNegative | YNegative);
-	if (EQ (left, Qminus))
-	  f->size_hint_flags |= XNegative;
-	else if (TYPE_RANGED_INTEGERP (int, left))
-	  {
-	    leftpos = XINT (left);
-	    if (leftpos < 0)
-	      f->size_hint_flags |= XNegative;
-	  }
-	else if (CONSP (left) && EQ (XCAR (left), Qminus)
-		 && CONSP (XCDR (left))
-		 && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (left)), INT_MAX))
-	  {
-	    leftpos = - XINT (XCAR (XCDR (left)));
+      /* Record the signs.  */
+      f->size_hint_flags &= ~ (XNegative | YNegative);
+      if (EQ (left, Qminus))
+	f->size_hint_flags |= XNegative;
+      else if (TYPE_RANGED_INTEGERP (int, left))
+	{
+	  leftpos = XINT (left);
+	  if (leftpos < 0)
 	    f->size_hint_flags |= XNegative;
-	  }
-	else if (CONSP (left) && EQ (XCAR (left), Qplus)
-		 && CONSP (XCDR (left))
-		 && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (left))))
-	  {
-	    leftpos = XINT (XCAR (XCDR (left)));
-	  }
+	}
+      else if (CONSP (left) && EQ (XCAR (left), Qminus)
+	       && CONSP (XCDR (left))
+	       && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (left)), INT_MAX))
+	{
+	  leftpos = - XINT (XCAR (XCDR (left)));
+	  f->size_hint_flags |= XNegative;
+	}
+      else if (CONSP (left) && EQ (XCAR (left), Qplus)
+	       && CONSP (XCDR (left))
+	       && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (left))))
+	leftpos = XINT (XCAR (XCDR (left)));
+      else if (FLOATP (left))
+	leftpos = frame_float (f, left, FRAME_FLOAT_LEFT, &parent_done,
+			       &outer_done, 0);

-	if (EQ (top, Qminus))
-	  f->size_hint_flags |= YNegative;
-	else if (TYPE_RANGED_INTEGERP (int, top))
-	  {
-	    toppos = XINT (top);
-	    if (toppos < 0)
-	      f->size_hint_flags |= YNegative;
-	  }
-	else if (CONSP (top) && EQ (XCAR (top), Qminus)
-		 && CONSP (XCDR (top))
-		 && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (top)), INT_MAX))
-	  {
-	    toppos = - XINT (XCAR (XCDR (top)));
+      if (EQ (top, Qminus))
+	f->size_hint_flags |= YNegative;
+      else if (TYPE_RANGED_INTEGERP (int, top))
+	{
+	  toppos = XINT (top);
+	  if (toppos < 0)
 	    f->size_hint_flags |= YNegative;
-	  }
-	else if (CONSP (top) && EQ (XCAR (top), Qplus)
-		 && CONSP (XCDR (top))
-		 && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (top))))
-	  {
-	    toppos = XINT (XCAR (XCDR (top)));
-	  }
-
+	}
+      else if (CONSP (top) && EQ (XCAR (top), Qminus)
+	       && CONSP (XCDR (top))
+	       && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (top)), INT_MAX))
+	{
+	  toppos = - XINT (XCAR (XCDR (top)));
+	  f->size_hint_flags |= YNegative;
+	}
+      else if (CONSP (top) && EQ (XCAR (top), Qplus)
+	       && CONSP (XCDR (top))
+	       && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (top))))
+	toppos = XINT (XCAR (XCDR (top)));
+      else if (FLOATP (top))
+	toppos = frame_float (f, top, FRAME_FLOAT_TOP, &parent_done,
+			      &outer_done, 0);

-	/* Store the numeric value of the position.  */
-	f->top_pos = toppos;
-	f->left_pos = leftpos;
+      /* Store the numeric value of the position.  */
+      f->top_pos = toppos;
+      f->left_pos = leftpos;

-	f->win_gravity = NorthWestGravity;
+      f->win_gravity = NorthWestGravity;

-	/* Actually set that position, and convert to absolute.  */
-	x_set_offset (f, leftpos, toppos, -1);
-      }
+      /* Actually set that position, and convert to absolute.  */
+      x_set_offset (f, leftpos, toppos, -1);
+    }

-    if (fullscreen_change)
-      {
-	Lisp_Object old_value = get_frame_param (f, Qfullscreen);
+  if (fullscreen_change)
+    {
+      Lisp_Object old_value = get_frame_param (f, Qfullscreen);

-	frame_size_history_add
-	  (f, Qx_set_fullscreen, 0, 0, list2 (old_value, fullscreen));
+      frame_size_history_add
+	(f, Qx_set_fullscreen, 0, 0, list2 (old_value, fullscreen));

-	store_frame_param (f, Qfullscreen, fullscreen);
-	if (!EQ (fullscreen, old_value))
-	  x_set_fullscreen (f, fullscreen, old_value);
-      }
+      store_frame_param (f, Qfullscreen, fullscreen);
+      if (!EQ (fullscreen, old_value))
+	x_set_fullscreen (f, fullscreen, old_value);
+    }

 #ifdef HAVE_X_WINDOWS
-    if ((!NILP (icon_left) || !NILP (icon_top))
-	&& ! (icon_left_no_change && icon_top_no_change))
-      x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
+  if ((!NILP (icon_left) || !NILP (icon_top))
+      && ! (icon_left_no_change && icon_top_no_change))
+    x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
 #endif /* HAVE_X_WINDOWS */
-  }

   SAFE_FREE ();
 }
@@ -3990,7 +4413,6 @@ struct frame_parm_table {
       adjust_frame_glyphs (f);
       SET_FRAME_GARBAGED (f);
     }
-
 }

 void
@@ -4204,6 +4626,22 @@ struct frame_parm_table {
   return;
 }

+
+/**
+ * x_set_no_special_glyphs:
+ *
+ * Set frame F's `no-special-glyphs' parameter which, if non-nil,
+ * suppresses the display of truncation and continuation glyphs
+ * outside fringes.
+ */
+void
+x_set_no_special_glyphs (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+  if (!EQ (new_value, old_value))
+    FRAME_NO_SPECIAL_GLYPHS (f) = !NILP (new_value);
+}
+
+
 #ifndef HAVE_NS

 /* Non-zero if mouse is grabbed on DPYINFO
@@ -4759,6 +5197,7 @@ or a list (- N) meaning -N pixels relative to bottom/right corner.
   Lisp_Object height, width, user_size, top, left, user_position;
   long window_prompting = 0;
   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
+  int parent_done = -1, outer_done = -1;

   /* Default values if we fall through.
      Actually, if that happens we should get
@@ -4823,6 +5262,21 @@ or a list (- N) meaning -N pixels relative to bottom/right corner.
 	      f->inhibit_horizontal_resize = true;
 	      *x_width = XINT (XCDR (width));
 	    }
+	  else if (FLOATP (width))
+	    {
+	      double d_width = XFLOAT_DATA (width);
+
+	      if (d_width < 0.0 || d_width > 1.0)
+		xsignal1 (Qargs_out_of_range, width);
+	      else
+		{
+		  int new_width = frame_float (f, width, FRAME_FLOAT_WIDTH,
+					       &parent_done, &outer_done, -1);
+
+		  if (new_width > -1)
+		    SET_FRAME_WIDTH (f, new_width);
+		}
+	    }
 	  else
 	    {
 	      CHECK_NUMBER (width);
@@ -4845,6 +5299,21 @@ or a list (- N) meaning -N pixels relative to bottom/right corner.
 	      f->inhibit_vertical_resize = true;
 	      *x_height = XINT (XCDR (height));
 	    }
+	  else if (FLOATP (height))
+	    {
+	      double d_height = XFLOAT_DATA (height);
+
+	      if (d_height < 0.0 || d_height > 1.0)
+		xsignal1 (Qargs_out_of_range, height);
+	      else
+		{
+		  int new_height = frame_float (f, height, FRAME_FLOAT_HEIGHT,
+						&parent_done, &outer_done, -1);
+
+		  if (new_height > -1)
+		    SET_FRAME_HEIGHT (f, new_height);
+		}
+	    }
 	  else
 	    {
 	      CHECK_NUMBER (height);
@@ -4885,6 +5354,9 @@ or a list (- N) meaning -N pixels relative to bottom/right corner.
 	{
 	  f->top_pos = XINT (XCAR (XCDR (top)));
 	}
+      else if (FLOATP (top))
+	f->top_pos = frame_float (f, top, FRAME_FLOAT_TOP, &parent_done,
+				  &outer_done, 0);
       else if (EQ (top, Qunbound))
 	f->top_pos = 0;
       else
@@ -4913,6 +5385,9 @@ or a list (- N) meaning -N pixels relative to bottom/right corner.
 	{
 	  f->left_pos = XINT (XCAR (XCDR (left)));
 	}
+      else if (FLOATP (left))
+	f->left_pos = frame_float (f, top, FRAME_FLOAT_LEFT, &parent_done,
+				   &outer_done, 0);
       else if (EQ (left, Qunbound))
 	f->left_pos = 0;
       else
@@ -5071,12 +5546,14 @@ or a list (- N) meaning -N pixels relative to bottom/right corner.
   DEFSYM (Qframep, "framep");
   DEFSYM (Qframe_live_p, "frame-live-p");
   DEFSYM (Qframe_windows_min_size, "frame-windows-min-size");
+  DEFSYM (Qdisplay_monitor_attributes_list, "display-monitor-attributes-list");
   DEFSYM (Qwindow__pixel_to_total, "window--pixel-to-total");
   DEFSYM (Qexplicit_name, "explicit-name");
   DEFSYM (Qheight, "height");
   DEFSYM (Qicon, "icon");
   DEFSYM (Qminibuffer, "minibuffer");
   DEFSYM (Qundecorated, "undecorated");
+  DEFSYM (Qno_special_glyphs, "no-special-glyphs");
   DEFSYM (Qparent_frame, "parent-frame");
   DEFSYM (Qskip_taskbar, "skip-taskbar");
   DEFSYM (Qno_focus_on_map, "no-focus-on-map");
@@ -5129,6 +5606,7 @@ or a list (- N) meaning -N pixels relative to bottom/right corner.
   DEFSYM (Qframes, "frames");
   DEFSYM (Qsource, "source");

+  DEFSYM (Qframe_edges, "frame-edges");
   DEFSYM (Qouter_edges, "outer-edges");
   DEFSYM (Qouter_position, "outer-position");
   DEFSYM (Qouter_size, "outer-size");
@@ -5220,6 +5698,11 @@ or a list (- N) meaning -N pixels relative to bottom/right corner.
   DEFSYM (Qmin_width, "min-width");
   DEFSYM (Qmin_height, "min-height");
   DEFSYM (Qmouse_wheel_frame, "mouse-wheel-frame");
+  DEFSYM (Qkeep_ratio, "keep-ratio");
+  DEFSYM (Qwidth_only, "width-only");
+  DEFSYM (Qheight_only, "height-only");
+  DEFSYM (Qleft_only, "left-only");
+  DEFSYM (Qtop_only, "top-only");

   {
     int i;
@@ -5564,8 +6047,8 @@ This variable is effective only with the X toolkit (and there only when
   defsubr (&Smodify_frame_parameters);
   defsubr (&Sframe_char_height);
   defsubr (&Sframe_char_width);
-  defsubr (&Sframe_pixel_height);
-  defsubr (&Sframe_pixel_width);
+  defsubr (&Sframe_native_height);
+  defsubr (&Sframe_native_width);
   defsubr (&Sframe_text_cols);
   defsubr (&Sframe_text_lines);
   defsubr (&Sframe_total_cols);
@@ -5575,7 +6058,7 @@ This variable is effective only with the X toolkit (and there only when
   defsubr (&Sscroll_bar_width);
   defsubr (&Sscroll_bar_height);
   defsubr (&Sfringe_width);
-  defsubr (&Sborder_width);
+  defsubr (&Sframe_internal_border_width);
   defsubr (&Sright_divider_width);
   defsubr (&Sbottom_divider_width);
   defsubr (&Stool_bar_pixel_width);
diff --git a/src/frame.h b/src/frame.h
index 4aa7c34..2feb09b 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -52,6 +52,19 @@ enum z_group
   z_group_below,
   z_group_above_suspended,
 };
+
+enum internal_border_part
+  {
+   INTERNAL_BORDER_NONE,
+   INTERNAL_BORDER_LEFT_EDGE,
+   INTERNAL_BORDER_TOP_LEFT_CORNER,
+   INTERNAL_BORDER_TOP_EDGE,
+   INTERNAL_BORDER_TOP_RIGHT_CORNER,
+   INTERNAL_BORDER_RIGHT_EDGE,
+   INTERNAL_BORDER_BOTTOM_RIGHT_CORNER,
+   INTERNAL_BORDER_BOTTOM_EDGE,
+   INTERNAL_BORDER_BOTTOM_LEFT_CORNER,
+  };
 #endif /* HAVE_WINDOW_SYSTEM */

 /* The structure representing a frame.  */
@@ -354,7 +367,11 @@ struct frame

   /* The z-group this frame's window belongs to. */
   ENUM_BF (z_group) z_group : 2;
-#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */
+
+  /* Non-zero if display of truncation and continuation glyphs outside
+     the fringes is suppressed.  */
+  bool_bf no_special_glyphs : 1;
+#endif /* HAVE_WINDOW_SYSTEM */

   /* Whether new_height and new_width shall be interpreted
      in pixels.  */
@@ -928,6 +945,7 @@ struct frame
 #define FRAME_SKIP_TASKBAR(f) ((f)->skip_taskbar)
 #define FRAME_NO_FOCUS_ON_MAP(f) ((f)->no_focus_on_map)
 #define FRAME_NO_ACCEPT_FOCUS(f) ((f)->no_accept_focus)
+#define FRAME_NO_SPECIAL_GLYPHS(f) ((f)->no_special_glyphs)
 #define FRAME_Z_GROUP(f) ((f)->z_group)
 #define FRAME_Z_GROUP_NONE(f) ((f)->z_group == z_group_none)
 #define FRAME_Z_GROUP_ABOVE(f) ((f)->z_group == z_group_above)
@@ -941,6 +959,7 @@ struct frame
 #define FRAME_SKIP_TASKBAR(f) ((void) f, 0)
 #define FRAME_NO_FOCUS_ON_MAP(f) ((void) f, 0)
 #define FRAME_NO_ACCEPT_FOCUS(f) ((void) f, 0)
+#define FRAME_NO_SPECIAL_GLYPHS(f) ((void) f, 0)
 #define FRAME_Z_GROUP(f) ((void) f, z_group_none)
 #define FRAME_Z_GROUP_NONE(f) ((void) f, true)
 #define FRAME_Z_GROUP_ABOVE(f) ((void) f, false)
@@ -1288,19 +1307,20 @@ extern void frame_size_history_add (struct frame *f, Lisp_Object fun_symbol,
   return FRAME_LEFT_FRINGE_WIDTH (f) + FRAME_RIGHT_FRINGE_WIDTH (f);
 }

-/* Pixel-width of internal border lines */
+/* Pixel-width of internal border lines.  */
 INLINE int
 FRAME_INTERNAL_BORDER_WIDTH (struct frame *f)
 {
   return frame_dimension (f->internal_border_width);
 }

-/* Pixel-size of window divider lines */
+/* Pixel-size of window divider lines.  */
 INLINE int
 FRAME_RIGHT_DIVIDER_WIDTH (struct frame *f)
 {
   return frame_dimension (f->right_divider_width);
 }
+
 INLINE int
 FRAME_BOTTOM_DIVIDER_WIDTH (struct frame *f)
 {
@@ -1498,6 +1518,7 @@ extern void x_set_bottom_divider_width (struct frame *, Lisp_Object,
 extern long x_figure_window_size (struct frame *, Lisp_Object, bool, int *, int *);

 extern void x_set_alpha (struct frame *, Lisp_Object, Lisp_Object);
+extern void x_set_no_special_glyphs (struct frame *, Lisp_Object, Lisp_Object);

 extern void validate_x_resource_name (void);

@@ -1521,6 +1542,7 @@ extern void x_set_window_size (struct frame *f, bool change_gravity,
 extern void free_frame_menubar (struct frame *);
 extern void x_free_frame_resources (struct frame *);
 extern bool frame_ancestor_p (struct frame *af, struct frame *df);
+extern enum internal_border_part frame_internal_border_part (struct frame *f, int x, int y);

 #if defined HAVE_X_WINDOWS
 extern void x_wm_set_icon_position (struct frame *, int, int);
diff --git a/src/keyboard.c b/src/keyboard.c
index 55486c6..b202d9b 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -5126,6 +5126,17 @@ in the same style as (current-time).
   SYMBOL_INDEX (Qrightmost), SYMBOL_INDEX (Qend_scroll), SYMBOL_INDEX (Qratio)
 };

+/* An array of symbol indexes of internal border parts, indexed by an enum
+   internal_border_part value.  Note that Qnil corresponds to
+   internal_border_part_none and should not appear in Lisp events.  */
+static short const internal_border_parts[] = {
+  SYMBOL_INDEX (Qnil), SYMBOL_INDEX (Qleft_edge),
+  SYMBOL_INDEX (Qtop_left_corner), SYMBOL_INDEX (Qtop_edge),
+  SYMBOL_INDEX (Qtop_right_corner), SYMBOL_INDEX (Qright_edge),
+  SYMBOL_INDEX (Qbottom_right_corner), SYMBOL_INDEX (Qbottom_edge),
+  SYMBOL_INDEX (Qbottom_left_corner)
+};
+
 /* A vector, indexed by button number, giving the down-going location
    of currently depressed buttons, both scroll bar and non-scroll bar.

@@ -5163,15 +5174,15 @@ in the same style as (current-time).
   Lisp_Object extra_info = Qnil;
   /* Coordinate pixel positions to return.  */
   int xret = 0, yret = 0;
-  /* The window under frame pixel coordinates (x,y)  */
-  Lisp_Object window = f
+  /* The window or frame under frame pixel coordinates (x,y)  */
+  Lisp_Object window_or_frame = f
     ? window_from_coordinates (f, XINT (x), XINT (y), &part, 0)
     : Qnil;

-  if (WINDOWP (window))
+  if (WINDOWP (window_or_frame))
     {
       /* It's a click in window WINDOW at frame coordinates (X,Y)  */
-      struct window *w = XWINDOW (window);
+      struct window *w = XWINDOW (window_or_frame);
       Lisp_Object string_info = Qnil;
       ptrdiff_t textpos = 0;
       int col = -1, row = -1;
@@ -5360,17 +5371,31 @@ in the same style as (current-time).
 					       make_number (row)),
 					extra_info)));
     }
-  else if (f != 0)
+
+#ifdef HAVE_WINDOW_SYSTEM
+  else if (f)
     {
       /* Return mouse pixel coordinates here.  */
-      XSETFRAME (window, f);
+      XSETFRAME (window_or_frame, f);
       xret = XINT (x);
       yret = XINT (y);
+
+      if (FRAME_LIVE_P (f)
+	  && FRAME_INTERNAL_BORDER_WIDTH (f) > 0
+	  && !NILP (get_frame_param (f, Qdrag_internal_border)))
+	{
+	  enum internal_border_part part
+	    = frame_internal_border_part (f, xret, yret);
+
+	  posn = builtin_lisp_symbol (internal_border_parts[part]);
+	}
     }
+#endif
+
   else
-    window = Qnil;
+    window_or_frame = Qnil;

-  return Fcons (window,
+  return Fcons (window_or_frame,
 		Fcons (posn,
 		       Fcons (Fcons (make_number (xret),
 				     make_number (yret)),
@@ -11158,6 +11183,17 @@ struct event_head
   Fset (Qinput_method_exit_on_first_char, Qnil);
   Fset (Qinput_method_use_echo_area, Qnil);

+  /* Symbols for dragging internal borders.  */
+  DEFSYM (Qdrag_internal_border, "drag-internal-border");
+  DEFSYM (Qleft_edge, "left-edge");
+  DEFSYM (Qtop_left_corner, "top-left-corner");
+  DEFSYM (Qtop_edge, "top-edge");
+  DEFSYM (Qtop_right_corner, "top-right-corner");
+  DEFSYM (Qright_edge, "right-edge");
+  DEFSYM (Qbottom_right_corner, "bottom-right-corner");
+  DEFSYM (Qbottom_edge, "bottom-edge");
+  DEFSYM (Qbottom_left_corner, "bottom-left-corner");
+
   /* Symbols to head events.  */
   DEFSYM (Qmouse_movement, "mouse-movement");
   DEFSYM (Qscroll_bar_movement, "scroll-bar-movement");
diff --git a/src/minibuf.c b/src/minibuf.c
index 1bbe276..4d91b48 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -874,6 +874,30 @@
   if (minibuf_level == 0)
     resize_mini_window (XWINDOW (window), 0);

+  /* Deal with frames that should be removed when exiting the
+     minibuffer.  */
+  {
+    Lisp_Object frames, frame1, val;
+    struct frame *f1;
+
+    FOR_EACH_FRAME (frames, frame1)
+      {
+	f1 = XFRAME (frame1);
+
+	if ((FRAME_PARENT_FRAME (f1)
+	     || !NILP (get_frame_param (f1, Qdelete_before)))
+	    && !NILP (val = (get_frame_param (f1, Qminibuffer_exit))))
+	  {
+	    if (EQ (val, Qiconify_frame))
+	      Ficonify_frame (frame1);
+	    else if (EQ (val, Qdelete_frame))
+	      Fdelete_frame (frame1, Qnil);
+	    else
+	      Fmake_frame_invisible (frame1, Qnil);
+	  }
+      }
+  }
+
   /* In case the previous minibuffer displayed in this miniwindow is
      dead, we may keep displaying this buffer (tho it's inactive), so reset it,
      to make sure we don't leave around bindings and stuff which only
@@ -1930,6 +1954,8 @@
   DEFSYM (Qactivate_input_method, "activate-input-method");
   DEFSYM (Qcase_fold_search, "case-fold-search");
   DEFSYM (Qmetadata, "metadata");
+  /* A frame parameter.  */
+  DEFSYM (Qminibuffer_exit, "minibuffer-exit");

   DEFVAR_LISP ("read-expression-history", Vread_expression_history,
 	       doc: /* A history list for arguments that are Lisp expressions to evaluate.
diff --git a/src/nsfns.m b/src/nsfns.m
index dbce279..68eba8b 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -984,6 +984,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side
   x_set_no_accept_focus,
   x_set_z_group, /* x_set_z_group */
   0, /* x_set_override_redirect */
+  x_set_no_special_glyphs,
 };

@@ -1256,6 +1257,8 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side
 		       "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
   x_default_parameter (f, parms, Qright_fringe, Qnil,
 		       "rightFringe", "RightFringe", RES_TYPE_NUMBER);
+  x_default_parameter (f, parms, Qno_special_glyphs, Qnil,
+		       NULL, NULL, RES_TYPE_BOOLEAN);

   init_frame_faces (f);

@@ -1325,6 +1328,15 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side
   f->output_data.ns->hourglass_cursor = [NSCursor disappearingItemCursor];
   f->output_data.ns->horizontal_drag_cursor = [NSCursor resizeLeftRightCursor];
   f->output_data.ns->vertical_drag_cursor = [NSCursor resizeUpDownCursor];
+  f->output_data.ns->left_edge_cursor = [NSCursor resizeLeftRightCursor];
+  f->output_data.ns->top_left_corner_cursor = [NSCursor arrowCursor];
+  f->output_data.ns->top_edge_cursor = [NSCursor resizeUpDownCursor];
+  f->output_data.ns->top_right_corner_cursor = [NSCursor arrowCursor];
+  f->output_data.ns->right_edge_cursor = [NSCursor resizeLeftRightCursor];
+  f->output_data.ns->bottom_right_corner_cursor = [NSCursor arrowCursor];
+  f->output_data.ns->bottom_edge_cursor = [NSCursor resizeUpDownCursor];
+  f->output_data.ns->bottom_left_corner_cursor = [NSCursor arrowCursor];
+
   FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor
      = [NSCursor arrowCursor];
   FRAME_DISPLAY_INFO (f)->horizontal_scroll_bar_cursor
diff --git a/src/nsterm.h b/src/nsterm.h
index bed0b92..84f7f0a 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -957,6 +957,14 @@ struct ns_output
   Cursor hourglass_cursor;
   Cursor horizontal_drag_cursor;
   Cursor vertical_drag_cursor;
+  Cursor left_edge_cursor;
+  Cursor top_left_corner_cursor;
+  Cursor top_edge_cursor;
+  Cursor top_right_corner_cursor;
+  Cursor right_edge_cursor;
+  Cursor bottom_right_corner_cursor;
+  Cursor bottom_edge_cursor;
+  Cursor bottom_left_corner_cursor;

   /* NS-specific */
   Cursor current_pointer;
diff --git a/src/w32fns.c b/src/w32fns.c
index e490588..b0842b5 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -5889,6 +5889,8 @@ struct frame *
 		       NULL, NULL, RES_TYPE_BOOLEAN);
   x_default_parameter (f, parameters, Qno_accept_focus, Qnil,
 		       NULL, NULL, RES_TYPE_BOOLEAN);
+  x_default_parameter (f, parameters, Qno_special_glyphs, Qnil,
+		       NULL, NULL, RES_TYPE_BOOLEAN);

   /* Process alpha here (Bug#16619).  On XP this fails with child
      frames.  For `no-focus-on-map' frames delay processing of alpha
@@ -5957,6 +5959,14 @@ struct frame *
   f->output_data.w32->hourglass_cursor = w32_load_cursor (IDC_WAIT);
   f->output_data.w32->horizontal_drag_cursor = w32_load_cursor (IDC_SIZEWE);
   f->output_data.w32->vertical_drag_cursor = w32_load_cursor (IDC_SIZENS);
+  f->output_data.w32->left_edge_cursor = w32_load_cursor (IDC_SIZEWE);
+  f->output_data.w32->top_left_corner_cursor = w32_load_cursor (IDC_SIZENWSE);
+  f->output_data.w32->top_edge_cursor = w32_load_cursor (IDC_SIZENS);
+  f->output_data.w32->top_right_corner_cursor = w32_load_cursor (IDC_SIZENESW);
+  f->output_data.w32->right_edge_cursor = w32_load_cursor (IDC_SIZEWE);
+  f->output_data.w32->bottom_right_corner_cursor = w32_load_cursor (IDC_SIZENWSE);
+  f->output_data.w32->bottom_edge_cursor = w32_load_cursor (IDC_SIZENS);
+  f->output_data.w32->bottom_left_corner_cursor = w32_load_cursor (IDC_SIZENESW);

   f->output_data.w32->current_cursor = f->output_data.w32->nontext_cursor;

@@ -7049,6 +7059,8 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object,
 		       "cursorColor", "Foreground", RES_TYPE_STRING);
   x_default_parameter (f, parms, Qborder_color, build_string ("black"),
 		       "borderColor", "BorderColor", RES_TYPE_STRING);
+  x_default_parameter (f, parms, Qno_special_glyphs, Qt,
+		       NULL, NULL, RES_TYPE_BOOLEAN);

   /* Init faces before x_default_parameter is called for the
      scroll-bar-width parameter because otherwise we end up in
@@ -8950,33 +8962,47 @@ value is a list of the form (LEFT, TOP, RIGHT, BOTTOM).  All values are
   if (EQ (type, Qouter_edges))
     {
       RECT rectangle;
+      BOOL success = false;

       block_input ();
       /* Outer frame rectangle, including outer borders and title bar. */
-      GetWindowRect (FRAME_W32_WINDOW (f), &rectangle);
+      success = GetWindowRect (FRAME_W32_WINDOW (f), &rectangle);
       unblock_input ();

-      return list4 (make_number (rectangle.left),
-		    make_number (rectangle.top),
-		    make_number (rectangle.right),
-		    make_number (rectangle.bottom));
+      if (success)
+	return list4 (make_number (rectangle.left),
+		      make_number (rectangle.top),
+		      make_number (rectangle.right),
+		      make_number (rectangle.bottom));
+      else
+	return Qnil;
     }
   else
     {
       RECT rectangle;
       POINT pt;
       int left, top, right, bottom;
+      BOOL success;

       block_input ();
       /* Inner frame rectangle, excluding borders and title bar.  */
-      GetClientRect (FRAME_W32_WINDOW (f), &rectangle);
+      success = GetClientRect (FRAME_W32_WINDOW (f), &rectangle);
       /* Get top-left corner of native rectangle in screen
 	 coordinates.  */
+      if (!success)
+	{
+	  unblock_input ();
+	  return Qnil;
+	}
+
       pt.x = 0;
       pt.y = 0;
-      ClientToScreen (FRAME_W32_WINDOW (f), &pt);
+      success = ClientToScreen (FRAME_W32_WINDOW (f), &pt);
       unblock_input ();

+      if (!success)
+	return Qnil;
+
       left = pt.x;
       top = pt.y;
       right = left + rectangle.right;
@@ -10330,6 +10356,7 @@ enum NI_Severity {
   x_set_no_accept_focus,
   x_set_z_group,
   0, /* x_set_override_redirect */
+  x_set_no_special_glyphs,
 };

 void
diff --git a/src/w32term.c b/src/w32term.c
index 712bdae..c37805c 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -5086,6 +5086,51 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object
 	  }

 	case WM_WINDOWPOSCHANGED:
+	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
+
+	  if (f)
+	    {
+	      RECT rect;
+	      int /* rows, columns, */ width, height, text_width, text_height;
+
+	      if (GetClientRect (msg.msg.hwnd, &rect)
+		  /* GetClientRect evidently returns (0, 0, 0, 0) if
+		     called on a minimized frame.  Such "dimensions"
+		     aren't useful anyway.  */
+		  && !(rect.bottom == 0
+		       && rect.top == 0
+		       && rect.left == 0
+		       && rect.right == 0))
+		{
+		  height = rect.bottom - rect.top;
+		  width = rect.right - rect.left;
+		  text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, width);
+		  text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, height);
+		  /* rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height); */
+		  /* columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width); */
+
+		  /* TODO: Clip size to the screen dimensions.  */
+
+		  /* Even if the number of character rows and columns
+		     has not changed, the font size may have changed,
+		     so we need to check the pixel dimensions as well.  */
+
+		  if (width != FRAME_PIXEL_WIDTH (f)
+		      || height != FRAME_PIXEL_HEIGHT (f)
+		      || text_width != FRAME_TEXT_WIDTH (f)
+		      || text_height != FRAME_TEXT_HEIGHT (f))
+		    {
+		      change_frame_size (f, text_width, text_height, 0, 1, 0, 1);
+		      SET_FRAME_GARBAGED (f);
+		      cancel_mouse_face (f);
+		      f->win_gravity = NorthWestGravity;
+		    }
+		}
+	    }
+
+	  check_visibility = 1;
+	  break;
+
 	case WM_ACTIVATE:
 	case WM_ACTIVATEAPP:
 	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
@@ -6052,7 +6097,7 @@ struct xim_inst_t
   int display_top = 0;
   struct frame *p = FRAME_PARENT_FRAME (f);

-  if (flags & (XNegative | YNegative))
+  if (!p && flags & (XNegative | YNegative))
     {
       Lisp_Object list;

@@ -6078,20 +6123,26 @@ struct xim_inst_t
     }

   /* Treat negative positions as relative to the rightmost bottommost
-     position that fits on the screen.  */
+     position that fits on the screen or parent frame.
+
+     I see no need for subtracting 1 from the border widths - is there
+     any on the remaining platforms?  Here these subtractions did put
+     the last pixel line/column of a frame off-display when, for
+     example, a (set-frame-parameter nil 'left '(- 0)) specification was
+     used - martin 20017-05-05. */
   if (flags & XNegative)
     {
       if (p)
 	f->left_pos = (FRAME_PIXEL_WIDTH (p)
 		       - FRAME_PIXEL_WIDTH (f)
 		       + f->left_pos
-		       - (left_right_borders_width - 1));
+		       - left_right_borders_width);
       else
 	f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f))
 		       + display_left
 		       - FRAME_PIXEL_WIDTH (f)
 		       + f->left_pos
-		       - (left_right_borders_width - 1));
+		       - left_right_borders_width);
     }

   if (flags & YNegative)
@@ -6100,13 +6151,13 @@ struct xim_inst_t
 	f->top_pos = (FRAME_PIXEL_HEIGHT (p)
 		      - FRAME_PIXEL_HEIGHT (f)
 		      + f->top_pos
-		      - (top_bottom_borders_height - 1));
+		      - top_bottom_borders_height);
       else
 	f->top_pos = (x_display_pixel_height (FRAME_DISPLAY_INFO (f))
 		      + display_top
 		      - FRAME_PIXEL_HEIGHT (f)
 		      + f->top_pos
-		      - (top_bottom_borders_height - 1));
+		      - top_bottom_borders_height);
     }

   /* The left_pos and top_pos are now relative to the top and left
diff --git a/src/w32term.h b/src/w32term.h
index 371cf90..9956682 100644
--- a/src/w32term.h
+++ b/src/w32term.h
@@ -345,6 +345,14 @@ struct w32_output
   Cursor hourglass_cursor;
   Cursor horizontal_drag_cursor;
   Cursor vertical_drag_cursor;
+  Cursor left_edge_cursor;
+  Cursor top_left_corner_cursor;
+  Cursor top_edge_cursor;
+  Cursor top_right_corner_cursor;
+  Cursor right_edge_cursor;
+  Cursor bottom_right_corner_cursor;
+  Cursor bottom_edge_cursor;
+  Cursor bottom_left_corner_cursor;

   /* Non-zero means hourglass cursor is currently displayed.  */
   unsigned hourglass_p : 1;
diff --git a/src/window.c b/src/window.c
index bf89f0e..4816bd6 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1208,13 +1208,13 @@ should be a buffer position (typically a marker) or nil.  If it is a
 		     - WINDOW_BOTTOM_DIVIDER_WIDTH (w))))
     return ON_HORIZONTAL_SCROLL_BAR;
   /* On the mode or header line?   */
-  else if ((WINDOW_WANTS_MODELINE_P (w)
+  else if ((window_wants_mode_line (w)
 	    && y >= (bottom_y
 		     - CURRENT_MODE_LINE_HEIGHT (w)
 		     - WINDOW_BOTTOM_DIVIDER_WIDTH (w))
 	    && y <= bottom_y - WINDOW_BOTTOM_DIVIDER_WIDTH (w)
 	    && (part = ON_MODE_LINE))
-	   || (WINDOW_WANTS_HEADER_LINE_P (w)
+	   || (window_wants_header_line (w)
 	       && y < top_y + CURRENT_HEADER_LINE_HEIGHT (w)
 	       && (part = ON_HEADER_LINE)))
     {
@@ -1851,7 +1851,7 @@ of the (first) text line, YPOS is negative.

   if (EQ (line, Qheader_line))
     {
-      if (!WINDOW_WANTS_HEADER_LINE_P (w))
+      if (!window_wants_header_line (w))
 	return Qnil;
       row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
       return row->enabled_p ? list4i (row->height, 0, 0, 0) : Qnil;
@@ -1898,6 +1898,129 @@ of the (first) text line, YPOS is negative.
   return list4i (row->height + min (0, row->y) - crop, i, row->y, crop);
 }

+DEFUN ("window-lines-pixel-dimensions", Fwindow_lines_pixel_dimensions, Swindow_lines_pixel_dimensions, 0, 6, 0,
+       doc: /* Return pixel dimensions of WINDOW's lines.
+The return value is a list of the x- and y-coordinates of the lower
+right corner of the last character of each line.  Return nil if the
+current glyph matrix of WINDOW is not up-to-date.
+
+Optional argument WINDOW specifies the window whose lines' dimensions
+shall be returned.  Nil or omitted means to return the dimensions for
+the selected window.
+
+FIRST, if non-nil, specifies the index of the first line whose
+dimensions shall be returned.  If FIRST is nil and BODY is non-nil,
+start with the first text line of WINDOW.  Otherwise, start with the
+first line of WINDOW.
+
+LAST, if non-nil, specifies the last line whose dimensions shall be
+returned.  If LAST is nil and BODY is non-nil, the last line is the last
+line of the body (text area) of WINDOW.  Otherwise, last is the last
+line of WINDOW.
+
+INVERSE, if nil, means that the y-pixel value returned for a specific
+line specifies the distance in pixels from the left edge (body edge if
+BODY is non-nil) of WINDOW to the right edge of the last glyph of that
+line.  INVERSE non-nil means that the y-pixel value returned for a
+specific line specifies the distance in pixels from the right edge of
+the last glyph of that line to the right edge (body edge if BODY is
+non-nil) of WINDOW.
+
+LEFT non-nil means to return the x- and y-coordinates of the lower left
+corner of the leftmost character on each line.  This is the value that
+should be used for buffers that mostly display text from right to left.
+
+If LEFT is non-nil and INVERSE is nil, this means that the y-pixel value
+returned for a specific line specifies the distance in pixels from the
+left edge of the last (leftmost) glyph of that line to the right edge
+(body edge if BODY is non-nil) of WINDOW.  If LEFT and INVERSE are both
+non-nil, the y-pixel value returned for a specific line specifies the
+distance in pixels from the left edge (body edge if BODY is non-nil) of
+WINDOW to the left edge of the last (leftmost) glyph of that line.
+
+Normally, the value of this function is not available while Emacs is
+busy, for example, when processing a command.  It should be retrievable
+though when run from an idle timer with a delay of zero seconds.  */)
+  (Lisp_Object window, Lisp_Object first, Lisp_Object last, Lisp_Object body, Lisp_Object inverse, Lisp_Object left)
+{
+  struct window *w = decode_live_window (window);
+  struct buffer *b;
+  struct glyph_row *row, *end_row;
+  int max_y = NILP (body) ? WINDOW_PIXEL_HEIGHT (w) : window_text_bottom_y (w);
+  Lisp_Object rows = Qnil;
+  int window_width = NILP (body) ? w->pixel_width : window_body_width (w, true);
+  int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
+  int subtract = NILP (body) ? 0 : header_line_height;
+  bool invert = !NILP (inverse);
+  bool left_flag = !NILP (left);
+
+  if (noninteractive || w->pseudo_window_p)
+    return Qnil;
+
+  CHECK_BUFFER (w->contents);
+  b = XBUFFER (w->contents);
+
+  /* Fail if current matrix is not up-to-date.  */
+  if (!w->window_end_valid
+      || windows_or_buffers_changed
+      || b->clip_changed
+      || b->prevent_redisplay_optimizations_p
+      || window_outdated (w))
+    return Qnil;
+
+  if (NILP (first))
+    row = (NILP (body)
+	   ? MATRIX_ROW (w->current_matrix, 0)
+	   : MATRIX_FIRST_TEXT_ROW (w->current_matrix));
+  else if (NUMBERP (first))
+    {
+      CHECK_RANGED_INTEGER (first, 0, w->current_matrix->nrows);
+      row = MATRIX_ROW (w->current_matrix, XINT (first));
+    }
+  else
+    error ("Invalid specification of first line");
+
+  if (NILP (last))
+
+    end_row = (NILP (body)
+	       ? MATRIX_ROW (w->current_matrix, w->current_matrix->nrows)
+	       : MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w));
+  else if (NUMBERP (last))
+    {
+      CHECK_RANGED_INTEGER (last, 0, w->current_matrix->nrows);
+      end_row = MATRIX_ROW (w->current_matrix, XINT (last));
+    }
+  else
+    error ("Invalid specification of last line");
+
+  while (row <= end_row && row->enabled_p
+	 && row->y + row->height < max_y)
+    {
+
+      if (left_flag)
+	{
+	  struct glyph *glyph = row->glyphs[TEXT_AREA];
+
+	  rows = Fcons (Fcons (make_number
+			       (invert
+				? glyph->pixel_width
+				: window_width - glyph->pixel_width),
+			       make_number (row->y + row->height - subtract)),
+			rows);
+	}
+      else
+	rows = Fcons (Fcons (make_number
+			     (invert
+			      ? window_width - row->pixel_width
+			      : row->pixel_width),
+			     make_number (row->y + row->height - subtract)),
+		      rows);
+      row++;
+    }
+
+  return Fnreverse (rows);
+}
+
 DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
        0, 1, 0,
        doc: /* Return non-nil when WINDOW is dedicated to its buffer.
@@ -2003,16 +2126,24 @@ return value is a list of elements of the form (PARAMETER . VALUE).  */)
   return Fcopy_alist (decode_valid_window (window)->window_parameters);
 }

+Lisp_Object
+window_parameter (struct window *w, Lisp_Object parameter)
+{
+  Lisp_Object result = Fassq (parameter, w->window_parameters);
+
+  return CDR_SAFE (result);
+}
+
+
 DEFUN ("window-parameter", Fwindow_parameter, Swindow_parameter,
        2, 2, 0,
        doc:  /* Return WINDOW's value for PARAMETER.
 WINDOW can be any window and defaults to the selected one.  */)
   (Lisp_Object window, Lisp_Object parameter)
 {
-  Lisp_Object result;
+  struct window *w = decode_any_window (window);

-  result = Fassq (parameter, decode_any_window (window)->window_parameters);
-  return CDR_SAFE (result);
+  return window_parameter (w, parameter);
 }

 DEFUN ("set-window-parameter", Fset_window_parameter,
@@ -4740,6 +4871,69 @@ SIDE t (or `right') specifies that the new window shall be located on
 }

+/**
+ * window_wants_mode_line:
+ *
+ * Return 1 if window W wants a mode line and is high enough to
+ * accomodate it, 0 otherwise.
+ *
+ * W wants a mode line if it's a leaf window and neither a minibuffer
+ * nor a pseudo window.  Moreover, its 'window-mode-line-format'
+ * parameter must not be 'none' and either that parameter or W's
+ * buffer's 'mode-line-format' value must be non-nil.  Finally, W must
+ * be higher than its frame's canonical character height.
+ */
+bool
+window_wants_mode_line (struct window *w)
+{
+  Lisp_Object window_mode_line_format =
+    window_parameter (w, Qmode_line_format);
+
+  return ((WINDOW_LEAF_P (w)
+	   && !MINI_WINDOW_P (w)
+	   && !WINDOW_PSEUDO_P (w)
+	   && !EQ (window_mode_line_format, Qnone)
+	   && (!NILP (window_mode_line_format)
+	       || !NILP (BVAR (XBUFFER (WINDOW_BUFFER (w)), mode_line_format)))
+	   && WINDOW_PIXEL_HEIGHT (w) > WINDOW_FRAME_LINE_HEIGHT (w))
+	  ? 1
+	  : 0);
+}
+
+
+/**
+ * window_wants_header_line:
+ *
+ * Return 1 if window W wants a header line and is high enough to
+ * accomodate it, 0 otherwise.
+ *
+ * W wants a header line if it's a leaf window and neither a minibuffer
+ * nor a pseudo window.  Moreover, its 'window-mode-line-format'
+ * parameter must not be 'none' and either that parameter or W's
+ * buffer's 'mode-line-format' value must be non-nil.  Finally, W must
+ * be higher than its frame's canonical character height and be able to
+ * accomodate a mode line too if necessary (the mode line prevails).
+ */
+bool
+window_wants_header_line (struct window *w)
+{
+  Lisp_Object window_header_line_format =
+    window_parameter (w, Qheader_line_format);
+
+  return ((WINDOW_LEAF_P (w)
+	   && !MINI_WINDOW_P (w)
+	   && !WINDOW_PSEUDO_P (w)
+	   && !EQ (window_header_line_format, Qnone)
+	   && (!NILP (window_header_line_format)
+	       || !NILP (BVAR (XBUFFER (WINDOW_BUFFER (w)), header_line_format)))
+	   && (WINDOW_PIXEL_HEIGHT (w)
+	       > (window_wants_mode_line (w)
+		  ? 2 * WINDOW_FRAME_LINE_HEIGHT (w)
+		  : WINDOW_FRAME_LINE_HEIGHT (w))))
+	  ? 1
+	  : 0);
+}
+
 /* Return number of lines of text (not counting mode lines) in W.  */

 int
@@ -4753,10 +4947,10 @@ SIDE t (or `right') specifies that the new window shall be located on
 	  || WINDOWP (w->contents)
 	  || !NILP (w->next)
 	  || !NILP (w->prev)
-	  || WINDOW_WANTS_MODELINE_P (w))
+	  || window_wants_mode_line (w))
 	--ht;

-      if (WINDOW_WANTS_HEADER_LINE_P (w))
+      if (window_wants_header_line (w))
 	--ht;
     }

@@ -7354,6 +7548,8 @@ Value is a list of the form (WIDTH COLUMNS VERTICAL-TYPE HEIGHT LINES
   DEFSYM (Qfloor, "floor");
   DEFSYM (Qceiling, "ceiling");
   DEFSYM (Qmark_for_redisplay, "mark-for-redisplay");
+  DEFSYM (Qmode_line_format, "mode-line-format");
+  DEFSYM (Qheader_line_format, "header-line-format");

   staticpro (&Vwindow_list);

@@ -7603,6 +7799,7 @@ this value for parameters without read syntax (like windows or frames).
   defsubr (&Sset_window_point);
   defsubr (&Sset_window_start);
   defsubr (&Swindow_dedicated_p);
+  defsubr (&Swindow_lines_pixel_dimensions);
   defsubr (&Sset_window_dedicated_p);
   defsubr (&Swindow_display_table);
   defsubr (&Sset_window_display_table);
diff --git a/src/window.h b/src/window.h
index acb8a5c..e9040f816 100644
--- a/src/window.h
+++ b/src/window.h
@@ -328,8 +328,9 @@ struct window
     /* True if this window is a minibuffer window.  */
     bool_bf mini : 1;

-    /* Meaningful only if contents is a window, true if this
-       internal window is used in horizontal combination.  */
+    /* Meaningful for internal windows only: true if this window is a
+       horizontal combination, false if it is a vertical
+       combination.  */
     bool_bf horizontal : 1;

     /* True means must regenerate mode line of this window.  */
@@ -481,15 +482,14 @@ struct window
 /* True if W is a minibuffer window.  */
 #define MINI_WINDOW_P(W) ((W)->mini)

-/* 1 if W is a non-only minibuffer window.  */
-/* The first check is redundant and the second overly complicated. */
-#define MINI_NON_ONLY_WINDOW_P(W)				\
-  (MINI_WINDOW_P (W)						\
-   && (EQ (W->prev, FRAME_ROOT_WINDOW (WINDOW_XFRAME (W)))))
+/* True if W is a minibuffer window on a frame that contains at least
+   one other window.  */
+#define MINI_NON_ONLY_WINDOW_P(W)	 \
+  (MINI_WINDOW_P (W) && !NILP ((W)->prev))

-/* 1 if W is a minibuffer-only window.  */
-#define MINI_ONLY_WINDOW_P(W)			\
-  (MINI_WINDOW_P (W) && NILP (W->prev))
+/* True if W is a minibuffer window that is alone on its frame.  */
+#define MINI_ONLY_WINDOW_P(W)		 \
+  (MINI_WINDOW_P (W) && NILP ((W)->prev))

 /* General window layout:

@@ -518,29 +518,34 @@ struct window

 /* A handy macro.  */

-/* Non-nil if W is leaf (carry the buffer).  */
-
+/* Non-nil if window W is leaf window (has a buffer).  */
 #define WINDOW_LEAF_P(W) \
   (BUFFERP ((W)->contents))

-/* Non-nil if W is internal.  */
+/* Non-nil if window W is internal (is a parent window).  */
 #define WINDOW_INTERNAL_P(W) \
   (WINDOWP ((W)->contents))

-/* True if W is a member of horizontal combination.  */
+/* True if window W is a horizontal combination of windows.  */
 #define WINDOW_HORIZONTAL_COMBINATION_P(W) \
   (WINDOW_INTERNAL_P (W) && (W)->horizontal)

-/* True if W is a member of vertical combination.  */
+/* True if window W is a vertical combination of windows.  */
 #define WINDOW_VERTICAL_COMBINATION_P(W) \
   (WINDOW_INTERNAL_P (W) && !(W)->horizontal)

-/* WINDOW's XFRAME.  */
+/* Window W's XFRAME.  */
 #define WINDOW_XFRAME(W) (XFRAME (WINDOW_FRAME ((W))))

-/* Whether WINDOW is a pseudo window.  */
+/* Whether window W is a pseudo window.  */
 #define WINDOW_PSEUDO_P(W) ((W)->pseudo_window_p)

+/* Window W's buffer.  */
+#define WINDOW_BUFFER(W)			\
+  (WINDOW_LEAF_P(W)				\
+   ? (W)->contents				\
+   : Qnil)					\
+
 /* Return the canonical column width of the frame of window W.  */
 #define WINDOW_FRAME_COLUMN_WIDTH(W) \
   (FRAME_COLUMN_WIDTH (WINDOW_XFRAME ((W))))
@@ -549,24 +554,24 @@ struct window
 #define WINDOW_FRAME_LINE_HEIGHT(W) \
   (FRAME_LINE_HEIGHT (WINDOW_XFRAME ((W))))

-/* Return the pixel width of window W.
-   This includes scroll bars and fringes.  */
+/* Return the pixel width of window W.  This includes dividers, scroll
+   bars, fringes and margins, if any.  */
 #define WINDOW_PIXEL_WIDTH(W) (W)->pixel_width

-/* Return the pixel height of window W.
-   This includes header and mode lines, if any.  */
+/* Return the pixel height of window W.  This includes dividers, scroll
+   bars, header and mode lines, if any.  */
 #define WINDOW_PIXEL_HEIGHT(W) (W)->pixel_height

-/* Return the width of window W in canonical column units.
-   This includes scroll bars and fringes.
-   This value is adjusted such that the sum of the widths of all child
+/* Return the width of window W in canonical column units.  This
+   includes dividers, scroll bars, fringes and margins, if any.  The
+   value is adjusted such that the sum of the widths of all child
    windows equals the width of their parent window.  */
 #define WINDOW_TOTAL_COLS(W) (W)->total_cols

-/* Return the height of window W in canonical line units.
-   This includes header and mode lines, if any.
-   This value is adjusted such that the sum of the heights of all child
-   windows equals the height of their parent window.  */
+/* Return the height of window W in canonical line units.  This includes
+   dividers, scroll bars, header and mode lines, if any.  The value is
+   adjusted such that the sum of the heights of all child windows equals
+   the height of their parent window.  */
 #define WINDOW_TOTAL_LINES(W) (W)->total_lines

 /* The smallest acceptable dimensions for a window.  Anything smaller
@@ -581,31 +586,63 @@ struct window
 #define MIN_SAFE_WINDOW_PIXEL_HEIGHT(W) \
   (WINDOW_FRAME_LINE_HEIGHT (W))

+/* True if window W has no other windows to its left on its frame.  */
+#define WINDOW_LEFTMOST_P(W)			\
+  (WINDOW_LEFT_PIXEL_EDGE (W) == 0)
+
+/* True if window W has no other windows above it on its frame.  */
+#define WINDOW_TOPMOST_P(W)			\
+  (WINDOW_TOP_PIXEL_EDGE (W) == 0)
+
+/* True if window W has no other windows to its right on its frame.  */
+#define WINDOW_RIGHTMOST_P(W)					\
+  (WINDOW_RIGHT_PIXEL_EDGE (W)					\
+   == (WINDOW_RIGHT_PIXEL_EDGE					\
+       (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W))))))	\
+
+/* True if window W has no other windows below it on its frame (the
+   minibuffer window is not counted in this respect unless W itself is a
+   minibuffer window).  */
+#define WINDOW_BOTTOMMOST_P(W)					\
+  (WINDOW_BOTTOM_PIXEL_EDGE (W)					\
+   == (WINDOW_BOTTOM_PIXEL_EDGE					\
+       (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W))))))	\
+
+/* True if window W takes up the full width of its frame.  */
+#define WINDOW_FULL_WIDTH_P(W)					\
+  (WINDOW_PIXEL_WIDTH (W)					\
+   == (WINDOW_PIXEL_WIDTH					\
+       (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W))))))	\
+
 /* Width of right divider of window W.  */
 #define WINDOW_RIGHT_DIVIDER_WIDTH(W)				\
-  ((WINDOW_RIGHTMOST_P (W) || MINI_WINDOW_P (W))		\
-   ? 0								\
-   : FRAME_RIGHT_DIVIDER_WIDTH (WINDOW_XFRAME (W)))
+  (WINDOW_RIGHTMOST_P (W)					\
+   ? 0 : FRAME_RIGHT_DIVIDER_WIDTH (WINDOW_XFRAME (W)))
+
+/* Width of bottom divider of window W.  */
+#define WINDOW_BOTTOM_DIVIDER_WIDTH(W)					\
+  (((WINDOW_BOTTOMMOST_P (W)						\
+     && NILP ((XWINDOW (FRAME_ROOT_WINDOW				\
+			(WINDOW_XFRAME (W))))->next))			\
+    || EQ ((W)->prev, FRAME_ROOT_WINDOW (WINDOW_XFRAME (W)))		\
+    || (W)->pseudo_window_p)						\
+   ? 0 : FRAME_BOTTOM_DIVIDER_WIDTH (WINDOW_XFRAME (W)))

 /* Return the canonical frame column at which window W starts.
    This includes a left-hand scroll bar, if any.  */
-
 #define WINDOW_LEFT_EDGE_COL(W) (W)->left_col

 /* Return the canonical frame column before which window W ends.
    This includes a right-hand scroll bar, if any.  */
-
 #define WINDOW_RIGHT_EDGE_COL(W) \
   (WINDOW_LEFT_EDGE_COL (W) + WINDOW_TOTAL_COLS (W))

 /* Return the canonical frame line at which window W starts.
    This includes a header line, if any.  */
-
 #define WINDOW_TOP_EDGE_LINE(W) (W)->top_line

 /* Return the canonical frame line before which window W ends.
    This includes a mode line, if any.  */
-
 #define WINDOW_BOTTOM_EDGE_LINE(W) \
   (WINDOW_TOP_EDGE_LINE (W) + WINDOW_TOTAL_LINES (W))

@@ -629,20 +666,17 @@ struct window

 /* Return the frame x-position at which window W starts.
    This includes a left-hand scroll bar, if any.  */
-
 #define WINDOW_LEFT_EDGE_X(W) \
   (FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W)) \
    + WINDOW_LEFT_PIXEL_EDGE (W))

 /* Return the frame x- position before which window W ends.
    This includes a right-hand scroll bar, if any.  */
-
 #define WINDOW_RIGHT_EDGE_X(W) \
   (FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W)) \
    + WINDOW_RIGHT_PIXEL_EDGE (W))

 /* True if W is a menu bar window.  */
-
 #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
 #define WINDOW_MENU_BAR_P(W) \
   (WINDOWP (WINDOW_XFRAME (W)->menu_bar_window) \
@@ -661,72 +695,24 @@ struct window
 #define WINDOW_TOOL_BAR_P(W) false
 #endif

-/* Return the frame y-position at which window W starts.
-   This includes a header line, if any.
-
-   PXW: With a menu or tool bar this is not symmetric to the _X values
-   since it _does_ include the internal border width.  */
+/* Return the frame y-position at which window W starts.  */
 #define WINDOW_TOP_EDGE_Y(W) \
   (((WINDOW_MENU_BAR_P (W) || WINDOW_TOOL_BAR_P (W)) \
     ? 0 : FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W))) \
    + WINDOW_TOP_PIXEL_EDGE (W))

-/* Return the frame y-position before which window W ends.
-   This includes a mode line, if any.  */
+/* Return the frame y-position before which window W ends.  */
 #define WINDOW_BOTTOM_EDGE_Y(W)				   \
   (((WINDOW_MENU_BAR_P (W) || WINDOW_TOOL_BAR_P (W))	   \
     ? 0 : FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W))) \
    + WINDOW_BOTTOM_PIXEL_EDGE (W))

-/* True if window W takes up the full width of its frame.  */
-#define WINDOW_FULL_WIDTH_P(W)					\
-  (WINDOW_PIXEL_WIDTH (W)					\
-   == (WINDOW_PIXEL_WIDTH					\
-       (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W))))))	\
-
-/* True if window W's has no other windows to its left in its frame.  */
-
-#define WINDOW_LEFTMOST_P(W) \
-  (WINDOW_LEFT_PIXEL_EDGE (W) == 0)
-
-/* True if window W's has no other windows above in its frame.  */
-#define WINDOW_TOPMOST_P(W) \
-  (WINDOW_TOP_PIXEL_EDGE (W) == 0)
-
-/* True if window W's has no other windows to its right in its frame.  */
-#define WINDOW_RIGHTMOST_P(W)					\
-  (WINDOW_RIGHT_PIXEL_EDGE (W)					\
-   == (WINDOW_RIGHT_PIXEL_EDGE					\
-       (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W))))))	\
-
-/* True if window W's has no other windows below it in its frame
-   (the minibuffer window is not counted in this respect).  */
-#define WINDOW_BOTTOMMOST_P(W)					\
-  (WINDOW_BOTTOM_PIXEL_EDGE (W)					\
-   == (WINDOW_BOTTOM_PIXEL_EDGE					\
-       (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W))))))	\
-
-/* Return the frame column at which the text (or left fringe) in
-   window W starts.  This is different from the `LEFT_EDGE' because it
-   does not include a left-hand scroll bar if any.  */
-#define WINDOW_BOX_LEFT_EDGE_COL(W) \
-  (WINDOW_LEFT_EDGE_COL (W) \
-   + WINDOW_LEFT_SCROLL_BAR_COLS (W))
-
-/* Return the pixel value where the text (or left fringe) in
-   window W starts.  This is different from the `LEFT_EDGE' because it
-   does not include a left-hand scroll bar if any.  */
+/* Return the pixel value where the text (or left fringe) in window W
+   starts.  */
 #define WINDOW_BOX_LEFT_PIXEL_EDGE(W)		\
   (WINDOW_LEFT_PIXEL_EDGE (W)			\
    + WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (W))

-/* Return the window column before which the text in window W ends.
-   This is different from WINDOW_RIGHT_EDGE_COL because it does not
-   include a scroll bar or window-separating line on the right edge.  */
-#define WINDOW_BOX_RIGHT_EDGE_COL(W) \
-  (WINDOW_RIGHT_EDGE_COL (W) \
-   - WINDOW_RIGHT_SCROLL_BAR_COLS (W))
-
 /* Return the pixel value before which the text in window W ends.  This
    is different from the `RIGHT_EDGE' because it does not include a
    right-hand scroll bar or window-separating line on the right
@@ -736,16 +722,16 @@ struct window
    - WINDOW_RIGHT_DIVIDER_WIDTH (W)		\
    - WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH (W))

-/* Return the frame position at which the text (or left fringe) in
-   window W starts.  This is different from the `LEFT_EDGE' because it
-   does not include a left-hand scroll bar if any.  */
+/* Return the frame x-position at which the text (or left fringe) in
+   window W starts.  This does not include a left-hand scroll bar if
+   any.  */
 #define WINDOW_BOX_LEFT_EDGE_X(W)		   \
   (FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W)) \
    + WINDOW_BOX_LEFT_PIXEL_EDGE (W))

-/* Return the window column before which the text in window W ends.
-   This is different from WINDOW_RIGHT_EDGE_COL because it does not
-   include a scroll bar or window-separating line on the right edge.  */
+/* Return the frame x-position before which the text in window W ends.
+   This does not include a scroll bar, divider or window-separating line
+   on the right edge.  */
 #define WINDOW_BOX_RIGHT_EDGE_X(W)		   \
   (FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W)) \
    + WINDOW_BOX_RIGHT_PIXEL_EDGE (W))
@@ -899,16 +885,6 @@ struct window
    ? WINDOW_BOX_RIGHT_EDGE_X (W)		\
    : WINDOW_LEFT_EDGE_X (W))

-/* Width of bottom divider of window W.  */
-#define WINDOW_BOTTOM_DIVIDER_WIDTH(W)					\
-  (((WINDOW_BOTTOMMOST_P (W)						\
-     && NILP ((XWINDOW (FRAME_ROOT_WINDOW				\
-			(WINDOW_XFRAME (W))))->next))			\
-    || EQ ((W)->prev, FRAME_ROOT_WINDOW (WINDOW_XFRAME (W)))		\
-    || (W)->pseudo_window_p)						\
-   ? 0									\
-   : FRAME_BOTTOM_DIVIDER_WIDTH (WINDOW_XFRAME (W)))
-
 /* Height that a scroll bar in window W should have, if there is one.
    Measured in pixels.  If scroll bars are turned off, this is still
    nonzero.  */
@@ -942,22 +918,22 @@ struct window
 /* Height in pixels of the mode line.
    May be zero if W doesn't have a mode line.  */
 #define WINDOW_MODE_LINE_HEIGHT(W)	\
-  (WINDOW_WANTS_MODELINE_P ((W))	\
+  (window_wants_mode_line ((W))		\
    ? CURRENT_MODE_LINE_HEIGHT (W)	\
    : 0)

 #define WINDOW_MODE_LINE_LINES(W)	\
-  WINDOW_WANTS_MODELINE_P (W)
+  window_wants_mode_line (W)

 /* Height in pixels of the header line.
    Zero if W doesn't have a header line.  */
 #define WINDOW_HEADER_LINE_HEIGHT(W)	\
-  (WINDOW_WANTS_HEADER_LINE_P (W)	\
+  (window_wants_header_line (W)		\
    ? CURRENT_HEADER_LINE_HEIGHT (W)	\
    : 0)

 #define WINDOW_HEADER_LINE_LINES(W)	\
-  WINDOW_WANTS_HEADER_LINE_P (W)
+  window_wants_header_line (W)

 /* Pixel height of window W without mode line, bottom scroll bar and
    bottom divider.  */
@@ -1114,10 +1090,13 @@ void set_window_buffer (Lisp_Object window, Lisp_Object buffer,
 extern Lisp_Object Vwindow_list;

 extern Lisp_Object window_list (void);
+extern Lisp_Object window_parameter (struct window *, Lisp_Object parameter);
 extern struct window *decode_live_window (Lisp_Object);
 extern struct window *decode_any_window (Lisp_Object);
 extern bool compare_window_configurations (Lisp_Object, Lisp_Object, bool);
 extern void mark_window_cursors_off (struct window *);
+extern bool window_wants_mode_line (struct window *);
+extern bool window_wants_header_line (struct window *);
 extern int window_internal_height (struct window *);
 extern int window_body_width (struct window *w, bool);
 enum margin_unit { MARGIN_IN_LINES, MARGIN_IN_PIXELS };
@@ -1133,7 +1112,6 @@ void set_window_buffer (Lisp_Object window, Lisp_Object buffer,
 extern void init_window (void);
 extern void syms_of_window (void);
 extern void keys_of_window (void);
-
 /* Move cursor to row/column position VPOS/HPOS, pixel coordinates
    Y/X. HPOS/VPOS are window-relative row and column numbers and X/Y
    are window-relative pixel positions.  This is always done during
diff --git a/src/xdisp.c b/src/xdisp.c
index 34ee877..7848489 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -921,7 +921,7 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object,

   height -= WINDOW_BOTTOM_DIVIDER_WIDTH (w);

-  if (WINDOW_WANTS_MODELINE_P (w))
+  if (window_wants_mode_line (w))
     height -= CURRENT_MODE_LINE_HEIGHT (w);

   height -= WINDOW_SCROLL_BAR_AREA_HEIGHT (w);
@@ -978,7 +978,7 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object,
      the appropriate glyph row has its `mode_line_p' flag set,
      and if it doesn't, uses estimate_mode_line_height instead.  */

-  if (WINDOW_WANTS_MODELINE_P (w))
+  if (window_wants_mode_line (w))
     {
       struct glyph_row *ml_row
 	= (w->current_matrix && w->current_matrix->rows
@@ -990,7 +990,7 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object,
 	height -= estimate_mode_line_height (f, CURRENT_MODE_LINE_FACE_ID (w));
     }

-  if (WINDOW_WANTS_HEADER_LINE_P (w))
+  if (window_wants_header_line (w))
     {
       struct glyph_row *hl_row
 	= (w->current_matrix && w->current_matrix->rows
@@ -1102,7 +1102,7 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object,
   if (box_y)
     {
       *box_y = WINDOW_TOP_EDGE_Y (w);
-      if (WINDOW_WANTS_HEADER_LINE_P (w))
+      if (window_wants_header_line (w))
 	*box_y += CURRENT_HEADER_LINE_HEIGHT (w);
     }
 }
@@ -1322,15 +1322,29 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object,
     return visible_p;

   /* Compute exact mode line heights.  */
-  if (WINDOW_WANTS_MODELINE_P (w))
-    w->mode_line_height
-      = display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w),
-			   BVAR (current_buffer, mode_line_format));
+  if (window_wants_mode_line (w))
+    {
+      Lisp_Object window_mode_line_format
+	= window_parameter (w, Qmode_line_format);
+
+      w->mode_line_height
+	= display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w),
+			     NILP (window_mode_line_format)
+			     ? BVAR (current_buffer, mode_line_format)
+			     : window_mode_line_format);
+    }

-  if (WINDOW_WANTS_HEADER_LINE_P (w))
-    w->header_line_height
-      = display_mode_line (w, HEADER_LINE_FACE_ID,
-			   BVAR (current_buffer, header_line_format));
+  if (window_wants_header_line (w))
+    {
+      Lisp_Object window_header_line_format
+	= window_parameter (w, Qheader_line_format);
+
+      w->header_line_height
+	= display_mode_line (w, HEADER_LINE_FACE_ID,
+			     NILP (window_header_line_format)
+			     ? BVAR (current_buffer, header_line_format)
+			     : window_header_line_format);
+    }

   start_display (&it, w, top);
   move_it_to (&it, charpos, -1, it.last_visible_y - 1, -1,
@@ -2842,13 +2856,12 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object,

   /* Get dimensions of truncation and continuation glyphs.  These are
      displayed as fringe bitmaps under X, but we need them for such
-     frames when the fringes are turned off.  But leave the dimensions
-     zero for tooltip frames, as these glyphs look ugly there and also
-     sabotage calculations of tooltip dimensions in x-show-tip.  */
+     frames when the fringes are turned off.  The no_special_glyphs slot
+     of the iterator's frame, when set, suppresses their display - by
+     default for tooltip frames and when set via the 'no-special-glyphs'
+     frame parameter.  */
 #ifdef HAVE_WINDOW_SYSTEM
-  if (!(FRAME_WINDOW_P (it->f)
-	&& FRAMEP (tip_frame)
-	&& it->f == XFRAME (tip_frame)))
+  if (!(FRAME_WINDOW_P (it->f) && it->f->no_special_glyphs))
 #endif
     {
       if (it->line_wrap == TRUNCATE)
@@ -2920,7 +2933,7 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object,
 	    it->last_visible_x -= it->continuation_pixel_width;
 	}

-      it->header_line_p = WINDOW_WANTS_HEADER_LINE_P (w);
+      it->header_line_p = window_wants_header_line (w);
       it->current_y = WINDOW_HEADER_LINE_HEIGHT (w) + w->vscroll;
     }

@@ -3019,7 +3032,7 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object,
 start_display (struct it *it, struct window *w, struct text_pos pos)
 {
   struct glyph_row *row;
-  bool first_vpos = WINDOW_WANTS_HEADER_LINE_P (w);
+  bool first_vpos = window_wants_header_line (w);

   row = w->desired_matrix->rows + first_vpos;
   init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID);
@@ -15799,7 +15812,7 @@ enum

       /* Find the start of the continued line.  This should be fast
 	 because find_newline is fast (newline cache).  */
-      row = w->desired_matrix->rows + WINDOW_WANTS_HEADER_LINE_P (w);
+      row = w->desired_matrix->rows + window_wants_header_line (w);
       init_iterator (&it, w, CHARPOS (start_pos), BYTEPOS (start_pos),
 		     row, DEFAULT_FACE_ID);
       reseat_at_previous_visible_line_start (&it);
@@ -15949,7 +15962,7 @@ enum
       this_scroll_margin = window_scroll_margin (w, MARGIN_IN_PIXELS);

       top_scroll_margin = this_scroll_margin;
-      if (WINDOW_WANTS_HEADER_LINE_P (w))
+      if (window_wants_header_line (w))
 	top_scroll_margin += CURRENT_HEADER_LINE_HEIGHT (w);

       /* Start with the row the cursor was displayed during the last
@@ -16732,7 +16745,7 @@ enum
 	     margin, even though this part handles windows that didn't
 	     scroll at all.  */
           int pixel_margin = margin * frame_line_height;
-	  bool header_line = WINDOW_WANTS_HEADER_LINE_P (w);
+	  bool header_line = window_wants_header_line (w);

 	  /* Note: We add an extra FRAME_LINE_HEIGHT, because the loop
 	     below, which finds the row to move point to, advances by
@@ -17299,15 +17312,15 @@ enum
        || (w->column_number_displayed != -1
 	   && (w->column_number_displayed != current_column ())))
       /* This means that the window has a mode line.  */
-      && (WINDOW_WANTS_MODELINE_P (w)
-	  || WINDOW_WANTS_HEADER_LINE_P (w)))
+      && (window_wants_mode_line (w)
+	  || window_wants_header_line (w)))
     {

       display_mode_lines (w);

       /* If mode line height has changed, arrange for a thorough
 	 immediate redisplay using the correct mode line height.  */
-      if (WINDOW_WANTS_MODELINE_P (w)
+      if (window_wants_mode_line (w)
 	  && CURRENT_MODE_LINE_HEIGHT (w) != DESIRED_MODE_LINE_HEIGHT (w))
 	{
 	  f->fonts_changed = true;
@@ -17318,7 +17331,7 @@ enum

       /* If header line height has changed, arrange for a thorough
 	 immediate redisplay using the correct header line height.  */
-      if (WINDOW_WANTS_HEADER_LINE_P (w)
+      if (window_wants_header_line (w)
 	  && CURRENT_HEADER_LINE_HEIGHT (w) != DESIRED_HEADER_LINE_HEIGHT (w))
 	{
 	  f->fonts_changed = true;
@@ -17583,7 +17596,7 @@ enum
     return false;

   /* If top-line visibility has changed, give up.  */
-  if (WINDOW_WANTS_HEADER_LINE_P (w)
+  if (window_wants_header_line (w)
       != MATRIX_HEADER_LINE_ROW (w->current_matrix)->mode_line_p)
     return false;

@@ -18818,7 +18831,7 @@ struct glyph_row *
 	    = MATRIX_ROW_VPOS (first_unchanged_at_end_row, w->current_matrix);
 	  int from = WINDOW_TOP_EDGE_LINE (w) + from_vpos;
 	  int end = (WINDOW_TOP_EDGE_LINE (w)
-		     + WINDOW_WANTS_HEADER_LINE_P (w)
+		     + window_wants_header_line (w)
 		     + window_internal_height (w));

 #if defined (HAVE_GPM) || defined (MSDOS)
@@ -18996,7 +19009,7 @@ struct glyph_row *
     {
       /* Displayed to end of window, but no line containing text was
 	 displayed.  Lines were deleted at the end of the window.  */
-      bool first_vpos = WINDOW_WANTS_HEADER_LINE_P (w);
+      bool first_vpos = window_wants_header_line (w);
       int vpos = w->window_end_vpos;
       struct glyph_row *current_row = current_matrix->rows + vpos;
       struct glyph_row *desired_row = desired_matrix->rows + vpos;
@@ -20696,7 +20709,7 @@ struct glyph_row *
   ptrdiff_t min_pos = ZV + 1, max_pos = 0;
   ptrdiff_t min_bpos UNINIT, max_bpos UNINIT;
   bool pending_handle_line_prefix = false;
-  int header_line = WINDOW_WANTS_HEADER_LINE_P (it->w);
+  int header_line = window_wants_header_line (it->w);
   bool hscroll_this_line = (cursor_vpos >= 0
 			    && it->vpos == cursor_vpos - header_line
 			    && hscrolling_current_line_p (it->w));
@@ -22649,20 +22662,30 @@ control characters RLO (u+202e) and LRO (u+202d).  See the
   line_number_displayed = false;
   w->column_number_displayed = -1;

-  if (WINDOW_WANTS_MODELINE_P (w))
+  if (window_wants_mode_line (w))
     {
+      Lisp_Object window_mode_line_format
+	= window_parameter (w, Qmode_line_format);
+
       struct window *sel_w = XWINDOW (old_selected_window);

       /* Select mode line face based on the real selected window.  */
       display_mode_line (w, CURRENT_MODE_LINE_FACE_ID_3 (sel_w, sel_w, w),
-			 BVAR (current_buffer, mode_line_format));
+			 NILP (window_mode_line_format)
+			 ? BVAR (current_buffer, mode_line_format)
+			 : window_mode_line_format);
       ++n;
     }

-  if (WINDOW_WANTS_HEADER_LINE_P (w))
+  if (window_wants_header_line (w))
     {
+      Lisp_Object window_header_line_format
+	= window_parameter (w, Qheader_line_format);
+
       display_mode_line (w, HEADER_LINE_FACE_ID,
-			 BVAR (current_buffer, header_line_format));
+			 NILP (window_header_line_format)
+			 ? BVAR (current_buffer, header_line_format)
+			 : window_header_line_format);
       ++n;
     }

@@ -30442,13 +30465,67 @@ A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the
 	  && part != ON_HEADER_LINE))
     clear_mouse_face (hlinfo);

+  /* Reset help_echo_string. It will get recomputed below.  */
+  help_echo_string = Qnil;
+
+#ifdef HAVE_WINDOW_SYSTEM
+  /* If the cursor is on the internal border of FRAME and FRAME's
+     internal border is draggable, provide some visual feedback.  */
+  if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0
+      && !NILP (get_frame_param (f, Qdrag_internal_border)))
+    {
+      enum internal_border_part part = frame_internal_border_part (f, x, y);
+
+      switch (part)
+	{
+	case INTERNAL_BORDER_NONE:
+	  if (cursor != FRAME_X_OUTPUT (f)->nontext_cursor)
+	    /* Reset cursor.  */
+	    cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+	  break;
+	case INTERNAL_BORDER_LEFT_EDGE:
+	  cursor = FRAME_X_OUTPUT (f)->left_edge_cursor;
+	  break;
+	case INTERNAL_BORDER_TOP_LEFT_CORNER:
+	  cursor = FRAME_X_OUTPUT (f)->top_left_corner_cursor;
+	  break;
+	case INTERNAL_BORDER_TOP_EDGE:
+	  cursor = FRAME_X_OUTPUT (f)->top_edge_cursor;
+	  break;
+	case INTERNAL_BORDER_TOP_RIGHT_CORNER:
+	  cursor = FRAME_X_OUTPUT (f)->top_right_corner_cursor;
+	  break;
+	case INTERNAL_BORDER_RIGHT_EDGE:
+	  cursor = FRAME_X_OUTPUT (f)->right_edge_cursor;
+	  break;
+	case INTERNAL_BORDER_BOTTOM_RIGHT_CORNER:
+	  cursor = FRAME_X_OUTPUT (f)->bottom_right_corner_cursor;
+	  break;
+	case INTERNAL_BORDER_BOTTOM_EDGE:
+	  cursor = FRAME_X_OUTPUT (f)->bottom_edge_cursor;
+	  break;
+	case INTERNAL_BORDER_BOTTOM_LEFT_CORNER:
+	  cursor = FRAME_X_OUTPUT (f)->bottom_left_corner_cursor;
+	  break;
+	default:
+	  /* This should not happen.  */
+	  if (cursor != FRAME_X_OUTPUT (f)->nontext_cursor)
+	    cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+	}
+
+      if (cursor != FRAME_X_OUTPUT (f)->nontext_cursor)
+	{
+	  /* Do we really want a help echo here?  */
+	  help_echo_string = build_string ("drag-mouse-1: resize frame");
+	  goto set_cursor;
+	}
+    }
+#endif /* HAVE_WINDOW_SYSTEM */
+
   /* Not on a window -> return.  */
   if (!WINDOWP (window))
     return;

-  /* Reset help_echo_string. It will get recomputed below.  */
-  help_echo_string = Qnil;
-
   /* Convert to window-relative pixel coordinates.  */
   w = XWINDOW (window);
   frame_to_window_pixel_xy (w, &x, &y);
@@ -30486,11 +30563,13 @@ A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the
     {
       cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
       help_echo_string = build_string ("drag-mouse-1: resize");
+      goto set_cursor;
     }
   else if (part == ON_RIGHT_DIVIDER)
     {
       cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
       help_echo_string = build_string ("drag-mouse-1: resize");
+      goto set_cursor;
     }
   else if (part == ON_BOTTOM_DIVIDER)
     if (! WINDOW_BOTTOMMOST_P (w)
@@ -30499,6 +30578,7 @@ A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the
       {
 	cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor;
 	help_echo_string = build_string ("drag-mouse-1: resize");
+	goto set_cursor;
       }
     else
       cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
@@ -31193,8 +31273,15 @@ A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the
       int x0 = WINDOW_RIGHT_EDGE_X (w) - WINDOW_RIGHT_DIVIDER_WIDTH (w);
       int x1 = WINDOW_RIGHT_EDGE_X (w);
       int y0 = WINDOW_TOP_EDGE_Y (w);
-      /* The bottom divider prevails.  */
-      int y1 = WINDOW_BOTTOM_EDGE_Y (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w);
+      int y1 = WINDOW_BOTTOM_EDGE_Y (w);
+
+      /* If W is horizontally combined and has a right sibling, don't
+	 draw over any bottom divider.  */
+      if (WINDOW_BOTTOM_DIVIDER_WIDTH (w)
+	  && !NILP (w->parent)
+	  && WINDOW_HORIZONTAL_COMBINATION_P (XWINDOW (w->parent))
+	  && !NILP (w->next))
+	y1 -= WINDOW_BOTTOM_DIVIDER_WIDTH (w);

       FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1);
     }
@@ -31213,8 +31300,22 @@ A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the
       int x1 = WINDOW_RIGHT_EDGE_X (w);
       int y0 = WINDOW_BOTTOM_EDGE_Y (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w);
       int y1 = WINDOW_BOTTOM_EDGE_Y (w);
+      struct window *p = !NILP (w->parent) ? XWINDOW (w->parent) : false;

-      FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1);
+      /* If W is vertically combined and has a sibling below, don't draw
+	 over any right divider.  */
+      if (WINDOW_RIGHT_DIVIDER_WIDTH (w)
+	  && p
+	  && ((WINDOW_VERTICAL_COMBINATION_P (p)
+	       && !NILP (w->next))
+	      || (WINDOW_HORIZONTAL_COMBINATION_P (p)
+		  && NILP (w->next)
+		  && !NILP (p->parent)
+		  && WINDOW_VERTICAL_COMBINATION_P (XWINDOW (p->parent))
+		  && !NILP (XWINDOW (p->parent)->next))))
+	x1 -= WINDOW_RIGHT_DIVIDER_WIDTH (w);
+
+	FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1);
     }
 }

@@ -31329,7 +31430,7 @@ A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the
 	}

       /* Display the mode line if there is one.  */
-      if (WINDOW_WANTS_MODELINE_P (w)
+      if (window_wants_mode_line (w)
 	  && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
 	      row->enabled_p)
 	  && row->y < r_bottom)
diff --git a/src/xfns.c b/src/xfns.c
index 7be2253..3dd1970 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -1120,6 +1120,14 @@ enum mouse_cursor {
   mouse_cursor_hand,
   mouse_cursor_horizontal_drag,
   mouse_cursor_vertical_drag,
+  mouse_cursor_left_edge,
+  mouse_cursor_top_left_corner,
+  mouse_cursor_top_edge,
+  mouse_cursor_top_right_corner,
+  mouse_cursor_right_edge,
+  mouse_cursor_bottom_right_corner,
+  mouse_cursor_bottom_edge,
+  mouse_cursor_bottom_left_corner,
   mouse_cursor_max
 };

@@ -1139,13 +1147,21 @@ struct mouse_cursor_types {

 /* This array must stay in sync with enum mouse_cursor above!  */
 static const struct mouse_cursor_types mouse_cursor_types[] = {
-  { "text",      &Vx_pointer_shape,                XC_xterm             },
-  { "nontext",   &Vx_nontext_pointer_shape,        XC_left_ptr          },
-  { "hourglass", &Vx_hourglass_pointer_shape,      XC_watch             },
-  { "modeline",  &Vx_mode_pointer_shape,           XC_xterm             },
-  { NULL,        &Vx_sensitive_text_pointer_shape, XC_hand2             },
-  { NULL,        &Vx_window_horizontal_drag_shape, XC_sb_h_double_arrow },
-  { NULL,        &Vx_window_vertical_drag_shape,   XC_sb_v_double_arrow },
+  { "text",      &Vx_pointer_shape,                    XC_xterm               },
+  { "nontext",   &Vx_nontext_pointer_shape,            XC_left_ptr            },
+  { "hourglass", &Vx_hourglass_pointer_shape,          XC_watch               },
+  { "modeline",  &Vx_mode_pointer_shape,               XC_xterm               },
+  { NULL,        &Vx_sensitive_text_pointer_shape,     XC_hand2               },
+  { NULL,        &Vx_window_horizontal_drag_shape,     XC_sb_h_double_arrow   },
+  { NULL,        &Vx_window_vertical_drag_shape,       XC_sb_v_double_arrow   },
+  { NULL,        &Vx_window_left_edge_shape,           XC_left_side           },
+  { NULL,        &Vx_window_top_left_corner_shape,     XC_top_left_corner     },
+  { NULL,        &Vx_window_top_edge_shape,            XC_top_side            },
+  { NULL,        &Vx_window_top_right_corner_shape,    XC_top_right_corner    },
+  { NULL,        &Vx_window_right_edge_shape,          XC_right_side          },
+  { NULL,        &Vx_window_bottom_right_corner_shape, XC_bottom_right_corner },
+  { NULL,        &Vx_window_bottom_edge_shape,         XC_bottom_side         },
+  { NULL,        &Vx_window_bottom_left_corner_shape,  XC_bottom_left_corner  },
 };

 struct mouse_cursor_data {
@@ -1296,6 +1312,14 @@ struct mouse_cursor_data {
   INSTALL_CURSOR (hand_cursor, hand);
   INSTALL_CURSOR (horizontal_drag_cursor, horizontal_drag);
   INSTALL_CURSOR (vertical_drag_cursor, vertical_drag);
+  INSTALL_CURSOR (left_edge_cursor, left_edge);
+  INSTALL_CURSOR (top_left_corner_cursor, top_left_corner);
+  INSTALL_CURSOR (top_edge_cursor, top_edge);
+  INSTALL_CURSOR (top_right_corner_cursor, top_right_corner);
+  INSTALL_CURSOR (right_edge_cursor, right_edge);
+  INSTALL_CURSOR (bottom_right_corner_cursor, bottom_right_corner);
+  INSTALL_CURSOR (bottom_edge_cursor, bottom_edge);
+  INSTALL_CURSOR (bottom_left_corner_cursor, bottom_left_corner);

 #undef INSTALL_CURSOR

@@ -3814,6 +3838,8 @@ struct mouse_cursor_data {
 		       "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
   x_default_parameter (f, parms, Qright_fringe, Qnil,
 		       "rightFringe", "RightFringe", RES_TYPE_NUMBER);
+  x_default_parameter (f, parms, Qno_special_glyphs, Qnil,
+		       NULL, NULL, RES_TYPE_BOOLEAN);

   x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground,
 					"scrollBarForeground",
@@ -6196,6 +6222,8 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object,
 		       "cursorColor", "Foreground", RES_TYPE_STRING);
   x_default_parameter (f, parms, Qborder_color, build_string ("black"),
 		       "borderColor", "BorderColor", RES_TYPE_STRING);
+  x_default_parameter (f, parms, Qno_special_glyphs, Qnil,
+		       NULL, NULL, RES_TYPE_BOOLEAN);

   /* Init faces before x_default_parameter is called for the
      scroll-bar-width parameter because otherwise we end up in
@@ -7486,6 +7514,7 @@ FRAMES should be nil (the selected frame), a frame, or a list of
   x_set_no_accept_focus,
   x_set_z_group,
   x_set_override_redirect,
+  x_set_no_special_glyphs,
 };

 void
@@ -7564,6 +7593,62 @@ FRAMES should be nil (the selected frame), a frame, or a list of
 or when you set the mouse color.  */);
   Vx_window_vertical_drag_shape = Qnil;

+  DEFVAR_LISP ("x-window-left-edge-cursor",
+	       Vx_window_left_edge_shape,
+  doc: /* Pointer shape indicating a left x-window edge can be dragged.
+This variable takes effect when you create a new frame
+or when you set the mouse color.  */);
+  Vx_window_left_edge_shape = Qnil;
+
+  DEFVAR_LISP ("x-window-top-left-corner-cursor",
+	       Vx_window_top_left_corner_shape,
+  doc: /* Pointer shape indicating a top left x-window corner can be dragged.
+This variable takes effect when you create a new frame
+or when you set the mouse color.  */);
+  Vx_window_top_left_corner_shape = Qnil;
+
+  DEFVAR_LISP ("x-window-top-edge-cursor",
+	       Vx_window_top_edge_shape,
+  doc: /* Pointer shape indicating a top x-window edge can be dragged.
+This variable takes effect when you create a new frame
+or when you set the mouse color.  */);
+  Vx_window_top_edge_shape = Qnil;
+
+  DEFVAR_LISP ("x-window-top-right-corner-cursor",
+	       Vx_window_top_right_corner_shape,
+  doc: /* Pointer shape indicating a top right x-window corner can be dragged.
+This variable takes effect when you create a new frame
+or when you set the mouse color.  */);
+  Vx_window_top_right_corner_shape = Qnil;
+
+  DEFVAR_LISP ("x-window-right-edge-cursor",
+	       Vx_window_right_edge_shape,
+  doc: /* Pointer shape indicating a right x-window edge can be dragged.
+This variable takes effect when you create a new frame
+or when you set the mouse color.  */);
+  Vx_window_right_edge_shape = Qnil;
+
+  DEFVAR_LISP ("x-window-bottom-right-corner-cursor",
+	       Vx_window_bottom_right_corner_shape,
+  doc: /* Pointer shape indicating a bottom right x-window corner can be dragged.
+This variable takes effect when you create a new frame
+or when you set the mouse color.  */);
+  Vx_window_bottom_right_corner_shape = Qnil;
+
+  DEFVAR_LISP ("x-window-bottom-edge-cursor",
+	       Vx_window_bottom_edge_shape,
+  doc: /* Pointer shape indicating a bottom x-window edge can be dragged.
+This variable takes effect when you create a new frame
+or when you set the mouse color.  */);
+  Vx_window_bottom_edge_shape = Qnil;
+
+  DEFVAR_LISP ("x-window-bottom-left-corner-cursor",
+	       Vx_window_bottom_left_corner_shape,
+  doc: /* Pointer shape indicating a bottom left x-window corner can be dragged.
+This variable takes effect when you create a new frame
+or when you set the mouse color.  */);
+  Vx_window_bottom_left_corner_shape = Qnil;
+
   DEFVAR_LISP ("x-cursor-fore-pixel", Vx_cursor_fore_pixel,
     doc: /* A string indicating the foreground color of the cursor box.  */);
   Vx_cursor_fore_pixel = Qnil;
diff --git a/src/xterm.c b/src/xterm.c
index c8836b7..a214cd8 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -11757,6 +11757,22 @@ struct x_error_message_stack {
 	XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->horizontal_drag_cursor);
       if (f->output_data.x->vertical_drag_cursor != 0)
 	XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->vertical_drag_cursor);
+      if (f->output_data.x->left_edge_cursor != 0)
+	XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->left_edge_cursor);
+      if (f->output_data.x->top_left_corner_cursor != 0)
+	XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->top_left_corner_cursor);
+      if (f->output_data.x->top_edge_cursor != 0)
+	XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->top_edge_cursor);
+      if (f->output_data.x->top_right_corner_cursor != 0)
+	XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->top_right_corner_cursor);
+      if (f->output_data.x->right_edge_cursor != 0)
+	XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->right_edge_cursor);
+      if (f->output_data.x->bottom_right_corner_cursor != 0)
+	XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->bottom_right_corner_cursor);
+      if (f->output_data.x->bottom_edge_cursor != 0)
+	XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->bottom_edge_cursor);
+      if (f->output_data.x->bottom_left_corner_cursor != 0)
+	XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->bottom_left_corner_cursor);

       XFlush (FRAME_X_DISPLAY (f));
     }
diff --git a/src/xterm.h b/src/xterm.h
index a752570..803feda 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -637,6 +637,14 @@ struct x_output
   Cursor horizontal_drag_cursor;
   Cursor vertical_drag_cursor;
   Cursor current_cursor;
+  Cursor left_edge_cursor;
+  Cursor top_left_corner_cursor;
+  Cursor top_edge_cursor;
+  Cursor top_right_corner_cursor;
+  Cursor right_edge_cursor;
+  Cursor bottom_right_corner_cursor;
+  Cursor bottom_edge_cursor;
+  Cursor bottom_left_corner_cursor;

   /* Window whose cursor is hourglass_cursor.  This window is temporarily
      mapped to display an hourglass cursor.  */