aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Rudalics2019-03-09 11:13:18 +0100
committerMartin Rudalics2019-03-09 11:13:18 +0100
commit4e082ce3941a9c1fcaae509897761d3e24e08625 (patch)
treec50e17baec00f63098e74ae750db28d8ba45f32b
parentd2270d8fc93b5fb0b82fec4d85d122ea4e38dff3 (diff)
downloademacs-4e082ce3941a9c1fcaae509897761d3e24e08625.tar.gz
emacs-4e082ce3941a9c1fcaae509897761d3e24e08625.zip
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.
-rw-r--r--doc/lispref/windows.texi106
-rw-r--r--etc/NEWS18
-rw-r--r--src/frame.c36
-rw-r--r--src/frame.h8
-rw-r--r--src/window.c195
5 files changed, 247 insertions, 116 deletions
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 6ac7aa67286..6b716323357 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
6046changed. @xref{Other Font Lock Variables}. 6046changed. @xref{Other Font Lock Variables}.
6047 6047
6048@cindex window change functions 6048@cindex window change functions
6049 The remainder of this section covers five hooks that are called at 6049 The remainder of this section covers six hooks that are called
6050the end of redisplay provided a significant, non-scrolling change of a 6050during redisplay provided a significant, non-scrolling change of a
6051window has been detected. For simplicity, these hooks and the 6051window has been detected. For simplicity, these hooks and the
6052functions they call will be collectively referred to as @dfn{window 6052functions they call will be collectively referred to as @dfn{window
6053change functions}. 6053change functions}.
@@ -6058,9 +6058,9 @@ detected, which means that a window was created, deleted or assigned
6058another buffer. 6058another buffer.
6059 6059
6060@defvar window-buffer-change-functions 6060@defvar window-buffer-change-functions
6061This variable specifies functions called at the end of redisplay when 6061This variable specifies functions called during redisplay when window
6062window buffers have changed. The value should be a list of functions 6062buffers have changed. The value should be a list of functions that
6063that take one argument. 6063take one argument.
6064 6064
6065Functions specified buffer-locally are called for any window showing 6065Functions specified buffer-locally are called for any window showing
6066the corresponding buffer if that window has been created or assigned 6066the corresponding buffer if that window has been created or assigned
@@ -6074,14 +6074,14 @@ In this case the frame is passed as argument.
6074@end defvar 6074@end defvar
6075 6075
6076@cindex window size change 6076@cindex window size change
6077The second of these hooks is run after a @dfn{window size change} has 6077The second of these hooks is run when a @dfn{window size change} has
6078been detected which means that a window was created, assigned another 6078been detected which means that a window was created, assigned another
6079buffer, or changed its total size or that of its text area. 6079buffer, or changed its total size or that of its text area.
6080 6080
6081@defvar window-size-change-functions 6081@defvar window-size-change-functions
6082This variable specifies functions called at the end of redisplay when 6082This variable specifies functions called during redisplay when a
6083a window size change occurred. The value should be a list of 6083window size change occurred. The value should be a list of functions
6084functions that take one argument. 6084that take one argument.
6085 6085
6086Functions specified buffer-locally are called for any window showing 6086Functions specified buffer-locally are called for any window showing
6087the corresponding buffer if that window has been added or assigned 6087the corresponding buffer if that window has been added or assigned
@@ -6097,13 +6097,13 @@ argument.
6097@end defvar 6097@end defvar
6098 6098
6099@cindex window selection change 6099@cindex window selection change
6100The third of these hooks is run after a @dfn{window selection change} 6100The third of these hooks is run when a @dfn{window selection change}
6101has selected another window since the last redisplay. 6101has selected another window since the last redisplay.
6102 6102
6103@defvar window-selection-change-functions 6103@defvar window-selection-change-functions
6104This variable specifies functions called at the end of redisplay when 6104This variable specifies functions called during redisplay when the
6105the selected window or a frame's selected window has changed. The 6105selected window or a frame's selected window has changed. The value
6106value should be a list of functions that take one argument. 6106should be a list of functions that take one argument.
6107 6107
6108Functions specified buffer-locally are called for any window showing 6108Functions specified buffer-locally are called for any window showing
6109the corresponding buffer if that window has been selected or 6109the corresponding buffer if that window has been selected or
@@ -6118,13 +6118,13 @@ run. In this case the frame is passed as argument.
6118@end defvar 6118@end defvar
6119 6119
6120@cindex window state change 6120@cindex window state change
6121The fourth of these hooks is run after a @dfn{window state change} has 6121The fourth of these hooks is run when a @dfn{window state change} has
6122been detected, which means that at least one of the three preceding 6122been detected, which means that at least one of the three preceding
6123window changes has occurred. 6123window changes has occurred.
6124 6124
6125@defvar window-state-change-functions 6125@defvar window-state-change-functions
6126This variable specifies functions called at the end of redisplay when 6126This variable specifies functions called during redisplay when a
6127a window buffer or size change occurred or the selected window or a 6127window buffer or size change occurred or the selected window or a
6128frame's selected window has changed. The value should be a list of 6128frame's selected window has changed. The value should be a list of
6129functions that take one argument. 6129functions that take one argument.
6130 6130
@@ -6141,6 +6141,10 @@ another buffer, changed its total or body size or that frame has been
6141selected or deselected or the frame's selected window has changed 6141selected or deselected or the frame's selected window has changed
6142since the last time window change functions were run. In this case 6142since the last time window change functions were run. In this case
6143the frame is passed as argument. 6143the frame is passed as argument.
6144
6145Functions specified by the default value are also run for a frame when
6146that frame's window state change flag (see below) has been set since
6147last redisplay.
6144@end defvar 6148@end defvar
6145 6149
6146@cindex window configuration change 6150@cindex window configuration change
@@ -6150,9 +6154,9 @@ size of a window changed. It differs from the four preceding hooks in
6150the way it is run. 6154the way it is run.
6151 6155
6152@defvar window-configuration-change-hook 6156@defvar window-configuration-change-hook
6153This variable specifies functions called at the end of redisplay when 6157This variable specifies functions called during redisplay when either
6154either the buffer or the size of a window has changed. The value 6158the buffer or the size of a window has changed. The value should be a
6155should be a list of functions that take no argument. 6159list of functions that take no argument.
6156 6160
6157Functions specified buffer-locally are called for any window showing 6161Functions specified buffer-locally are called for any window showing
6158the corresponding buffer if at least one window on that frame has been 6162the 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
6168frame temporarily selected and the selected window's buffer current. 6172frame temporarily selected and the selected window's buffer current.
6169@end defvar 6173@end defvar
6170 6174
6171Window change functions are called at the end of redisplay for each 6175Finally, Emacs runs a normal hook that generalizes the behavior of
6172frame as follows: First, any buffer-local window buffer change 6176@code{window-state-change-functions}.
6173function, window size change function, selected window change and 6177
6174window state change functions are called in this order. Next, the 6178@defvar window-state-change-hook
6175default values for these functions are called in the same order. Then 6179The default value of this variable specifies functions called during
6176any buffer-local window configuration change functions are called 6180redisplay when a window state change has been detected or the window
6177followed by functions specified by the default value of those 6181state change flag has been set on at least one frame. The value
6178functions. 6182should be a list of functions that take no argument.
6183
6184Applications should put a function on this hook only if they want to
6185react to changes that happened on (or have been signaled for) two or
6186more frames since last redisplay. In every other case, putting the
6187function on @code{window-state-change-functions} should be preferred.
6188@end defvar
6189
6190Window change functions are called during redisplay for each frame as
6191follows: First, any buffer-local window buffer change function, window
6192size change function, selected window change and window state change
6193functions are called in this order. Next, the default values for
6194these functions are called in the same order. Then any buffer-local
6195window configuration change functions are called followed by functions
6196specified by the default value of those functions. Finally, functions
6197on @code{window-state-change-hook} are run.
6179 6198
6180 Window change functions are run for a specific frame only if a 6199 Window change functions are run for a specific frame only if a
6181corresponding change was registered for that frame earlier. Such 6200corresponding change was registered for that frame earlier. Such
@@ -6189,6 +6208,27 @@ only if that excursion still persists at the time change functions are
6189run. If it is exited earlier, hooks will be run only if registered by 6208run. If it is exited earlier, hooks will be run only if registered by
6190a change outside the scope of that excursion. 6209a change outside the scope of that excursion.
6191 6210
6211@cindex window state change flag
6212 The @dfn{window state change flag} of a frame, if set, will cause
6213the default values of @code{window-state-change-functions} (for that
6214frame) and @code{window-state-change-hook} to be run during next
6215redisplay regardless of whether a window state change actually
6216occurred for that frame or not. After running any functions on these
6217hooks, the flag is reset for each frame. Applications can set that
6218flag and inspect its value using the following functions.
6219
6220@defun set-frame-window-state-change &optional frame arg
6221This function sets @var{frame}'s window state change flag if @var{arg}
6222is non-@code{nil} and resets it otherwise. @var{frame} must be a live
6223frame and defaults to the selected one.
6224@end defun
6225
6226@defun frame-window-state-change &optional frame
6227This functions returns @code{t} if @var{frame}'s window state change
6228flag is set and @code{nil} otherwise. @var{frame} must be a live
6229frame and defaults to the selected one.
6230@end defun
6231
6192 While window change functions are run, the functions described next 6232 While window change functions are run, the functions described next
6193can be called to get more insight into what has changed for a specific 6233can be called to get more insight into what has changed for a specific
6194window or frame since the last redisplay. All these functions take a 6234window or frame since the last redisplay. All these functions take a
@@ -6250,12 +6290,10 @@ change functions were run.
6250 6290
6251Note that window change functions provide no information about which 6291Note that window change functions provide no information about which
6252windows have been deleted since the last time they were run. If 6292windows have been deleted since the last time they were run. If
6253necessary, an application should remember any window showing a 6293necessary, applications should remember any window showing a specific
6254specific buffer in a local variable of that buffer and update it in a 6294buffer in a local variable of that buffer and update it in a function
6255function run by the default value of 6295run by the default values of any of the hooks that are run when a
6256@code{window-buffer-change-functions} or 6296window buffer change was detected.
6257@code{window-configuration-change-hook} (the only hooks triggered by
6258the deletion of windows).
6259 6297
6260 The following caveats should be considered when adding a function 6298 The following caveats should be considered when adding a function
6261to window change functions: 6299to window change functions:
@@ -6272,7 +6310,7 @@ the buffer, size or selection status of any window because there is no
6272guarantee that the information about such a change will be propagated 6310guarantee that the information about such a change will be propagated
6273to other window change functions. If at all, any such change should 6311to other window change functions. If at all, any such change should
6274be executed only by the last function listed by the default value of 6312be executed only by the last function listed by the default value of
6275@code{window-configuration-change-hook}. 6313@code{window-state-change-hook}.
6276 6314
6277@item 6315@item
6278Macros like @code{save-window-excursion}, @code{with-selected-window} 6316Macros like @code{save-window-excursion}, @code{with-selected-window}
diff --git a/etc/NEWS b/etc/NEWS
index 3e347b5318a..1095ecc7e5e 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1424,18 +1424,20 @@ displaying the same buffer. See the node "(elisp) Face Remapping"
1424of the Emacs Lisp Reference manual for more detail. 1424of the Emacs Lisp Reference manual for more detail.
1425 1425
1426+++ 1426+++
1427** Window change functions have been redesigned completely. 1427** Window change functions have been redesigned.
1428 1428
1429Hooks reacting to window changes run now only when redisplay detects 1429Hooks reacting to window changes run now only when redisplay detects
1430that a change has actually occurred. The five hooks provided are: 1430that a change has actually occurred. Six hooks are now provided:
1431'window-buffer-change-functions' (run after window buffers have 1431'window-buffer-change-functions' (run after window buffers have
1432changed), 'window-size-change-functions' (run after a window was 1432changed), 'window-size-change-functions' (run after a window was
1433assigned a new buffer or size), 'window-configuration-change-hook' 1433assigned a new buffer or size), 'window-configuration-change-hook'
1434(like the former but run also when a window was deleted), 1434(like the former but run also when a window was deleted),
1435'window-selection-change-functions' (run when the selected window 1435'window-selection-change-functions' (run when the selected window
1436changed) and 'window-state-change-functions' (run when any of the 1436changed) and 'window-state-change-functions' and
1437preceding ones is run). 'window-scroll-functions' are unaffected by 1437'window-state-change-hook' (run when any of the preceding ones is
1438these changes. 1438run). Applications can enforce running the latter two using the new
1439function 'set-frame-window-state-change'. 'window-scroll-functions'
1440are unaffected by these changes.
1439 1441
1440In addition, a number of functions now allow the caller to detect what 1442In addition, a number of functions now allow the caller to detect what
1441has changed since last redisplay: 'window-old-buffer' returns for any 1443has changed since last redisplay: 'window-old-buffer' returns for any
@@ -1447,10 +1449,8 @@ during last redisplay. 'window-old-pixel-width' (renamed from
1447'window-old-body-pixel-width' and 'window-old-body-pixel-height' 1449'window-old-body-pixel-width' and 'window-old-body-pixel-height'
1448return the total and body sizes of any window during last redisplay. 1450return the total and body sizes of any window during last redisplay.
1449 1451
1450One consequence of these changes is that all window change functions 1452See the section "(elisp) Window Hooks" in the Elisp manual for a
1451run now after functions run by 'post-command-hook'. See the section 1453detailed explanation of the new behavior.
1452"(elisp) Window Hooks" in the Elisp manual for a detailed explanation
1453of the new behavior.
1454 1454
1455+++ 1455+++
1456** New buffer display action alist entry 'dedicated'. 1456** New buffer display action alist entry 'dedicated'.
diff --git a/src/frame.c b/src/frame.c
index 1219569068e..c336369dbb5 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -3611,6 +3611,40 @@ bottom edge of FRAME's display. */)
3611 3611
3612 return Qt; 3612 return Qt;
3613} 3613}
3614
3615DEFUN ("frame-window-state-change", Fframe_window_state_change,
3616 Sframe_window_state_change, 0, 1, 0,
3617 doc: /* Return t if FRAME's window state change flag is set, nil otherwise.
3618FRAME must be a live frame and defaults to the selected one.
3619
3620If FRAME's window state change flag is set, the default values of
3621`window-state-change-functions' and `window-state-change-hook' will be
3622run during next redisplay, regardless of whether a window state change
3623actually occurred on FRAME or not. After that, the value of this flag
3624is reset. */)
3625 (Lisp_Object frame)
3626{
3627 return FRAME_WINDOW_STATE_CHANGE (decode_live_frame (frame)) ? Qt : Qnil;
3628}
3629
3630DEFUN ("set-frame-window-state-change", Fset_frame_window_state_change,
3631 Sset_frame_window_state_change, 0, 2, 0,
3632 doc: /* Set FRAME's window state change flag according to ARG.
3633Set FRAME's window state change flag if ARG is non-nil, reset it
3634otherwise.
3635
3636If FRAME's window state change flag is set, the default values of
3637`window-state-change-functions' and `window-state-change-hook' will be
3638run during next redisplay, regardless of whether a window state change
3639actually occurred on FRAME or not. After that, the value of FRAME's
3640window state change flag is reset. */)
3641 (Lisp_Object frame, Lisp_Object arg)
3642{
3643 struct frame *f = decode_live_frame (frame);
3644
3645 return (FRAME_WINDOW_STATE_CHANGE (f) = !NILP (arg)) ? Qt : Qnil;
3646}
3647
3614 3648
3615/*********************************************************************** 3649/***********************************************************************
3616 Frame Parameters 3650 Frame Parameters
@@ -6256,6 +6290,8 @@ iconify the top level frame instead. */);
6256 defsubr (&Sframe_position); 6290 defsubr (&Sframe_position);
6257 defsubr (&Sset_frame_position); 6291 defsubr (&Sset_frame_position);
6258 defsubr (&Sframe_pointer_visible_p); 6292 defsubr (&Sframe_pointer_visible_p);
6293 defsubr (&Sframe_window_state_change);
6294 defsubr (&Sset_frame_window_state_change);
6259 6295
6260#ifdef HAVE_WINDOW_SYSTEM 6296#ifdef HAVE_WINDOW_SYSTEM
6261 defsubr (&Sx_get_resource); 6297 defsubr (&Sx_get_resource);
diff --git a/src/frame.h b/src/frame.h
index 544e0bef17a..5bac24b077e 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -334,6 +334,10 @@ struct frame
334 frame. */ 334 frame. */
335 bool_bf window_change : 1; 335 bool_bf window_change : 1;
336 336
337 /* True if running window state change functions has been explicitly
338 requested for this frame since last redisplay. */
339 bool_bf window_state_change : 1;
340
337 /* True if the mouse has moved on this display device 341 /* True if the mouse has moved on this display device
338 since the last time we checked. */ 342 since the last time we checked. */
339 bool_bf mouse_moved : 1; 343 bool_bf mouse_moved : 1;
@@ -944,6 +948,10 @@ default_pixels_per_inch_y (void)
944 window change functions were run on F. */ 948 window change functions were run on F. */
945#define FRAME_WINDOW_CHANGE(f) (f)->window_change 949#define FRAME_WINDOW_CHANGE(f) (f)->window_change
946 950
951/* True if running window state change functions has been explicitly
952 requested for this frame since last redisplay. */
953#define FRAME_WINDOW_STATE_CHANGE(f) (f)->window_state_change
954
947/* The minibuffer window of frame F, if it has one; otherwise nil. */ 955/* The minibuffer window of frame F, if it has one; otherwise nil. */
948#define FRAME_MINIBUF_WINDOW(f) f->minibuffer_window 956#define FRAME_MINIBUF_WINDOW(f) f->minibuffer_window
949 957
diff --git a/src/window.c b/src/window.c
index 8543cbf5ae9..c498ae81cdb 100644
--- a/src/window.c
+++ b/src/window.c
@@ -88,6 +88,9 @@ static Lisp_Object old_selected_window;
88 by setting it to nil. */ 88 by setting it to nil. */
89Lisp_Object Vwindow_list; 89Lisp_Object Vwindow_list;
90 90
91/* True mean window_change_record has to record all live frames. */
92static bool window_change_record_frames;
93
91/* The mini-buffer window of the selected frame. 94/* The mini-buffer window of the selected frame.
92 Note that you cannot test for mini-bufferness of an arbitrary window 95 Note that you cannot test for mini-bufferness of an arbitrary window
93 by comparing against this; but you can test for mini-bufferness of 96 by comparing against this; but you can test for mini-bufferness of
@@ -3426,8 +3429,8 @@ run_window_configuration_change_hook (struct frame *f)
3426 XSETFRAME (frame, f); 3429 XSETFRAME (frame, f);
3427 3430
3428 if (NILP (Vrun_hooks) 3431 if (NILP (Vrun_hooks)
3429 || !(f->can_x_set_window_size) 3432 || !f->can_x_set_window_size
3430 || !(f->after_make_frame)) 3433 || !f->after_make_frame)
3431 return; 3434 return;
3432 3435
3433 /* Use the right buffer. Matters when running the local hooks. */ 3436 /* 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)
3574 3577
3575 3578
3576/** 3579/**
3577 * window_change_record_frame:
3578 *
3579 * Record changes for FRAME. This records FRAME's selected window,
3580 * updates FRAME's change stamp, records the states of all live
3581 * windows of FRAME via window_change_record_windows and resets
3582 * FRAME's window_change flag.
3583 */
3584static void
3585window_change_record_frame (Lisp_Object frame)
3586{
3587 struct frame *f = XFRAME (frame);
3588
3589 /* Record selected window. */
3590 fset_old_selected_window (f, FRAME_SELECTED_WINDOW (f));
3591
3592 /* Bump up FRAME's change stamp. If this wraps, make it 1 to avoid
3593 that a new window (whose change stamp is always set to 0) gets
3594 reported as "existing before". */
3595 f->change_stamp += 1;
3596 if (f->change_stamp == 0)
3597 f->change_stamp = 1;
3598
3599 /* Bump up the change stamps of all live windows on this frame so
3600 the next call of this function can tell whether any of them
3601 "existed before" and record state for each of these windows. */
3602 f->number_of_windows
3603 = window_change_record_windows (f->root_window, f->change_stamp, 0);
3604
3605 /* Reset our flag. */
3606 FRAME_WINDOW_CHANGE (f) = false;
3607}
3608
3609
3610/**
3611 * window_change_record: 3580 * window_change_record:
3612 * 3581 *
3582 * For each frame that has recorded changes, record its selected
3583 * window, update Fchange stamp, record the states of all its live
3584 * windows via window_change_record_windows and reset its
3585 * window_change and window_state_change flags.
3586 *
3613 * Record selected window in old_selected_window and selected frame in 3587 * Record selected window in old_selected_window and selected frame in
3614 * old_selected_frame. 3588 * old_selected_frame.
3615 */ 3589 */
3616static void 3590static void
3617window_change_record (void) 3591window_change_record (void)
3618{ 3592{
3593 if (window_change_record_frames)
3594 {
3595 Lisp_Object tail, frame;
3596
3597 FOR_EACH_FRAME (tail, frame)
3598 {
3599 struct frame *f = XFRAME (frame);
3600
3601 /* Record FRAME's selected window. */
3602 fset_old_selected_window (f, FRAME_SELECTED_WINDOW (f));
3603
3604 /* Bump up FRAME's change stamp. If this wraps, make it 1 to avoid
3605 that a new window (whose change stamp is always set to 0) gets
3606 reported as "existing before". */
3607 f->change_stamp += 1;
3608 if (f->change_stamp == 0)
3609 f->change_stamp = 1;
3610
3611 /* Bump up the change stamps of all live windows on this frame so
3612 the next call of this function can tell whether any of them
3613 "existed before" and record state for each of these windows. */
3614 f->number_of_windows
3615 = window_change_record_windows (f->root_window, f->change_stamp, 0);
3616
3617 /* Reset our flags. */
3618 FRAME_WINDOW_CHANGE (f) = false;
3619 FRAME_WINDOW_STATE_CHANGE (f) = false;
3620 }
3621 }
3622
3619 /* Strictly spoken we don't need old_selected_window at all - its 3623 /* Strictly spoken we don't need old_selected_window at all - its
3620 value is the old selected window of old_selected_frame. */ 3624 value is the old selected window of old_selected_frame. */
3621 old_selected_window = selected_window; 3625 old_selected_window = selected_window;
@@ -3647,8 +3651,18 @@ run_window_change_functions_1 (Lisp_Object symbol, Lisp_Object buffer,
3647 3651
3648 while (CONSP (funs)) 3652 while (CONSP (funs))
3649 { 3653 {
3650 if (!EQ (XCAR (funs), Qt)) 3654 if (!EQ (XCAR (funs), Qt)
3651 safe_call1 (XCAR (funs), window_or_frame); 3655 && (NILP (buffer)
3656 ? FRAME_LIVE_P (XFRAME (window_or_frame))
3657 : WINDOW_LIVE_P (window_or_frame)))
3658 {
3659 /* Any function called here may change the state of any
3660 frame. Make sure to record changes for each live frame
3661 in window_change_record later. */
3662 window_change_record_frames = true;
3663 safe_call1 (XCAR (funs), window_or_frame);
3664 }
3665
3652 funs = XCDR (funs); 3666 funs = XCDR (funs);
3653 } 3667 }
3654} 3668}
@@ -3661,8 +3675,9 @@ run_window_change_functions_1 (Lisp_Object symbol, Lisp_Object buffer,
3661 * must be called from a "safe" position in redisplay_internal. 3675 * must be called from a "safe" position in redisplay_internal.
3662 * 3676 *
3663 * Do not run any functions for a frame whose window_change flag is 3677 * Do not run any functions for a frame whose window_change flag is
3664 * nil and where no window selection happened since the last time this 3678 * nil, where no window selection happened and whose window state
3665 * function was called. Also, skip any tooltip frame. 3679 * change flag was not set since the last time this function was
3680 * called. Never run any functions for tooltip frames.
3666 * 3681 *
3667 * The change functions run are, in this order: 3682 * The change functions run are, in this order:
3668 * 3683 *
@@ -3679,25 +3694,35 @@ run_window_change_functions_1 (Lisp_Object symbol, Lisp_Object buffer,
3679 * `window-selected-change-functions' run for a window that was 3694 * `window-selected-change-functions' run for a window that was
3680 * (de-)selected since the last time window change functions were run. 3695 * (de-)selected since the last time window change functions were run.
3681 * 3696 *
3697 * `window-state-change-functions' run for a window for which any of
3698 * the above three changes occurred.
3699 *
3682 * A buffer-local value of these functions is run if and only if the 3700 * A buffer-local value of these functions is run if and only if the
3683 * window for which the functions are run, currently shows the buffer. 3701 * window for which the functions are run currently shows the buffer.
3684 * Each call gets one argument - the window showing the buffer. This 3702 * Each call gets one argument - the window showing the buffer. This
3685 * means that the buffer-local value of these functions may be called 3703 * means that the buffer-local value of these functions may be called
3686 * as many times at the buffer is shown on the frame. 3704 * as many times as the buffer is shown on the frame.
3687 * 3705 *
3688 * The default value of these functions is called only after all 3706 * The default values of these functions are called only after all
3689 * buffer-local values for all of these functions have been run. Each 3707 * buffer-local values for all of these functions have been run. Each
3690 * such call receives one argument - the frame for which this function 3708 * such call receives one argument - the frame for which a change
3691 * is run. 3709 * occurred. Functions on `window-state-change-functions' are run
3710 * also if the corresponding frame's window state change flag has been
3711 * set.
3692 * 3712 *
3693 * After the three change functions cited above have been run in the 3713 * After the four change functions cited above have been run in the
3694 * indicated way, functions on 'window-configuration-change-hook' are 3714 * indicated way, functions on 'window-configuration-change-hook' are
3695 * run. A buffer-local value is run if a window shows that buffer and 3715 * run. A buffer-local value is run if a window shows that buffer and
3696 * has either changed its buffer or its body or total size or did not 3716 * has either changed its buffer or its body or total size or did not
3697 * appear on this frame since the last time window change functions 3717 * appear on this frame since the last time window change functions
3698 * were run. The functions are called without argument and the 3718 * were run. The functions are called without argument and with the
3699 * buffer's window selected. The default value is run without 3719 * buffer's window selected. The default value is run without
3700 * argument and the frame for which the function is run selected. 3720 * argument and with the frame for which the function is run selected.
3721 *
3722 * In a final step, functions on `window-state-change-hook' are run
3723 * provided a window state change has occurred or the window state
3724 * change flag has been set on at least one frame. Each of these
3725 * functions is called without argument.
3701 * 3726 *
3702 * This function does not save and restore match data. Any functions 3727 * This function does not save and restore match data. Any functions
3703 * it calls are responsible for doing that themselves. 3728 * it calls are responsible for doing that themselves.
@@ -3707,8 +3732,10 @@ run_window_change_functions (void)
3707{ 3732{
3708 Lisp_Object tail, frame; 3733 Lisp_Object tail, frame;
3709 bool selected_frame_change = !EQ (selected_frame, old_selected_frame); 3734 bool selected_frame_change = !EQ (selected_frame, old_selected_frame);
3710 ptrdiff_t count_outer = SPECPDL_INDEX (); 3735 bool run_window_state_change_hook = false;
3736 ptrdiff_t count = SPECPDL_INDEX ();
3711 3737
3738 window_change_record_frames = false;
3712 record_unwind_protect_void (window_change_record); 3739 record_unwind_protect_void (window_change_record);
3713 specbind (Qinhibit_redisplay, Qt); 3740 specbind (Qinhibit_redisplay, Qt);
3714 3741
@@ -3725,19 +3752,21 @@ run_window_change_functions (void)
3725 || EQ (frame, selected_frame))); 3752 || EQ (frame, selected_frame)));
3726 bool frame_selected_window_change 3753 bool frame_selected_window_change
3727 = !EQ (FRAME_OLD_SELECTED_WINDOW (f), FRAME_SELECTED_WINDOW (f)); 3754 = !EQ (FRAME_OLD_SELECTED_WINDOW (f), FRAME_SELECTED_WINDOW (f));
3755 bool frame_window_state_change = FRAME_WINDOW_STATE_CHANGE (f);
3728 bool window_deleted = false; 3756 bool window_deleted = false;
3729 Lisp_Object windows; 3757 Lisp_Object windows;
3730 ptrdiff_t number_of_windows; 3758 ptrdiff_t number_of_windows;
3731 ptrdiff_t count_inner = SPECPDL_INDEX ();
3732 3759
3733 if (!f->can_x_set_window_size 3760 if (!FRAME_LIVE_P (f)
3761 || !f->can_x_set_window_size
3734 || !f->after_make_frame 3762 || !f->after_make_frame
3735 || FRAME_TOOLTIP_P (f) 3763 || FRAME_TOOLTIP_P (f)
3736 || !(frame_window_change 3764 || !(frame_window_change
3737 || frame_selected_change 3765 || frame_selected_change
3738 || frame_selected_window_change)) 3766 || frame_selected_window_change
3739 /* Either we cannot run hooks for this frame yet or no window 3767 || frame_window_state_change))
3740 change has been reported for this frame since the last time 3768 /* Either we are not allowed to run hooks for this frame or no
3769 window change has been reported for it since the last time
3741 we ran window change functions on it. */ 3770 we ran window change functions on it. */
3742 continue; 3771 continue;
3743 3772
@@ -3745,8 +3774,6 @@ run_window_change_functions (void)
3745 windows = Fnreverse (window_sub_list (root, Qnil)); 3774 windows = Fnreverse (window_sub_list (root, Qnil));
3746 number_of_windows = 0; 3775 number_of_windows = 0;
3747 3776
3748 record_unwind_protect (window_change_record_frame, frame);
3749
3750 /* The following loop collects all data needed to tell whether 3777 /* The following loop collects all data needed to tell whether
3751 the default value of a hook shall be run and runs any buffer 3778 the default value of a hook shall be run and runs any buffer
3752 local hooks right away. */ 3779 local hooks right away. */
@@ -3857,13 +3884,21 @@ run_window_change_functions (void)
3857 (Qwindow_selection_change_functions, Qnil, frame); 3884 (Qwindow_selection_change_functions, Qnil, frame);
3858 3885
3859 /* A frame has changed state when a size or buffer change 3886 /* A frame has changed state when a size or buffer change
3860 occurrd or its selected window has changed or when it was 3887 occurred, its selected window has changed, when it was
3861 (de-)selected. */ 3888 (de-)selected or its window state change flag was set. */
3862 if ((frame_selected_change || frame_selected_window_change 3889 if ((frame_selected_change || frame_selected_window_change
3863 || frame_buffer_change || window_deleted || frame_size_change) 3890 || frame_buffer_change || window_deleted
3891 || frame_size_change || frame_window_state_change)
3864 && FRAME_LIVE_P (f)) 3892 && FRAME_LIVE_P (f))
3865 run_window_change_functions_1 3893 {
3866 (Qwindow_state_change_functions, Qnil, frame); 3894 run_window_change_functions_1
3895 (Qwindow_state_change_functions, Qnil, frame);
3896 /* Make sure to run 'window-state-change-hook' later. */
3897 run_window_state_change_hook = true;
3898 /* Make sure to record changes for each live frame in
3899 window_change_record later. */
3900 window_change_record_frames = true;
3901 }
3867 3902
3868 /* A frame's configuration changed when one of its windows has 3903 /* A frame's configuration changed when one of its windows has
3869 changed buffer or size or at least one window was deleted. */ 3904 changed buffer or size or at least one window was deleted. */
@@ -3871,17 +3906,16 @@ run_window_change_functions (void)
3871 /* This will run any buffer local window configuration change 3906 /* This will run any buffer local window configuration change
3872 hook as well. */ 3907 hook as well. */
3873 run_window_configuration_change_hook (f); 3908 run_window_configuration_change_hook (f);
3874
3875 if (!FRAME_LIVE_P (f))
3876 continue;
3877
3878 /* Record changes (via window_change_record_frame) for this
3879 frame, even when an unhandled error occurred. */
3880 unbind_to (count_inner, Qnil);
3881 } 3909 }
3882 3910
3883 /* Record selected window and frame. */ 3911 /* Run 'window-state-change-hook' if at least one frame has changed
3884 unbind_to (count_outer, Qnil); 3912 state. */
3913 if (run_window_state_change_hook && !NILP (Vwindow_state_change_hook))
3914 safe_run_hooks (Qwindow_state_change_hook);
3915
3916 /* Record changes for all frames (if asked for), selected window and
3917 frame. */
3918 unbind_to (count, Qnil);
3885} 3919}
3886 3920
3887/* Make WINDOW display BUFFER. RUN_HOOKS_P means it's allowed 3921/* Make WINDOW display BUFFER. RUN_HOOKS_P means it's allowed
@@ -7999,6 +8033,7 @@ syms_of_window (void)
7999 Fput (Qscroll_down, Qscroll_command, Qt); 8033 Fput (Qscroll_down, Qscroll_command, Qt);
8000 8034
8001 DEFSYM (Qwindow_configuration_change_hook, "window-configuration-change-hook"); 8035 DEFSYM (Qwindow_configuration_change_hook, "window-configuration-change-hook");
8036 DEFSYM (Qwindow_state_change_hook, "window-state-change-hook");
8002 DEFSYM (Qwindow_state_change_functions, "window-state-change-functions"); 8037 DEFSYM (Qwindow_state_change_functions, "window-state-change-functions");
8003 DEFSYM (Qwindow_size_change_functions, "window-size-change-functions"); 8038 DEFSYM (Qwindow_size_change_functions, "window-size-change-functions");
8004 DEFSYM (Qwindow_buffer_change_functions, "window-buffer-change-functions"); 8039 DEFSYM (Qwindow_buffer_change_functions, "window-buffer-change-functions");
@@ -8132,11 +8167,25 @@ redisplay. In this case the window is passed as argument.
8132 8167
8133Functions specified by the default value are called for each frame if 8168Functions specified by the default value are called for each frame if
8134at least one window on that frame has been added, deleted, changed its 8169at least one window on that frame has been added, deleted, changed its
8135buffer or its total or body size or the frame has been (de-)selected 8170buffer or its total or body size or the frame has been (de-)selected,
8136or its selected window has changed since the last redisplay. In this 8171its selected window has changed or the window state change flag has
8137case the frame is passed as argument. */); 8172been set for this frame since the last redisplay. In this case the
8173frame is passed as argument. */);
8138 Vwindow_state_change_functions = Qnil; 8174 Vwindow_state_change_functions = Qnil;
8139 8175
8176 DEFVAR_LISP ("window-state-change-hook", Vwindow_state_change_hook,
8177 doc: /* Functions called during redisplay when the window state changed.
8178The value should be a list of functions that take no argument.
8179
8180This hook is called during redisplay when at least one window has been
8181added, deleted, (de-)selected, changed its buffer or its total or body
8182size or the window state change flag has been set for at least one
8183frame. This hook is called after all other window change functions
8184have been run and should be used only if a function should react to
8185changes that happened on at least two frames since last redisplay or
8186the function intends to change the window configuration. */);
8187 Vwindow_state_change_hook = Qnil;
8188
8140 DEFVAR_LISP ("window-configuration-change-hook", Vwindow_configuration_change_hook, 8189 DEFVAR_LISP ("window-configuration-change-hook", Vwindow_configuration_change_hook,
8141 doc: /* Functions called during redisplay when window configuration has changed. 8190 doc: /* Functions called during redisplay when window configuration has changed.
8142The value should be a list of functions that take no argument. 8191The value should be a list of functions that take no argument.