From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: martin rudalics Newsgroups: gmane.emacs.devel Subject: Fix `window-configuration-change-hook' and `window-size-change-functions' Date: Mon, 22 Feb 2016 13:59:54 +0100 Message-ID: <56CB064A.9060101@gmx.at> References: <83k2skhhz1.fsf@gnu.org> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------020200040005050006060906" X-Trace: ger.gmane.org 1456146037 9593 80.91.229.3 (22 Feb 2016 13:00:37 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Mon, 22 Feb 2016 13:00:37 +0000 (UTC) Cc: emacs-devel Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Mon Feb 22 14:00:29 2016 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1aXq6D-0004pC-07 for ged-emacs-devel@m.gmane.org; Mon, 22 Feb 2016 14:00:25 +0100 Original-Received: from localhost ([::1]:48993 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aXq6C-0003cw-At for ged-emacs-devel@m.gmane.org; Mon, 22 Feb 2016 08:00:24 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:50617) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aXq5w-0003Na-CR for emacs-devel@gnu.org; Mon, 22 Feb 2016 08:00:17 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aXq5q-0000Jb-Jx for emacs-devel@gnu.org; Mon, 22 Feb 2016 08:00:08 -0500 Original-Received: from mout.gmx.net ([212.227.17.22]:49381) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aXq5q-0000F8-1f for emacs-devel@gnu.org; Mon, 22 Feb 2016 08:00:02 -0500 Original-Received: from [192.168.1.101] ([212.95.7.75]) by mail.gmx.com (mrgmx101) with ESMTPSA (Nemesis) id 0M50aI-1Zk1C42ioY-00zGa0 for ; Mon, 22 Feb 2016 13:59:58 +0100 In-Reply-To: <83k2skhhz1.fsf@gnu.org> X-Provags-ID: V03:K0:xF8iMyC3deYjc/4LleQz90EmM9D3Jo3QS8uCWdqVYFZ7xPFKiln I9tqeDFnisxmugFSdXGJLsK5ug4Igaw32tcIZjFWYTH4P2Kz/Igj+htFxnVJ/PWfEvBbCqm 32dhG0axkpVCwTqg/vJ8Q7d+AruRXaQ+DaJSWGz9Q2H59ky1IjhrAC69CjcwFX6tL0Nxnx9 gLsIbkA974Jtak2Gleoqg== X-UI-Out-Filterresults: notjunk:1;V01:K0:kzZWZpp1eRA=:ovHrSXdwO49gT0/et5skW+ keWTJtyP1iZ8UpvzNXd2dowoK7+sm2Wx7Hn3QGaFniUDras2sELx91yGrDdMcYjHGA8B4JSor GNjdpczrgWXlQaEGq1kh7TWk1DhiSpVEMbYEfpDd59d+FPhCylelS0p6y71CWnuqSco5v2zrr zwuvQkv1vgHupg5mLJ11CmjtlaVEZAoPi2k48n9OHjKifKNNzscF8XMjaFTJ7wKlYemJPVdPu 8zJXDSyDIn6Ufgz5iVmEEuR7lMQxaL+DQ2qY3DKY2q4rONuMdKSVMDtPEgC10SdPJfxVJi1VY IG2+K4PyboqVuITrQvfdE0f7y2lJfehK8l8x16mqK1F3lcViAxQeYEFGYYT1mJ1He1BcUAzqT gp2blOBH9AwNIkRK37h2OOjAaNygYtVW3ARg6RUiGQ+2hV3A06cAn91+kYcgODLkKFjvtn+s1 DKyVaXsJki56ngisArbR6eQlXU9KdrfEFrCIxqVZBqq4LRsJ4SV4tFeG2XID4bqpjWGOGrCx3 EC1YJ6zKz701eX3LTGbA2rai8agVIs/P3052E2JikgIrYUG1NDAgXNmlLXdt8H23pbdBCt1YQ 93MimfQWEhbQZ/Ic73QgiIcLbT65jo936/uhkMZgj7D0OwEvWj21LFZ2arvf+uHVA6hJvUA2Y jU3SCpePoSs07t4pXP4nonHUXRpWqlfHL2K8Uldo6dWnj4bthph+t1dd42tuqBcXzVwkSAeP6 BABbI4WzVNKuTyMLPXKwwDAsT1KQ23SQqvKD908L3OSTgy4PvoWvkXDQKW95F6V3MkephHcp X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 212.227.17.22 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:200451 Archived-At: This is a multi-part message in MIME format. --------------020200040005050006060906 Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit From archived bug#21333: 25.0.50; window-size-change-functions not called after mini-window resize: > If anything, IMO we should _reduce_ the number of unrelated events > that trigger a call to these functions. For example, currently any > command that reads from the minibuffer will trigger it, because when > read-from-minibuffer exits, it restores the window configuration by > calling set-window-configuration, which is documented to trigger these > functions. That just doesn't make any sense to me, since most reads > from the minibuffer don't resize any windows! I plan to install in the next days the attached patch which tries to fix this and also some other issues discussed in this thread. Please have a look. martin Fix `window-configuration-change-hook' and `window-size-change-functions' (1) Run `window-configuration-change-hook' if and only if a window was deleted/created or shows another buffer. (2) Run `window-size-change-functions' if and only if at least one window changed its size (in a few cases `window-size-change-functions' will also run when no window changed its size). (3) Provide two functions `window-old-pixel-height' and `window-old-pixel-width' 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 old_pixel_width and old_pixel_height. (WINDOW_INTERNAL_P): New macro. * src/window.c (Fwindow_old_pixel_width) (Fwindow_old_pixel_height): 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_old_pixel_sizes) (run_window_size_change_functions): New functions. (make_window): Initialize old_pixel_width and old_pixel_height fields. (Fdelete_window_internal): Don't call run_window_configuration_change_hook. (struct saved_window): Add old_pixel_height and old_pixel_width fields. (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 old_pixel_height and old_pixel_width fields. (Vwindow_size_change_functions): Move 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-old-pixel-height' and `window-old-pixel-width'. (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'. --------------020200040005050006060906 Content-Type: text/plain; charset=windows-1252; name="window-hooks.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="window-hooks.diff" diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index f61f08a..eac3bd6 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -545,6 +545,12 @@ Window Sizes children. @end defun +@defun window-old-pixel-height &optional Lisp_Object &optional window +This function returns the height of window @var{window} in pixels at the= +time @code{window-size-change-functions} was run for the last time on +@var{window}'s frame (@pxref{Window Hooks}). +@end defun + @cindex window pixel width @cindex pixel width of a window @cindex total pixel width of a window @@ -559,6 +565,12 @@ Window Sizes the screen areas spanned by its children. @end defun +@defun window-old-pixel-width &optional Lisp_Object &optional window +This function returns the width of window @var{window} in pixels at the +time @code{window-size-change-functions} was run for the last time on +@var{window}'s frame (@pxref{Window Hooks}). +@end defun + @cindex full-width window @cindex full-height window The following functions can be used to determine whether a given @@ -4087,11 +4099,11 @@ Window Configurations The argument @var{configuration} must be a value that was previously returned by @code{current-window-configuration}. The configuration is restored in the frame from which @var{configuration} was made, whether -that frame is selected or not. This always counts as a window size -change and triggers execution of the @code{window-size-change-functions}= -(@pxref{Window Hooks}), because @code{set-window-configuration} doesn't -know how to tell whether the new configuration actually differs from the= -old one. +that frame is selected or not. In some rare cases this may trigger +execution of the @code{window-size-change-functions} (@pxref{Window +Hooks}) even if the size of windows did not change at all. The +@code{window-configuration-change-hook} functions will be called if and +only if at least one window was added to or deleted from the frame. If the frame from which @var{configuration} was saved is dead, all this function does is restore the three variables @code{window-min-height}, @@ -4378,33 +4390,37 @@ Window Hooks @end defvar @defvar window-size-change-functions -This variable holds a list of functions to be called if the size of -any window changes for any reason. The functions are called at the -beginning of a redisplay cycle, and just once for each frame on which -size changes have occurred. - -Each function receives the frame as its sole argument. There is no -direct way to find out which windows on that frame have changed size, or= -precisely how. However, if a size-change function records, at each -call, the existing windows and their sizes, it can also compare the -present sizes and the previous sizes. - -Creating or deleting windows counts as a size change, and therefore -causes these functions to be called. Changing the frame size also -counts, because it changes the sizes of the existing windows. +This variable holds a list of functions to be called if the size of any +window changes for any reason. The functions are called once per +redisplay, and once for each frame on which size changes have occurred. + +Each function receives the frame as its sole argument. To find out +whether a specific window has changed size, compare the return values of= +@code{window-old-pixel-width} and @code{window-pixel-width} respectively= +@code{window-old-pixel-height} and @code{window-pixel-height} for that +window (@pxref{Window Sizes}). + +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 +that was added intermittently has been deleted afterwards. In these +cases none of the windows on the frame will appear to have changed its +size. You may use @code{save-selected-window} in these functions (@pxref{Selecting Windows}). However, do not use @code{save-window-excursion} (@pxref{Window Configurations}); exiting -that macro counts as a size change, which would cause these functions -to be called over and over. +that macro counts as a size change, which would cause these functions to= +be called again. @end defvar @defvar window-configuration-change-hook -A normal hook that is run every time you change the window configuration= -of an existing frame. This includes splitting or deleting windows, -changing the sizes of windows, or displaying a different buffer in a -window. +A normal hook that is run every time the window configuration of a frame= +changes. Window configuration changes include splitting and deleting +windows and the display of a different buffer in a window. Resizing the= +frame or individual windows do not count as configuration changes. Use +@code{window-size-change-functions}, see above, when you want to track +size changes that are not caused by the deletion or creation of windows.= The buffer-local part of this hook is run once for each window on the affected frame, with the relevant window selected and its buffer diff --git a/lisp/window.el b/lisp/window.el index e4669c1..1c679ae 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -3136,10 +3136,10 @@ window--sanitize-window-sizes (walk-window-tree (lambda (window) (let ((delta (- (window-min-size window horizontal nil t) - (window-size window horizontal t)))) - (when (> delta 0) - (if (window-resizable-p window delta horizontal nil t) - (window-resize window delta horizontal nil t) + (window-size window horizontal t)))) + (when (> delta 0) + (if (window-resizable-p window delta horizontal nil t) + (window-resize window delta horizontal nil t) (setq value nil)))))) value)) diff --git a/src/frame.c b/src/frame.c index 8c86afe..df473ae 100644 --- a/src/frame.c +++ b/src/frame.c @@ -591,8 +591,6 @@ adjust_frame_size (struct frame *f, int new_width, in= t new_height, int inhibit, || new_pixel_height !=3D old_pixel_height); unblock_input (); - - run_window_configuration_change_hook (f); } /* Allocate basically initialized frame. */ diff --git a/src/frame.h b/src/frame.h index 71dab4b..d9424ab 100644 --- a/src/frame.h +++ b/src/frame.h @@ -288,8 +288,9 @@ struct frame cleared. */ bool_bf explicit_name : 1; - /* True if size of some window on this frame has changed. */ - bool_bf window_sizes_changed : 1; + /* True if configuration of windows on this frame has changed since + last call of run_window_size_change_functions. */ + bool_bf window_configuration_changed : 1; /* True if the mouse has moved on this display device since the last time we checked. */ @@ -828,10 +829,10 @@ default_pixels_per_inch_y (void) are frozen on frame F. */ #define FRAME_WINDOWS_FROZEN(f) (f)->frozen_window_starts -/* True if a size change has been requested for frame F - but not yet really put into effect. This can be true temporarily - when an X event comes in at a bad time. */ -#define FRAME_WINDOW_SIZES_CHANGED(f) (f)->window_sizes_changed +/* True if the frame's window configuration has changed since last call + of run_window_size_change_functions. */ +#define FRAME_WINDOW_CONFIGURATION_CHANGED(f) \ + ((f)->window_configuration_changed) /* 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 e1a30ee..7267a25 100644 --- a/src/window.c +++ b/src/window.c @@ -720,6 +720,30 @@ the height of the screen areas spanned by its childr= en. */) return make_number (decode_valid_window (window)->pixel_height); } +DEFUN ("window-old-pixel-width", Fwindow_old_pixel_width, Swindow_old_pi= xel_width, 0, 1, 0, + doc: /* Return the old width of window WINDOW in pixels. +WINDOW must be a valid window and defaults to the selected one. + +The return value is the pixel width of WINDOW at the last time +`window-size-change-functions' was run. It's zero if WINDOW was made +after that. */) + (Lisp_Object window) +{ + return make_number (decode_valid_window (window)->old_pixel_width); +} + +DEFUN ("window-old-pixel-height", Fwindow_old_pixel_height, Swindow_old_= pixel_height, 0, 1, 0, + doc: /* Return the old height of window WINDOW in pixels. +WINDOW must be a valid window and defaults to the selected one. + +The return value is the pixel height of WINDOW at the last time +`window-size-change-functions' was run. It's zero if WINDOW was made +after that. */) + (Lisp_Object window) +{ + return make_number (decode_valid_window (window)->old_pixel_height); +} + DEFUN ("window-total-height", Fwindow_total_height, Swindow_total_height= , 0, 2, 0, doc: /* Return the height of window WINDOW in lines. WINDOW must be a valid window and defaults to the selected one. @@ -2879,6 +2903,7 @@ window-start value is reasonable when this function= is called. */) Lisp_Object sibling, pwindow, swindow IF_LINT (=3D Qnil), delta; ptrdiff_t startpos IF_LINT (=3D 0), startbyte IF_LINT (=3D 0); int top IF_LINT (=3D 0), new_top; + bool resize_failed =3D false; w =3D decode_valid_window (window); XSETWINDOW (window, w); @@ -2978,8 +3003,6 @@ window-start value is reasonable when this function= is called. */) fset_redisplay (f); Vwindow_list =3D Qnil; - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; - bool resize_failed =3D false; if (!WINDOW_LEAF_P (w)) { @@ -3229,6 +3252,76 @@ If WINDOW is omitted or nil, it defaults to the se= lected window. */) return Qnil; } + +/* Compare old and present pixel sizes of windows in tree rooted at W. + Return true iff any of these windows differs in size. */ + +static bool +window_size_changed (struct window *w) +{ + if (w->pixel_width !=3D w->old_pixel_width + || w->pixel_height !=3D w->old_pixel_height) + return true; + + if (WINDOW_INTERNAL_P (w)) + { + w =3D XWINDOW (w->contents); + while (w) + { + if (window_size_changed (w)) + return true; + + w =3D NILP (w->next) ? 0 : XWINDOW (w->next); + } + } + + return false; +} + +/* Set old pixel sizes of windows in tree rooted at W to their present + pixel sizes. */ + +static void +window_set_old_pixel_sizes (struct window *w) +{ + w->old_pixel_width =3D w->pixel_width; + w->old_pixel_height =3D w->pixel_height; + + if (WINDOW_INTERNAL_P (w)) + { + w =3D XWINDOW (w->contents); + while (w) + { + window_set_old_pixel_sizes (w); + w =3D NILP (w->next) ? 0 : XWINDOW (w->next); + } + } +} + + +void +run_window_size_change_functions (Lisp_Object frame) +{ + struct frame *f =3D XFRAME (frame); + struct window *r =3D XWINDOW (FRAME_ROOT_WINDOW (f)); + Lisp_Object functions =3D Vwindow_size_change_functions; + + if (FRAME_WINDOW_CONFIGURATION_CHANGED (f) || + window_size_changed (r)) + { + while (CONSP (functions)) + { + if (!EQ (XCAR (functions), Qt)) + call1 (XCAR (functions), frame); + functions =3D XCDR (functions); + } + + window_set_old_pixel_sizes (r); + FRAME_WINDOW_CONFIGURATION_CHANGED (f) =3D false; + } +} + + /* Make WINDOW display BUFFER. RUN_HOOKS_P means it's allowed to run hooks. See make_frame for a case where it's not allowed. KEEP_MARGINS_P means that the current margins, fringes, and @@ -3263,15 +3356,9 @@ set_window_buffer (Lisp_Object window, Lisp_Object= buffer, if (!(keep_margins_p && samebuf)) { /* If we're not actually changing the buffer, don't reset hscroll - and vscroll. This case happens for example when called from - change_frame_size_1, where we use a dummy call to - Fset_window_buffer on the frame's selected window (and no - other) just in order to run window-configuration-change-hook - (no longer true since change_frame_size_1 directly calls - run_window_configuration_change_hook). Resetting hscroll and - vscroll here is problematic for things like image-mode and - doc-view-mode since it resets the image's position whenever we - resize the frame. */ + and vscroll. Resetting hscroll and vscroll here is problematic + for things like image-mode and doc-view-mode since it resets + the image's position whenever we resize the frame. */ w->hscroll =3D w->min_hscroll =3D w->hscroll_whole =3D 0; w->suspend_auto_hscroll =3D false; w->vscroll =3D 0; @@ -3283,10 +3370,8 @@ set_window_buffer (Lisp_Object window, Lisp_Object= buffer, w->start_at_line_beg =3D false; w->force_start =3D false; } - /* Maybe we could move this into the `if' but it's not obviously safe = and - I doubt it's worth the trouble. */ - wset_redisplay (w); + wset_redisplay (w); wset_update_mode_line (w); /* We must select BUFFER to run the window-scroll-functions and to loo= k up @@ -3314,7 +3399,7 @@ set_window_buffer (Lisp_Object window, Lisp_Object = buffer, if (run_hooks_p) { - if (! NILP (Vwindow_scroll_functions)) + if (!NILP (Vwindow_scroll_functions)) run_hook_with_args_2 (Qwindow_scroll_functions, window, Fmarker_position (w->start)); if (!samebuf) @@ -3559,6 +3644,8 @@ make_window (void) w->phys_cursor_width =3D -1; #endif w->sequence_number =3D ++sequence_number; + w->old_pixel_width =3D 0; + w->old_pixel_height =3D 0; w->scroll_bar_width =3D -1; w->scroll_bar_height =3D -1; w->column_number_displayed =3D -1; @@ -3922,7 +4009,6 @@ be applied on the Elisp level. */) window_resize_apply (r, horflag); fset_redisplay (f); - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; adjust_frame_glyphs (f); unblock_input (); @@ -4087,7 +4173,6 @@ resize_frame_windows (struct frame *f, int size, bo= ol horflag, bool pixelwise) } } - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; fset_redisplay (f); } @@ -4214,7 +4299,6 @@ set correctly. See the code of `split-window' for = how this is done. */) p =3D XWINDOW (o->parent); fset_redisplay (f); - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; new =3D make_window (); n =3D XWINDOW (new); wset_frame (n, frame); @@ -4383,7 +4467,6 @@ Signal an error when WINDOW is the only window on i= ts frame. */) fset_redisplay (f); Vwindow_list =3D Qnil; - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; wset_next (w, Qnil); /* Don't delete w->next too. */ free_window_matrices (w); @@ -4451,9 +4534,6 @@ Signal an error when WINDOW is the only window on i= ts frame. */) } else unblock_input (); - - /* Must be run by the caller: - run_window_configuration_change_hook (f); */ } else /* We failed: Relink WINDOW into window tree. */ @@ -4527,7 +4607,6 @@ grow_mini_window (struct window *w, int delta, bool= pixelwise) /* Enforce full redisplay of the frame. */ /* FIXME: Shouldn't window--resize-root-window-vertically do it? */ fset_redisplay (f); - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; adjust_frame_glyphs (f); unblock_input (); } @@ -4567,7 +4646,6 @@ shrink_mini_window (struct window *w, bool pixelwis= e) /* Enforce full redisplay of the frame. */ /* FIXME: Shouldn't window--resize-root-window-vertically do it? */ fset_redisplay (f); - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; adjust_frame_glyphs (f); unblock_input (); } @@ -4610,7 +4688,6 @@ DEFUN ("resize-mini-window-internal", Fresize_mini_= window_internal, Sresize_mini w->top_line =3D r->top_line + r->total_lines; fset_redisplay (f); - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; adjust_frame_glyphs (f); unblock_input (); return Qt; @@ -5948,6 +6025,7 @@ struct saved_window Lisp_Object window, buffer, start, pointm, old_pointm; Lisp_Object pixel_left, pixel_top, pixel_height, pixel_width; + Lisp_Object old_pixel_height, old_pixel_width; Lisp_Object left_col, top_line, total_cols, total_lines; Lisp_Object normal_cols, normal_lines; Lisp_Object hscroll, min_hscroll, hscroll_whole, suspend_auto_hscroll;= @@ -6063,6 +6141,12 @@ the return value is nil. Otherwise the value is t= =2E */) struct window *root_window; struct window **leaf_windows; ptrdiff_t i, k, n_leaf_windows; + /* Records whether a window has been added or removed wrt the + original configuration. */ + bool window_changed =3D false; + /* Records whether a window has changed its buffer wrt the + original configuration. */ + bool buffer_changed =3D false; /* Don't do this within the main loop below: This may call Lisp code and is thus potentially unsafe while input is blocked. */ @@ -6071,12 +6155,18 @@ the return value is nil. Otherwise the value is = t. */) p =3D SAVED_WINDOW_N (saved_windows, k); window =3D p->window; w =3D XWINDOW (window); + + if (NILP (w->contents)) + /* A dead window that will be resurrected, the window + configuration will change. */ + window_changed =3D true; + if (BUFFERP (w->contents) && !EQ (w->contents, p->buffer) && BUFFER_LIVE_P (XBUFFER (p->buffer))) /* If a window we restore gets another buffer, record the window's old buffer. */ - call1 (Qrecord_window_buffer, window); + call1 (Qrecord_window_buffer, window); } /* Disallow x_set_window_size, temporarily. */ @@ -6100,7 +6190,6 @@ the return value is nil. Otherwise the value is t.= */) } fset_redisplay (f); - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; /* Problem: Freeing all matrices and later allocating them again is a serious redisplay flickering problem. What we would @@ -6156,6 +6245,8 @@ the return value is nil. Otherwise the value is t.= */) w->pixel_top =3D XFASTINT (p->pixel_top); w->pixel_width =3D XFASTINT (p->pixel_width); w->pixel_height =3D XFASTINT (p->pixel_height); + w->old_pixel_width =3D XFASTINT (p->old_pixel_width); + w->old_pixel_height =3D XFASTINT (p->old_pixel_height); w->left_col =3D XFASTINT (p->left_col); w->top_line =3D XFASTINT (p->top_line); w->total_cols =3D XFASTINT (p->total_cols); @@ -6203,6 +6294,9 @@ the return value is nil. Otherwise the value is t.= */) if (BUFFERP (p->buffer) && BUFFER_LIVE_P (XBUFFER (p->buffer))) /* If saved buffer is alive, install it. */ { + if (!EQ (w->contents, p->buffer)) + /* Record buffer configuration change. */ + buffer_changed =3D true; wset_buffer (w, p->buffer); w->start_at_line_beg =3D !NILP (p->start_at_line_beg); set_marker_restricted (w->start, p->start, w->contents); @@ -6236,6 +6330,8 @@ the return value is nil. Otherwise the value is t.= */) else if (!NILP (w->start)) /* Leaf window has no live buffer, get one. */ { + /* Record buffer configuration change. */ + buffer_changed =3D true; /* Get the buffer via other_buffer_safely in order to avoid showing an unimportant buffer and, if necessary, to recreate *scratch* in the course (part of Juanma's bs-show @@ -6283,7 +6379,10 @@ the return value is nil. Otherwise the value is t= =2E */) /* Now, free glyph matrices in windows that were not reused. */ for (i =3D 0; i < n_leaf_windows; i++) if (NILP (leaf_windows[i]->contents)) - free_window_matrices (leaf_windows[i]); + { + free_window_matrices (leaf_windows[i]); + window_changed =3D true; + } /* Allow x_set_window_size again and apply frame size changes if needed. */ @@ -6303,7 +6402,8 @@ the return value is nil. Otherwise the value is t.= */) /* Record the selected window's buffer here. The window should already be the selected one from the call above. */ - select_window (data->current_window, Qnil, false); + if (WINDOW_LIVE_P (data->current_window)) + select_window (data->current_window, Qnil, false); /* Fselect_window will have made f the selected frame, so we reselect the proper frame here. Fhandle_switch_frame will change the @@ -6313,7 +6413,32 @@ the return value is nil. Otherwise the value is t= =2E */) if (FRAME_LIVE_P (XFRAME (data->selected_frame))) do_switch_frame (data->selected_frame, 0, 0, Qnil); - run_window_configuration_change_hook (f); + if (window_changed) + /* At least one window has been added or removed. Run + `window-configuration-change-hook' and make sure + `window-size-change-functions' get run later. + + We have to do this in order to capture the following + scenario: Suppose our frame contains two live windows W1 and + W2 and =E2=80=98set-window-configuration=E2=80=99 replaces them by t= wo + windows W3 and W4 that were dead the last time + run_window_size_change_functions was run. If W3 and W4 have + the same values for their old and new pixel sizes but these + values differ from those of W1 and W2, the sizes of our + frame's two live windows changed but window_size_changed has + no means to detect that fact. + + Obviously, this will get us false positives, for example, + when we restore the original configuration with W1 and W2 + before run_window_size_change_functions gets called. */ + { + run_window_configuration_change_hook (f); + FRAME_WINDOW_CONFIGURATION_CHANGED (f) =3D true; + } + else if (buffer_changed) + /* At least one window has changed its buffer. Run + `window-configuration-change-hook' only. */ + run_window_configuration_change_hook (f); } if (!NILP (new_current_buffer)) @@ -6464,6 +6589,8 @@ save_window_save (Lisp_Object window, struct Lisp_V= ector *vector, ptrdiff_t i) p->pixel_top =3D make_number (w->pixel_top); p->pixel_width =3D make_number (w->pixel_width); p->pixel_height =3D make_number (w->pixel_height); + p->old_pixel_width =3D make_number (w->old_pixel_width); + p->old_pixel_height =3D make_number (w->old_pixel_height); p->left_col =3D make_number (w->left_col); p->top_line =3D make_number (w->top_line); p->total_cols =3D make_number (w->total_cols); @@ -7246,6 +7373,16 @@ selected; while the global part is run only once f= or the modified frame, with the relevant frame selected. */); Vwindow_configuration_change_hook =3D Qnil; + DEFVAR_LISP ("window-size-change-functions", Vwindow_size_change_funct= ions, + doc: /* Functions called during redisplay, if window sizes have chan= ged. +The value should be a list of functions that take one argument. +During the first part of redisplay, for each frame, if any of its window= s +have changed size since the last redisplay, or have been split or delete= d, +all the functions in the list are called, with the frame as argument. +If redisplay decides to resize the minibuffer window, it calls these +functions on behalf of that as well. */); + Vwindow_size_change_functions =3D Qnil; + DEFVAR_LISP ("recenter-redisplay", Vrecenter_redisplay, doc: /* Non-nil means `recenter' redraws entire frame. If this option is non-nil, then the `recenter' command with a nil @@ -7374,6 +7511,8 @@ displayed after a scrolling operation to be somewha= t inaccurate. */); defsubr (&Swindow_use_time); defsubr (&Swindow_pixel_width); defsubr (&Swindow_pixel_height); + defsubr (&Swindow_old_pixel_width); + defsubr (&Swindow_old_pixel_height); defsubr (&Swindow_total_width); defsubr (&Swindow_total_height); defsubr (&Swindow_normal_size); diff --git a/src/window.h b/src/window.h index c29207d..dea1d19 100644 --- a/src/window.h +++ b/src/window.h @@ -214,6 +214,11 @@ struct window int pixel_width; int pixel_height; + /* The pixel sizes of the window at the last time + `window-size-change-functions' was run. */ + int old_pixel_width; + int old_pixel_height; + /* The size of the window. */ int total_cols; int total_lines; @@ -499,15 +504,17 @@ wset_next_buffers (struct window *w, Lisp_Object va= l) #define WINDOW_LEAF_P(W) \ (BUFFERP ((W)->contents)) -/* True if W is a member of horizontal combination. */ +/* Non-nil if W is internal. */ +#define WINDOW_INTERNAL_P(W) \ + (WINDOWP ((W)->contents)) +/* True if W is a member of horizontal combination. */ #define WINDOW_HORIZONTAL_COMBINATION_P(W) \ - (WINDOWP ((W)->contents) && (W)->horizontal) + (WINDOW_INTERNAL_P (W) && (W)->horizontal) /* True if W is a member of vertical combination. */ - #define WINDOW_VERTICAL_COMBINATION_P(W) \ - (WINDOWP ((W)->contents) && !(W)->horizontal) + (WINDOW_INTERNAL_P (W) && !(W)->horizontal) /* WINDOW's XFRAME. */ #define WINDOW_XFRAME(W) (XFRAME (WINDOW_FRAME ((W)))) @@ -1014,6 +1021,7 @@ extern void shrink_mini_window (struct window *, bo= ol); extern int window_relative_x_coord (struct window *, enum window_part, i= nt); void run_window_configuration_change_hook (struct frame *f); +void run_window_size_change_functions (Lisp_Object); /* Make WINDOW display BUFFER. RUN_HOOKS_P means it's allowed 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 fed5879..4330f10 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -11786,24 +11786,7 @@ prepare_menu_bars (void) && !XBUFFER (w->contents)->text->redisplay) continue; - /* If a window on this frame changed size, report that to - the user and clear the size-change flag. */ - if (FRAME_WINDOW_SIZES_CHANGED (f)) - { - Lisp_Object functions; - - /* Clear flag first in case we get an error below. */ - FRAME_WINDOW_SIZES_CHANGED (f) =3D false; - functions =3D Vwindow_size_change_functions; - - while (CONSP (functions)) - { - if (!EQ (XCAR (functions), Qt)) - call1 (XCAR (functions), frame); - functions =3D XCDR (functions); - } - } - + run_window_size_change_functions (frame); menu_bar_hooks_run =3D update_menu_bar (f, false, menu_bar_hooks_run)= ; #ifdef HAVE_WINDOW_SYSTEM update_tool_bar (f, false); @@ -13599,24 +13582,12 @@ redisplay_internal (void) it's too late for the hooks in window-size-change-functions, which have been examined already in prepare_menu_bars. So in that case we call the hooks here only for the selected frame. */ - if (sf->redisplay && FRAME_WINDOW_SIZES_CHANGED (sf)) + if (sf->redisplay) { - Lisp_Object functions; ptrdiff_t count1 =3D SPECPDL_INDEX (); record_unwind_save_match_data (); - - /* Clear flag first in case we get an error below. */ - FRAME_WINDOW_SIZES_CHANGED (sf) =3D false; - functions =3D Vwindow_size_change_functions; - - while (CONSP (functions)) - { - if (!EQ (XCAR (functions), Qt)) - call1 (XCAR (functions), selected_frame); - functions =3D XCDR (functions); - } - + run_window_size_change_functions (selected_frame); unbind_to (count1, Qnil); } @@ -13638,22 +13609,10 @@ redisplay_internal (void) { if (sf->redisplay) { - Lisp_Object functions; ptrdiff_t count1 =3D SPECPDL_INDEX (); record_unwind_save_match_data (); - - /* Clear flag first in case we get an error below. */ - FRAME_WINDOW_SIZES_CHANGED (sf) =3D false; - functions =3D Vwindow_size_change_functions; - - while (CONSP (functions)) - { - if (!EQ (XCAR (functions), Qt)) - call1 (XCAR (functions), selected_frame); - functions =3D XCDR (functions); - } - + run_window_size_change_functions (selected_frame); unbind_to (count1, Qnil); } @@ -31447,16 +31406,6 @@ If nil, disable message logging. If t, log mess= ages but don't truncate the buffer when it becomes large. */); Vmessage_log_max =3D make_number (1000); - DEFVAR_LISP ("window-size-change-functions", Vwindow_size_change_funct= ions, - doc: /* Functions called during redisplay, if window sizes have chan= ged. -The value should be a list of functions that take one argument. -During the first part of redisplay, for each frame, if any of its window= s -have changed size since the last redisplay, or have been split or delete= d, -all the functions in the list are called, with the frame as argument. -If redisplay decides to resize the minibuffer window, it calls these -functions on behalf of that as well. */); - Vwindow_size_change_functions =3D Qnil; - DEFVAR_LISP ("window-scroll-functions", Vwindow_scroll_functions, doc: /* List of functions to call before redisplaying a window with = scrolling. Each function is called with two arguments, the window and its new diff --git a/src/xfns.c b/src/xfns.c index 20ac627..2a50a5a 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) } #endif /* not USE_X_TOOLKIT && not USE_GTK */ adjust_frame_glyphs (f); - run_window_configuration_change_hook (f); } c:\emacs-git\quick>c:/Programme/MinGW/msys/1.0/bin/bash.exe --login -i -c= "cd /c/emacs-git/quick/ ; git status" c:/Programme/MinGW/msys/1.0/bin/bash.exe --login -i -c "cd /c/emacs-git/= quick/ ; git status" On branch master Your branch is up-to-date with 'origin/master'. Changes not staged for commit: (use "git add ..." to update what will be committed) (use "git checkout -- ..." to discard changes in working director= y) modified: doc/lispref/windows.texi modified: lisp/window.el modified: src/frame.c modified: src/frame.h modified: src/window.c modified: src/window.h modified: src/xdisp.c modified: src/xfns.c no changes added to commit (use "git add" and/or "git commit -a") c:\emacs-git\quick>c:/Programme/MinGW/msys/1.0/bin/bash.exe --login -i -c= "cd /c/emacs-git/quick/ ; git diff" c:/Programme/MinGW/msys/1.0/bin/bash.exe --login -i -c "cd /c/emacs-git/= quick/ ; git diff" diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index f61f08a..eac3bd6 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -545,6 +545,12 @@ Window Sizes children. @end defun +@defun window-old-pixel-height &optional Lisp_Object &optional window +This function returns the height of window @var{window} in pixels at the= +time @code{window-size-change-functions} was run for the last time on +@var{window}'s frame (@pxref{Window Hooks}). +@end defun + @cindex window pixel width @cindex pixel width of a window @cindex total pixel width of a window @@ -559,6 +565,12 @@ Window Sizes the screen areas spanned by its children. @end defun +@defun window-old-pixel-width &optional Lisp_Object &optional window +This function returns the width of window @var{window} in pixels at the +time @code{window-size-change-functions} was run for the last time on +@var{window}'s frame (@pxref{Window Hooks}). +@end defun + @cindex full-width window @cindex full-height window The following functions can be used to determine whether a given @@ -4087,11 +4099,11 @@ Window Configurations The argument @var{configuration} must be a value that was previously returned by @code{current-window-configuration}. The configuration is restored in the frame from which @var{configuration} was made, whether -that frame is selected or not. This always counts as a window size -change and triggers execution of the @code{window-size-change-functions}= -(@pxref{Window Hooks}), because @code{set-window-configuration} doesn't -know how to tell whether the new configuration actually differs from the= -old one. +that frame is selected or not. In some rare cases this may trigger +execution of the @code{window-size-change-functions} (@pxref{Window +Hooks}) even if the size of windows did not change at all. The +@code{window-configuration-change-hook} functions will be called if and +only if at least one window was added to or deleted from the frame. If the frame from which @var{configuration} was saved is dead, all this function does is restore the three variables @code{window-min-height}, @@ -4378,33 +4390,37 @@ Window Hooks @end defvar @defvar window-size-change-functions -This variable holds a list of functions to be called if the size of -any window changes for any reason. The functions are called at the -beginning of a redisplay cycle, and just once for each frame on which -size changes have occurred. - -Each function receives the frame as its sole argument. There is no -direct way to find out which windows on that frame have changed size, or= -precisely how. However, if a size-change function records, at each -call, the existing windows and their sizes, it can also compare the -present sizes and the previous sizes. - -Creating or deleting windows counts as a size change, and therefore -causes these functions to be called. Changing the frame size also -counts, because it changes the sizes of the existing windows. +This variable holds a list of functions to be called if the size of any +window changes for any reason. The functions are called once per +redisplay, and once for each frame on which size changes have occurred. + +Each function receives the frame as its sole argument. To find out +whether a specific window has changed size, compare the return values of= +@code{window-old-pixel-width} and @code{window-pixel-width} respectively= +@code{window-old-pixel-height} and @code{window-pixel-height} for that +window (@pxref{Window Sizes}). + +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 +that was added intermittently has been deleted afterwards. In these +cases none of the windows on the frame will appear to have changed its +size. You may use @code{save-selected-window} in these functions (@pxref{Selecting Windows}). However, do not use @code{save-window-excursion} (@pxref{Window Configurations}); exiting -that macro counts as a size change, which would cause these functions -to be called over and over. +that macro counts as a size change, which would cause these functions to= +be called again. @end defvar @defvar window-configuration-change-hook -A normal hook that is run every time you change the window configuration= -of an existing frame. This includes splitting or deleting windows, -changing the sizes of windows, or displaying a different buffer in a -window. +A normal hook that is run every time the window configuration of a frame= +changes. Window configuration changes include splitting and deleting +windows and the display of a different buffer in a window. Resizing the= +frame or individual windows do not count as configuration changes. Use +@code{window-size-change-functions}, see above, when you want to track +size changes that are not caused by the deletion or creation of windows.= The buffer-local part of this hook is run once for each window on the affected frame, with the relevant window selected and its buffer diff --git a/src/frame.c b/src/frame.c index 8c86afe..df473ae 100644 --- a/src/frame.c +++ b/src/frame.c @@ -591,8 +591,6 @@ adjust_frame_size (struct frame *f, int new_width, in= t new_height, int inhibit, || new_pixel_height !=3D old_pixel_height); unblock_input (); - - run_window_configuration_change_hook (f); } /* Allocate basically initialized frame. */ diff --git a/src/frame.h b/src/frame.h index 71dab4b..d9424ab 100644 --- a/src/frame.h +++ b/src/frame.h @@ -288,8 +288,9 @@ struct frame cleared. */ bool_bf explicit_name : 1; - /* True if size of some window on this frame has changed. */ - bool_bf window_sizes_changed : 1; + /* True if configuration of windows on this frame has changed since + last call of run_window_size_change_functions. */ + bool_bf window_configuration_changed : 1; /* True if the mouse has moved on this display device since the last time we checked. */ @@ -828,10 +829,10 @@ default_pixels_per_inch_y (void) are frozen on frame F. */ #define FRAME_WINDOWS_FROZEN(f) (f)->frozen_window_starts -/* True if a size change has been requested for frame F - but not yet really put into effect. This can be true temporarily - when an X event comes in at a bad time. */ -#define FRAME_WINDOW_SIZES_CHANGED(f) (f)->window_sizes_changed +/* True if the frame's window configuration has changed since last call + of run_window_size_change_functions. */ +#define FRAME_WINDOW_CONFIGURATION_CHANGED(f) \ + ((f)->window_configuration_changed) /* 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 e1a30ee..5b03a24 100644 --- a/src/window.c +++ b/src/window.c @@ -720,6 +720,30 @@ the height of the screen areas spanned by its childr= en. */) return make_number (decode_valid_window (window)->pixel_height); } +DEFUN ("window-old-pixel-width", Fwindow_old_pixel_width, Swindow_old_pi= xel_width, 0, 1, 0, + doc: /* Return the old width of window WINDOW in pixels. +WINDOW must be a valid window and defaults to the selected one. + +The return value is the pixel width of WINDOW at the last time +`window-size-change-functions' was run. It's zero if WINDOW was made +after that. */) + (Lisp_Object window) +{ + return make_number (decode_valid_window (window)->old_pixel_width); +} + +DEFUN ("window-old-pixel-height", Fwindow_old_pixel_height, Swindow_old_= pixel_height, 0, 1, 0, + doc: /* Return the old height of window WINDOW in pixels. +WINDOW must be a valid window and defaults to the selected one. + +The return value is the pixel height of WINDOW at the last time +`window-size-change-functions' was run. It's zero if WINDOW was made +after that. */) + (Lisp_Object window) +{ + return make_number (decode_valid_window (window)->old_pixel_height); +} + DEFUN ("window-total-height", Fwindow_total_height, Swindow_total_height= , 0, 2, 0, doc: /* Return the height of window WINDOW in lines. WINDOW must be a valid window and defaults to the selected one. @@ -2879,6 +2903,7 @@ window-start value is reasonable when this function= is called. */) Lisp_Object sibling, pwindow, swindow IF_LINT (=3D Qnil), delta; ptrdiff_t startpos IF_LINT (=3D 0), startbyte IF_LINT (=3D 0); int top IF_LINT (=3D 0), new_top; + bool resize_failed =3D false; w =3D decode_valid_window (window); XSETWINDOW (window, w); @@ -2978,8 +3003,6 @@ window-start value is reasonable when this function= is called. */) fset_redisplay (f); Vwindow_list =3D Qnil; - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; - bool resize_failed =3D false; if (!WINDOW_LEAF_P (w)) { @@ -3229,6 +3252,76 @@ If WINDOW is omitted or nil, it defaults to the se= lected window. */) return Qnil; } + +/* Compare old and present pixel sizes of windows in tree rooted at W. + Return true iff any of these windows differs in size. */ + +static bool +window_size_changed (struct window *w) +{ + if (w->pixel_width !=3D w->old_pixel_width + || w->pixel_height !=3D w->old_pixel_height) + return true; + + if (WINDOW_INTERNAL_P (w)) + { + w =3D XWINDOW (w->contents); + while (w) + { + if (window_size_changed (w)) + return true; + + w =3D NILP (w->next) ? 0 : XWINDOW (w->next); + } + } + + return false; +} + +/* Set old pixel sizes of windows in tree rooted at W to their present + pixel sizes. */ + +static void +window_set_old_pixel_sizes (struct window *w) +{ + w->old_pixel_width =3D w->pixel_width; + w->old_pixel_height =3D w->pixel_height; + + if (WINDOW_INTERNAL_P (w)) + { + w =3D XWINDOW (w->contents); + while (w) + { + window_set_old_pixel_sizes (w); + w =3D NILP (w->next) ? 0 : XWINDOW (w->next); + } + } +} + + +void +run_window_size_change_functions (Lisp_Object frame) +{ + struct frame *f =3D XFRAME (frame); + struct window *r =3D XWINDOW (FRAME_ROOT_WINDOW (f)); + Lisp_Object functions =3D Vwindow_size_change_functions; + + if (FRAME_WINDOW_CONFIGURATION_CHANGED (f) || + window_size_changed (r)) + { + while (CONSP (functions)) + { + if (!EQ (XCAR (functions), Qt)) + call1 (XCAR (functions), frame); + functions =3D XCDR (functions); + } + + window_set_old_pixel_sizes (r); + FRAME_WINDOW_CONFIGURATION_CHANGED (f) =3D false; + } +} + + /* Make WINDOW display BUFFER. RUN_HOOKS_P means it's allowed to run hooks. See make_frame for a case where it's not allowed. KEEP_MARGINS_P means that the current margins, fringes, and @@ -3263,15 +3356,9 @@ set_window_buffer (Lisp_Object window, Lisp_Object= buffer, if (!(keep_margins_p && samebuf)) { /* If we're not actually changing the buffer, don't reset hscroll - and vscroll. This case happens for example when called from - change_frame_size_1, where we use a dummy call to - Fset_window_buffer on the frame's selected window (and no - other) just in order to run window-configuration-change-hook - (no longer true since change_frame_size_1 directly calls - run_window_configuration_change_hook). Resetting hscroll and - vscroll here is problematic for things like image-mode and - doc-view-mode since it resets the image's position whenever we - resize the frame. */ + and vscroll. Resetting hscroll and vscroll here is problematic + for things like image-mode and doc-view-mode since it resets + the image's position whenever we resize the frame. */ w->hscroll =3D w->min_hscroll =3D w->hscroll_whole =3D 0; w->suspend_auto_hscroll =3D false; w->vscroll =3D 0; @@ -3283,10 +3370,8 @@ set_window_buffer (Lisp_Object window, Lisp_Object= buffer, w->start_at_line_beg =3D false; w->force_start =3D false; } - /* Maybe we could move this into the `if' but it's not obviously safe = and - I doubt it's worth the trouble. */ - wset_redisplay (w); + wset_redisplay (w); wset_update_mode_line (w); /* We must select BUFFER to run the window-scroll-functions and to loo= k up @@ -3314,7 +3399,7 @@ set_window_buffer (Lisp_Object window, Lisp_Object = buffer, if (run_hooks_p) { - if (! NILP (Vwindow_scroll_functions)) + if (!NILP (Vwindow_scroll_functions)) run_hook_with_args_2 (Qwindow_scroll_functions, window, Fmarker_position (w->start)); if (!samebuf) @@ -3559,6 +3644,8 @@ make_window (void) w->phys_cursor_width =3D -1; #endif w->sequence_number =3D ++sequence_number; + w->old_pixel_width =3D 0; + w->old_pixel_height =3D 0; w->scroll_bar_width =3D -1; w->scroll_bar_height =3D -1; w->column_number_displayed =3D -1; @@ -3922,7 +4009,6 @@ be applied on the Elisp level. */) window_resize_apply (r, horflag); fset_redisplay (f); - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; adjust_frame_glyphs (f); unblock_input (); @@ -4087,7 +4173,6 @@ resize_frame_windows (struct frame *f, int size, bo= ol horflag, bool pixelwise) } } - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; fset_redisplay (f); } @@ -4214,7 +4299,6 @@ set correctly. See the code of `split-window' for = how this is done. */) p =3D XWINDOW (o->parent); fset_redisplay (f); - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; new =3D make_window (); n =3D XWINDOW (new); wset_frame (n, frame); @@ -4383,7 +4467,6 @@ Signal an error when WINDOW is the only window on i= ts frame. */) fset_redisplay (f); Vwindow_list =3D Qnil; - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; wset_next (w, Qnil); /* Don't delete w->next too. */ free_window_matrices (w); @@ -4451,9 +4534,6 @@ Signal an error when WINDOW is the only window on i= ts frame. */) } else unblock_input (); - - /* Must be run by the caller: - run_window_configuration_change_hook (f); */ } else /* We failed: Relink WINDOW into window tree. */ @@ -4527,7 +4607,6 @@ grow_mini_window (struct window *w, int delta, bool= pixelwise) /* Enforce full redisplay of the frame. */ /* FIXME: Shouldn't window--resize-root-window-vertically do it? */ fset_redisplay (f); - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; adjust_frame_glyphs (f); unblock_input (); } @@ -4567,7 +4646,6 @@ shrink_mini_window (struct window *w, bool pixelwis= e) /* Enforce full redisplay of the frame. */ /* FIXME: Shouldn't window--resize-root-window-vertically do it? */ fset_redisplay (f); - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; adjust_frame_glyphs (f); unblock_input (); } @@ -4610,7 +4688,6 @@ DEFUN ("resize-mini-window-internal", Fresize_mini_= window_internal, Sresize_mini w->top_line =3D r->top_line + r->total_lines; fset_redisplay (f); - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; adjust_frame_glyphs (f); unblock_input (); return Qt; @@ -5948,6 +6025,7 @@ struct saved_window Lisp_Object window, buffer, start, pointm, old_pointm; Lisp_Object pixel_left, pixel_top, pixel_height, pixel_width; + Lisp_Object old_pixel_height, old_pixel_width; Lisp_Object left_col, top_line, total_cols, total_lines; Lisp_Object normal_cols, normal_lines; Lisp_Object hscroll, min_hscroll, hscroll_whole, suspend_auto_hscroll;= @@ -6063,6 +6141,12 @@ the return value is nil. Otherwise the value is t= =2E */) struct window *root_window; struct window **leaf_windows; ptrdiff_t i, k, n_leaf_windows; + /* Records whether a window has been added or removed wrt the + original configuration. */ + bool window_changed =3D false; + /* Records whether a window has changed its buffer wrt the + original configuration. */ + bool buffer_changed =3D false; /* Don't do this within the main loop below: This may call Lisp code and is thus potentially unsafe while input is blocked. */ @@ -6071,6 +6155,12 @@ the return value is nil. Otherwise the value is t= =2E */) p =3D SAVED_WINDOW_N (saved_windows, k); window =3D p->window; w =3D XWINDOW (window); + + if (NILP (w->contents)) + /* A dead window that will be resurrected, the window + configuration will change. */ + window_changed =3D true; + if (BUFFERP (w->contents) && !EQ (w->contents, p->buffer) && BUFFER_LIVE_P (XBUFFER (p->buffer))) @@ -6100,7 +6190,6 @@ the return value is nil. Otherwise the value is t.= */) } fset_redisplay (f); - FRAME_WINDOW_SIZES_CHANGED (f) =3D true; /* Problem: Freeing all matrices and later allocating them again is a serious redisplay flickering problem. What we would @@ -6156,6 +6245,8 @@ the return value is nil. Otherwise the value is t.= */) w->pixel_top =3D XFASTINT (p->pixel_top); w->pixel_width =3D XFASTINT (p->pixel_width); w->pixel_height =3D XFASTINT (p->pixel_height); + w->old_pixel_width =3D XFASTINT (p->old_pixel_width); + w->old_pixel_height =3D XFASTINT (p->old_pixel_height); w->left_col =3D XFASTINT (p->left_col); w->top_line =3D XFASTINT (p->top_line); w->total_cols =3D XFASTINT (p->total_cols); @@ -6203,6 +6294,9 @@ the return value is nil. Otherwise the value is t.= */) if (BUFFERP (p->buffer) && BUFFER_LIVE_P (XBUFFER (p->buffer))) /* If saved buffer is alive, install it. */ { + if (!EQ (w->contents, p->buffer)) + /* Record buffer configuration change. */ + buffer_changed =3D true; wset_buffer (w, p->buffer); w->start_at_line_beg =3D !NILP (p->start_at_line_beg); set_marker_restricted (w->start, p->start, w->contents); @@ -6236,6 +6330,8 @@ the return value is nil. Otherwise the value is t.= */) else if (!NILP (w->start)) /* Leaf window has no live buffer, get one. */ { + /* Record buffer configuration change. */ + buffer_changed =3D true; /* Get the buffer via other_buffer_safely in order to avoid showing an unimportant buffer and, if necessary, to recreate *scratch* in the course (part of Juanma's bs-show @@ -6283,7 +6379,10 @@ the return value is nil. Otherwise the value is t= =2E */) /* Now, free glyph matrices in windows that were not reused. */ for (i =3D 0; i < n_leaf_windows; i++) if (NILP (leaf_windows[i]->contents)) - free_window_matrices (leaf_windows[i]); + { + free_window_matrices (leaf_windows[i]); + window_changed =3D true; + } /* Allow x_set_window_size again and apply frame size changes if needed. */ @@ -6303,7 +6402,8 @@ the return value is nil. Otherwise the value is t.= */) /* Record the selected window's buffer here. The window should already be the selected one from the call above. */ - select_window (data->current_window, Qnil, false); + if (WINDOW_LIVE_P (data->current_window)) + select_window (data->current_window, Qnil, false); /* Fselect_window will have made f the selected frame, so we reselect the proper frame here. Fhandle_switch_frame will change the @@ -6313,7 +6413,32 @@ the return value is nil. Otherwise the value is t= =2E */) if (FRAME_LIVE_P (XFRAME (data->selected_frame))) do_switch_frame (data->selected_frame, 0, 0, Qnil); - run_window_configuration_change_hook (f); + if (window_changed) + /* At least one window has been added or removed. Run + `window-configuration-change-hook' and make sure + `window-size-change-functions' get run later. + + We have to do this in order to capture the following + scenario: Suppose our frame contains two live windows W1 and + W2 and =E2=80=98set-window-configuration=E2=80=99 replaces them by t= wo + windows W3 and W4 that were dead the last time + run_window_size_change_functions was run. If W3 and W4 have + the same values for their old and new pixel sizes but these + values differ from those of W1 and W2, the sizes of our + frame's two live windows changed but window_size_changed has + no means to detect that fact. + + Obviously, this will get us false positives, for example, + when we restore the original configuration with W1 and W2 + before run_window_size_change_functions gets called. */ + { + run_window_configuration_change_hook (f); + FRAME_WINDOW_CONFIGURATION_CHANGED (f) =3D true; + } + else if (buffer_changed) + /* At least one window has changed its buffer. Run + `window-configuration-change-hook' only. */ + run_window_configuration_change_hook (f); } if (!NILP (new_current_buffer)) @@ -6464,6 +6589,8 @@ save_window_save (Lisp_Object window, struct Lisp_V= ector *vector, ptrdiff_t i) p->pixel_top =3D make_number (w->pixel_top); p->pixel_width =3D make_number (w->pixel_width); p->pixel_height =3D make_number (w->pixel_height); + p->old_pixel_width =3D make_number (w->old_pixel_width); + p->old_pixel_height =3D make_number (w->old_pixel_height); p->left_col =3D make_number (w->left_col); p->top_line =3D make_number (w->top_line); p->total_cols =3D make_number (w->total_cols); @@ -7246,6 +7373,16 @@ selected; while the global part is run only once f= or the modified frame, with the relevant frame selected. */); Vwindow_configuration_change_hook =3D Qnil; + DEFVAR_LISP ("window-size-change-functions", Vwindow_size_change_funct= ions, + doc: /* Functions called during redisplay, if window sizes have chan= ged. +The value should be a list of functions that take one argument. +During the first part of redisplay, for each frame, if any of its window= s +have changed size since the last redisplay, or have been split or delete= d, +all the functions in the list are called, with the frame as argument. +If redisplay decides to resize the minibuffer window, it calls these +functions on behalf of that as well. */); + Vwindow_size_change_functions =3D Qnil; + DEFVAR_LISP ("recenter-redisplay", Vrecenter_redisplay, doc: /* Non-nil means `recenter' redraws entire frame. If this option is non-nil, then the `recenter' command with a nil @@ -7374,6 +7511,8 @@ displayed after a scrolling operation to be somewha= t inaccurate. */); defsubr (&Swindow_use_time); defsubr (&Swindow_pixel_width); defsubr (&Swindow_pixel_height); + defsubr (&Swindow_old_pixel_width); + defsubr (&Swindow_old_pixel_height); defsubr (&Swindow_total_width); defsubr (&Swindow_total_height); defsubr (&Swindow_normal_size); diff --git a/src/window.h b/src/window.h index c29207d..dea1d19 100644 --- a/src/window.h +++ b/src/window.h @@ -214,6 +214,11 @@ struct window int pixel_width; int pixel_height; + /* The pixel sizes of the window at the last time + `window-size-change-functions' was run. */ + int old_pixel_width; + int old_pixel_height; + /* The size of the window. */ int total_cols; int total_lines; @@ -499,15 +504,17 @@ wset_next_buffers (struct window *w, Lisp_Object va= l) #define WINDOW_LEAF_P(W) \ (BUFFERP ((W)->contents)) -/* True if W is a member of horizontal combination. */ +/* Non-nil if W is internal. */ +#define WINDOW_INTERNAL_P(W) \ + (WINDOWP ((W)->contents)) +/* True if W is a member of horizontal combination. */ #define WINDOW_HORIZONTAL_COMBINATION_P(W) \ - (WINDOWP ((W)->contents) && (W)->horizontal) + (WINDOW_INTERNAL_P (W) && (W)->horizontal) /* True if W is a member of vertical combination. */ - #define WINDOW_VERTICAL_COMBINATION_P(W) \ - (WINDOWP ((W)->contents) && !(W)->horizontal) + (WINDOW_INTERNAL_P (W) && !(W)->horizontal) /* WINDOW's XFRAME. */ #define WINDOW_XFRAME(W) (XFRAME (WINDOW_FRAME ((W)))) @@ -1014,6 +1021,7 @@ extern void shrink_mini_window (struct window *, bo= ol); extern int window_relative_x_coord (struct window *, enum window_part, i= nt); void run_window_configuration_change_hook (struct frame *f); +void run_window_size_change_functions (Lisp_Object); /* Make WINDOW display BUFFER. RUN_HOOKS_P means it's allowed 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 fed5879..4330f10 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -11786,24 +11786,7 @@ prepare_menu_bars (void) && !XBUFFER (w->contents)->text->redisplay) continue; - /* If a window on this frame changed size, report that to - the user and clear the size-change flag. */ - if (FRAME_WINDOW_SIZES_CHANGED (f)) - { - Lisp_Object functions; - - /* Clear flag first in case we get an error below. */ - FRAME_WINDOW_SIZES_CHANGED (f) =3D false; - functions =3D Vwindow_size_change_functions; - - while (CONSP (functions)) - { - if (!EQ (XCAR (functions), Qt)) - call1 (XCAR (functions), frame); - functions =3D XCDR (functions); - } - } - + run_window_size_change_functions (frame); menu_bar_hooks_run =3D update_menu_bar (f, false, menu_bar_hooks_run)= ; #ifdef HAVE_WINDOW_SYSTEM update_tool_bar (f, false); @@ -13599,24 +13582,12 @@ redisplay_internal (void) it's too late for the hooks in window-size-change-functions, which have been examined already in prepare_menu_bars. So in that case we call the hooks here only for the selected frame. */ - if (sf->redisplay && FRAME_WINDOW_SIZES_CHANGED (sf)) + if (sf->redisplay) { - Lisp_Object functions; ptrdiff_t count1 =3D SPECPDL_INDEX (); record_unwind_save_match_data (); - - /* Clear flag first in case we get an error below. */ - FRAME_WINDOW_SIZES_CHANGED (sf) =3D false; - functions =3D Vwindow_size_change_functions; - - while (CONSP (functions)) - { - if (!EQ (XCAR (functions), Qt)) - call1 (XCAR (functions), selected_frame); - functions =3D XCDR (functions); - } - + run_window_size_change_functions (selected_frame); unbind_to (count1, Qnil); } @@ -13638,22 +13609,10 @@ redisplay_internal (void) { if (sf->redisplay) { - Lisp_Object functions; ptrdiff_t count1 =3D SPECPDL_INDEX (); record_unwind_save_match_data (); - - /* Clear flag first in case we get an error below. */ - FRAME_WINDOW_SIZES_CHANGED (sf) =3D false; - functions =3D Vwindow_size_change_functions; - - while (CONSP (functions)) - { - if (!EQ (XCAR (functions), Qt)) - call1 (XCAR (functions), selected_frame); - functions =3D XCDR (functions); - } - + run_window_size_change_functions (selected_frame); unbind_to (count1, Qnil); } @@ -31447,16 +31406,6 @@ If nil, disable message logging. If t, log mess= ages but don't truncate the buffer when it becomes large. */); Vmessage_log_max =3D make_number (1000); - DEFVAR_LISP ("window-size-change-functions", Vwindow_size_change_funct= ions, - doc: /* Functions called during redisplay, if window sizes have chan= ged. -The value should be a list of functions that take one argument. -During the first part of redisplay, for each frame, if any of its window= s -have changed size since the last redisplay, or have been split or delete= d, -all the functions in the list are called, with the frame as argument. -If redisplay decides to resize the minibuffer window, it calls these -functions on behalf of that as well. */); - Vwindow_size_change_functions =3D Qnil; - DEFVAR_LISP ("window-scroll-functions", Vwindow_scroll_functions, doc: /* List of functions to call before redisplaying a window with = scrolling. Each function is called with two arguments, the window and its new diff --git a/src/xfns.c b/src/xfns.c index 20ac627..2a50a5a 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) } #endif /* not USE_X_TOOLKIT && not USE_GTK */ adjust_frame_glyphs (f); - run_window_configuration_change_hook (f); } --------------020200040005050006060906--