emacs-diffs
[Top][All Lists]
Advanced

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

[Emacs-diffs] master 4e082ce: Further redesign of window change function


From: Martin Rudalics
Subject: [Emacs-diffs] master 4e082ce: Further redesign of window change functions
Date: Sat, 9 Mar 2019 05:14:30 -0500 (EST)

branch: master
commit 4e082ce3941a9c1fcaae509897761d3e24e08625
Author: Martin Rudalics <address@hidden>
Commit: Martin Rudalics <address@hidden>

    Further redesign of window change functions
    
    * doc/lispref/windows.texi (Window Hooks): Revise description
    of window change functions.  Add documentation for
    'window-state-change-hook' and window state change flag.
    * etc/NEWS: Update entry for window change functions.
    * src/frame.c (Fframe_window_state_change)
    (Fset_frame_window_state_change): New functions.
    * src/frame.h (struct frame): New boolean window_state_change.
    (FRAME_WINDOW_STATE_CHANGE): New macro.
    * src/window.c (window_change_record_frames): New static
    boolean.
    (window_change_record_frame): Remove function - code moved to
    window_change_record.
    (window_change_record): Record frame changes here taking
    window_change_record_frames into account.
    (run_window_change_functions_1): Set window_change_record_frames
    whenever we run one of our hooks.
    (run_window_change_functions): Run hooks also when
    FRAME_WINDOW_STATE_CHANGE has been set.  Run
    Vwindow_state_change_hook.  Leave decision whether to record
    changes for all frames to window_change_record.
    (Vwindow_state_change_functions): Update doc-string.
    (Vwindow_state_change_hook): New normal hook.
---
 doc/lispref/windows.texi | 106 +++++++++++++++++---------
 etc/NEWS                 |  18 ++---
 src/frame.c              |  36 +++++++++
 src/frame.h              |   8 ++
 src/window.c             | 195 +++++++++++++++++++++++++++++------------------
 5 files changed, 247 insertions(+), 116 deletions(-)

diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 6ac7aa6..6b71632 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -6046,8 +6046,8 @@ buffer are (re)fontified because a window was scrolled or 
its size
 changed.  @xref{Other Font Lock Variables}.
 
 @cindex window change functions
-   The remainder of this section covers five hooks that are called at
-the end of redisplay provided a significant, non-scrolling change of a
+   The remainder of this section covers six hooks that are called
+during 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}.
@@ -6058,9 +6058,9 @@ detected, which means that a window was created, deleted 
or assigned
 another buffer.
 
 @defvar 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.
+This variable specifies 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 any window showing
 the corresponding buffer if that window has been created or assigned
@@ -6074,14 +6074,14 @@ In this case the frame is passed as argument.
 @end defvar
 
 @cindex window size change
-The second of these hooks is run after a @dfn{window size change} has
+The second of these hooks is run when 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 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.
+This variable specifies functions called during 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
@@ -6097,13 +6097,13 @@ argument.
 @end defvar
 
 @cindex window selection change
-The third of these hooks is run after a @dfn{window selection change}
+The third of these hooks is run when a @dfn{window selection change}
 has selected another window since the last redisplay.
 
 @defvar 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.
+This variable specifies functions called during 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
@@ -6118,13 +6118,13 @@ run.  In this case the frame is passed as argument.
 @end defvar
 
 @cindex window state change
-The fourth of these hooks is run after a @dfn{window state change} has
+The fourth of these hooks is run when a @dfn{window state change} has
 been detected, which means that at least one of the three preceding
 window changes has occurred.
 
 @defvar window-state-change-functions
-This variable specifies functions called at the end of redisplay when
-a window buffer or size change occurred or the selected window or a
+This variable specifies functions called during redisplay when a
+window buffer or size change occurred or the selected window or a
 frame's selected window has changed.  The value should be a list of
 functions that take one argument.
 
@@ -6141,6 +6141,10 @@ another buffer, changed its total or body size or 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.
+
+Functions specified by the default value are also run for a frame when
+that frame's window state change flag (see below) has been set since
+last redisplay.
 @end defvar
 
 @cindex window configuration change
@@ -6150,9 +6154,9 @@ size of a window changed.  It differs from the four 
preceding hooks in
 the way it is run.
 
 @defvar window-configuration-change-hook
-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.
+This variable specifies functions called during 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
@@ -6168,14 +6172,29 @@ window change functions were run.  Each call is 
performed with the
 frame temporarily selected and the selected window's buffer current.
 @end defvar
 
-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, selected window change and
-window state 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.
+Finally, Emacs runs a normal hook that generalizes the behavior of
address@hidden
+
address@hidden window-state-change-hook
+The default value of this variable specifies functions called during
+redisplay when a window state change has been detected or the window
+state change flag has been set on at least one frame.  The value
+should be a list of functions that take no argument.
+
+Applications should put a function on this hook only if they want to
+react to changes that happened on (or have been signaled for) two or
+more frames since last redisplay.  In every other case, putting the
+function on @code{window-state-change-functions} should be preferred.
address@hidden defvar
+
+Window change functions are called during redisplay for each frame as
+follows: First, any buffer-local window buffer change function, window
+size change function, selected window change and window state 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.  Finally, functions
+on @code{window-state-change-hook} are run.
 
    Window change functions are run for a specific frame only if a
 corresponding change was registered for that frame earlier.  Such
@@ -6189,6 +6208,27 @@ 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.
 
address@hidden window state change flag
+   The @dfn{window state change flag} of a frame, if set, will cause
+the default values of @code{window-state-change-functions} (for that
+frame) and @code{window-state-change-hook} to be run during next
+redisplay regardless of whether a window state change actually
+occurred for that frame or not.  After running any functions on these
+hooks, the flag is reset for each frame.  Applications can set that
+flag and inspect its value using the following functions.
+
address@hidden set-frame-window-state-change &optional frame arg
+This function sets @var{frame}'s window state change flag if @var{arg}
+is address@hidden and resets it otherwise.  @var{frame} must be a live
+frame and defaults to the selected one.
address@hidden defun
+
address@hidden frame-window-state-change &optional frame
+This functions returns @code{t} if @var{frame}'s window state change
+flag is set and @code{nil} otherwise.  @var{frame} must be a live
+frame and defaults to the selected one.
address@hidden defun
+
    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
@@ -6250,12 +6290,10 @@ change functions were run.
 
 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).
+necessary, applications 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 values of any of the hooks that are run when a
+window buffer change was detected.
 
    The following caveats should be considered when adding a function
 to window change functions:
@@ -6272,7 +6310,7 @@ 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
 
 @item
 Macros like @code{save-window-excursion}, @code{with-selected-window}
diff --git a/etc/NEWS b/etc/NEWS
index 3e347b5..1095ecc 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1424,18 +1424,20 @@ displaying the same buffer.  See the node "(elisp) Face 
Remapping"
 of the Emacs Lisp Reference manual for more detail.
 
 +++
-** Window change functions have been redesigned completely.
+** Window change functions have been redesigned.
 
 Hooks reacting to window changes run now only when redisplay detects
-that a change has actually occurred.  The five hooks provided are:
+that a change has actually occurred.  Six hooks are now provided:
 '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),
 'window-selection-change-functions' (run when the selected window
-changed) and 'window-state-change-functions' (run when any of the
-preceding ones is run).  'window-scroll-functions' are unaffected by
-these changes.
+changed) and 'window-state-change-functions' and
+'window-state-change-hook' (run when any of the preceding ones is
+run).  Applications can enforce running the latter two using the new
+function 'set-frame-window-state-change'.  '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
@@ -1447,10 +1449,8 @@ during last redisplay.  'window-old-pixel-width' 
(renamed from
 '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.
+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/src/frame.c b/src/frame.c
index 1219569..c336369 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -3611,6 +3611,40 @@ bottom edge of FRAME's display.  */)
 
   return Qt;
 }
