emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] scratch/ns/next fe937bb 7/8: Merge branch 'master' into sc


From: Alan Third
Subject: [Emacs-diffs] scratch/ns/next fe937bb 7/8: Merge branch 'master' into scratch/ns/next
Date: Tue, 15 Jan 2019 12:12:30 -0500 (EST)

branch: scratch/ns/next
commit fe937bb2de68c641238db0c845de7c1abadda743
Merge: 1fcde76 c48ea7c
Author: Alan Third <address@hidden>
Commit: Alan Third <address@hidden>

    Merge branch 'master' into scratch/ns/next
---
 admin/notes/copyright    |   3 -
 doc/lispref/windows.texi | 314 +++++++++++++------
 etc/CENSORSHIP           |   8 -
 etc/FTP                  |   9 -
 etc/GNU                  |   8 -
 etc/LINUX-GNU            |   8 -
 etc/MORE.STUFF           |   8 -
 etc/NEWS                 |  27 +-
 etc/ORDERS               |   8 -
 etc/THE-GNU-PROJECT      |   8 -
 etc/WHY-FREE             |   8 -
 lisp/erc/erc-track.el    |   5 +-
 lisp/frame.el            |  11 +-
 lisp/help.el             |   5 +-
 lisp/net/rcirc.el        |   8 +-
 lisp/progmodes/sql.el    |   8 +-
 lisp/window.el           |  30 +-
 src/alloc.c              |  13 +
 src/dispextern.h         |  13 +-
 src/fns.c                |  11 +-
 src/frame.c              |  25 +-
 src/frame.h              |  46 ++-
 src/image.c              |  78 +++--
 src/window.c             | 767 ++++++++++++++++++++++++++++++++++-------------
 src/window.h             |  27 +-
 src/xdisp.c              |  72 +++--
 src/xterm.c              |  14 +-
 27 files changed, 1024 insertions(+), 518 deletions(-)

diff --git a/admin/notes/copyright b/admin/notes/copyright
index b2c74a8..e22db6b 100644
--- a/admin/notes/copyright
+++ b/admin/notes/copyright
@@ -161,9 +161,6 @@ etc/letter.pbm,letter.xpm
   - trivial, no notice needed.
 <https://lists.gnu.org/r/emacs-devel/2007-02/msg00324.html>
 
-etc/FTP, ORDERS
-  - trivial (at time of writing), no license needed
-
 etc/HELLO
   standard notices. Just a note that although the file itself is not
   really copyrightable, in the wider context of it being part of
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index a085318..6b5aa66 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -568,12 +568,6 @@ its pixel height is the pixel height of the screen areas 
spanned by its
 children.
 @end defun
 
address@hidden window-pixel-height-before-size-change &optional Lisp_Object 
&optional window
-This function returns the height of window @var{window} in pixels at the
-time @code{window-size-change-functions} was run for the last time on
address@hidden's frame (@pxref{Window Hooks}).
address@hidden defun
-
 @cindex window pixel width
 @cindex pixel width of a window
 @cindex total pixel width of a window
@@ -588,12 +582,6 @@ If @var{window} is an internal window, its pixel width is 
the width of
 the screen areas spanned by its children.
 @end defun
 
address@hidden window-pixel-width-before-size-change &optional Lisp_Object 
&optional window
-This function returns the width of window @var{window} in pixels at the
-time @code{window-size-change-functions} was run for the last time on
address@hidden's frame (@pxref{Window Hooks}).
address@hidden defun
-
 @cindex full-width window
 @cindex full-height window
   The following functions can be used to determine whether a given
@@ -5705,10 +5693,6 @@ prevent the code in @var{forms} from opening new 
windows, because new
 windows might be opened in other frames (@pxref{Choosing Window}), and
 @code{save-window-excursion} only saves and restores the window
 configuration on the current frame.
-
-Do not use this macro in @code{window-size-change-functions}; exiting
-the macro triggers execution of @code{window-size-change-functions},
-leading to an endless loop.
 @end defmac
 
 @defun window-configuration-p object
@@ -5827,10 +5811,10 @@ This function sets @var{window}'s value of 
@var{parameter} to
 is the selected window.
 @end defun
 
-By default, the functions that save and restore window configurations or the
-states of windows (@pxref{Window Configurations}) do not care about
-window parameters.  This means that when you change the value of a
-parameter within the body of a @code{save-window-excursion}, the
+By default, the functions that save and restore window configurations
+or the states of windows (@pxref{Window Configurations}) do not care
+about window parameters.  This means that when you change the value of
+a parameter within the body of a @code{save-window-excursion}, the
 previous value is not restored when that macro exits.  It also means
 that when you restore via @code{window-state-put} a window state saved
 earlier by @code{window-state-get}, all cloned windows have their
@@ -6019,27 +6003,26 @@ applications.  It might be replaced by an improved 
solution in future
 versions of Emacs.
 @end table
 
+
 @node Window Hooks
 @section Hooks for Window Scrolling and Changes
 @cindex hooks for window operations
 
-This section describes how a Lisp program can take action whenever a
-window displays a different part of its buffer or a different buffer.
-There are three actions that can change this: scrolling the window,
-switching buffers in the window, and changing the size of the window.
-The first two actions run @code{window-scroll-functions}; the last runs
address@hidden
+This section describes how Lisp programs can take action after a
+window has been scrolled or other window modifications occurred.  We
+first consider the case where a window shows a different part of its
+buffer.
 
 @defvar window-scroll-functions
 This variable holds a list of functions that Emacs should call before
-redisplaying a window with scrolling.  Displaying a different buffer in
-the window also runs these functions.
+redisplaying a window with scrolling.  Displaying a different buffer
+in a window and making a new window also call these functions.
 
-This variable is not a normal hook, because each function is called with
-two arguments: the window, and its new display-start position.  At the
-time of the call, the display-start position of the window argument is
-already set to its new value, and the buffer to be displayed in the
-window is already set as the current buffer.
+This variable is not a normal hook, because each function is called
+with two arguments: the window, and its new display-start position.
+At the time of the call, the display-start position of the argument
+window is already set to its new value, and the buffer to be displayed
+in the window is set as the current buffer.
 
 These functions must take care when using @code{window-end}
 (@pxref{Window Start and End}); if you need an up-to-date value, you
@@ -6050,63 +6033,226 @@ is scrolled.  It's not designed for that, and such use 
probably won't
 work.
 @end defvar
 
address@hidden run-window-scroll-functions &optional window
-This function calls @code{window-scroll-functions} for the specified
address@hidden, which defaults to the selected window.
address@hidden defun
+In addition, you can use @code{jit-lock-register} to register a Font
+Lock fontification function, which will be called whenever parts of a
+buffer are (re)fontified because a window was scrolled or its size
+changed.  @xref{Other Font Lock Variables}.
+
address@hidden window change functions
+   The remainder of this section covers four hooks that are called at
+the end of redisplay provided a significant, non-scrolling change of a
+window has been detected.  For simplicity, these hooks and the
+functions they call will be collectively referred to as @dfn{window
+change functions}.
+
address@hidden window buffer change
+The first of these hooks is run after a @dfn{window buffer change} is
+detected, which means that a window was created, deleted or assigned
+another buffer.
+
address@hidden window-buffer-change-functions
+This variable specifies functions called at the end of redisplay when
+window buffers have changed.  The value should be a list of functions
+that take one argument.
+
+Functions specified buffer-locally are called for any window showing
+the corresponding buffer if that window has been created or assigned
+that buffer since the last time window change functions were run.  In
+this case the window is passed as argument.
+
+Functions specified by the default value are called for a frame if at
+least one window on that frame has been added, deleted or assigned
+another buffer since the last time window change functions were run.
+In this case the frame is passed as argument.
address@hidden defvar
+
address@hidden window size change
+The second of these hooks is run after a @dfn{window size change} has
+been detected which means that a window was created, assigned another
+buffer, or changed its total size or that of its text area.
 
 @defvar window-size-change-functions
-This variable holds a list of functions to be called if the size of any
-window changes for any reason.  The functions are called once per
-redisplay, and once for each frame on which size changes have occurred.
-
-Each function receives the frame as its sole argument.  To find out
-whether a specific window has changed size, compare the return values of
address@hidden and
address@hidden respectively
address@hidden and
address@hidden for that window (@pxref{Window Sizes}).
-
-The buffer-local value of this hook is run once for the buffer and the
-frame in question, provided at least one window showing the buffer on
-that frame has changed its size.  As it still receives the frame as
-its sole argument, any function called on a buffer-local basis will be
-oblivious to which window(s) showing the buffer changed its (their)
-size and has to check out these windows by using the method described
-in the previous paragraph.
-
-These function are usually only called when at least one window was
-added or has changed size since the last time this hook was run for
-the associated frame.  In some rare cases this hook also runs when a
-window that was added intermittently has been deleted afterwards.  In
-these cases none of the windows on the frame will appear to have
-changed its size.
+This variable specifies functions called at the end of redisplay when
+a window size change occurred.  The value should be a list of
+functions that take one argument.
+
+Functions specified buffer-locally are called for any window showing
+the corresponding buffer if that window has been added or assigned
+another buffer, total or body size since the last time window change
+functions were run.  In this case the window is passed as argument.
+
+Functions specified by the default value are called for a frame if at
+least one window on that frame has been added or assigned another
+buffer, total or body size since the last time window change functions
+were run.  In this case the frame is passed as argument.
address@hidden defvar
+
address@hidden window selection change
+The third of these hooks is run after a @dfn{window selection change}
+has selected another window since the last redisplay.
+
address@hidden window-selection-change-functions
+This variable specifies functions called at the end of redisplay when
+the selected window or a frame's selected window has changed.  The
+value should be a list of functions that take one argument.
+
+Functions specified buffer-locally are called for any window showing
+the corresponding buffer if that window has been selected or
+deselected (among all windows or among all windows on its frame) since
+the last time window change functions were run.  In this case the
+window is passed as argument.
+
+Functions specified by the default value are called for a frame if
+that frame has been selected or deselected or the frame's selected
+window has changed since the last time window change functions were
+run.  In this case the frame is passed as argument.
 @end defvar
 
address@hidden window configuration change
+The fourth of these hooks is run when a @dfn{window configuration
+change} has been detected which means that either the buffer or the
+size of a window changed.
+
 @defvar window-configuration-change-hook
-A normal hook that is run every time the window configuration of a
-frame changes.  Window configuration changes include splitting and
-deleting windows, and the display of a different buffer in a window.
-
-The hook can be also used for tracking changes of window sizes.  It
-is, however, not run when the size of a frame changes or automatic
-resizing of a minibuffer window (@pxref{Minibuffer Windows}) changes
-the size of another window.  As a rule, adding a function to
address@hidden, see above, is the recommended way
-for reliably tracking size changes of any window.
-
-The buffer-local value of this hook is run once for each window on the
-affected frame, with the relevant window selected and its buffer
-current.  The global value of this hook is run once for the modified
-frame, with that frame selected.
+This variable specifies functions called at the end of redisplay when
+either the buffer or the size of a window has changed.  The value
+should be a list of functions that take no argument.
+
+Functions specified buffer-locally are called for any window showing
+the corresponding buffer if at least one window on that frame has been
+added, deleted or assigned another buffer, total or body size since
+the last time window change functions were run.  Each call is
+performed with the window showing the buffer temporarily selected and
+its buffer current.
+
+Functions specified by the default value are called for each frame if
+at least one window on that frame has been added, deleted or assigned
+another buffer, total or body size since the last time window change
+functions were run.  Each call is performed with the frame temporarily
+selected and the selected window's buffer current.
 @end defvar
 
address@hidden run-window-configuration-change-hook &optional frame
-This function runs @code{window-configuration-change-hook} for the
-specified @var{frame}, which defaults to the selected frame.
+Window change functions are called at the end of redisplay for each
+frame as follows: First, any buffer-local window buffer change
+function, window size change function and selected window change
+functions are called in this order.  Next, the default values for
+these functions are called in the same order.  Then any buffer-local
+window configuration change functions are called followed by functions
+specified by the default value of those functions.
+
+   Window change functions are run for a specific frame only if a
+corresponding change was registered for that frame earlier.  Such
+changes include the creation or deletion of a window or the assignment
+of another buffer or size to a window.  Note that even when such a
+change has been registered, this does not mean that any of the hooks
+described above is run.  If, for example, a change was registered
+within the scope of a window excursion (@pxref{Window
+Configurations}), this will trigger a call of window change functions
+only if that excursion still persists at the time change functions are
+run.  If it is exited earlier, hooks will be run only if registered by
+a change outside the scope of that excursion.
+
+   While window change functions are run, the functions described next
+can be called to get more insight into what has changed for a specific
+window or frame since the last redisplay.  All these functions take a
+live window as single, optional argument, defaulting to the selected
+window.
+
address@hidden window-old-buffer &optional window
+This function returns the buffer shown in @var{window} at the last
+time window change functions were run for @var{window}'s frame.  If it
+returns @code{nil}, @var{window} has been created after that.  If it
+returns @code{t}, @var{window} was not shown at that time but has been
+restored from a previously saved window configuration afterwards.
+Otherwise, the return value is the buffer shown by @code{window} at
+that time.
 @end defun
 
-  In addition, you can use @code{jit-lock-register} to register a Font
-Lock fontification function, which will be called whenever parts of a
-buffer are (re)fontified because a window was scrolled or its size
-changed.  @xref{Other Font Lock Variables}.
address@hidden window-old-pixel-width &optional window
+This function returns the total pixel width of @var{window} the
+last time window change functions found @code{window} live on its
+frame.  It is zero if @code{window} was created after that.
address@hidden defun
+
address@hidden window-old-pixel-height &optional window
+This function returns the total pixel height of @var{window} the last
+time window change functions found @code{window} live on its frame.
+It is zero if @code{window} was created after that.
address@hidden defun
+
address@hidden window-old-body-pixel-width &optional window
+This function returns the pixel width of @var{window}'s text area the
+last time window change functions found @code{window} live on its
+frame.  It is zero if @code{window} was created after that.
address@hidden defun
+
address@hidden window-old-body-pixel-height &optional window
+This function returns the pixel height of @var{window}'s text area the
+last time window change functions found @code{window} live on its
+frame.  It is zero if @code{window} was created after that.
address@hidden defun
+
+In order to find out which window or frame was selected the last time
+window change functions were run, the following functions can be used:
+
address@hidden frame-old-selected-window &optional frame
+This function returns the selected window of @var{frame} at the last
+time window change functions were run.  If omitted or @code{nil}
address@hidden defaults to the selected frame.
address@hidden defun
+
address@hidden old-selected-window
+This function returns the selected window at the last time window
+change functions were run.
address@hidden defun
+
address@hidden old-selected-frame
+This function returns the selected frame at the last time window
+change functions were run.
address@hidden defun
+
+Note that window change functions provide no information about which
+windows have been deleted since the last time they were run.  If
+necessary, an application should remember any window showing a
+specific buffer in a local variable of that buffer and update it in a
+function run by the default value of
address@hidden or
address@hidden (the only hooks triggered by
+the deletion of windows).
+
+   The following caveats should be considered when adding a function
+to window change functions:
+
address@hidden @bullet
address@hidden
+Some operations will not trigger a call of window change functions.
+These include showing another buffer in a minibuffer window or any
+change of a tooltip window.
+
address@hidden
+Window change functions should not create or delete windows or change
+the buffer, size or selection status of any window because there is no
+guarantee that the information about such a change will be propagated
+to other window change functions.  If at all, any such change should
+be executed only by the last function listed by the default value of
address@hidden
+
address@hidden
+Macros like @code{save-window-excursion}, @code{with-selected-window}
+or @code{with-current-buffer} can be used when running window change
+functions.
+
address@hidden
+Running window change functions does not save and restore match data.
+Unless running @code{window-configuration-change-hook} it does not
+save or restore the selected window or frame or the current buffer
+either.
+
address@hidden
+Any redisplay triggering the run of window change functions may be
+aborted.  If the abort occurs before window change functions have run
+to their completion, they will be run again with the previous values,
+that is, as if redisplay had not been performed.  If aborted later,
+they will be run with the new values, that is, as if redisplay had
+been actually performed.
address@hidden itemize
diff --git a/etc/CENSORSHIP b/etc/CENSORSHIP
deleted file mode 100644
index cd779e4..0000000
--- a/etc/CENSORSHIP
+++ /dev/null
@@ -1,8 +0,0 @@
-Censoring my Software
-
-Note added March 2014:
-
-This file is obsolete and will be removed in future.
-Please update any references to use
-
-<https://www.gnu.org/philosophy/censoring-emacs.html>
diff --git a/etc/FTP b/etc/FTP
deleted file mode 100644
index ebd2695..0000000
--- a/etc/FTP
+++ /dev/null
@@ -1,9 +0,0 @@
-For information about how to download GNU Emacs, please see:
-<https://www.gnu.org/software/emacs/>
-
-For general GNU software downloading, please see
-<https://www.gnu.org/order/ftp.html>
-
-Note added January 2014:
-This file is obsolete and will be removed in future.
-Please update any links to use the above URLs.
diff --git a/etc/GNU b/etc/GNU
deleted file mode 100644
index f8078d4..0000000
--- a/etc/GNU
+++ /dev/null
@@ -1,8 +0,0 @@
-The GNU Manifesto
-
-Note added March 2014:
-
-This file is obsolete and will be removed in future.
-Please update any references to use
-  info node `(emacs)Manifesto'
-instead.
diff --git a/etc/LINUX-GNU b/etc/LINUX-GNU
deleted file mode 100644
index 0f45e15..0000000
--- a/etc/LINUX-GNU
+++ /dev/null
@@ -1,8 +0,0 @@
-Linux and the GNU system
-
-Note added March 2014:
-
-This file is obsolete and will be removed in future.
-Please update any references to use
-
-<https://www.gnu.org/gnu/linux-and-gnu.html>
diff --git a/etc/MORE.STUFF b/etc/MORE.STUFF
deleted file mode 100644
index e3f2c16..0000000
--- a/etc/MORE.STUFF
+++ /dev/null
@@ -1,8 +0,0 @@
-More Neat Stuff for your Emacs
-
-Note added January 2014:
-
-This file is obsolete and will be removed in future.
-Please update any links to use
-  info node `(efaq)Packages that do not come with Emacs'
-instead.
diff --git a/etc/NEWS b/etc/NEWS
index a96ec78..bb214f2 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1283,9 +1283,30 @@ displaying the same buffer.  See the node "(elisp) Face 
Remapping"
 of the Emacs Lisp Reference manual for more detail.
 
 +++
-** Special handling of buffer-local 'window-size-change-functions'.
-A buffer-local value of this hook is now run only if at least one
-window showing the buffer has changed its size.
+** Window change functions have been redesigned completely.
+Hooks reacting to window changes run now only when redisplay detects
+that a change has actually occurred.  The four hooks provided are:
+'window-buffer-change-functions' (run after window buffers have
+changed), 'window-size-change-functions' (run after a window was
+assigned a new buffer or size), 'window-configuration-change-hook'
+(like the former but run also when a window was deleted) and
+'window-selection-change-functions' (run when the selected window
+changed).  'window-scroll-functions' are unaffected by these changes.
+
+In addition, a number of functions now allow the caller to detect what
+has changed since last redisplay: 'window-old-buffer' returns for any
+window the buffer it showed at that time.  ‘old-selected-window’ and
+'old-selected-frame' return the window and frame that were selected
+during last redisplay.  'window-old-pixel-width' (renamed from
+'window-pixel-width-before-size-change'), 'window-old-pixel-height'
+(renamed from 'window-pixel-height-before-size-change'),
+'window-old-body-pixel-width' and 'window-old-body-pixel-height'
+return the total and body sizes of any window during last redisplay.
+
+One consequence of these changes is that all window change functions
+run now after functions run by 'post-command-hook'.  See the section
+"(elisp) Window Hooks" in the Elisp manual for a detailed explanation
+of the new behavior.
 
 +++
 ** New buffer display action alist entry 'dedicated'.
diff --git a/etc/ORDERS b/etc/ORDERS
deleted file mode 100644
index 1df755d..0000000
--- a/etc/ORDERS
+++ /dev/null
@@ -1,8 +0,0 @@
-Printed copies of Emacs manuals
-
-Note added January 2014:
-
-This file is obsolete and will be removed in future.
-Please update any links to use
-  info node `(emacs)Printed Books'
-instead.
diff --git a/etc/THE-GNU-PROJECT b/etc/THE-GNU-PROJECT
deleted file mode 100644
index d2aa155..0000000
--- a/etc/THE-GNU-PROJECT
+++ /dev/null
@@ -1,8 +0,0 @@
-The GNU Project
-
-Note added March 2014:
-
-This file is obsolete and will be removed in future.
-Please update any references to use
-
-<https://www.gnu.org/gnu/thegnuproject.html>
diff --git a/etc/WHY-FREE b/etc/WHY-FREE
deleted file mode 100644
index cd2c2fc..0000000
--- a/etc/WHY-FREE
+++ /dev/null
@@ -1,8 +0,0 @@
-Why Software Should Not Have Owners
-
-Note added March 2014:
-
-This file is obsolete and will be removed in future.
-Please update any references to use
-
-<https://www.gnu.org/philosophy/why-free.html>
diff --git a/lisp/erc/erc-track.el b/lisp/erc/erc-track.el
index c966cf8..f42bd64 100644
--- a/lisp/erc/erc-track.el
+++ b/lisp/erc/erc-track.el
@@ -640,7 +640,7 @@ only consider active buffers visible.")
   (unless (minibuffer-window-active-p (minibuffer-window))
     ;; delay this until command has finished to make sure window is
     ;; actually visible before clearing activity
-    (add-hook 'post-command-hook 'erc-modified-channels-update)))
+    (erc-modified-channels-update)))
 
 (defvar erc-modified-channels-update-inside nil
   "Variable to prevent running `erc-modified-channels-update' multiple
@@ -669,8 +669,7 @@ ARGS are ignored."
                  (erc-modified-channels-remove-buffer buffer))))
            erc-modified-channels-alist)
       (when removed-channel
-       (erc-modified-channels-display)))
-    (remove-hook 'post-command-hook 'erc-modified-channels-update)))
+       (erc-modified-channels-display)))))
 
 (defvar erc-track-mouse-face (if (featurep 'xemacs)
                                 'modeline-mousable
diff --git a/lisp/frame.el b/lisp/frame.el
index 8341ba1..dc81302 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -1745,20 +1745,17 @@ for FRAME."
   (let* ((frame (window-normalize-frame frame))
          (root (frame-root-window frame))
          (mini (minibuffer-window frame))
-         (mini-height-before-size-change 0)
+         (mini-old-height 0)
          (mini-height 0))
     ;; FRAME's minibuffer window counts iff it's on FRAME and FRAME is
     ;; not a minibuffer-only frame.
     (when (and (eq (window-frame mini) frame) (not (eq mini root)))
-      (setq mini-height-before-size-change
-            (window-pixel-height-before-size-change mini))
+      (setq mini-old-height (window-old-pixel-height mini))
       (setq mini-height (window-pixel-height mini)))
     ;; Return non-nil when either the width of the root or the sum of
     ;; the heights of root and minibuffer window changed.
-    (or (/= (window-pixel-width-before-size-change root)
-            (window-pixel-width root))
-        (/= (+ (window-pixel-height-before-size-change root)
-               mini-height-before-size-change)
+    (or (/= (window-old-pixel-width root) (window-pixel-width root))
+        (/= (+ (window-old-pixel-height root) mini-old-height)
             (+ (window-pixel-height root) mini-height)))))
 
 ;;;; Frame/display capabilities.
diff --git a/lisp/help.el b/lisp/help.el
index 5fa1876..d1f4735 100644
--- a/lisp/help.el
+++ b/lisp/help.el
@@ -425,13 +425,11 @@ is specified by the variable `message-log-max'."
 (defun view-order-manuals ()
   "Display information on how to buy printed copies of Emacs manuals."
   (interactive)
-;;  (view-help-file "ORDERS")
   (info "(emacs)Printed Books"))
 
 (defun view-emacs-FAQ ()
   "Display the Emacs Frequently Asked Questions (FAQ) file."
   (interactive)
-  ;; (find-file-read-only (expand-file-name "FAQ" data-directory))
   (info "(efaq)"))
 
 (defun view-emacs-problems ()
@@ -444,7 +442,8 @@ is specified by the variable `message-log-max'."
   (interactive)
   (view-help-file "DEBUG"))
 
-;; This used to visit MORE.STUFF; maybe it should just be removed.
+;; This used to visit a plain text file etc/MORE.STUFF;
+;; maybe this command should just be removed.
 (defun view-external-packages ()
   "Display info on where to get more Emacs packages."
   (interactive)
diff --git a/lisp/net/rcirc.el b/lisp/net/rcirc.el
index 8635546..47681cc 100644
--- a/lisp/net/rcirc.el
+++ b/lisp/net/rcirc.el
@@ -2064,9 +2064,7 @@ activity.  Only run if the buffer is not visible and
 (defvar rcirc-visible-buffers nil)
 (defun rcirc-window-configuration-change ()
   (unless (minibuffer-window-active-p (minibuffer-window))
-    ;; delay this until command has finished to make sure window is
-    ;; actually visible before clearing activity
-    (add-hook 'post-command-hook 'rcirc-window-configuration-change-1)))
+    (rcirc-window-configuration-change-1)))
 
 (defun rcirc-window-configuration-change-1 ()
   ;; clear activity and overlay arrows
@@ -2090,9 +2088,7 @@ activity.  Only run if the buffer is not visible and
                            rcirc-activity)))
     ;; update the mode-line string
     (unless (equal old-activity rcirc-activity)
-      (rcirc-update-activity-string)))
-
-  (remove-hook 'post-command-hook 'rcirc-window-configuration-change-1))
+      (rcirc-update-activity-string))))
 
 
 ;;; buffer name abbreviation
diff --git a/lisp/progmodes/sql.el b/lisp/progmodes/sql.el
index ebde684..6ad2212 100644
--- a/lisp/progmodes/sql.el
+++ b/lisp/progmodes/sql.el
@@ -2668,13 +2668,17 @@ argument must be a plist keyword accepted by
 
   (let* ((p (assoc product sql-product-alist))
          (v (plist-get (cdr p) feature)))
-    (if p
+    (if (and p v)
         (if (and
              (member feature sql-indirect-features)
              (symbolp v))
             (set v newvalue)
           (setcdr p (plist-put (cdr p) feature newvalue)))
-      (error "`%s' is not a known product; use `sql-add-product' to add it 
first." product))))
+      (progn
+       (when (null p)
+         (error "`%s' is not a known product; use `sql-add-product' to add it 
first." product))
+       (when (null v)
+         (error "`%s' is not a known feature for `%s'; use `sql-add-product' 
to add it first." feature product))))))
 
 (defun sql-get-product-feature (product feature &optional fallback 
not-indirect)
   "Lookup FEATURE associated with a SQL PRODUCT.
diff --git a/lisp/window.el b/lisp/window.el
index 751263c..424d052 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -2043,6 +2043,8 @@ doc-string of `window-resizable'."
 ;; Aliases of functions defined in window.c.
 (defalias 'window-height 'window-total-height)
 (defalias 'window-width 'window-body-width)
+(defalias 'window-pixel-width-before-size-change 'window-old-pixel-width)
+(defalias 'window-pixel-height-before-size-change 'window-old-pixel-height)
 
 (defun window-full-height-p (&optional window)
   "Return t if WINDOW is as high as its containing frame.
@@ -2759,8 +2761,7 @@ as small) as possible, but don't signal an error."
        ;; The following routine catches the case where we want to resize
        ;; a minibuffer-only frame.
        (when (resize-mini-window-internal window)
-         (window--pixel-to-total frame)
-         (run-window-configuration-change-hook frame))))))
+         (window--pixel-to-total frame))))))
 
 (defun window--resize-apply-p (frame &optional horizontal)
   "Return t when a window on FRAME shall be resized vertically.
@@ -2858,9 +2859,7 @@ instead."
        (window--resize-siblings window delta horizontal ignore))
       (when (window--resize-apply-p frame horizontal)
        (if (window-resize-apply frame horizontal)
-           (progn
-             (window--pixel-to-total frame horizontal)
-             (run-window-configuration-change-hook frame))
+           (window--pixel-to-total frame horizontal)
          (error "Failed to apply resizing %s" window))))
      (t
       (error "Cannot resize window %s" window)))))
@@ -3579,9 +3578,7 @@ move it as far as possible in the desired direction."
        ;; Don't report an error in the standard case.
        (when (window--resize-apply-p frame horizontal)
          (if (window-resize-apply frame horizontal)
-             (progn
-               (window--pixel-to-total frame horizontal)
-               (run-window-configuration-change-hook frame))
+             (window--pixel-to-total frame horizontal)
            ;; But do report an error if applying the changes fails.
            (error "Failed adjusting window %s" window))))))))
 
@@ -4112,7 +4109,6 @@ that is its frame's root window."
          ;; `delete-window-internal' has selected a window that should
          ;; not be selected, fix this here.
          (other-window -1 frame))
-       (run-window-configuration-change-hook frame)
        (window--check frame)
        ;; Always return nil.
        nil))))
@@ -4198,7 +4194,6 @@ any window whose `no-delete-other-windows' parameter is 
non-nil."
       ;; If WINDOW is the main window of its frame do nothing.
       (unless (eq window main)
        (delete-other-windows-internal window main)
-       (run-window-configuration-change-hook frame)
        (window--check frame))
       ;; Always return nil.
       nil)))
@@ -5186,7 +5181,6 @@ frame.  The selected window is not changed by this 
function."
          (unless size
             (window--sanitize-window-sizes horizontal))
 
-         (run-window-configuration-change-hook frame)
          (run-window-scroll-functions new)
          (window--check frame)
          ;; Always return the new window.
@@ -5417,15 +5411,13 @@ window."
     (balance-windows-1 window)
     (when (window--resize-apply-p frame)
       (window-resize-apply frame)
-      (window--pixel-to-total frame)
-      (run-window-configuration-change-hook frame))
+      (window--pixel-to-total frame))
     ;; Balance horizontally.
     (window--resize-reset (window-frame window) t)
     (balance-windows-1 window t)
     (when (window--resize-apply-p frame t)
       (window-resize-apply frame t)
-      (window--pixel-to-total frame t)
-      (run-window-configuration-change-hook frame))))
+      (window--pixel-to-total frame t))))
 
 (defun window-fixed-size-p (&optional window direction)
   "Return t if WINDOW cannot be resized in DIRECTION.
@@ -9441,15 +9433,7 @@ displaying that processes's buffer."
               (when size
                 (set-process-window-size process (cdr size) (car size))))))))))
 
-;; Remove the following call in Emacs 27, running
-;; 'window-size-change-functions' should suffice.
 (add-hook 'window-configuration-change-hook 'window--adjust-process-windows)
-
-;; Catch any size changes not handled by
-;; 'window-configuration-change-hook' (Bug#32720, "another issue" in
-;; Bug#33230).
-(add-hook 'window-size-change-functions (lambda (_frame)
-                                          (window--adjust-process-windows)))
 
 ;; Some of these are in tutorial--default-keys, so update that if you
 ;; change these.
diff --git a/src/alloc.c b/src/alloc.c
index 407ac72..31e8da7 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -2774,6 +2774,19 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0,
     {
       if (cons_block_index == CONS_BLOCK_SIZE)
        {
+         /* Maximum number of conses that should be active at any
+            given time, so that list lengths fit into a ptrdiff_t and
+            into a fixnum.  */
+         ptrdiff_t max_conses = min (PTRDIFF_MAX, MOST_POSITIVE_FIXNUM);
+
+         /* This check is typically optimized away, as a runtime
+            check is needed only on weird platforms where a count of
+            distinct conses might not fit.  */
+         if (max_conses < INTPTR_MAX / sizeof (struct Lisp_Cons)
+             && (max_conses - CONS_BLOCK_SIZE
+                 < total_free_conses + total_conses))
+           memory_full (sizeof (struct cons_block));
+
          struct cons_block *new
            = lisp_align_malloc (sizeof *new, MEM_TYPE_CONS);
          memset (new->gcmarkbits, 0, sizeof new->gcmarkbits);
diff --git a/src/dispextern.h b/src/dispextern.h
index b064875..9cea321 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -32,7 +32,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #endif /* USE_X_TOOLKIT */
 
 #ifdef HAVE_XRENDER
-#include <X11/extensions/Xrender.h>
+# include <X11/extensions/Xrender.h>
 #endif
 #else /* !HAVE_X_WINDOWS */
 
@@ -2938,10 +2938,9 @@ struct redisplay_interface
 
 #ifdef HAVE_WINDOW_SYSTEM
 
-#if defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER) \
-  || defined (HAVE_NS)
-#define HAVE_NATIVE_SCALING
-#endif
+# if defined HAVE_XRENDER || defined HAVE_NS
+#  define HAVE_NATIVE_SCALING
+# endif
 
 /* Structure describing an image.  Specific image formats like XBM are
    converted into this form, so that display only has to deal with
@@ -2967,10 +2966,10 @@ struct image
      synchronized to Pixmap.  */
   XImagePtr ximg, mask_img;
 
-#ifdef HAVE_NATIVE_SCALING
+# ifdef HAVE_NATIVE_SCALING
   /* Picture versions of pixmap and mask for compositing.  */
   Picture picture, mask_picture;
-#endif
+# endif
 #endif
 
   /* Colors allocated for this image, if any.  Allocated via xmalloc.  */
diff --git a/src/fns.c b/src/fns.c
index 0fad6f4..6fcb38e 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -101,9 +101,7 @@ list_length (Lisp_Object list)
   FOR_EACH_TAIL (list)
     i++;
   CHECK_LIST_END (list, list);
-  if (i <= min (PTRDIFF_MAX, MOST_POSITIVE_FIXNUM))
-    return i;
-  overflow_error ();
+  return i;
 }
 
 
@@ -141,14 +139,13 @@ DEFUN ("safe-length", Fsafe_length, Ssafe_length, 1, 1, 0,
        doc: /* Return the length of a list, but avoid error or infinite loop.
 This function never gets an error.  If LIST is not really a list,
 it returns 0.  If LIST is circular, it returns an integer that is at
-least the number of distinct elements.
-Value is a fixnum, if it's small enough, otherwise a bignum.  */)
+least the number of distinct elements.  */)
   (Lisp_Object list)
 {
   intptr_t len = 0;
   FOR_EACH_TAIL_SAFE (list)
     len++;
-  return INT_TO_INTEGER (len);
+  return make_fixnum (len);
 }
 
 DEFUN ("proper-list-p", Fproper_list_p, Sproper_list_p, 1, 1, 0,
@@ -168,8 +165,6 @@ A proper list is neither circular nor dotted (i.e., its 
last cdr is nil).  */
     }
   if (!NILP (last_tail))
     return Qnil;
-  if (MOST_POSITIVE_FIXNUM < len)
-    overflow_error ();
   return make_fixnum (len);
 }
 
diff --git a/src/frame.c b/src/frame.c
index ca6704a..6d93abd 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -55,9 +55,11 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #endif
 
 /* The currently selected frame.  */
-
 Lisp_Object selected_frame;
 
+/* The selected frame the last time window change functions were run.  */
+Lisp_Object old_selected_frame;
+
 /* A frame which is not just a mini-buffer, or NULL if there are no such
    frames.  This is usually the most recent such frame that was selected.  */
 
@@ -855,7 +857,8 @@ make_frame (bool mini_p)
   f->ns_transparent_titlebar = false;
 #endif
 #endif
-
+  /* This one should never be zero.  */
+  f->change_stamp = 1;
   root_window = make_window ();
   rw = XWINDOW (root_window);
   if (mini_p)
@@ -1451,7 +1454,8 @@ This function returns FRAME, or nil if FRAME has been 
deleted.  */)
   return do_switch_frame (frame, 1, 0, norecord);
 }
 
-DEFUN ("handle-switch-frame", Fhandle_switch_frame, Shandle_switch_frame, 1, 
1, "^e",
+DEFUN ("handle-switch-frame", Fhandle_switch_frame,
+       Shandle_switch_frame, 1, 1, "^e",
        doc: /* Handle a switch-frame event EVENT.
 Switch-frame events are usually bound to this function.
 A switch-frame event is an event Emacs sends itself to
@@ -1471,6 +1475,18 @@ DEFUN ("selected-frame", Fselected_frame, 
Sselected_frame, 0, 0, 0,
 {
   return selected_frame;
 }
+
+DEFUN ("old-selected-frame", Fold_selected_frame,
+       Sold_selected_frame, 0, 0, 0,
+       doc: /* Return the old selected FRAME.
+FRAME must be a live frame and defaults to the selected one.
+
+The return value is the frame selected the last time window change
+functions were run.  */)
+  (void)
+{
+  return old_selected_frame;
+}
 
 DEFUN ("frame-list", Fframe_list, Sframe_list,
        0, 0, 0,
@@ -6098,9 +6114,10 @@ iconify the top level frame instead.  */);
   defsubr (&Swindow_system);
   defsubr (&Sframe_windows_min_size);
   defsubr (&Smake_terminal_frame);
-  defsubr (&Shandle_switch_frame);
   defsubr (&Sselect_frame);
+  defsubr (&Shandle_switch_frame);
   defsubr (&Sselected_frame);
+  defsubr (&Sold_selected_frame);
   defsubr (&Sframe_list);
   defsubr (&Sframe_parent);
   defsubr (&Sframe_ancestor_p);
diff --git a/src/frame.h b/src/frame.h
index b705902..ab3efdf 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -125,6 +125,10 @@ struct frame
      The selected window of the selected frame is Emacs's selected window.  */
   Lisp_Object selected_window;
 
+  /* This frame's selected window when run_window_change_functions was
+     called the last time on this frame.  */
+  Lisp_Object old_selected_window;
+
   /* This frame's minibuffer window.
      Most frames have their own minibuffer windows,
      but only the selected frame's minibuffer window
@@ -321,9 +325,14 @@ struct frame
      cleared.  */
   bool_bf explicit_name : 1;
 
-  /* True if configuration of windows on this frame has changed since
-     last call of run_window_size_change_functions.  */
-  bool_bf window_configuration_changed : 1;
+  /* True if at least one window on this frame changed since the last
+     call of run_window_change_functions.  Changes are either "state
+     changes" (a window has been created, deleted or got assigned
+     another buffer) or "size changes" (the total or body size of a
+     window changed).  run_window_change_functions exits early unless
+     either this flag is true or a window selection happened on this
+     frame.  */
+  bool_bf window_change : 1;
 
   /* True if the mouse has moved on this display device
      since the last time we checked.  */
@@ -406,6 +415,20 @@ struct frame
 
   /* Bitfield area ends here.  */
 
+  /* This frame's change stamp, set the last time window change
+     functions were run for this frame.  Should never be 0 because
+     that's the change stamp of a new window.  A window was not on a
+     frame the last run_window_change_functions was called on it if
+     it's change stamp differs from that of its frame.  */
+  int change_stamp;
+
+  /* This frame's number of windows, set the last time window change
+     functions were run for this frame.  Should never be 0 even for
+     minibuffer-only frames.  If no window has been added, this allows
+     to detect whether a window was deleted on this frame since the
+     last time run_window_change_functions was called on it.  */
+  ptrdiff_t number_of_windows;
+
   /* Number of lines (rounded up) of tool bar.  REMOVE THIS  */
   int tool_bar_lines;
 
@@ -662,6 +685,11 @@ fset_selected_window (struct frame *f, Lisp_Object val)
   f->selected_window = val;
 }
 INLINE void
+fset_old_selected_window (struct frame *f, Lisp_Object val)
+{
+  f->old_selected_window = val;
+}
+INLINE void
 fset_title (struct frame *f, Lisp_Object val)
 {
   f->title = val;
@@ -908,10 +936,9 @@ default_pixels_per_inch_y (void)
    are frozen on frame F.  */
 #define FRAME_WINDOWS_FROZEN(f) (f)->frozen_window_starts
 
-/* True if the frame's window configuration has changed since last call
-   of run_window_size_change_functions.  */
-#define FRAME_WINDOW_CONFIGURATION_CHANGED(f)  \
-  (f)->window_configuration_changed
+/* True if at least one window changed on frame F since the last time
+   window change functions were run on F.  */
+#define FRAME_WINDOW_CHANGE(f) (f)->window_change
 
 /* The minibuffer window of frame F, if it has one; otherwise nil.  */
 #define FRAME_MINIBUF_WINDOW(f) f->minibuffer_window
@@ -919,8 +946,10 @@ default_pixels_per_inch_y (void)
 /* The root window of the window tree of frame F.  */
 #define FRAME_ROOT_WINDOW(f) f->root_window
 
-/* The currently selected window of the window tree of frame F.  */
+/* The currently selected window of frame F.  */
 #define FRAME_SELECTED_WINDOW(f) f->selected_window
+/* The old selected window of frame F.  */
+#define FRAME_OLD_SELECTED_WINDOW(f) f->old_selected_window
 
 #define FRAME_INSERT_COST(f) (f)->insert_line_cost
 #define FRAME_DELETE_COST(f) (f)->delete_line_cost
@@ -1215,6 +1244,7 @@ SET_FRAME_VISIBLE (struct frame *f, int v)
   (f)->iconified = (eassert (0 <= (i) && (i) <= 1), (i))
 
 extern Lisp_Object selected_frame;
+extern Lisp_Object old_selected_frame;
 
 #if ! (defined USE_GTK || defined HAVE_NS)
 extern int frame_default_tool_bar_height;
diff --git a/src/image.c b/src/image.c
index 84c31dc..2fae105 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1859,47 +1859,48 @@ compute_image_size (size_t width, size_t height,
   *d_width = desired_width;
   *d_height = desired_height;
 }
+#endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_SCALING */
 
-#ifdef HAVE_NATIVE_SCALING
 static void
 x_set_image_size (struct frame *f, struct image *img)
 {
-#ifdef HAVE_IMAGEMAGICK
+#ifdef HAVE_NATIVE_SCALING
+# ifdef HAVE_IMAGEMAGICK
   /* ImageMagick images are already the correct size.  */
-  if (!EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick))
-#endif
-    {
-      int width, height;
+  if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick))
+    return;
+# endif
 
-      compute_image_size (img->width, img->height, img->spec, &width, &height);
+  int width, height;
+  compute_image_size (img->width, img->height, img->spec, &width, &height);
 
-#ifdef HAVE_NS
-      ns_image_set_size (img->pixmap, width, height);
-      img->width = width;
-      img->height = height;
-#endif
+# ifdef HAVE_NS
+  ns_image_set_size (img->pixmap, width, height);
+  img->width = width;
+  img->height = height;
+# endif
 
-#ifdef HAVE_XRENDER
-      if (img->picture)
-      {
-        double xscale = (double) img->width/width;
-        double yscale = (double) img->height/height;
+# ifdef HAVE_XRENDER
+  if (img->picture)
+    {
+      double xscale = img->width / (double) width;
+      double yscale = img->height / (double) height;
 
-        XTransform tmat = {{{XDoubleToFixed (xscale), XDoubleToFixed (0), 
XDoubleToFixed (0)},
-                            {XDoubleToFixed (0), XDoubleToFixed (yscale), 
XDoubleToFixed (0)},
-                            {XDoubleToFixed (0), XDoubleToFixed (0), 
XDoubleToFixed (1)}}};
+      XTransform tmat
+       = {{{XDoubleToFixed (xscale), XDoubleToFixed (0), XDoubleToFixed (0)},
+           {XDoubleToFixed (0), XDoubleToFixed (yscale), XDoubleToFixed (0)},
+           {XDoubleToFixed (0), XDoubleToFixed (0), XDoubleToFixed (1)}}};
 
-        XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, 
FilterBest, 0, 0);
-        XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat);
+      XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest,
+                              0, 0);
+      XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat);
 
-        img->width = width;
-        img->height = height;
-      }
-#endif
+      img->width = width;
+      img->height = height;
     }
-}
+# endif
 #endif
-#endif /* HAVE_IMAGEMAGICK || HAVE_XRENDER || HAVE_NS  */
+}
 
 
 /* Return the id of image with Lisp specification SPEC on frame F.
@@ -1956,9 +1957,7 @@ lookup_image (struct frame *f, Lisp_Object spec)
             `:background COLOR'.  */
          Lisp_Object ascent, margin, relief, bg;
          int relief_bound;
-#ifdef HAVE_NATIVE_SCALING
           x_set_image_size (f, img);
-#endif
 
          ascent = image_spec_value (spec, QCascent, NULL);
          if (FIXNUMP (ascent))
@@ -2139,9 +2138,6 @@ x_create_x_image_and_pixmap (struct frame *f, int width, 
int height, int depth,
   Display *display = FRAME_X_DISPLAY (f);
   Drawable drawable = FRAME_X_DRAWABLE (f);
   Screen *screen = FRAME_X_SCREEN (f);
-#ifdef HAVE_XRENDER
-  int event_basep, error_basep;
-#endif
 
   eassert (input_blocked_p ());
 
@@ -2178,7 +2174,8 @@ x_create_x_image_and_pixmap (struct frame *f, int width, 
int height, int depth,
       return 0;
     }
 
-#ifdef HAVE_XRENDER
+# ifdef HAVE_XRENDER
+  int event_basep, error_basep;
   if (picture && XRenderQueryExtension (display, &event_basep, &error_basep))
     {
       XRenderPictFormat *format;
@@ -2191,7 +2188,7 @@ x_create_x_image_and_pixmap (struct frame *f, int width, 
int height, int depth,
                                           : PictStandardA8);
       *picture = XRenderCreatePicture (display, *pixmap, format, 0, &attr);
     }
-#endif
+# endif
 
   return 1;
 #endif /* HAVE_X_WINDOWS */
@@ -2367,14 +2364,13 @@ image_create_x_image_and_pixmap (struct frame *f, 
struct image *img,
 {
   eassert ((!mask_p ? img->pixmap : img->mask) == NO_PIXMAP);
 
-  return x_create_x_image_and_pixmap (f, width, height, depth, ximg,
-                                     !mask_p ? &img->pixmap : &img->mask,
+  Picture *picture = NULL;
 #ifdef HAVE_XRENDER
-                                      !mask_p ? &img->picture : 
&img->mask_picture
-#else
-                                      NULL
+  picture = !mask_p ? &img->picture : &img->mask_picture;
 #endif
-                                      );
+  return x_create_x_image_and_pixmap (f, width, height, depth, ximg,
+                                     !mask_p ? &img->pixmap : &img->mask,
+                                     picture);
 }
 
 /* Put X image XIMG into image IMG on frame F, as a mask if and only
diff --git a/src/window.c b/src/window.c
index 72185f9..0fc4f62 100644
--- a/src/window.c
+++ b/src/window.c
@@ -77,6 +77,11 @@ static void apply_window_adjustment (struct window *);
    FRAME_SELECTED_WINDOW (selected_frame).  */
 Lisp_Object selected_window;
 
+/* The value of selected_window at the last time window change
+   functions were run.  This is always the same as
+   FRAME_OLD_SELECTED_WINDOW (old_selected_frame).  */
+Lisp_Object old_selected_window;
+
 /* A list of all windows for use by next_window and Fwindow_list.
    Functions creating or deleting windows should invalidate this cache
    by setting it to nil.  */
@@ -304,6 +309,12 @@ wset_buffer (struct window *w, Lisp_Object val)
   adjust_window_count (w, 1);
 }
 
+static void
+wset_old_buffer (struct window *w, Lisp_Object val)
+{
+  w->old_buffer = val;
+}
+
 DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
        doc: /* Return t if OBJECT is a window and nil otherwise.  */)
   (Lisp_Object object)
@@ -428,6 +439,22 @@ return the selected window of that frame.  */)
   return window;
 }
 
+DEFUN ("frame-old-selected-window", Fframe_old_selected_window,
+       Sframe_old_selected_window, 0, 1, 0,
+       doc: /* Return old selected window of FRAME.
+FRAME must be a live frame and defaults to the selected one.
+
+The return value is the window selected on FRAME the last time window
+change functions were run for FRAME.  */)
+  (Lisp_Object frame)
+{
+  if (NILP (frame))
+    frame = selected_frame;
+  CHECK_LIVE_FRAME (frame);
+
+  return XFRAME (frame)->old_selected_window;
+}
+
 DEFUN ("set-frame-selected-window", Fset_frame_selected_window,
        Sset_frame_selected_window, 2, 3, 0,
        doc: /* Set selected window of FRAME to WINDOW.
@@ -465,6 +492,16 @@ selected windows appears and to which many commands apply. 
 */)
   return selected_window;
 }
 
+DEFUN ("old-selected-window", Fold_selected_window,
+       Sold_selected_window, 0, 0, 0,
+       doc: /* Return the old selected window.
+The return value is the window selected the last time window change
+functions were run.  */)
+  (void)
+{
+  return old_selected_window;
+}
+
 EMACS_INT window_select_count;
 
 /* If select_window is called with inhibit_point_swap true it will
@@ -597,9 +634,33 @@ Return nil for an internal window or a deleted window.  */)
   (Lisp_Object window)
 {
   struct window *w = decode_any_window (window);
+
   return WINDOW_LEAF_P (w) ? w->contents : Qnil;
 }
 
+DEFUN ("window-old-buffer", Fwindow_old_buffer, Swindow_old_buffer, 0, 1, 0,
+       doc: /* Return the old buffer displayed by WINDOW.
+WINDOW must be a live window and defaults to the selected one.
+
+The return value is the buffer shown in WINDOW at the last time window
+change functions were run.  It is nil if WINDOW was created after
+that.  It is t if WINDOW has been restored from a window configuration
+after that.  */)
+  (Lisp_Object window)
+{
+  struct window *w = decode_live_window (window);
+
+  return (NILP (w->old_buffer)
+         /* A new window.  */
+         ? Qnil
+         : (w->change_stamp != WINDOW_XFRAME (w)->change_stamp)
+         /* A window restored from a configuration.  */
+         ? Qt
+         /* A window that was live the last time seen by window
+            change functions.  */
+         : w->old_buffer);
+}
+
 DEFUN ("window-parent", Fwindow_parent, Swindow_parent, 0, 1, 0,
        doc: /* Return the parent window of window WINDOW.
 WINDOW must be a valid window and defaults to the selected one.
@@ -723,34 +784,32 @@ the height of the screen areas spanned by its children.  
*/)
   return make_fixnum (decode_valid_window (window)->pixel_height);
 }
 
