diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index 6b5aa66a955..afb81e6874f 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -1758,7 +1758,7 @@ raise the frame or make sure input focus is directed to that frame. @xref{Input Focus}. @end defun -@cindex select window hook +@cindex select window hooks @cindex running a hook when a window gets selected For historical reasons, Emacs does not run a separate hook whenever a window gets selected. Applications and internal routines often @@ -1774,8 +1774,8 @@ useful. However, when its @var{norecord} argument is @code{nil}, @code{select-window} updates the buffer list and thus indirectly runs the normal hook @code{buffer-list-update-hook} (@pxref{Buffer List}). -Consequently, that hook provides a reasonable way to run a function -whenever a window gets selected more ``permanently''. +Consequently, that hook provides one way to run a function whenever a +window gets selected more ``permanently''. Since @code{buffer-list-update-hook} is also run by functions that are not related to window management, it will usually make sense to save the @@ -1787,6 +1787,13 @@ temporarily passes a non-@code{nil} @var{norecord} argument. If possible, the macro @code{with-selected-window} (see below) should be used in such cases. + Emacs also runs the hook @code{window-selection-change-functions} +whenever the redisplay routine detects that another window has been +selected since last redisplay. @xref{Window Hooks}, for a detailed +explanation. @code{window-state-change-functions} (described in the +same section) is another abnormal hook run after a different window +has been selected but is triggered by other window changes as well. + @cindex most recently selected windows The sequence of calls to @code{select-window} with a non-@code{nil} @var{norecord} argument determines an ordering of windows by their @@ -6039,7 +6046,7 @@ 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 four hooks that are called at + The remainder of this section covers five 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 @@ -6108,10 +6115,37 @@ window has changed since the last time window change functions were 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 +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 +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 added or assigned +another buffer, total or body size or 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 at +least one window on that frame has been added, deleted or assigned +another buffer, 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. +@end defvar + @cindex window configuration change -The fourth of these hooks is run when a @dfn{window configuration +The fifth 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. +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 diff --git a/etc/NEWS b/etc/NEWS index 02503073c1c..10bcc5a2ecc 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1303,14 +1303,17 @@ of the Emacs Lisp Reference manual for more detail. +++ ** 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: +that a change has actually occurred. The five 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 +(like the former but run also when a window was deleted), 'window-selection-change-functions' (run when the selected window -changed). 'window-scroll-functions' are unaffected by these changes. +changed) and 'window-state-change-functions' (run when any of the +preceding ones is run). '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 diff --git a/src/window.c b/src/window.c index 7eb532f78cf..c0d745995a8 100644 --- a/src/window.c +++ b/src/window.c @@ -3799,7 +3799,7 @@ run_window_change_functions (void) run_window_change_functions_1 (Qwindow_size_change_functions, buffer, window); - /* This window's selection has changed when it it was + /* This window's selection has changed when it was (de-)selected as its frame's or the globally selected window. */ if (((frame_selected_change @@ -3811,6 +3811,21 @@ run_window_change_functions (void) && WINDOW_LIVE_P (window)) run_window_change_functions_1 (Qwindow_selection_change_functions, buffer, window); + + /* This window's state has changed when its buffer or size + changed or it was (de-)selected as its frame's or the + globally selected window. */ + if ((window_buffer_change + || window_size_change + || ((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_state_change_functions, buffer, window); } /* When the number of windows on a frame has decreased, at least @@ -3840,6 +3855,15 @@ run_window_change_functions (void) run_window_change_functions_1 (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. */ + if ((frame_selected_change || frame_selected_window_change + || frame_buffer_change || window_deleted || frame_size_change) + && FRAME_LIVE_P (f)) + run_window_change_functions_1 + (Qwindow_state_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)) @@ -4650,16 +4674,26 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) /* For a leaf root window just set the size. */ if (horflag) { + bool changed = r->pixel_width != new_pixel_size; + r->total_cols = new_size; r->pixel_width = new_pixel_size; + + if (changed && !WINDOW_PSEUDO_P (r)) + FRAME_WINDOW_CHANGE (f) = true; } else { + bool changed = r->pixel_height != new_pixel_size; + r->top_line = FRAME_TOP_MARGIN (f); r->pixel_top = FRAME_TOP_MARGIN_HEIGHT (f); r->total_lines = new_size; r->pixel_height = new_pixel_size; + + if (changed && !WINDOW_PSEUDO_P (r)) + FRAME_WINDOW_CHANGE (f) = true; } else { @@ -7953,6 +7987,7 @@ syms_of_window (void) Fput (Qscroll_down, Qscroll_command, Qt); DEFSYM (Qwindow_configuration_change_hook, "window-configuration-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"); DEFSYM (Qwindow_selection_change_functions, "window-selection-change-functions"); @@ -8074,6 +8109,22 @@ 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-state-change-functions", Vwindow_state_change_functions, + doc: /* Functions called during redisplay when the window state 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, +resized, changed its buffer or has been (de-)selected 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, 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. */); + 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.