Commit 8e7712c7 authored by Martin Rudalics's avatar Martin Rudalics

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'.
parent ef52e66e
......@@ -545,6 +545,12 @@ its pixel height is the pixel height of the screen areas spanned by its
children.
@end defun
@defun window-pixel-height-before-size-change &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 @@ If @var{window} is an internal window, its pixel width is the width of
the screen areas spanned by its children.
@end defun
@defun window-pixel-width-before-size-change &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 @@ was created for.
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,38 @@ work.
@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-pixel-width-before-size-change} and
@code{window-pixel-width} respectively
@code{window-pixel-height-before-size-change} 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
......
......@@ -591,8 +591,6 @@ adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit,
|| new_pixel_height != old_pixel_height);
unblock_input ();
run_window_configuration_change_hook (f);
}
/* Allocate basically initialized frame. */
......
......@@ -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
......
This diff is collapsed.
......@@ -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 pixel_width_before_size_change;
int pixel_height_before_size_change;
/* The size of the window. */
int total_cols;
int total_lines;
......@@ -499,15 +504,17 @@ wset_next_buffers (struct window *w, Lisp_Object val)
#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 *, bool);
extern int window_relative_x_coord (struct window *, enum window_part, int);
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. */
......
......@@ -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) = false;
functions = Vwindow_size_change_functions;
while (CONSP (functions))
{
if (!EQ (XCAR (functions), Qt))
call1 (XCAR (functions), frame);
functions = XCDR (functions);
}
}
run_window_size_change_functions (frame);
menu_bar_hooks_run = 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 = SPECPDL_INDEX ();
record_unwind_save_match_data ();
/* Clear flag first in case we get an error below. */
FRAME_WINDOW_SIZES_CHANGED (sf) = false;
functions = Vwindow_size_change_functions;
while (CONSP (functions))
{
if (!EQ (XCAR (functions), Qt))
call1 (XCAR (functions), selected_frame);
functions = 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 = SPECPDL_INDEX ();
record_unwind_save_match_data ();
/* Clear flag first in case we get an error below. */
FRAME_WINDOW_SIZES_CHANGED (sf) = false;
functions = Vwindow_size_change_functions;
while (CONSP (functions))
{
if (!EQ (XCAR (functions), Qt))
call1 (XCAR (functions), selected_frame);
functions = 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 messages but don't truncate
the buffer when it becomes large. */);
Vmessage_log_max = make_number (1000);
DEFVAR_LISP ("window-size-change-functions", Vwindow_size_change_functions,
doc: /* Functions called during redisplay, if window sizes have changed.
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 windows
have changed size since the last redisplay, or have been split or deleted,
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 = 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
......
......@@ -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);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment