From 6a00f2babf84f309fa00269bff3abef7eb502023 Mon Sep 17 00:00:00 2001 From: Martin Rudalics Date: Mon, 10 Sep 2018 10:05:20 +0200 Subject: [PATCH] Handle buffer-local 'window-size-change-functions' specially (Bug#32637) * src/window.c (run_window_size_change_functions): Run a buffer-local value once per each frame and only if at least one window showing the buffer on that frame has changed its size. (Bug#32637) * doc/lispref/windows.texi (Window Hooks): Describe new behavior of buffer-local 'window-size-change-functions'. --- doc/lispref/windows.texi | 8 +++++++ etc/NEWS | 5 +++++ src/window.c | 48 +++++++++++++++++++++++++++++++++++----- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index 3eaa15a6036..7cfa5ead5f1 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -5205,6 +5205,14 @@ whether a specific window has changed size, compare the return values of @code{window-pixel-height-before-size-change} and @code{window-pixel-height} for that window (@pxref{Window Sizes}). +The buffer-local value of this hook is run once for the buffer and the +frame in question, provided at least one window showing the buffer on +that frame has changed its size. As it still receives the frame as +its sole argument, any function called on a buffer-local basis will be +oblivious to which window(s) showing the buffer changed its (their) +size and has to check out these windows by using the method described +in the previous paragraph. + These function are usually only called when at least one window was added or has changed size since the last time this hook was run for the associated frame. In some rare cases this hook also runs when a window diff --git a/etc/NEWS b/etc/NEWS index ff65a5520d5..9ab26222ec2 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -963,6 +963,11 @@ now support filters, allowing faces to vary between different windows displaying the same buffer. See the Info node "Face Remapping" of the Emacs Lisp Reference manual for more detail. ++++ +** Special handling of buffer-local 'window-size-change-functions'. +A buffer-local value of this hook is now run only if at least one +window showing the buffer has changed its size. + +++ ** New function assoc-delete-all. diff --git a/src/window.c b/src/window.c index 04de9656809..b81469b9d69 100644 --- a/src/window.c +++ b/src/window.c @@ -3442,7 +3442,11 @@ run_window_size_change_functions (Lisp_Object frame) { struct frame *f = XFRAME (frame); struct window *r = XWINDOW (FRAME_ROOT_WINDOW (f)); - Lisp_Object functions = Vwindow_size_change_functions; + + if (NILP (Vrun_hooks) + || !(f->can_x_set_window_size) + || !(f->after_make_frame)) + return; if (FRAME_WINDOW_CONFIGURATION_CHANGED (f) /* Here we implicitly exclude the possibility that the height of @@ -3450,11 +3454,44 @@ run_window_size_change_functions (Lisp_Object frame) of FRAME's root window alone. */ || window_size_changed (r)) { - while (CONSP (functions)) + Lisp_Object globals = Fdefault_value (Qwindow_size_change_functions); + Lisp_Object windows = Fwindow_list (frame, Qlambda, Qnil); + /* The buffers for which the local hook was already run. */ + Lisp_Object buffers = Qnil; + + for (; CONSP (windows); windows = XCDR (windows)) + { + Lisp_Object window = XCAR (windows); + Lisp_Object buffer = Fwindow_buffer (window); + + /* Run a buffer-local value only once for that buffer and + only if at least one window showing that buffer on FRAME + actually changed its size. Note that the function is run + with FRAME as its argument and as such oblivious to the + window checked below. */ + if (window_size_changed (XWINDOW (window)) + && !Fmemq (buffer, buffers) + && Flocal_variable_p (Qwindow_size_change_functions, buffer)) + { + Lisp_Object locals + = Fbuffer_local_value (Qwindow_size_change_functions, buffer); + + while (CONSP (locals)) + { + if (!EQ (XCAR (locals), Qt)) + safe_call1 (XCAR (locals), frame); + locals = XCDR (locals); + } + + buffers = Fcons (buffer, buffers); + } + } + + while (CONSP (globals)) { - if (!EQ (XCAR (functions), Qt)) - safe_call1 (XCAR (functions), frame); - functions = XCDR (functions); + if (!EQ (XCAR (globals), Qt)) + safe_call1 (XCAR (globals), frame); + globals = XCDR (globals); } window_set_before_size_change_sizes (r); @@ -7556,6 +7593,7 @@ syms_of_window (void) Fput (Qscroll_down, Qscroll_command, Qt); DEFSYM (Qwindow_configuration_change_hook, "window-configuration-change-hook"); + DEFSYM (Qwindow_size_change_functions, "window-size-change-functions"); DEFSYM (Qwindowp, "windowp"); DEFSYM (Qwindow_configuration_p, "window-configuration-p"); DEFSYM (Qwindow_live_p, "window-live-p"); -- 2.39.2