+
+DEFUN ("frame-window-state-change", Fframe_window_state_change,
+       Sframe_window_state_change, 0, 1, 0,
+       doc: /* Return t if FRAME's window state change flag is set, nil 
otherwise.
+FRAME must be a live frame and defaults to the selected one.
+
+If FRAME's window state change flag is set, the default values of
+`window-state-change-functions' and `window-state-change-hook' will be
+run during next redisplay, regardless of whether a window state change
+actually occurred on FRAME or not.  After that, the value of this flag
+is reset.  */)
+     (Lisp_Object frame)
+{
+  return FRAME_WINDOW_STATE_CHANGE (decode_live_frame (frame)) ? Qt : Qnil;
+}
+
+DEFUN ("set-frame-window-state-change", Fset_frame_window_state_change,
+       Sset_frame_window_state_change, 0, 2, 0,
+       doc: /* Set FRAME's window state change flag according to ARG.
+Set FRAME's window state change flag if ARG is non-nil, reset it
+otherwise.
+
+If FRAME's window state change flag is set, the default values of
+`window-state-change-functions' and `window-state-change-hook' will be
+run during next redisplay, regardless of whether a window state change
+actually occurred on FRAME or not.  After that, the value of FRAME's
+window state change flag is reset.  */)
+     (Lisp_Object frame, Lisp_Object arg)
+{
+  struct frame *f = decode_live_frame (frame);
+
+  return (FRAME_WINDOW_STATE_CHANGE (f) = !NILP (arg)) ? Qt : Qnil;
+}
+
 
 /***********************************************************************
                                Frame Parameters
@@ -6256,6 +6290,8 @@ iconify the top level frame instead.  */);
   defsubr (&Sframe_position);
   defsubr (&Sset_frame_position);
   defsubr (&Sframe_pointer_visible_p);
+  defsubr (&Sframe_window_state_change);
+  defsubr (&Sset_frame_window_state_change);
 
 #ifdef HAVE_WINDOW_SYSTEM
   defsubr (&Sx_get_resource);
diff --git a/src/frame.h b/src/frame.h
index 544e0be..5bac24b 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -334,6 +334,10 @@ struct frame
      frame.  */
   bool_bf window_change : 1;
 
+  /* True if running window state change functions has been explicitly
+     requested for this frame since last redisplay.  */
+  bool_bf window_state_change : 1;
+
   /* True if the mouse has moved on this display device
      since the last time we checked.  */
   bool_bf mouse_moved : 1;
@@ -944,6 +948,10 @@ default_pixels_per_inch_y (void)
    window change functions were run on F.  */
 #define FRAME_WINDOW_CHANGE(f) (f)->window_change
 
+/* True if running window state change functions has been explicitly
+   requested for this frame since last redisplay.  */
+#define FRAME_WINDOW_STATE_CHANGE(f) (f)->window_state_change
+
 /* The minibuffer window of frame F, if it has one; otherwise nil.  */
 #define FRAME_MINIBUF_WINDOW(f) f->minibuffer_window
 
diff --git a/src/window.c b/src/window.c
index 8543cbf..c498ae8 100644
--- a/src/window.c
+++ b/src/window.c
@@ -88,6 +88,9 @@ static Lisp_Object old_selected_window;
    by setting it to nil.  */
 Lisp_Object Vwindow_list;
 
+/* True mean window_change_record has to record all live frames.  */
+static bool window_change_record_frames;
+
 /* The mini-buffer window of the selected frame.
    Note that you cannot test for mini-bufferness of an arbitrary window
    by comparing against this; but you can test for mini-bufferness of
@@ -3426,8 +3429,8 @@ run_window_configuration_change_hook (struct frame *f)
   XSETFRAME (frame, f);
 
   if (NILP (Vrun_hooks)
-      || !(f->can_x_set_window_size)
-      || !(f->after_make_frame))
+      || !f->can_x_set_window_size
+      || !f->after_make_frame)
     return;
 
   /* Use the right buffer.  Matters when running the local hooks.  */
