aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMartin Rudalics2016-02-23 12:08:55 +0100
committerMartin Rudalics2016-02-23 12:08:55 +0100
commit8e7712c7afc47a8a861a9f4d6a10be1f78a2dac6 (patch)
tree46b7a58fae8aa09fc316cec8231697f84282a319 /src
parentef52e66efd78aac4c4e5bd5e11870e5ba3b37a1e (diff)
downloademacs-8e7712c7afc47a8a861a9f4d6a10be1f78a2dac6.tar.gz
emacs-8e7712c7afc47a8a861a9f4d6a10be1f78a2dac6.zip
Fix `window-configuration-change-hook' and `window-size-change-functions'
(1) Run `window-configuration-change-hook' if and only if at least one window was deleted or created or shows another buffer since last redisplay. (2) Run `window-size-change-functions' if and only if at least one window changed its size since last redisplay (in a few cases `window-size-change-functions' will also run when no window changed its size). (3) Provide two functions `window-pixel-height-before-size-change' and `window-pixel-width-before-size-change' that allow to easily detect which window changed size. * src/frame.h (struct frame): New boolean member window_configuration_changed. (FRAME_WINDOW_SIZES_CHANGED): Remove macro. (FRAME_WINDOW_CONFIGURATION_CHANGED): New macro. * src/frame.c (adjust_frame_size): Don't run `window-configuration-change-hook'. * src/window.h (struct window): New fields pixel_width_before_size_change and pixel_height_before_size_change. (WINDOW_INTERNAL_P): New macro. * src/window.c (Fwindow_pixel_width_before_size_change) (Fwindow_pixel_height_before_size_change): New functions. (Fdelete_other_windows_internal, Fwindow_resize_apply) (resize_frame_windows, Fsplit_window_internal) (Fdelete_window_internal, grow_mini_window) (shrink_mini_window, Fresize_mini_window_internal): Don't call FRAME_WINDOW_SIZES_CHANGED. (window_size_changed, window_set_before_size_change_sizes) (run_window_size_change_functions): New functions. (make_window): Initialize pixel_width_before_size_change and pixel_height_before_size_change. (Fdelete_window_internal): Don't call run_window_configuration_change_hook. (struct saved_window): Add pixel_height_before_size_change and pixel_width_before_size_change. (Fset_window_configuration): Try to identify window configuration changes correctly so run_window_configuration_change_hook and run_window_size_change_functions run only if configuration and size really changed. (save_window_save): Set the pixel_height_before_size_change and pixel_width_before_size_change fields. (Vwindow_size_change_functions): Move here definiton from xdisp.c. * src/xdisp.c (prepare_menu_bars, redisplay_internal): Call run_window_size_change_functions. (Vwindow_size_change_functions): Move definition to window.c. * src/xfns.c (x_set_menu_bar_lines): Don't call run_window_configuration_change_hook. * doc/lispref/windows.texi (Window Sizes): Document new functions `window-pixel-height-before-size-change' and `window-pixel-width-before-size-change'. (Window Configurations): Mention that this may trigger execution of `window-size-change-functions' although no window changed size. (Window Hooks): Update descriptions of `window-size-change-functions' and `window-configuration-change-hook'.
Diffstat (limited to 'src')
-rw-r--r--src/frame.c2
-rw-r--r--src/frame.h13
-rw-r--r--src/window.c205
-rw-r--r--src/window.h16
-rw-r--r--src/xdisp.c59
-rw-r--r--src/xfns.c1
6 files changed, 199 insertions, 97 deletions
diff --git a/src/frame.c b/src/frame.c
index 8c86afe4efb..df473aebc21 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -591,8 +591,6 @@ adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit,
591 || new_pixel_height != old_pixel_height); 591 || new_pixel_height != old_pixel_height);
592 592
593 unblock_input (); 593 unblock_input ();
594
595 run_window_configuration_change_hook (f);
596} 594}
597 595
598/* Allocate basically initialized frame. */ 596/* Allocate basically initialized frame. */
diff --git a/src/frame.h b/src/frame.h
index 71dab4b1cb1..d9424ab5965 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -288,8 +288,9 @@ struct frame
288 cleared. */ 288 cleared. */
289 bool_bf explicit_name : 1; 289 bool_bf explicit_name : 1;
290 290
291 /* True if size of some window on this frame has changed. */ 291 /* True if configuration of windows on this frame has changed since
292 bool_bf window_sizes_changed : 1; 292 last call of run_window_size_change_functions. */
293 bool_bf window_configuration_changed : 1;
293 294
294 /* True if the mouse has moved on this display device 295 /* True if the mouse has moved on this display device
295 since the last time we checked. */ 296 since the last time we checked. */
@@ -828,10 +829,10 @@ default_pixels_per_inch_y (void)
828 are frozen on frame F. */ 829 are frozen on frame F. */
829#define FRAME_WINDOWS_FROZEN(f) (f)->frozen_window_starts 830#define FRAME_WINDOWS_FROZEN(f) (f)->frozen_window_starts
830 831
831/* True if a size change has been requested for frame F 832/* True if the frame's window configuration has changed since last call
832 but not yet really put into effect. This can be true temporarily 833 of run_window_size_change_functions. */
833 when an X event comes in at a bad time. */ 834#define FRAME_WINDOW_CONFIGURATION_CHANGED(f) \
834#define FRAME_WINDOW_SIZES_CHANGED(f) (f)->window_sizes_changed 835 ((f)->window_configuration_changed)
835 836
836/* The minibuffer window of frame F, if it has one; otherwise nil. */ 837/* The minibuffer window of frame F, if it has one; otherwise nil. */
837#define FRAME_MINIBUF_WINDOW(f) f->minibuffer_window 838#define FRAME_MINIBUF_WINDOW(f) f->minibuffer_window
diff --git a/src/window.c b/src/window.c
index e1a30ee5714..29c35875039 100644
--- a/src/window.c
+++ b/src/window.c
@@ -720,6 +720,34 @@ the height of the screen areas spanned by its children. */)
720 return make_number (decode_valid_window (window)->pixel_height); 720 return make_number (decode_valid_window (window)->pixel_height);
721} 721}
722 722
723DEFUN ("window-pixel-width-before-size-change", Fwindow_pixel_width_before_size_change,
724 Swindow_pixel_width_before_size_change, 0, 1, 0,
725 doc: /* Return pixel width of window WINDOW before last size changes.
726WINDOW must be a valid window and defaults to the selected one.
727
728The return value is the pixel width of WINDOW at the last time
729`window-size-change-functions' was run. It's zero if WINDOW was made
730after that. */)
731 (Lisp_Object window)
732{
733 return (make_number
734 (decode_valid_window (window)->pixel_width_before_size_change));
735}
736
737DEFUN ("window-pixel-height-before-size-change", Fwindow_pixel_height_before_size_change,
738 Swindow_pixel_height_before_size_change, 0, 1, 0,
739 doc: /* Return pixel height of window WINDOW before last size changes.
740WINDOW must be a valid window and defaults to the selected one.
741
742The return value is the pixel height of WINDOW at the last time
743`window-size-change-functions' was run. It's zero if WINDOW was made
744after that. */)
745 (Lisp_Object window)
746{
747 return (make_number
748 (decode_valid_window (window)->pixel_height_before_size_change));
749}
750
723DEFUN ("window-total-height", Fwindow_total_height, Swindow_total_height, 0, 2, 0, 751DEFUN ("window-total-height", Fwindow_total_height, Swindow_total_height, 0, 2, 0,
724 doc: /* Return the height of window WINDOW in lines. 752 doc: /* Return the height of window WINDOW in lines.
725WINDOW must be a valid window and defaults to the selected one. 753WINDOW must be a valid window and defaults to the selected one.
@@ -2879,6 +2907,7 @@ window-start value is reasonable when this function is called. */)
2879 Lisp_Object sibling, pwindow, swindow IF_LINT (= Qnil), delta; 2907 Lisp_Object sibling, pwindow, swindow IF_LINT (= Qnil), delta;
2880 ptrdiff_t startpos IF_LINT (= 0), startbyte IF_LINT (= 0); 2908 ptrdiff_t startpos IF_LINT (= 0), startbyte IF_LINT (= 0);
2881 int top IF_LINT (= 0), new_top; 2909 int top IF_LINT (= 0), new_top;
2910 bool resize_failed = false;
2882 2911
2883 w = decode_valid_window (window); 2912 w = decode_valid_window (window);
2884 XSETWINDOW (window, w); 2913 XSETWINDOW (window, w);
@@ -2978,8 +3007,6 @@ window-start value is reasonable when this function is called. */)
2978 3007
2979 fset_redisplay (f); 3008 fset_redisplay (f);
2980 Vwindow_list = Qnil; 3009 Vwindow_list = Qnil;
2981 FRAME_WINDOW_SIZES_CHANGED (f) = true;
2982 bool resize_failed = false;
2983 3010
2984 if (!WINDOW_LEAF_P (w)) 3011 if (!WINDOW_LEAF_P (w))
2985 { 3012 {
@@ -3229,6 +3256,76 @@ If WINDOW is omitted or nil, it defaults to the selected window. */)
3229 return Qnil; 3256 return Qnil;
3230} 3257}
3231 3258
3259
3260/* Compare old and present pixel sizes of windows in tree rooted at W.
3261 Return true iff any of these windows differs in size. */
3262
3263static bool
3264window_size_changed (struct window *w)
3265{
3266 if (w->pixel_width != w->pixel_width_before_size_change
3267 || w->pixel_height != w->pixel_height_before_size_change)
3268 return true;
3269
3270 if (WINDOW_INTERNAL_P (w))
3271 {
3272 w = XWINDOW (w->contents);
3273 while (w)
3274 {
3275 if (window_size_changed (w))
3276 return true;
3277
3278 w = NILP (w->next) ? 0 : XWINDOW (w->next);
3279 }
3280 }
3281
3282 return false;
3283}
3284
3285/* Set before size change pixel sizes of windows in tree rooted at W to
3286 their present pixel sizes. */
3287
3288static void
3289window_set_before_size_change_sizes (struct window *w)
3290{
3291 w->pixel_width_before_size_change = w->pixel_width;
3292 w->pixel_height_before_size_change = w->pixel_height;
3293
3294 if (WINDOW_INTERNAL_P (w))
3295 {
3296 w = XWINDOW (w->contents);
3297 while (w)
3298 {
3299 window_set_before_size_change_sizes (w);
3300 w = NILP (w->next) ? 0 : XWINDOW (w->next);
3301 }
3302 }
3303}
3304
3305
3306void
3307run_window_size_change_functions (Lisp_Object frame)
3308{
3309 struct frame *f = XFRAME (frame);
3310 struct window *r = XWINDOW (FRAME_ROOT_WINDOW (f));
3311 Lisp_Object functions = Vwindow_size_change_functions;
3312
3313 if (FRAME_WINDOW_CONFIGURATION_CHANGED (f) ||
3314 window_size_changed (r))
3315 {
3316 while (CONSP (functions))
3317 {
3318 if (!EQ (XCAR (functions), Qt))
3319 call1 (XCAR (functions), frame);
3320 functions = XCDR (functions);
3321 }
3322
3323 window_set_before_size_change_sizes (r);
3324 FRAME_WINDOW_CONFIGURATION_CHANGED (f) = false;
3325 }
3326}
3327
3328
3232/* Make WINDOW display BUFFER. RUN_HOOKS_P means it's allowed 3329/* Make WINDOW display BUFFER. RUN_HOOKS_P means it's allowed
3233 to run hooks. See make_frame for a case where it's not allowed. 3330 to run hooks. See make_frame for a case where it's not allowed.
3234 KEEP_MARGINS_P means that the current margins, fringes, and 3331 KEEP_MARGINS_P means that the current margins, fringes, and
@@ -3263,15 +3360,9 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer,
3263 3360
3264 if (!(keep_margins_p && samebuf)) 3361 if (!(keep_margins_p && samebuf))
3265 { /* If we're not actually changing the buffer, don't reset hscroll 3362 { /* If we're not actually changing the buffer, don't reset hscroll
3266 and vscroll. This case happens for example when called from 3363 and vscroll. Resetting hscroll and vscroll here is problematic
3267 change_frame_size_1, where we use a dummy call to 3364 for things like image-mode and doc-view-mode since it resets
3268 Fset_window_buffer on the frame's selected window (and no 3365 the image's position whenever we resize the frame. */
3269 other) just in order to run window-configuration-change-hook
3270 (no longer true since change_frame_size_1 directly calls
3271 run_window_configuration_change_hook). Resetting hscroll and
3272 vscroll here is problematic for things like image-mode and
3273 doc-view-mode since it resets the image's position whenever we
3274 resize the frame. */
3275 w->hscroll = w->min_hscroll = w->hscroll_whole = 0; 3366 w->hscroll = w->min_hscroll = w->hscroll_whole = 0;
3276 w->suspend_auto_hscroll = false; 3367 w->suspend_auto_hscroll = false;
3277 w->vscroll = 0; 3368 w->vscroll = 0;
@@ -3283,10 +3374,8 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer,
3283 w->start_at_line_beg = false; 3374 w->start_at_line_beg = false;
3284 w->force_start = false; 3375 w->force_start = false;
3285 } 3376 }
3286 /* Maybe we could move this into the `if' but it's not obviously safe and
3287 I doubt it's worth the trouble. */
3288 wset_redisplay (w);
3289 3377
3378 wset_redisplay (w);
3290 wset_update_mode_line (w); 3379 wset_update_mode_line (w);
3291 3380
3292 /* We must select BUFFER to run the window-scroll-functions and to look up 3381 /* We must select BUFFER to run the window-scroll-functions and to look up
@@ -3314,7 +3403,7 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer,
3314 3403
3315 if (run_hooks_p) 3404 if (run_hooks_p)
3316 { 3405 {
3317 if (! NILP (Vwindow_scroll_functions)) 3406 if (!NILP (Vwindow_scroll_functions))
3318 run_hook_with_args_2 (Qwindow_scroll_functions, window, 3407 run_hook_with_args_2 (Qwindow_scroll_functions, window,
3319 Fmarker_position (w->start)); 3408 Fmarker_position (w->start));
3320 if (!samebuf) 3409 if (!samebuf)
@@ -3559,6 +3648,8 @@ make_window (void)
3559 w->phys_cursor_width = -1; 3648 w->phys_cursor_width = -1;
3560#endif 3649#endif
3561 w->sequence_number = ++sequence_number; 3650 w->sequence_number = ++sequence_number;
3651 w->pixel_width_before_size_change = 0;
3652 w->pixel_height_before_size_change = 0;
3562 w->scroll_bar_width = -1; 3653 w->scroll_bar_width = -1;
3563 w->scroll_bar_height = -1; 3654 w->scroll_bar_height = -1;
3564 w->column_number_displayed = -1; 3655 w->column_number_displayed = -1;
@@ -3922,7 +4013,6 @@ be applied on the Elisp level. */)
3922 window_resize_apply (r, horflag); 4013 window_resize_apply (r, horflag);
3923 4014
3924 fset_redisplay (f); 4015 fset_redisplay (f);
3925 FRAME_WINDOW_SIZES_CHANGED (f) = true;
3926 4016
3927 adjust_frame_glyphs (f); 4017 adjust_frame_glyphs (f);
3928 unblock_input (); 4018 unblock_input ();
@@ -4087,7 +4177,6 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
4087 } 4177 }
4088 } 4178 }
4089 4179
4090 FRAME_WINDOW_SIZES_CHANGED (f) = true;
4091 fset_redisplay (f); 4180 fset_redisplay (f);
4092} 4181}
4093 4182
@@ -4214,7 +4303,6 @@ set correctly. See the code of `split-window' for how this is done. */)
4214 p = XWINDOW (o->parent); 4303 p = XWINDOW (o->parent);
4215 4304
4216 fset_redisplay (f); 4305 fset_redisplay (f);
4217 FRAME_WINDOW_SIZES_CHANGED (f) = true;
4218 new = make_window (); 4306 new = make_window ();
4219 n = XWINDOW (new); 4307 n = XWINDOW (new);
4220 wset_frame (n, frame); 4308 wset_frame (n, frame);
@@ -4383,7 +4471,6 @@ Signal an error when WINDOW is the only window on its frame. */)
4383 4471
4384 fset_redisplay (f); 4472 fset_redisplay (f);
4385 Vwindow_list = Qnil; 4473 Vwindow_list = Qnil;
4386 FRAME_WINDOW_SIZES_CHANGED (f) = true;
4387 4474
4388 wset_next (w, Qnil); /* Don't delete w->next too. */ 4475 wset_next (w, Qnil); /* Don't delete w->next too. */
4389 free_window_matrices (w); 4476 free_window_matrices (w);
@@ -4451,9 +4538,6 @@ Signal an error when WINDOW is the only window on its frame. */)
4451 } 4538 }
4452 else 4539 else
4453 unblock_input (); 4540 unblock_input ();
4454
4455 /* Must be run by the caller:
4456 run_window_configuration_change_hook (f); */
4457 } 4541 }
4458 else 4542 else
4459 /* We failed: Relink WINDOW into window tree. */ 4543 /* We failed: Relink WINDOW into window tree. */
@@ -4527,7 +4611,6 @@ grow_mini_window (struct window *w, int delta, bool pixelwise)
4527 /* Enforce full redisplay of the frame. */ 4611 /* Enforce full redisplay of the frame. */
4528 /* FIXME: Shouldn't window--resize-root-window-vertically do it? */ 4612 /* FIXME: Shouldn't window--resize-root-window-vertically do it? */
4529 fset_redisplay (f); 4613 fset_redisplay (f);
4530 FRAME_WINDOW_SIZES_CHANGED (f) = true;
4531 adjust_frame_glyphs (f); 4614 adjust_frame_glyphs (f);
4532 unblock_input (); 4615 unblock_input ();
4533 } 4616 }
@@ -4567,7 +4650,6 @@ shrink_mini_window (struct window *w, bool pixelwise)
4567 /* Enforce full redisplay of the frame. */ 4650 /* Enforce full redisplay of the frame. */
4568 /* FIXME: Shouldn't window--resize-root-window-vertically do it? */ 4651 /* FIXME: Shouldn't window--resize-root-window-vertically do it? */
4569 fset_redisplay (f); 4652 fset_redisplay (f);
4570 FRAME_WINDOW_SIZES_CHANGED (f) = true;
4571 adjust_frame_glyphs (f); 4653 adjust_frame_glyphs (f);
4572 unblock_input (); 4654 unblock_input ();
4573 } 4655 }
@@ -4610,7 +4692,6 @@ DEFUN ("resize-mini-window-internal", Fresize_mini_window_internal, Sresize_mini
4610 w->top_line = r->top_line + r->total_lines; 4692 w->top_line = r->top_line + r->total_lines;
4611 4693
4612 fset_redisplay (f); 4694 fset_redisplay (f);
4613 FRAME_WINDOW_SIZES_CHANGED (f) = true;
4614 adjust_frame_glyphs (f); 4695 adjust_frame_glyphs (f);
4615 unblock_input (); 4696 unblock_input ();
4616 return Qt; 4697 return Qt;
@@ -5948,6 +6029,7 @@ struct saved_window
5948 6029
5949 Lisp_Object window, buffer, start, pointm, old_pointm; 6030 Lisp_Object window, buffer, start, pointm, old_pointm;
5950 Lisp_Object pixel_left, pixel_top, pixel_height, pixel_width; 6031 Lisp_Object pixel_left, pixel_top, pixel_height, pixel_width;
6032 Lisp_Object pixel_height_before_size_change, pixel_width_before_size_change;
5951 Lisp_Object left_col, top_line, total_cols, total_lines; 6033 Lisp_Object left_col, top_line, total_cols, total_lines;
5952 Lisp_Object normal_cols, normal_lines; 6034 Lisp_Object normal_cols, normal_lines;
5953 Lisp_Object hscroll, min_hscroll, hscroll_whole, suspend_auto_hscroll; 6035 Lisp_Object hscroll, min_hscroll, hscroll_whole, suspend_auto_hscroll;
@@ -6063,6 +6145,12 @@ the return value is nil. Otherwise the value is t. */)
6063 struct window *root_window; 6145 struct window *root_window;
6064 struct window **leaf_windows; 6146 struct window **leaf_windows;
6065 ptrdiff_t i, k, n_leaf_windows; 6147 ptrdiff_t i, k, n_leaf_windows;
6148 /* Records whether a window has been added or removed wrt the
6149 original configuration. */
6150 bool window_changed = false;
6151 /* Records whether a window has changed its buffer wrt the
6152 original configuration. */
6153 bool buffer_changed = false;
6066 6154
6067 /* Don't do this within the main loop below: This may call Lisp 6155 /* Don't do this within the main loop below: This may call Lisp
6068 code and is thus potentially unsafe while input is blocked. */ 6156 code and is thus potentially unsafe while input is blocked. */
@@ -6071,6 +6159,12 @@ the return value is nil. Otherwise the value is t. */)
6071 p = SAVED_WINDOW_N (saved_windows, k); 6159 p = SAVED_WINDOW_N (saved_windows, k);
6072 window = p->window; 6160 window = p->window;
6073 w = XWINDOW (window); 6161 w = XWINDOW (window);
6162
6163 if (NILP (w->contents))
6164 /* A dead window that will be resurrected, the window
6165 configuration will change. */
6166 window_changed = true;
6167
6074 if (BUFFERP (w->contents) 6168 if (BUFFERP (w->contents)
6075 && !EQ (w->contents, p->buffer) 6169 && !EQ (w->contents, p->buffer)
6076 && BUFFER_LIVE_P (XBUFFER (p->buffer))) 6170 && BUFFER_LIVE_P (XBUFFER (p->buffer)))
@@ -6100,7 +6194,6 @@ the return value is nil. Otherwise the value is t. */)
6100 } 6194 }
6101 6195
6102 fset_redisplay (f); 6196 fset_redisplay (f);
6103 FRAME_WINDOW_SIZES_CHANGED (f) = true;
6104 6197
6105 /* Problem: Freeing all matrices and later allocating them again 6198 /* Problem: Freeing all matrices and later allocating them again
6106 is a serious redisplay flickering problem. What we would 6199 is a serious redisplay flickering problem. What we would
@@ -6156,6 +6249,10 @@ the return value is nil. Otherwise the value is t. */)
6156 w->pixel_top = XFASTINT (p->pixel_top); 6249 w->pixel_top = XFASTINT (p->pixel_top);
6157 w->pixel_width = XFASTINT (p->pixel_width); 6250 w->pixel_width = XFASTINT (p->pixel_width);
6158 w->pixel_height = XFASTINT (p->pixel_height); 6251 w->pixel_height = XFASTINT (p->pixel_height);
6252 w->pixel_width_before_size_change
6253 = XFASTINT (p->pixel_width_before_size_change);
6254 w->pixel_height_before_size_change
6255 = XFASTINT (p->pixel_height_before_size_change);
6159 w->left_col = XFASTINT (p->left_col); 6256 w->left_col = XFASTINT (p->left_col);
6160 w->top_line = XFASTINT (p->top_line); 6257 w->top_line = XFASTINT (p->top_line);
6161 w->total_cols = XFASTINT (p->total_cols); 6258 w->total_cols = XFASTINT (p->total_cols);
@@ -6203,6 +6300,9 @@ the return value is nil. Otherwise the value is t. */)
6203 if (BUFFERP (p->buffer) && BUFFER_LIVE_P (XBUFFER (p->buffer))) 6300 if (BUFFERP (p->buffer) && BUFFER_LIVE_P (XBUFFER (p->buffer)))
6204 /* If saved buffer is alive, install it. */ 6301 /* If saved buffer is alive, install it. */
6205 { 6302 {
6303 if (!EQ (w->contents, p->buffer))
6304 /* Record buffer configuration change. */
6305 buffer_changed = true;
6206 wset_buffer (w, p->buffer); 6306 wset_buffer (w, p->buffer);
6207 w->start_at_line_beg = !NILP (p->start_at_line_beg); 6307 w->start_at_line_beg = !NILP (p->start_at_line_beg);
6208 set_marker_restricted (w->start, p->start, w->contents); 6308 set_marker_restricted (w->start, p->start, w->contents);
@@ -6236,6 +6336,8 @@ the return value is nil. Otherwise the value is t. */)
6236 else if (!NILP (w->start)) 6336 else if (!NILP (w->start))
6237 /* Leaf window has no live buffer, get one. */ 6337 /* Leaf window has no live buffer, get one. */
6238 { 6338 {
6339 /* Record buffer configuration change. */
6340 buffer_changed = true;
6239 /* Get the buffer via other_buffer_safely in order to 6341 /* Get the buffer via other_buffer_safely in order to
6240 avoid showing an unimportant buffer and, if necessary, to 6342 avoid showing an unimportant buffer and, if necessary, to
6241 recreate *scratch* in the course (part of Juanma's bs-show 6343 recreate *scratch* in the course (part of Juanma's bs-show
@@ -6283,7 +6385,10 @@ the return value is nil. Otherwise the value is t. */)
6283 /* Now, free glyph matrices in windows that were not reused. */ 6385 /* Now, free glyph matrices in windows that were not reused. */
6284 for (i = 0; i < n_leaf_windows; i++) 6386 for (i = 0; i < n_leaf_windows; i++)
6285 if (NILP (leaf_windows[i]->contents)) 6387 if (NILP (leaf_windows[i]->contents))
6286 free_window_matrices (leaf_windows[i]); 6388 {
6389 free_window_matrices (leaf_windows[i]);
6390 window_changed = true;
6391 }
6287 6392
6288 /* Allow x_set_window_size again and apply frame size changes if 6393 /* Allow x_set_window_size again and apply frame size changes if
6289 needed. */ 6394 needed. */
@@ -6303,7 +6408,8 @@ the return value is nil. Otherwise the value is t. */)
6303 6408
6304 /* Record the selected window's buffer here. The window should 6409 /* Record the selected window's buffer here. The window should
6305 already be the selected one from the call above. */ 6410 already be the selected one from the call above. */
6306 select_window (data->current_window, Qnil, false); 6411 if (WINDOW_LIVE_P (data->current_window))
6412 select_window (data->current_window, Qnil, false);
6307 6413
6308 /* Fselect_window will have made f the selected frame, so we 6414 /* Fselect_window will have made f the selected frame, so we
6309 reselect the proper frame here. Fhandle_switch_frame will change the 6415 reselect the proper frame here. Fhandle_switch_frame will change the
@@ -6313,7 +6419,32 @@ the return value is nil. Otherwise the value is t. */)
6313 if (FRAME_LIVE_P (XFRAME (data->selected_frame))) 6419 if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
6314 do_switch_frame (data->selected_frame, 0, 0, Qnil); 6420 do_switch_frame (data->selected_frame, 0, 0, Qnil);
6315 6421
6316 run_window_configuration_change_hook (f); 6422 if (window_changed)
6423 /* At least one window has been added or removed. Run
6424 `window-configuration-change-hook' and make sure
6425 `window-size-change-functions' get run later.
6426
6427 We have to do this in order to capture the following
6428 scenario: Suppose our frame contains two live windows W1 and
6429 W2 and ‘set-window-configuration’ replaces them by two
6430 windows W3 and W4 that were dead the last time
6431 run_window_size_change_functions was run. If W3 and W4 have
6432 the same values for their old and new pixel sizes but these
6433 values differ from those of W1 and W2, the sizes of our
6434 frame's two live windows changed but window_size_changed has
6435 no means to detect that fact.
6436
6437 Obviously, this will get us false positives, for example,
6438 when we restore the original configuration with W1 and W2
6439 before run_window_size_change_functions gets called. */
6440 {
6441 run_window_configuration_change_hook (f);
6442 FRAME_WINDOW_CONFIGURATION_CHANGED (f) = true;
6443 }
6444 else if (buffer_changed)
6445 /* At least one window has changed its buffer. Run
6446 `window-configuration-change-hook' only. */
6447 run_window_configuration_change_hook (f);
6317 } 6448 }
6318 6449
6319 if (!NILP (new_current_buffer)) 6450 if (!NILP (new_current_buffer))
@@ -6464,6 +6595,10 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, ptrdiff_t i)
6464 p->pixel_top = make_number (w->pixel_top); 6595 p->pixel_top = make_number (w->pixel_top);
6465 p->pixel_width = make_number (w->pixel_width); 6596 p->pixel_width = make_number (w->pixel_width);
6466 p->pixel_height = make_number (w->pixel_height); 6597 p->pixel_height = make_number (w->pixel_height);
6598 p->pixel_width_before_size_change
6599 = make_number (w->pixel_width_before_size_change);
6600 p->pixel_height_before_size_change
6601 = make_number (w->pixel_height_before_size_change);
6467 p->left_col = make_number (w->left_col); 6602 p->left_col = make_number (w->left_col);
6468 p->top_line = make_number (w->top_line); 6603 p->top_line = make_number (w->top_line);
6469 p->total_cols = make_number (w->total_cols); 6604 p->total_cols = make_number (w->total_cols);
@@ -7246,6 +7381,16 @@ selected; while the global part is run only once for the modified frame,
7246with the relevant frame selected. */); 7381with the relevant frame selected. */);
7247 Vwindow_configuration_change_hook = Qnil; 7382 Vwindow_configuration_change_hook = Qnil;
7248 7383
7384 DEFVAR_LISP ("window-size-change-functions", Vwindow_size_change_functions,
7385 doc: /* Functions called during redisplay, if window sizes have changed.
7386The value should be a list of functions that take one argument.
7387During the first part of redisplay, for each frame, if any of its windows
7388have changed size since the last redisplay, or have been split or deleted,
7389all the functions in the list are called, with the frame as argument.
7390If redisplay decides to resize the minibuffer window, it calls these
7391functions on behalf of that as well. */);
7392 Vwindow_size_change_functions = Qnil;
7393
7249 DEFVAR_LISP ("recenter-redisplay", Vrecenter_redisplay, 7394 DEFVAR_LISP ("recenter-redisplay", Vrecenter_redisplay,
7250 doc: /* Non-nil means `recenter' redraws entire frame. 7395 doc: /* Non-nil means `recenter' redraws entire frame.
7251If this option is non-nil, then the `recenter' command with a nil 7396If this option is non-nil, then the `recenter' command with a nil
@@ -7374,6 +7519,8 @@ displayed after a scrolling operation to be somewhat inaccurate. */);
7374 defsubr (&Swindow_use_time); 7519 defsubr (&Swindow_use_time);
7375 defsubr (&Swindow_pixel_width); 7520 defsubr (&Swindow_pixel_width);
7376 defsubr (&Swindow_pixel_height); 7521 defsubr (&Swindow_pixel_height);
7522 defsubr (&Swindow_pixel_width_before_size_change);
7523 defsubr (&Swindow_pixel_height_before_size_change);
7377 defsubr (&Swindow_total_width); 7524 defsubr (&Swindow_total_width);
7378 defsubr (&Swindow_total_height); 7525 defsubr (&Swindow_total_height);
7379 defsubr (&Swindow_normal_size); 7526 defsubr (&Swindow_normal_size);
diff --git a/src/window.h b/src/window.h
index c29207d6356..a4d4dfe3ff4 100644
--- a/src/window.h
+++ b/src/window.h
@@ -214,6 +214,11 @@ struct window
214 int pixel_width; 214 int pixel_width;
215 int pixel_height; 215 int pixel_height;
216 216
217 /* The pixel sizes of the window at the last time
218 `window-size-change-functions' was run. */
219 int pixel_width_before_size_change;
220 int pixel_height_before_size_change;
221
217 /* The size of the window. */ 222 /* The size of the window. */
218 int total_cols; 223 int total_cols;
219 int total_lines; 224 int total_lines;
@@ -499,15 +504,17 @@ wset_next_buffers (struct window *w, Lisp_Object val)
499#define WINDOW_LEAF_P(W) \ 504#define WINDOW_LEAF_P(W) \
500 (BUFFERP ((W)->contents)) 505 (BUFFERP ((W)->contents))
501 506
502/* True if W is a member of horizontal combination. */ 507/* Non-nil if W is internal. */
508#define WINDOW_INTERNAL_P(W) \
509 (WINDOWP ((W)->contents))
503 510
511/* True if W is a member of horizontal combination. */
504#define WINDOW_HORIZONTAL_COMBINATION_P(W) \ 512#define WINDOW_HORIZONTAL_COMBINATION_P(W) \
505 (WINDOWP ((W)->contents) && (W)->horizontal) 513 (WINDOW_INTERNAL_P (W) && (W)->horizontal)
506 514
507/* True if W is a member of vertical combination. */ 515/* True if W is a member of vertical combination. */
508
509#define WINDOW_VERTICAL_COMBINATION_P(W) \ 516#define WINDOW_VERTICAL_COMBINATION_P(W) \
510 (WINDOWP ((W)->contents) && !(W)->horizontal) 517 (WINDOW_INTERNAL_P (W) && !(W)->horizontal)
511 518
512/* WINDOW's XFRAME. */ 519/* WINDOW's XFRAME. */
513#define WINDOW_XFRAME(W) (XFRAME (WINDOW_FRAME ((W)))) 520#define WINDOW_XFRAME(W) (XFRAME (WINDOW_FRAME ((W))))
@@ -1014,6 +1021,7 @@ extern void shrink_mini_window (struct window *, bool);
1014extern int window_relative_x_coord (struct window *, enum window_part, int); 1021extern int window_relative_x_coord (struct window *, enum window_part, int);
1015 1022
1016void run_window_configuration_change_hook (struct frame *f); 1023void run_window_configuration_change_hook (struct frame *f);
1024void run_window_size_change_functions (Lisp_Object);
1017 1025
1018/* Make WINDOW display BUFFER. RUN_HOOKS_P means it's allowed 1026/* Make WINDOW display BUFFER. RUN_HOOKS_P means it's allowed
1019 to run hooks. See make_frame for a case where it's not allowed. */ 1027 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 fed58799eaa..4330f106002 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -11786,24 +11786,7 @@ prepare_menu_bars (void)
11786 && !XBUFFER (w->contents)->text->redisplay) 11786 && !XBUFFER (w->contents)->text->redisplay)
11787 continue; 11787 continue;
11788 11788
11789 /* If a window on this frame changed size, report that to 11789 run_window_size_change_functions (frame);
11790 the user and clear the size-change flag. */
11791 if (FRAME_WINDOW_SIZES_CHANGED (f))
11792 {
11793 Lisp_Object functions;
11794
11795 /* Clear flag first in case we get an error below. */
11796 FRAME_WINDOW_SIZES_CHANGED (f) = false;
11797 functions = Vwindow_size_change_functions;
11798
11799 while (CONSP (functions))
11800 {
11801 if (!EQ (XCAR (functions), Qt))
11802 call1 (XCAR (functions), frame);
11803 functions = XCDR (functions);
11804 }
11805 }
11806
11807 menu_bar_hooks_run = update_menu_bar (f, false, menu_bar_hooks_run); 11790 menu_bar_hooks_run = update_menu_bar (f, false, menu_bar_hooks_run);
11808#ifdef HAVE_WINDOW_SYSTEM 11791#ifdef HAVE_WINDOW_SYSTEM
11809 update_tool_bar (f, false); 11792 update_tool_bar (f, false);
@@ -13599,24 +13582,12 @@ redisplay_internal (void)
13599 it's too late for the hooks in window-size-change-functions, 13582 it's too late for the hooks in window-size-change-functions,
13600 which have been examined already in prepare_menu_bars. So in 13583 which have been examined already in prepare_menu_bars. So in
13601 that case we call the hooks here only for the selected frame. */ 13584 that case we call the hooks here only for the selected frame. */
13602 if (sf->redisplay && FRAME_WINDOW_SIZES_CHANGED (sf)) 13585 if (sf->redisplay)
13603 { 13586 {
13604 Lisp_Object functions;
13605 ptrdiff_t count1 = SPECPDL_INDEX (); 13587 ptrdiff_t count1 = SPECPDL_INDEX ();
13606 13588
13607 record_unwind_save_match_data (); 13589 record_unwind_save_match_data ();
13608 13590 run_window_size_change_functions (selected_frame);
13609 /* Clear flag first in case we get an error below. */
13610 FRAME_WINDOW_SIZES_CHANGED (sf) = false;
13611 functions = Vwindow_size_change_functions;
13612
13613 while (CONSP (functions))
13614 {
13615 if (!EQ (XCAR (functions), Qt))
13616 call1 (XCAR (functions), selected_frame);
13617 functions = XCDR (functions);
13618 }
13619
13620 unbind_to (count1, Qnil); 13591 unbind_to (count1, Qnil);
13621 } 13592 }
13622 13593
@@ -13638,22 +13609,10 @@ redisplay_internal (void)
13638 { 13609 {
13639 if (sf->redisplay) 13610 if (sf->redisplay)
13640 { 13611 {
13641 Lisp_Object functions;
13642 ptrdiff_t count1 = SPECPDL_INDEX (); 13612 ptrdiff_t count1 = SPECPDL_INDEX ();
13643 13613
13644 record_unwind_save_match_data (); 13614 record_unwind_save_match_data ();
13645 13615 run_window_size_change_functions (selected_frame);
13646 /* Clear flag first in case we get an error below. */
13647 FRAME_WINDOW_SIZES_CHANGED (sf) = false;
13648 functions = Vwindow_size_change_functions;
13649
13650 while (CONSP (functions))
13651 {
13652 if (!EQ (XCAR (functions), Qt))
13653 call1 (XCAR (functions), selected_frame);
13654 functions = XCDR (functions);
13655 }
13656
13657 unbind_to (count1, Qnil); 13616 unbind_to (count1, Qnil);
13658 } 13617 }
13659 13618
@@ -31447,16 +31406,6 @@ If nil, disable message logging. If t, log messages but don't truncate
31447the buffer when it becomes large. */); 31406the buffer when it becomes large. */);
31448 Vmessage_log_max = make_number (1000); 31407 Vmessage_log_max = make_number (1000);
31449 31408
31450 DEFVAR_LISP ("window-size-change-functions", Vwindow_size_change_functions,
31451 doc: /* Functions called during redisplay, if window sizes have changed.
31452The value should be a list of functions that take one argument.
31453During the first part of redisplay, for each frame, if any of its windows
31454have changed size since the last redisplay, or have been split or deleted,
31455all the functions in the list are called, with the frame as argument.
31456If redisplay decides to resize the minibuffer window, it calls these
31457functions on behalf of that as well. */);
31458 Vwindow_size_change_functions = Qnil;
31459
31460 DEFVAR_LISP ("window-scroll-functions", Vwindow_scroll_functions, 31409 DEFVAR_LISP ("window-scroll-functions", Vwindow_scroll_functions,
31461 doc: /* List of functions to call before redisplaying a window with scrolling. 31410 doc: /* List of functions to call before redisplaying a window with scrolling.
31462Each function is called with two arguments, the window and its new 31411Each function is called with two arguments, the window and its new
diff --git a/src/xfns.c b/src/xfns.c
index 20ac6271715..2a50a5a5f99 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -1313,7 +1313,6 @@ x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
1313 } 1313 }
1314#endif /* not USE_X_TOOLKIT && not USE_GTK */ 1314#endif /* not USE_X_TOOLKIT && not USE_GTK */
1315 adjust_frame_glyphs (f); 1315 adjust_frame_glyphs (f);
1316 run_window_configuration_change_hook (f);
1317} 1316}
1318 1317
1319 1318