-DEFUN ("window-pixel-width-before-size-change",
-       Fwindow_pixel_width_before_size_change,
-       Swindow_pixel_width_before_size_change, 0, 1, 0,
-       doc: /* Return pixel width of window WINDOW before last size changes.
+DEFUN ("window-old-pixel-width", Fwindow_old_pixel_width,
+       Swindow_old_pixel_width, 0, 1, 0,
+       doc: /* Return old total pixel width of WINDOW.
 WINDOW must be a valid window and defaults to the selected one.
 
-The return value is the pixel width of WINDOW at the last time
-`window-size-change-functions' was run.  It's zero if WINDOW was made
-after that.  */)
+The return value is the total pixel width of WINDOW after the last
+time window change functions found WINDOW live on its frame.  It is
+zero if WINDOW was created after that.  */)
   (Lisp_Object window)
 {
   return (make_fixnum
-         (decode_valid_window (window)->pixel_width_before_size_change));
+         (decode_valid_window (window)->old_pixel_width));
 }
 
-DEFUN ("window-pixel-height-before-size-change",
-       Fwindow_pixel_height_before_size_change,
-       Swindow_pixel_height_before_size_change, 0, 1, 0,
-       doc: /* Return pixel height of window WINDOW before last size changes.
+DEFUN ("window-old-pixel-height", Fwindow_old_pixel_height,
+       Swindow_old_pixel_height, 0, 1, 0,
+       doc: /* Return old total pixel height of WINDOW.
 WINDOW must be a valid window and defaults to the selected one.
 
-The return value is the pixel height of WINDOW at the last time
-`window-size-change-functions' was run.  It's zero if WINDOW was made
-after that.  */)
+The return value is the total pixel height of WINDOW after the last
+time window change functions found WINDOW live on its frame.  It is
+zero if WINDOW was created after that.  */)
   (Lisp_Object window)
 {
   return (make_fixnum
-         (decode_valid_window (window)->pixel_height_before_size_change));
+         (decode_valid_window (window)->old_pixel_height));
 }
 
 DEFUN ("window-total-height", Fwindow_total_height, Swindow_total_height, 0, 
2, 0,
@@ -984,6 +1043,26 @@ window_body_width (struct window *w, bool pixelwise)
              0);
 }
 