@@ -3574,48 +3577,49 @@ window_change_record_windows (Lisp_Object window, int 
stamp, ptrdiff_t number)
 
 
 /**
- * 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);
-
-  /* Record selected window.  */
-  fset_old_selected_window (f, FRAME_SELECTED_WINDOW (f));
-
-  /* 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;
-
-  /* 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);
-
-  /* Reset our flag.  */
-  FRAME_WINDOW_CHANGE (f) = false;
-}
-
-
-/**
  * window_change_record:
  *
+ * For each frame that has recorded changes, record its selected
+ * window, update Fchange stamp, record the states of all its live
+ * windows via window_change_record_windows and reset its
+ * window_change and window_state_change flags.
+ *
  * Record selected window in old_selected_window and selected frame in
  * old_selected_frame.
  */
 static void
 window_change_record (void)
 {
+  if (window_change_record_frames)
+    {
+      Lisp_Object tail, frame;
+
+      FOR_EACH_FRAME (tail, frame)
+       {
+         struct frame *f = XFRAME (frame);
+
+         /* Record FRAME's selected window.  */
+         fset_old_selected_window (f, FRAME_SELECTED_WINDOW (f));
+
+         /* 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;
+
+         /* 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);
+
+         /* Reset our flags.  */
+         FRAME_WINDOW_CHANGE (f) = false;
+         FRAME_WINDOW_STATE_CHANGE (f) = false;
+       }
+    }
+
   /* 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;
@@ -3647,8 +3651,18 @@ run_window_change_functions_1 (Lisp_Object symbol, 
Lisp_Object buffer,
 
   while (CONSP (funs))
     {
-      if (!EQ (XCAR (funs), Qt))
-       safe_call1 (XCAR (funs), window_or_frame);
+      if (!EQ (XCAR (funs), Qt)
+         && (NILP (buffer)
+             ? FRAME_LIVE_P (XFRAME (window_or_frame))
+             : WINDOW_LIVE_P (window_or_frame)))
+       {
+         /* Any function called here may change the state of any
+            frame.  Make sure to record changes for each live frame
+            in window_change_record later.  */
+         window_change_record_frames = true;
+         safe_call1 (XCAR (funs), window_or_frame);
+       }
+
       funs = XCDR (funs);
     }
 }
@@ -3661,8 +3675,9 @@ run_window_change_functions_1 (Lisp_Object symbol, 
Lisp_Object buffer,
  * 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.
+ * nil, where no window selection happened and whose window state
+ * change flag was not set since the last time this function was
+ * called.  Never run any functions for tooltip frames.
  *
  * The change functions run are, in this order:
  *
@@ -3679,25 +3694,35 @@ run_window_change_functions_1 (Lisp_Object symbol, 
Lisp_Object buffer,
  * `window-selected-change-functions' run for a window that was
  * (de-)selected since the last time window change functions were run.
  *
+ * `window-state-change-functions' run for a window for which any of
+ * the above three changes occurred.
+ *
  * 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.
+ * 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.
+ * as many times as the buffer is shown on the frame.
  *
- * The default value of these functions is called only after all
+ * The default values of these functions are 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.
+ * such call receives one argument - the frame for which a change
+ * occurred.  Functions on `window-state-change-functions' are run
+ * also if the corresponding frame's window state change flag has been
+ * set.
  *
- * After the three change functions cited above have been run in the
+ * After the four 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
+ * were run.  The functions are called without argument and with the
  * buffer's window selected.  The default value is run without
- * argument and the frame for which the function is run selected.
+ * argument and with the frame for which the function is run selected.
+ *
+ * In a final step, functions on `window-state-change-hook' are run
+ * provided a window state change has occurred or the window state
+ * change flag has been set on at least one frame.  Each of these
+ * functions is called without argument.
  *
  * This function does not save and restore match data.  Any functions
  * it calls are responsible for doing that themselves.
@@ -3707,8 +3732,10 @@ 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 ();
+  bool run_window_state_change_hook = false;
+  ptrdiff_t count = SPECPDL_INDEX ();
 
+  window_change_record_frames = false;
   record_unwind_protect_void (window_change_record);
   specbind (Qinhibit_redisplay, Qt);
 
@@ -3725,19 +3752,21 @@ run_window_change_functions (void)
               || EQ (frame, selected_frame)));
       bool frame_selected_window_change
        = !EQ (FRAME_OLD_SELECTED_WINDOW (f), FRAME_SELECTED_WINDOW (f));
+      bool frame_window_state_change = FRAME_WINDOW_STATE_CHANGE (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
+      if (!FRAME_LIVE_P (f)
+         || !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
+              || frame_selected_window_change
+              || frame_window_state_change))
+       /* Either we are not allowed to run hooks for this frame or no
+          window change has been reported for it since the last time
           we ran window change functions on it.  */
        continue;
 
@@ -3745,8 +3774,6 @@ run_window_change_functions (void)
       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.  */
@@ -3857,13 +3884,21 @@ run_window_change_functions (void)
          (Qwindow_selection_change_functions, Qnil, frame);
 
       /* A frame has changed state when a size or buffer change
-        occurrd or its selected window has changed or when it was
-        (de-)selected.  */
+        occurred, its selected window has changed, when it was
+        (de-)selected or its window state change flag was set.  */
       if ((frame_selected_change || frame_selected_window_change
-          || frame_buffer_change || window_deleted || frame_size_change)
+          || frame_buffer_change || window_deleted
+          || frame_size_change || frame_window_state_change)
          && FRAME_LIVE_P (f))
-       run_window_change_functions_1
-         (Qwindow_state_change_functions, Qnil, frame);
+       {
+         run_window_change_functions_1
+           (Qwindow_state_change_functions, Qnil, frame);
+         /* Make sure to run 'window-state-change-hook' later.  */
+         run_window_state_change_hook = true;
+         /*  Make sure to record changes for each live frame in
+            window_change_record later.  */
+         window_change_record_frames = true;
+       }
 
       /* A frame's configuration changed when one of its windows has
         changed buffer or size or at least one window was deleted.  */
@@ -3871,17 +3906,16 @@ run_window_change_functions (void)
        /* This will run any buffer local window configuration change
           hook as well.  */
        run_window_configuration_change_hook (f);
-
-      if (!FRAME_LIVE_P (f))
-       continue;
-
-      /* 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);
+  /* Run 'window-state-change-hook' if at least one frame has changed
+     state.  */
+  if (run_window_state_change_hook && !NILP (Vwindow_state_change_hook))
+    safe_run_hooks (Qwindow_state_change_hook);
+
+  /* Record changes for all frames (if asked for), selected window and
+     frame.  */
+  unbind_to (count, Qnil);
 }
 
 /* Make WINDOW display BUFFER.  RUN_HOOKS_P means it's allowed
@@ -7999,6 +8033,7 @@ syms_of_window (void)
   Fput (Qscroll_down, Qscroll_command, Qt);
 
   DEFSYM (Qwindow_configuration_change_hook, 
"window-configuration-change-hook");
+  DEFSYM (Qwindow_state_change_hook, "window-state-change-hook");
   DEFSYM (Qwindow_state_change_functions, "window-state-change-functions");
   DEFSYM (Qwindow_size_change_functions, "window-size-change-functions");
   DEFSYM (Qwindow_buffer_change_functions, "window-buffer-change-functions");
@@ -8132,11 +8167,25 @@ 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, changed its
-buffer or its total or body size or the frame has been (de-)selected
-or its selected window has changed since the last redisplay.  In this
-case the frame is passed as argument.  */);
+buffer or its total or body size or the frame has been (de-)selected,
+its selected window has changed or the window state change flag has
+been set for this frame since the last redisplay.  In this case the
+frame is passed as argument.  */);
   Vwindow_state_change_functions = Qnil;
 
+  DEFVAR_LISP ("window-state-change-hook", Vwindow_state_change_hook,
+              doc: /* Functions called during redisplay when the window state 
changed.
+The value should be a list of functions that take no argument.
+
+This hook is called during redisplay when at least one window has been
+added, deleted, (de-)selected, changed its buffer or its total or body
+size or the window state change flag has been set for at least one
+frame.  This hook is called after all other window change functions
+have been run and should be used only if a function should react to
+changes that happened on at least two frames since last redisplay or
+the function intends to change the window configuration.  */);
+  Vwindow_state_change_hook = 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.



reply via email to

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