+DEFUN ("window-body-width", Fwindow_body_width, Swindow_body_width, 0, 2, 0,
+       doc: /* Return the width of WINDOW's text area.
+WINDOW must be a live window and defaults to the selected one.  Optional
+argument PIXELWISE non-nil means return the width in pixels.  The return
+value does not include any vertical dividers, fringes or marginal areas,
+or scroll bars.
+
+If PIXELWISE is nil, return the largest integer smaller than WINDOW's
+pixel width divided by the character width of WINDOW's frame.  This
+means that if a column at the right of the text area is only partially
+visible, that column is not counted.
+
+Note that the returned value includes the column reserved for the
+continuation glyph.  */)
+  (Lisp_Object window, Lisp_Object pixelwise)
+{
+  return make_fixnum (window_body_width (decode_live_window (window),
+                                        !NILP (pixelwise)));
+}
+
 DEFUN ("window-body-height", Fwindow_body_height, Swindow_body_height, 0, 2, 0,
        doc: /* Return the height of WINDOW's text area.
 WINDOW must be a live window and defaults to the selected one.  Optional
@@ -1001,24 +1080,34 @@ visible, that line is not counted.  */)
                                          !NILP (pixelwise)));
 }
 
-DEFUN ("window-body-width", Fwindow_body_width, Swindow_body_width, 0, 2, 0,
-       doc: /* Return the width of WINDOW's text area.
-WINDOW must be a live window and defaults to the selected one.  Optional
-argument PIXELWISE non-nil means return the width in pixels.  The return
-value does not include any vertical dividers, fringes or marginal areas,
-or scroll bars.
+DEFUN ("window-old-body-pixel-width",
+       Fwindow_old_body_pixel_width,
+       Swindow_old_body_pixel_width, 0, 1, 0,
+       doc: /* Return old width of WINDOW's text area in pixels.
+WINDOW must be a live window and defaults to the selected one.
 
-If PIXELWISE is nil, return the largest integer smaller than WINDOW's
-pixel width divided by the character width of WINDOW's frame.  This
-means that if a column at the right of the text area is only partially
-visible, that column is not counted.
+The return value is the pixel width of WINDOW's text area after the
+last time window change functions found WINDOW live on its frame.  It
+is zero if WINDOW was created after that.  */)
+  (Lisp_Object window)
+{
+  return (make_fixnum
+         (decode_live_window (window)->old_body_pixel_width));
+}
 
-Note that the returned value includes the column reserved for the
-continuation glyph.  */)
-  (Lisp_Object window, Lisp_Object pixelwise)
+DEFUN ("window-old-body-pixel-height",
+       Fwindow_old_body_pixel_height,
+       Swindow_old_body_pixel_height, 0, 1, 0,
+       doc: /* Return old height of WINDOW's text area in pixels.
+WINDOW must be a live window and defaults to the selected one.
+
+The return value is the pixel height of WINDOW's text area after the
+last time window change functions found WINDOW live on its frame.  It
+is zero if WINDOW was created after that.  */)
+  (Lisp_Object window)
 {
-  return make_fixnum (window_body_width (decode_live_window (window),
-                                        !NILP (pixelwise)));
+  return (make_fixnum
+         (decode_live_window (window)->old_body_pixel_height));
 }
 
 DEFUN ("window-mode-line-height", Fwindow_mode_line_height,
@@ -3264,7 +3353,7 @@ window-start value is reasonable when this function is 
called.  */)
   adjust_frame_glyphs (f);
   unblock_input ();
 
-  run_window_configuration_change_hook (f);
+  FRAME_WINDOW_CHANGE (f) = true;
 
   return Qnil;
 }
@@ -3318,6 +3407,15 @@ select_frame_norecord (Lisp_Object frame)
     Fselect_frame (frame, Qt);
 }
 
+/**
+ * run_window_configuration_change_hook:
+ *
+ * Run any functions on 'window-configuration-change-hook' for the
+ * frame specified by F.  The buffer-local values are run with the
+ * window showing the buffer selected.  The default value is run with
+ * the frame specified by F selected.  All functions are called with
+ * the selected window's buffer current.
+ */
 static void
 run_window_configuration_change_hook (struct frame *f)
 {
@@ -3371,7 +3469,10 @@ run_window_configuration_change_hook (struct frame *f)
 DEFUN ("run-window-configuration-change-hook", 
Frun_window_configuration_change_hook,
        Srun_window_configuration_change_hook, 0, 1, 0,
        doc: /* Run `window-configuration-change-hook' for FRAME.
-If FRAME is omitted or nil, it defaults to the selected frame.  */)
+If FRAME is omitted or nil, it defaults to the selected frame.
+
+This function should not be needed any more and will be therefore
+considered obsolete.  */)
   (Lisp_Object frame)
 {
   run_window_configuration_change_hook (decode_live_frame (frame));
@@ -3381,130 +3482,381 @@ If FRAME is omitted or nil, it defaults to the 
selected frame.  */)
 DEFUN ("run-window-scroll-functions", Frun_window_scroll_functions,
        Srun_window_scroll_functions, 0, 1, 0,
        doc: /* Run `window-scroll-functions' for WINDOW.
-If WINDOW is omitted or nil, it defaults to the selected window.  */)
+If WINDOW is omitted or nil, it defaults to the selected window.
+
+This function is curently only called by 'split-window' for the new
+window after it has established the size of the new window.  */)
   (Lisp_Object window)
 {
-  if (! NILP (Vwindow_scroll_functions))
+  struct window *w = decode_live_window (window);
+  ptrdiff_t count = SPECPDL_INDEX ();
+
+  record_unwind_current_buffer ();
+  Fset_buffer (w->contents);
+  if (!NILP (Vwindow_scroll_functions))
     run_hook_with_args_2 (Qwindow_scroll_functions, window,
-                         Fmarker_position (decode_live_window 
(window)->start));
+                         Fmarker_position (w->start));
+  unbind_to (count, Qnil);
+
   return Qnil;
 }
 
 
-/* Compare old and present pixel sizes of windows in tree rooted at W.
-   Return true iff any of these windows differs in size.  */
-
-static bool
-window_size_changed (struct window *w)
+/**
+ * window_sub_list:
+ *
+ * Return list of live windows constructed by traversing any window
+ * sub-tree rooted at WINDOW in preorder followed by right siblings of
+ * WINDOW.  Called from outside with second argument WINDOWS nil.  The
+ * returned list is in reverse order.
+ */
+static Lisp_Object
+window_sub_list (Lisp_Object window, Lisp_Object windows)
 {
-  if (w->pixel_width != w->pixel_width_before_size_change
-      || w->pixel_height != w->pixel_height_before_size_change)
-    return true;
 
-  if (WINDOW_INTERNAL_P (w))
+  struct window *w = XWINDOW (window);
+
+  while (w)
     {
-      w = XWINDOW (w->contents);
-      while (w)
-       {
-         if (window_size_changed (w))
-           return true;
+      if (WINDOW_INTERNAL_P (w))
+       windows = window_sub_list (w->contents, windows);
+      else
+       windows = Fcons (window, windows);
 
-         w = NILP (w->next) ? 0 : XWINDOW (w->next);
-       }
+      window = w->next;
+      w = NILP (window) ? 0 : XWINDOW (window);
     }
 
-  return false;
+  return windows;
 }
 
-/* Set before size change pixel sizes of windows in tree rooted at W to
-   their present pixel sizes.  */
 
-static void
-window_set_before_size_change_sizes (struct window *w)
+/**
+ * window_change_record_windows:
+ *
+ * Record changes for all live windows found by traversing any window
+ * sub-tree rooted at WINDOW in preorder followed by any right
+ * siblings of WINDOW.  This sets the old buffer, old pixel and old
+ * body pixel sizes of each live window found to the respective
+ * current values.  It also sets the change stamp of each window found
+ * to STAMP.  Return the number of live windows found.
+ *
+ * When not called by itself recursively, WINDOW is its frame's root
+ * window, STAMP is the current change stamp of WINDOW's frame and
+ * NUMBER is 0.
+ */
+static ptrdiff_t
+window_change_record_windows (Lisp_Object window, int stamp, ptrdiff_t number)
 {
-  w->pixel_width_before_size_change = w->pixel_width;
-  w->pixel_height_before_size_change = w->pixel_height;
+  struct window *w = XWINDOW (window);
 
-  if (WINDOW_INTERNAL_P (w))
+  while (w)
     {
-      w = XWINDOW (w->contents);
-      while (w)
+      if (WINDOW_INTERNAL_P (w))
+       number = window_change_record_windows (w->contents, stamp, number);
+      else
        {
-         window_set_before_size_change_sizes (w);
-         w = NILP (w->next) ? 0 : XWINDOW (w->next);
+         number += 1;
+         w->change_stamp = stamp;
+         wset_old_buffer (w, w->contents);
+         w->old_pixel_width = w->pixel_width;
+         w->old_pixel_height = w->pixel_height;
+         w->old_body_pixel_width = window_body_width (w, true);
+         w->old_body_pixel_height = window_body_height (w, true);
        }
+
+      w = NILP (w->next) ? 0 : XWINDOW (w->next);
     }
+
+  return number;
 }
 
 
-void
-run_window_size_change_functions (Lisp_Object frame)
+/**
+ * window_change_record_frame:
+ *
+ * Record changes for FRAME.  This records FRAME's selected window,
+ * updates FRAME's change stamp, records the states of all live
+ * windows of FRAME via window_change_record_windows and resets
+ * FRAME's window_change flag.
+ */
+static void
+window_change_record_frame (Lisp_Object frame)
 {
   struct frame *f = XFRAME (frame);
-  struct window *r = XWINDOW (FRAME_ROOT_WINDOW (f));
 
-  if (NILP (Vrun_hooks)
-      || !(f->can_x_set_window_size)
-      || !(f->after_make_frame))
-    return;
+  /* Record selected window.  */
+  fset_old_selected_window (f, FRAME_SELECTED_WINDOW (f));
 
-  if (FRAME_WINDOW_CONFIGURATION_CHANGED (f)
-      /* Here we implicitly exclude the possibility that the height of
-        FRAME and its minibuffer window both change leaving the height
-        of FRAME's root window alone.  */
-      || window_size_changed (r))
-    {
-      Lisp_Object globals = Fdefault_value (Qwindow_size_change_functions);
-      Lisp_Object windows = Fwindow_list (frame, Qlambda, Qnil);
-      /* The buffers for which the local hook was already run.  */
-      Lisp_Object buffers = Qnil;
+  /* Bump up FRAME's change stamp.  If this wraps, make it 1 to avoid
+     that a new window (whose change stamp is always set to 0) gets
+     reported as "existing before".  */
+  f->change_stamp += 1;
+  if (f->change_stamp == 0)
+    f->change_stamp = 1;
 
-      for (; CONSP (windows); windows = XCDR (windows))
-       {
-         Lisp_Object window = XCAR (windows);
-         Lisp_Object buffer = Fwindow_buffer (window);
-
-         /* Run a buffer-local value only once for that buffer and
-            only if at least one window showing that buffer on FRAME
-            actually changed its size.  Note that the function is run
-            with FRAME as its argument and as such oblivious to the
-            window checked below.  */
-         if (window_size_changed (XWINDOW (window))
-             && !NILP (Flocal_variable_p (Qwindow_size_change_functions, 
buffer))
-             && NILP (Fmemq (buffer, buffers)))
-           {
-             Lisp_Object locals
-               = Fbuffer_local_value (Qwindow_size_change_functions, buffer);
+  /* Bump up the change stamps of all live windows on this frame so
+     the next call of this function can tell whether any of them
+     "existed before" and record state for each of these windows.  */
+  f->number_of_windows
+    = window_change_record_windows (f->root_window, f->change_stamp, 0);
 
-             while (CONSP (locals))
-               {
-                 if (!EQ (XCAR (locals), Qt))
-                   safe_call1 (XCAR (locals), frame);
-                 locals = XCDR (locals);
-               }
+  /* Reset our flag.  */
+  FRAME_WINDOW_CHANGE (f) = false;
+}
 
-             buffers = Fcons (buffer, buffers);
-           }
-       }
 
-      while (CONSP (globals))
+/**
+ * window_change_record:
+ *
+ * Record selected window in old_selected_window and selected frame in
+ * old_selected_frame.
+ */
+static void
+window_change_record (void)
+{
+  /* Strictly spoken we don't need old_selected_window at all - its
+     value is the old selected window of old_selected_frame.  */
+  old_selected_window = selected_window;
+  old_selected_frame = selected_frame;
+}
+
+
+/**
+ * run_window_change_functions_1:
+ *
+ * Run window change functions specified by SYMBOL with argument
+ * WINDOW_OR_FRAME.  If BUFFER is nil, WINDOW_OR_FRAME specifies a
+ * frame.  In this case, run the default value of SYMBOL.  Otherwise,
+ * WINDOW_OR_FRAME denotes a window showing BUFFER.  In this case, run
+ * the buffer local value of SYMBOL in BUFFER, if any.
+ */
+static void
+run_window_change_functions_1 (Lisp_Object symbol, Lisp_Object buffer,
+                              Lisp_Object window_or_frame)
+{
+  Lisp_Object funs = Qnil;
+
+  if (NILP (buffer))
+    funs = Fdefault_value (symbol);
+  else if (!NILP (Fassoc (symbol, BVAR (XBUFFER (buffer), local_var_alist),
+                         Qnil)))
+    /* Don't run global value buffer-locally.  */
+    funs = buffer_local_value (symbol, buffer);
+
+  while (CONSP (funs))
+    {
+      if (!EQ (XCAR (funs), Qt))
+       safe_call1 (XCAR (funs), window_or_frame);
+      funs = XCDR (funs);
+    }
+}
+
+
+/**
+ * run_window_change_functions:
+ *
+ * Run window change functions for each live frame.  This function
+ * must be called from a "safe" position in redisplay_internal.
+ *
+ * Do not run any functions for a frame whose window_change flag is
+ * nil and where no window selection happened since the last time this
+ * function was called.  Also, skip any tooltip frame.
+ *
+ * The change functions run are, in this order:
+ *
+ * 'window-buffer-change-functions' which are run for a window that
+ * changed its buffer or that was not shown the last time window
+ * change functions were run.  The default value is also run when a
+ * window was deleted since the last time window change functions were
+ * run.
+ *
+ * `window-size-change-functions' run for a window that changed its
+ * body or total size, a window that changed its buffer or a window
+ * that was not shown the last time window change functions were run.
+ *
+ * `window-selected-change-functions' run for a window that was
+ * (de-)selected since the last time window change functions were run.
+ *
+ * A buffer-local value of these functions is run if and only if the
+ * window for which the functions are run, currently shows the buffer.
+ * Each call gets one argument - the window showing the buffer.  This
+ * means that the buffer-local value of these functions may be called
+ * as many times at the buffer is shown on the frame.
+ *
+ * The default value of these functions is called only after all
+ * buffer-local values for all of these functions have been run.  Each
+ * such call receives one argument - the frame for which this function
+ * is run.
+ *
+ * After the three change functions cited above have been run in the
+ * indicated way, functions on 'window-configuration-change-hook' are
+ * run.  A buffer-local value is run if a window shows that buffer and
+ * has either changed its buffer or its body or total size or did not
+ * appear on this frame since the last time window change functions
+ * were run.  The functions are called without argument and the
+ * buffer's window selected.  The default value is run without
+ * argument and the frame for which the function is run selected.
+ *
+ * This function does not save and restore match data.  Any functions
+ * it calls are responsible for doing that themselves.
+ */
+void
+run_window_change_functions (void)
+{
+  Lisp_Object tail, frame;
+  bool selected_frame_change = !EQ (selected_frame, old_selected_frame);
+  ptrdiff_t count_outer = SPECPDL_INDEX ();
+
+  record_unwind_protect_void (window_change_record);
+
+  FOR_EACH_FRAME (tail, frame)
+    {
+      struct frame *f = XFRAME (frame);
+      Lisp_Object root = FRAME_ROOT_WINDOW (f);
+      bool frame_window_change = FRAME_WINDOW_CHANGE (f);
+      bool window_buffer_change, window_size_change;
+      bool frame_buffer_change = false, frame_size_change = false;
+      bool frame_selected_change
+       = (selected_frame_change
+          && (EQ (frame, old_selected_frame)
+              || EQ (frame, selected_frame)));
+      bool frame_selected_window_change
+       = !EQ (FRAME_OLD_SELECTED_WINDOW (f), FRAME_SELECTED_WINDOW (f));
+      bool window_deleted = false;
+      Lisp_Object windows;
+      ptrdiff_t number_of_windows;
+      ptrdiff_t count_inner = SPECPDL_INDEX ();
+
+      if (!f->can_x_set_window_size
+         || !f->after_make_frame
+         || FRAME_TOOLTIP_P (f)
+         || !(frame_window_change
+              || frame_selected_change
+              || frame_selected_window_change))
+       /* Either we cannot run hooks for this frame yet or no window
+          change has been reported for this frame since the last time
+          we ran window change functions on it.  */
+       continue;
+
+      /* Analyze windows and run buffer locals hooks in pre-order.  */
+      windows = Fnreverse (window_sub_list (root, Qnil));
+      number_of_windows = 0;
+
+      record_unwind_protect (window_change_record_frame, frame);
+
+      /* The following loop collects all data needed to tell whether
+        the default value of a hook shall be run and runs any buffer
+        local hooks right away.  */
+      for (; CONSP (windows); windows = XCDR (windows))
        {
-         if (!EQ (XCAR (globals), Qt))
-           safe_call1 (XCAR (globals), frame);
-         globals = XCDR (globals);
+         Lisp_Object window = XCAR (windows);
+         struct window *w = XWINDOW (window);
+         Lisp_Object buffer = WINDOW_BUFFER (w);
+
+         /* Count this window even if it has been deleted while
+            running a hook.  */
+         number_of_windows += 1;
+
+         if (!WINDOW_LIVE_P (window))
+           continue;
+
+         /* A "buffer change" means either the window's buffer
+            changed or the window was not part of this frame the last
+            time window change functions were run for it.  */
+         window_buffer_change =
+           (frame_window_change
+            && (!EQ (buffer, w->old_buffer)
+                || w->change_stamp != f->change_stamp));
+         /* A "size change" means either a buffer change or that the
+            total or body size of the window has changed.
+
+            Note: A buffer change implies a size change because either
+            this window didn't show the buffer before or this window
+            didn't show the buffer the last time the window change
+            functions were run.  In either case, an application
+            tracing size changes in a buffer-locally fashion might
+            want to be informed about that change.  */
+         window_size_change =
+           (frame_window_change
+            && (window_buffer_change
+                || w->pixel_width != w->old_pixel_width
+                || w->pixel_height != w->old_pixel_height
+                || window_body_width (w, true) != w->old_body_pixel_width
+                || window_body_height (w, true) != w->old_body_pixel_height));
+
+         /* The following two are needed when running the default
+            values for this frame below.  */
+         frame_buffer_change = frame_buffer_change || window_buffer_change;
+         frame_size_change = frame_size_change || window_size_change;
+
+         if (window_buffer_change)
+           run_window_change_functions_1
+             (Qwindow_buffer_change_functions, buffer, window);
+
+         if (window_size_change && WINDOW_LIVE_P (window))
+           run_window_change_functions_1
+             (Qwindow_size_change_functions, buffer, window);
+
+         /* This window's selection has changed when it it was
+            (de-)selected as its frame's or the globally selected
+            window.  */
+         if (((frame_selected_change
+               && (EQ (window, old_selected_window)
+                   || EQ (window, selected_window)))
+              || (frame_selected_window_change
+                  && (EQ (window, FRAME_OLD_SELECTED_WINDOW (f))
+                      || EQ (window, FRAME_SELECTED_WINDOW (f)))))
+             && WINDOW_LIVE_P (window))
+           run_window_change_functions_1
+             (Qwindow_selection_change_functions, buffer, window);
        }
 
-      window_set_before_size_change_sizes (r);
+      /* When the number of windows on a frame has decreased, at least
+        one window of that frame was deleted.  In that case, we want
+        to run the default buffer and configuration change hooks.  The
+        default size change hook is not necessarily run in that case,
+        but usually will be unless the deletion was "compensated" by
+        a reduction of the frame size or an increase of a minibuffer
+        window size.  */
+      window_deleted = number_of_windows < f->number_of_windows;
+      /* A frame changed buffers when one of its windows has changed
+        its buffer or at least one window was deleted.  */
+      if ((frame_buffer_change || window_deleted) && FRAME_LIVE_P (f))
+       run_window_change_functions_1
+         (Qwindow_buffer_change_functions, Qnil, frame);
+
+      /* A size change occurred when at least one of the frame's
+        windows has changed size.  */
+      if (frame_size_change && FRAME_LIVE_P (f))
+       run_window_change_functions_1
+         (Qwindow_size_change_functions, Qnil, frame);
+
+      /* A frame has changed its window selection when its selected
+        window has changed or when it was (de-)selected.  */
+      if ((frame_selected_change || frame_selected_window_change)
+         && FRAME_LIVE_P (f))
+       run_window_change_functions_1
+         (Qwindow_selection_change_functions, Qnil, frame);
+
+      /* A frame's configuration changed when one of its windows has
+        changed buffer or size or at least one window was deleted.  */
+      if ((frame_size_change || window_deleted) && FRAME_LIVE_P (f))
+       /* This will run any buffer local window configuration change
+          hook as well.  */
+       run_window_configuration_change_hook (f);
 
-      if (FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
-       /* Record size of FRAME's minibuffer window too.  */
-       window_set_before_size_change_sizes
-         (XWINDOW (FRAME_MINIBUF_WINDOW (f)));
+      if (!FRAME_LIVE_P (f))
+       continue;
 
-      FRAME_WINDOW_CONFIGURATION_CHANGED (f) = false;
+      /* Record changes (via window_change_record_frame) for this
+        frame, even when an unhandled error occurred.  */
+      unbind_to (count_inner, Qnil);
     }
-}
 
+  /* Record selected window and frame.  */
+  unbind_to (count_outer, Qnil);
+}
 
 /* Make WINDOW display BUFFER.  RUN_HOOKS_P means it's allowed
    to run hooks.  See make_frame for a case where it's not allowed.
@@ -3581,14 +3933,18 @@ set_window_buffer (Lisp_Object window, Lisp_Object 
buffer,
       apply_window_adjustment (w);
     }
 
-  if (run_hooks_p)
-    {
-      if (!NILP (Vwindow_scroll_functions))
-       run_hook_with_args_2 (Qwindow_scroll_functions, window,
-                             Fmarker_position (w->start));
-      if (!samebuf)
-       run_window_configuration_change_hook (XFRAME (WINDOW_FRAME (w)));
-    }
+  if (run_hooks_p && !NILP (Vwindow_scroll_functions))
+    run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                         Fmarker_position (w->start));
+
+  /* Ensure that window change functions are run later if the buffer
+     differs and the window is neither a mini nor a pseudo window.
+
+     Note: Running window change functions for the minibuffer is noisy
+     and was generally suppressed in the past.  Is there any reason we
+     should run them?  */
+  if (!samebuf && !MINI_WINDOW_P (w) && !WINDOW_PSEUDO_P (w))
+    FRAME_WINDOW_CHANGE (XFRAME (w->frame)) = true;
 
   unbind_to (count, Qnil);
 }
@@ -3828,8 +4184,6 @@ make_window (void)
   w->phys_cursor_width = -1;
 #endif
   w->sequence_number = ++sequence_number;
-  w->pixel_width_before_size_change = 0;
-  w->pixel_height_before_size_change = 0;
   w->scroll_bar_width = -1;
   w->scroll_bar_height = -1;
   w->column_number_displayed = -1;
@@ -4095,6 +4449,9 @@ window_resize_apply (struct window *w, bool horflag)
   else
     /* Bug#15957.  */
     w->window_end_valid = false;
+
+  if (!WINDOW_PSEUDO_P (w))
+    FRAME_WINDOW_CHANGE (WINDOW_XFRAME (w)) = true;
 }
 
 
@@ -4559,17 +4916,11 @@ set correctly.  See the code of `split-window' for how 
this is done.  */)
   block_input ();
   window_resize_apply (p, horflag);
   adjust_frame_glyphs (f);
-  /* Set buffer of NEW to buffer of reference window.  Don't run
-     any hooks.  */
-  set_window_buffer (new, r->contents, false, true);
+  /* Set buffer of NEW to buffer of reference window.  */
+  set_window_buffer (new, r->contents, true, true);
+  FRAME_WINDOW_CHANGE (f) = true;
   unblock_input ();
 
-  /* Maybe we should run the scroll functions in Elisp (which already
-     runs the configuration change hook).  */
-  if (! NILP (Vwindow_scroll_functions))
-    run_hook_with_args_2 (Qwindow_scroll_functions, new,
-                         Fmarker_position (n->start));
-  /* Return NEW.  */
   return new;
 }
 
@@ -4720,6 +5071,8 @@ Signal an error when WINDOW is the only window on its 
frame.  */)
        }
       else
        unblock_input ();
+
+      FRAME_WINDOW_CHANGE (f) = true;
     }
   else
     /* We failed: Relink WINDOW into window tree.  */
@@ -6310,7 +6663,6 @@ struct saved_window
 
   Lisp_Object window, buffer, start, pointm, old_pointm;
   Lisp_Object pixel_left, pixel_top, pixel_height, pixel_width;
-  Lisp_Object pixel_height_before_size_change, pixel_width_before_size_change;
   Lisp_Object left_col, top_line, total_cols, total_lines;
   Lisp_Object normal_cols, normal_lines;
   Lisp_Object hscroll, min_hscroll, hscroll_whole, suspend_auto_hscroll;
@@ -6426,12 +6778,6 @@ the return value is nil.  Otherwise the value is t.  */)
       struct window *root_window;
       struct window **leaf_windows;
       ptrdiff_t i, k, n_leaf_windows;
-      /* Records whether a window has been added or removed wrt the
-        original configuration.  */
-      bool window_changed = false;
-      /* Records whether a window has changed its buffer wrt the
-        original configuration.  */
-      bool buffer_changed = false;
 
       /* Don't do this within the main loop below: This may call Lisp
         code and is thus potentially unsafe while input is blocked.  */
@@ -6441,11 +6787,6 @@ the return value is nil.  Otherwise the value is t.  */)
          window = p->window;
          w = XWINDOW (window);
 
-         if (NILP (w->contents))
-           /* A dead window that will be resurrected, the window
-              configuration will change.  */
-           window_changed = true;
-
          if (BUFFERP (w->contents)
              && !EQ (w->contents, p->buffer)
              && BUFFER_LIVE_P (XBUFFER (p->buffer)))
@@ -6530,10 +6871,6 @@ the return value is nil.  Otherwise the value is t.  */)
          w->pixel_top = XFIXNAT (p->pixel_top);
          w->pixel_width = XFIXNAT (p->pixel_width);
          w->pixel_height = XFIXNAT (p->pixel_height);
-         w->pixel_width_before_size_change
-           = XFIXNAT (p->pixel_width_before_size_change);
-         w->pixel_height_before_size_change
-           = XFIXNAT (p->pixel_height_before_size_change);
          w->left_col = XFIXNAT (p->left_col);
          w->top_line = XFIXNAT (p->top_line);
          w->total_cols = XFIXNAT (p->total_cols);
@@ -6581,9 +6918,6 @@ the return value is nil.  Otherwise the value is t.  */)
          if (BUFFERP (p->buffer) && BUFFER_LIVE_P (XBUFFER (p->buffer)))
            /* If saved buffer is alive, install it.  */
            {
-             if (!EQ (w->contents, p->buffer))
-               /* Record buffer configuration change.  */
-               buffer_changed = true;
              wset_buffer (w, p->buffer);
              w->start_at_line_beg = !NILP (p->start_at_line_beg);
              set_marker_restricted (w->start, p->start, w->contents);
@@ -6617,8 +6951,6 @@ the return value is nil.  Otherwise the value is t.  */)
          else if (!NILP (w->start))
            /* Leaf window has no live buffer, get one.  */
            {
-             /* Record buffer configuration change.  */
-             buffer_changed = true;
              /* Get the buffer via other_buffer_safely in order to
                 avoid showing an unimportant buffer and, if necessary, to
                 recreate *scratch* in the course (part of Juanma's bs-show
@@ -6666,10 +6998,7 @@ the return value is nil.  Otherwise the value is t.  */)
       /* Now, free glyph matrices in windows that were not reused.  */
       for (i = 0; i < n_leaf_windows; i++)
        if (NILP (leaf_windows[i]->contents))
-         {
-           free_window_matrices (leaf_windows[i]);
-           window_changed = true;
-         }
+         free_window_matrices (leaf_windows[i]);
 
       /* Allow x_set_window_size again and apply frame size changes if
         needed.  */
@@ -6699,35 +7028,10 @@ the return value is nil.  Otherwise the value is t.  */)
         selected window.  */
       if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
        do_switch_frame (data->selected_frame, 0, 0, Qnil);
-
-      if (window_changed)
-       /* At least one window has been added or removed.  Run
-          `window-configuration-change-hook' and make sure
-          `window-size-change-functions' get run later.
-
-          We have to do this in order to capture the following
-          scenario: Suppose our frame contains two live windows W1 and
-          W2 and 'set-window-configuration' replaces them by two
-          windows W3 and W4 that were dead the last time
-          run_window_size_change_functions was run.  If W3 and W4 have
-          the same values for their old and new pixel sizes but these
-          values differ from those of W1 and W2, the sizes of our
-          frame's two live windows changed but window_size_changed has
-          no means to detect that fact.
-
-          Obviously, this will get us false positives, for example,
-          when we restore the original configuration with W1 and W2
-          before run_window_size_change_functions gets called.  */
-       {
-         run_window_configuration_change_hook (f);
-         FRAME_WINDOW_CONFIGURATION_CHANGED (f) = true;
-       }
-      else if (buffer_changed)
-       /* At least one window has changed its buffer.  Run
-          `window-configuration-change-hook' only.  */
-       run_window_configuration_change_hook (f);
     }
 
+  FRAME_WINDOW_CHANGE (f) = true;
+
   if (!NILP (new_current_buffer))
     {
       Fset_buffer (new_current_buffer);
@@ -6889,10 +7193,6 @@ save_window_save (Lisp_Object window, struct Lisp_Vector 
*vector, ptrdiff_t i)
       p->pixel_top = make_fixnum (w->pixel_top);
       p->pixel_width = make_fixnum (w->pixel_width);
       p->pixel_height = make_fixnum (w->pixel_height);
-      p->pixel_width_before_size_change
-       = make_fixnum (w->pixel_width_before_size_change);
-      p->pixel_height_before_size_change
-       = make_fixnum (w->pixel_height_before_size_change);
       p->left_col = make_fixnum (w->left_col);
       p->top_line = make_fixnum (w->top_line);
       p->total_cols = make_fixnum (w->total_cols);
@@ -7581,9 +7881,9 @@ init_window_once (void)
 {
   struct frame *f = make_initial_frame ();
   XSETFRAME (selected_frame, f);
-  Vterminal_frame = selected_frame;
+  old_selected_frame = Vterminal_frame = selected_frame;
   minibuf_window = f->minibuffer_window;
-  selected_window = f->selected_window;
+  old_selected_window = selected_window = f->selected_window;
 }
 
 void
@@ -7604,6 +7904,8 @@ syms_of_window (void)
 
   DEFSYM (Qwindow_configuration_change_hook, 
"window-configuration-change-hook");
   DEFSYM (Qwindow_size_change_functions, "window-size-change-functions");
+  DEFSYM (Qwindow_buffer_change_functions, "window-buffer-change-functions");
+  DEFSYM (Qwindow_selection_change_functions, 
"window-selection-change-functions");
   DEFSYM (Qwindowp, "windowp");
   DEFSYM (Qwindow_configuration_p, "window-configuration-p");
   DEFSYM (Qwindow_live_p, "window-live-p");
@@ -7688,24 +7990,66 @@ on their symbols to be controlled by this variable.  
*/);
   Vwindow_point_insertion_type = Qnil;
   DEFSYM (Qwindow_point_insertion_type, "window-point-insertion-type");
 
-  DEFVAR_LISP ("window-configuration-change-hook",
-              Vwindow_configuration_change_hook,
-              doc: /* Functions to call when window configuration changes.
-The buffer-local value is run once per window, with the relevant window
-selected; while the global value is run only once for the modified frame,
-with the relevant frame selected.  */);
-  Vwindow_configuration_change_hook = Qnil;
+  DEFVAR_LISP ("window-buffer-change-functions", 
Vwindow_buffer_change_functions,
+              doc: /* Functions called during redisplay when window buffers 
have changed.
+The value should be a list of functions that take one argument.
+
+Functions specified buffer-locally are called for each window showing
+the corresponding buffer if and only if that window has been added or
+changed its buffer since the last redisplay.  In this case the window
+is passed as argument.
+
+Functions specified by the default value are called for each frame if
+at least one window on that frame has been added, deleted or changed
+its buffer since the last redisplay.  In this case the frame is passed
+as argument.  */);
+  Vwindow_buffer_change_functions = Qnil;
 
   DEFVAR_LISP ("window-size-change-functions", Vwindow_size_change_functions,
-    doc: /* Functions called during redisplay, if window sizes have changed.
+              doc: /* Functions called during redisplay when window sizes have 
changed.
 The value should be a list of functions that take one argument.
-During the first part of redisplay, for each frame, if any of its windows
-have changed size since the last redisplay, or have been split or deleted,
-all the functions in the list are called, with the frame as argument.
-If redisplay decides to resize the minibuffer window, it calls these
-functions on behalf of that as well.  */);
+
+Functions specified buffer-locally are called for each window showing
+the corresponding buffer if and only if that window has been added or
+changed its buffer or its total or body size since the last redisplay.
+In this case the window is passed as argument.
+
+Functions specified by the default value are called for each frame if
+at least one window on that frame has been added or changed its buffer
+or its total or body size since the last redisplay.  In this case the
+frame is passed as argument.  */);
   Vwindow_size_change_functions = Qnil;
 
+  DEFVAR_LISP ("window-selection-change-functions", 
Vwindow_selection_change_functions,
+              doc: /* Functions called during redisplay when the selected 
window has changed.
+The value should be a list of functions that take one argument.
+
+Functions specified buffer-locally are called for each window showing
+the corresponding buffer if and only if that window has been selected
+or deselected since the last redisplay.  In this case the window is
+passed as argument.
+
+Functions specified by the default value are called for each frame if
+the frame's selected window has changed since the last redisplay.  In
+this case the frame is passed as argument.  */);
+  Vwindow_selection_change_functions = Qnil;
+
+  DEFVAR_LISP ("window-configuration-change-hook", 
Vwindow_configuration_change_hook,
+              doc: /* Functions called during redisplay when window 
configuration has changed.
+The value should be a list of functions that take no argument.
+
+Functions specified buffer-locally are called for each window showing
+the corresponding buffer if at least one window on that frame has been
+added, deleted or changed its buffer or its total or body size since
+the last redisplay.  Each call is performed with the window showing
+the buffer temporarily selected.
+
+Functions specified by the default value are called for each frame if
+at least one window on that frame has been added, deleted or changed
+its buffer or its total or body size since the last redisplay.  Each
+call is performed with the frame temporarily selected.  */);
+  Vwindow_configuration_change_hook = Qnil;
+
   DEFVAR_LISP ("recenter-redisplay", Vrecenter_redisplay,
               doc: /* Non-nil means `recenter' redraws entire frame.
 If this option is non-nil, then the `recenter' command with a nil
@@ -7817,6 +8161,7 @@ displayed after a scrolling operation to be somewhat 
inaccurate.  */);
   Vfast_but_imprecise_scrolling = false;
 
   defsubr (&Sselected_window);
+  defsubr (&Sold_selected_window);
   defsubr (&Sminibuffer_window);
   defsubr (&Swindow_minibuffer_p);
   defsubr (&Swindowp);
@@ -7826,10 +8171,12 @@ displayed after a scrolling operation to be somewhat 
inaccurate.  */);
   defsubr (&Sframe_root_window);
   defsubr (&Sframe_first_window);
   defsubr (&Sframe_selected_window);
+  defsubr (&Sframe_old_selected_window);
   defsubr (&Sset_frame_selected_window);
   defsubr (&Spos_visible_in_window_p);
   defsubr (&Swindow_line_height);
   defsubr (&Swindow_buffer);
+  defsubr (&Swindow_old_buffer);
   defsubr (&Swindow_parent);
   defsubr (&Swindow_top_child);
   defsubr (&Swindow_left_child);
@@ -7840,8 +8187,10 @@ displayed after a scrolling operation to be somewhat 
inaccurate.  */);
   defsubr (&Swindow_use_time);
   defsubr (&Swindow_pixel_width);
   defsubr (&Swindow_pixel_height);
-  defsubr (&Swindow_pixel_width_before_size_change);
-  defsubr (&Swindow_pixel_height_before_size_change);
+  defsubr (&Swindow_old_pixel_width);
+  defsubr (&Swindow_old_pixel_height);
+  defsubr (&Swindow_old_body_pixel_width);
+  defsubr (&Swindow_old_body_pixel_height);
   defsubr (&Swindow_total_width);
   defsubr (&Swindow_total_height);
   defsubr (&Swindow_normal_size);
diff --git a/src/window.h b/src/window.h
index ee6ec3b..9c4aea8 100644
--- a/src/window.h
+++ b/src/window.h
@@ -142,6 +142,11 @@ struct window
        as well.  */
     Lisp_Object contents;
 
+    /* The old buffer of this window, set to this window's buffer by
+       run_window_change_functions every time it sees this window.
+       Unused for internal windows.  */
+    Lisp_Object old_buffer;
+
     /* A marker pointing to where in the text to start displaying.
        BIDI Note: This is the _logical-order_ start, i.e. the smallest
        buffer position visible in the window, not necessarily the
@@ -229,6 +234,14 @@ struct window
     /* Unique number of window assigned when it was created.  */
     EMACS_INT sequence_number;
 
+    /* The change stamp of this window.  Set to 0 when the window is
+       created, it is set to its frame's change stamp every time
+       run_window_change_functions is run on that frame with this
+       window live.  It is left alone when the window exists only
+       within a window configuration.  Not useful for internal
+       windows.  */
+    int change_stamp;
+
     /* The upper left corner pixel coordinates of this window, as
        integers relative to upper left corner of frame = 0, 0.  */
     int pixel_left;
@@ -243,10 +256,13 @@ struct window
     int pixel_width;
     int pixel_height;
 
-    /* The pixel sizes of the window at the last time
-       `window-size-change-functions' was run.  */
-    int pixel_width_before_size_change;
-    int pixel_height_before_size_change;
+    /* The pixel and pixel body sizes of the window at the last time
+       run_window_change_functions was run with this window live.  Not
+       useful for internal windows.  */
+    int old_pixel_width;
+    int old_pixel_height;
+    int old_body_pixel_width;
+    int old_body_pixel_height;
 
     /* The size of the window.  */
     int total_cols;
@@ -1023,6 +1039,7 @@ wset_next_buffers (struct window *w, Lisp_Object val)
    This value is always the same as FRAME_SELECTED_WINDOW (selected_frame).  */
 
 extern Lisp_Object selected_window;
+extern Lisp_Object old_selected_window;
 
 /* This is a time stamp for window selection, so we can find the least
    recently used window.  Its only users are Fselect_window,
@@ -1051,7 +1068,7 @@ extern void grow_mini_window (struct window *, int, bool);
 extern void shrink_mini_window (struct window *, bool);
 extern int window_relative_x_coord (struct window *, enum window_part, int);
 
-void run_window_size_change_functions (Lisp_Object);
+void run_window_change_functions (void);
 
 /* Make WINDOW display BUFFER.  RUN_HOOKS_P means it's allowed
    to run hooks.  See make_frame for a case where it's not allowed.  */
diff --git a/src/xdisp.c b/src/xdisp.c
index 5029039..cd4f9e1 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -2786,6 +2786,7 @@ init_iterator (struct it *it, struct window *w,
               struct glyph_row *row, enum face_id base_face_id)
 {
   enum face_id remapped_base_face_id = base_face_id;
+  int body_width = 0, body_height = 0;
 
   /* Some precondition checks.  */
   eassert (w != NULL && it != NULL);
@@ -2962,7 +2963,7 @@ init_iterator (struct it *it, struct window *w,
     {
       /* Mode lines, menu bar in terminal frames.  */
       it->first_visible_x = 0;
-      it->last_visible_x = WINDOW_PIXEL_WIDTH (w);
+      it->last_visible_x = body_width = WINDOW_PIXEL_WIDTH (w);
     }
   else
     {
@@ -2982,8 +2983,12 @@ init_iterator (struct it *it, struct window *w,
       else
        it->first_visible_x =
          window_hscroll_limited (w, it->f) * FRAME_COLUMN_WIDTH (it->f);
-      it->last_visible_x = (it->first_visible_x
-                           + window_box_width (w, TEXT_AREA));
+
+      body_width = window_box_width (w, TEXT_AREA);
+      if (!w->pseudo_window_p && !MINI_WINDOW_P (w)
+         && body_width != w->old_body_pixel_width)
+       FRAME_WINDOW_CHANGE (it->f) = true;
+      it->last_visible_x = it->first_visible_x + body_width;
 
       /* If we truncate lines, leave room for the truncation glyph(s) at
         the right margin.  Otherwise, leave room for the continuation
@@ -2997,7 +3002,8 @@ init_iterator (struct it *it, struct window *w,
        }
 
       it->header_line_p = window_wants_header_line (w);
-      it->current_y = WINDOW_HEADER_LINE_HEIGHT (w) + w->vscroll;
+      body_height = WINDOW_HEADER_LINE_HEIGHT (w);
+      it->current_y =  body_height + w->vscroll;
     }
 
   /* Leave room for a border glyph.  */
@@ -3006,6 +3012,10 @@ init_iterator (struct it *it, struct window *w,
     it->last_visible_x -= 1;
 
   it->last_visible_y = window_text_bottom_y (w);
+  body_height += it->last_visible_y;
+  if (!w->pseudo_window_p && !MINI_WINDOW_P (w)
+      && body_height != w->old_body_pixel_height)
+    FRAME_WINDOW_CHANGE (it->f) = true;
 
   /* For mode lines and alike, arrange for the first glyph having a
      left box line if the face specifies a box.  */
@@ -12200,8 +12210,6 @@ prepare_menu_bars (void)
              && !XBUFFER (w->contents)->text->redisplay)
            continue;
 
-         run_window_size_change_functions (frame);
-
          if (FRAME_PARENT_FRAME (f))
            continue;
 
@@ -14111,20 +14119,6 @@ redisplay_internal (void)
     {
       echo_area_display (false);
 
-      /* If echo_area_display resizes the mini-window, the redisplay and
-        window_sizes_changed flags of the selected frame are set, but
-        it's too late for the hooks in window-size-change-functions,
-        which have been examined already in prepare_menu_bars.  So in
-        that case we call the hooks here only for the selected frame.  */
-      if (sf->redisplay)
-       {
-         ptrdiff_t count1 = SPECPDL_INDEX ();
-
-         record_unwind_save_match_data ();
-         run_window_size_change_functions (selected_frame);
-         unbind_to (count1, Qnil);
-       }
-
       if (message_cleared_p)
        update_miniwindow_p = true;
 
@@ -14141,15 +14135,6 @@ redisplay_internal (void)
           && (current_buffer->clip_changed || window_outdated (w))
           && resize_mini_window (w, false))
     {
-      if (sf->redisplay)
-       {
-         ptrdiff_t count1 = SPECPDL_INDEX ();
-
-         record_unwind_save_match_data ();
-         run_window_size_change_functions (selected_frame);
-         unbind_to (count1, Qnil);
-       }
-
       /* Resized active mini-window to fit the size of what it is
          showing if its contents might have changed.  */
       must_finish = true;
@@ -14339,7 +14324,19 @@ redisplay_internal (void)
                  && (w = XWINDOW (selected_window)) != sw)
                goto retry;
 
-             /* We used to always goto end_of_redisplay here, but this
+             if (!NILP (Vrun_hooks))
+               {
+                 run_window_change_functions ();
+
+                 /* If windows or buffers changed or selected_window
+                    changed, redisplay again.  */
+                 if ((windows_or_buffers_changed)
+                     || (WINDOWP (selected_window)
+                         && (w = XWINDOW (selected_window)) != sw))
+                   goto retry;
+               }
+
+               /* We used to always goto end_of_redisplay here, but this
                 isn't enough if we have a blinking cursor.  */
              if (w->cursor_off_p == w->last_cursor_off_p)
                goto end_of_redisplay;
@@ -14698,9 +14695,22 @@ redisplay_internal (void)
   /* If we just did a pending size change, or have additional
      visible frames, or selected_window changed, redisplay again.  */
   if ((windows_or_buffers_changed && !pending)
-      || (WINDOWP (selected_window) && (w = XWINDOW (selected_window)) != sw))
+      || (WINDOWP (selected_window)
+         && (w = XWINDOW (selected_window)) != sw))
     goto retry;
 
+  if (!NILP (Vrun_hooks))
+    {
+      run_window_change_functions ();
+
+      /* If windows or buffers changed or selected_window changed,
+        redisplay again.  */
+      if ((windows_or_buffers_changed)
+         || (WINDOWP (selected_window)
+             && (w = XWINDOW (selected_window)) != sw))
+       goto retry;
+    }
+
   /* Clear the face and image caches.
 
      We used to do this only if consider_all_windows_p.  But the cache
diff --git a/src/xterm.c b/src/xterm.c
index fbbf61d..6327038 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -3001,13 +3001,14 @@ x_composite_image (struct glyph_string *s, Pixmap dest,
                         width, height);
 
       XRenderFreePicture (s->display, destination);
+      return;
     }
-  else
 #endif
-    XCopyArea (s->display, s->img->pixmap,
-               dest, s->gc,
-               srcX, srcY,
-               width, height, dstX, dstY);
+
+  XCopyArea (s->display, s->img->pixmap,
+            dest, s->gc,
+            srcX, srcY,
+            width, height, dstX, dstY);
 }
 
 
@@ -3060,7 +3061,8 @@ x_draw_image_foreground (struct glyph_string *s)
          image_rect.width = s->slice.width;
          image_rect.height = s->slice.height;
          if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
-            x_composite_image (s, FRAME_X_DRAWABLE (s->f), s->slice.x + r.x - 
x, s->slice.y + r.y - y,
+            x_composite_image (s, FRAME_X_DRAWABLE (s->f),
+                              s->slice.x + r.x - x, s->slice.y + r.y - y,
                                r.x, r.y, r.width, r.height);
        }
       else



reply via email to

[Prev in Thread] Current Thread [Next in Thread]