diff options
Diffstat (limited to 'src/window.c')
-rw-r--r-- | src/window.c | 2966 |
1 files changed, 1894 insertions, 1072 deletions
diff --git a/src/window.c b/src/window.c index ba86d73911f..12a212a85ac 100644 --- a/src/window.c +++ b/src/window.c @@ -1,6 +1,6 @@ /* Window creation, deletion and examination for GNU Emacs. Does not include redisplay. - Copyright (C) 1985-1987, 1993-1998, 2000-2017 Free Software + Copyright (C) 1985-1987, 1993-1998, 2000-2022 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -20,7 +20,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <config.h> -#include <stdio.h> +/* Work around GCC bug 102671. */ +#if 10 <= __GNUC__ +# pragma GCC diagnostic ignored "-Wanalyzer-null-dereference" +#endif #include "lisp.h" #include "buffer.h" @@ -42,6 +45,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #ifdef MSDOS #include "msdos.h" #endif +#include "pdumper.h" static ptrdiff_t count_windows (struct window *); static ptrdiff_t get_leaf_windows (struct window *, struct window **, @@ -60,12 +64,13 @@ static void select_window_1 (Lisp_Object, bool); static void run_window_configuration_change_hook (struct frame *); static struct window *set_window_fringes (struct window *, Lisp_Object, - Lisp_Object, Lisp_Object); + Lisp_Object, Lisp_Object, + Lisp_Object); static struct window *set_window_margins (struct window *, Lisp_Object, Lisp_Object); static struct window *set_window_scroll_bars (struct window *, Lisp_Object, Lisp_Object, Lisp_Object, - Lisp_Object); + Lisp_Object, Lisp_Object); static void apply_window_adjustment (struct window *); /* This is the window in which the terminal's cursor should @@ -77,11 +82,19 @@ static void apply_window_adjustment (struct window *); FRAME_SELECTED_WINDOW (selected_frame). */ Lisp_Object selected_window; +/* The value of selected_window at the last time window change + functions were run. This is always the same as + FRAME_OLD_SELECTED_WINDOW (old_selected_frame). */ +static Lisp_Object old_selected_window; + /* A list of all windows for use by next_window and Fwindow_list. Functions creating or deleting windows should invalidate this cache by setting it to nil. */ Lisp_Object Vwindow_list; +/* True mean window_change_record has to record all live frames. */ +static bool window_change_record_frames; + /* The mini-buffer window of the selected frame. Note that you cannot test for mini-bufferness of an arbitrary window by comparing against this; but you can test for mini-bufferness of @@ -207,20 +220,6 @@ wset_combination (struct window *w, bool horflag, Lisp_Object val) w->horizontal = horflag; } -static void -wset_update_mode_line (struct window *w) -{ - /* If this window is the selected window on its frame, set the - global variable update_mode_lines, so that x_consider_frame_title - will consider this frame's title for redisplay. */ - Lisp_Object fselected_window = XFRAME (WINDOW_FRAME (w))->selected_window; - - if (WINDOWP (fselected_window) && XWINDOW (fselected_window) == w) - update_mode_lines = 42; - else - w->update_mode_line = true; -} - /* True if leaf window W doesn't reflect the actual state of displayed buffer due to its text or overlays change. */ @@ -304,6 +303,12 @@ wset_buffer (struct window *w, Lisp_Object val) adjust_window_count (w, 1); } +static void +wset_old_buffer (struct window *w, Lisp_Object val) +{ + w->old_buffer = val; +} + DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0, doc: /* Return t if OBJECT is a window and nil otherwise. */) (Lisp_Object object) @@ -370,7 +375,7 @@ If FRAME is omitted or nil, it defaults to the selected frame. */) DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1, 0, - doc: /* Return non-nil if WINDOW is a minibuffer window. + doc: /* Return t if WINDOW is a minibuffer window. WINDOW must be a valid window and defaults to the selected one. */) (Lisp_Object window) { @@ -428,6 +433,22 @@ return the selected window of that frame. */) return window; } +DEFUN ("frame-old-selected-window", Fframe_old_selected_window, + Sframe_old_selected_window, 0, 1, 0, + doc: /* Return old selected window of FRAME. +FRAME must be a live frame and defaults to the selected one. + +The return value is the window selected on FRAME the last time window +change functions were run for FRAME. */) + (Lisp_Object frame) +{ + if (NILP (frame)) + frame = selected_frame; + CHECK_LIVE_FRAME (frame); + + return XFRAME (frame)->old_selected_window; +} + DEFUN ("set-frame-selected-window", Fset_frame_selected_window, Sset_frame_selected_window, 2, 3, 0, doc: /* Set selected window of FRAME to WINDOW. @@ -452,6 +473,7 @@ Return WINDOW. */) else { fset_selected_window (XFRAME (frame), window); + /* Don't clear FRAME's select_mini_window_flag here. */ return window; } } @@ -459,12 +481,24 @@ Return WINDOW. */) DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0, doc: /* Return the selected window. The selected window is the window in which the standard cursor for -selected windows appears and to which many commands apply. */) +selected windows appears and to which many commands apply. + +Also see `old-selected-window' and `minibuffer-selected-window'. */) (void) { return selected_window; } +DEFUN ("old-selected-window", Fold_selected_window, + Sold_selected_window, 0, 0, 0, + doc: /* Return the old selected window. +The return value is the window selected the last time window change +functions were run. */) + (void) +{ + return old_selected_window; +} + EMACS_INT window_select_count; /* If select_window is called with inhibit_point_swap true it will @@ -478,10 +512,21 @@ select_window (Lisp_Object window, Lisp_Object norecord, { struct window *w; struct frame *sf; + Lisp_Object frame; + struct frame *f; CHECK_LIVE_WINDOW (window); w = XWINDOW (window); + frame = WINDOW_FRAME (w); + f = XFRAME (frame); + + if (FRAME_TOOLTIP_P (f)) + /* Do not select a tooltip window (Bug#47207). */ + error ("Cannot select a tooltip window"); + + /* We deinitely want to select WINDOW, not the mini-window. */ + f->select_mini_window_flag = false; /* Make the selected window's buffer current. */ Fset_buffer (w->contents); @@ -502,16 +547,18 @@ select_window (Lisp_Object window, Lisp_Object norecord, redisplay_other_windows (); sf = SELECTED_FRAME (); - if (XFRAME (WINDOW_FRAME (w)) != sf) + if (f != sf) { - fset_selected_window (XFRAME (WINDOW_FRAME (w)), window); + fset_selected_window (f, window); /* Use this rather than Fhandle_switch_frame so that FRAME_FOCUS_FRAME is moved appropriately as we move around in the state where a minibuffer in a separate frame is active. */ - Fselect_frame (WINDOW_FRAME (w), norecord); + Fselect_frame (frame, norecord); /* Fselect_frame called us back so we've done all the work already. */ - eassert (EQ (window, selected_window)); + eassert (EQ (window, selected_window) + || (EQ (window, f->minibuffer_window) + && NILP (Fminibufferp (XWINDOW (window)->contents, Qt)))); return window; } else @@ -577,11 +624,12 @@ equals the special symbol `mark-for-redisplay'. Run `buffer-list-update-hook' unless NORECORD is non-nil. Note that applications and internal routines often select a window temporarily for various purposes; mostly, to simplify coding. As a rule, such -selections should be not recorded and therefore will not pollute +selections should not be recorded and therefore will not pollute `buffer-list-update-hook'. Selections that "really count" are those causing a visible change in the next redisplay of WINDOW's frame and -should be always recorded. So if you think of running a function each -time a window gets selected put it on `buffer-list-update-hook'. +should always be recorded. So if you think of running a function each +time a window gets selected, put it on `buffer-list-update-hook' or +`window-selection-change-functions'. Also note that the main editor command loop sets the current buffer to the buffer of the selected window before each command. */) @@ -597,9 +645,33 @@ Return nil for an internal window or a deleted window. */) (Lisp_Object window) { struct window *w = decode_any_window (window); + return WINDOW_LEAF_P (w) ? w->contents : Qnil; } +DEFUN ("window-old-buffer", Fwindow_old_buffer, Swindow_old_buffer, 0, 1, 0, + doc: /* Return the old buffer displayed by WINDOW. +WINDOW must be a live window and defaults to the selected one. + +The return value is the buffer shown in WINDOW at the last time window +change functions were run. It is nil if WINDOW was created after +that. It is t if WINDOW has been restored from a window configuration +after that. */) + (Lisp_Object window) +{ + struct window *w = decode_live_window (window); + + return (NILP (w->old_buffer) + /* A new window. */ + ? Qnil + : (w->change_stamp != WINDOW_XFRAME (w)->change_stamp) + /* A window restored from a configuration. */ + ? Qt + /* A window that was live the last time seen by window + change functions. */ + : w->old_buffer); +} + DEFUN ("window-parent", Fwindow_parent, Swindow_parent, 0, 1, 0, doc: /* Return the parent window of window WINDOW. WINDOW must be a valid window and defaults to the selected one. @@ -695,7 +767,20 @@ one. The window with the lowest use time is the least recently selected one. */) (Lisp_Object window) { - return make_number (decode_live_window (window)->use_time); + return make_fixnum (decode_live_window (window)->use_time); +} + +DEFUN ("window-bump-use-time", Fwindow_bump_use_time, + Swindow_bump_use_time, 0, 1, 0, + doc: /* Mark WINDOW as having been most recently used. +WINDOW must be a live window and defaults to the selected one. */) + (Lisp_Object window) +{ + struct window *w = decode_live_window (window); + + w->use_time = ++window_select_count; + + return Qnil; } DEFUN ("window-pixel-width", Fwindow_pixel_width, Swindow_pixel_width, 0, 1, 0, @@ -708,7 +793,7 @@ an internal window, its pixel width is the width of the screen areas spanned by its children. */) (Lisp_Object window) { - return make_number (decode_valid_window (window)->pixel_width); + return make_fixnum (decode_valid_window (window)->pixel_width); } DEFUN ("window-pixel-height", Fwindow_pixel_height, Swindow_pixel_height, 0, 1, 0, @@ -720,37 +805,35 @@ divider, if any. If WINDOW is an internal window, its pixel height is the height of the screen areas spanned by its children. */) (Lisp_Object window) { - return make_number (decode_valid_window (window)->pixel_height); + return make_fixnum (decode_valid_window (window)->pixel_height); } -DEFUN ("window-pixel-width-before-size-change", - Fwindow_pixel_width_before_size_change, - Swindow_pixel_width_before_size_change, 0, 1, 0, - doc: /* Return pixel width of window WINDOW before last size changes. +DEFUN ("window-old-pixel-width", Fwindow_old_pixel_width, + Swindow_old_pixel_width, 0, 1, 0, + doc: /* Return old total pixel width of WINDOW. 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. */) +The return value is the total pixel width of WINDOW after the last +time window change functions found WINDOW live on its frame. It is +zero if WINDOW was created after that. */) (Lisp_Object window) { - return (make_number - (decode_valid_window (window)->pixel_width_before_size_change)); + return (make_fixnum + (decode_valid_window (window)->old_pixel_width)); } -DEFUN ("window-pixel-height-before-size-change", - Fwindow_pixel_height_before_size_change, - Swindow_pixel_height_before_size_change, 0, 1, 0, - doc: /* Return pixel height of window WINDOW before last size changes. +DEFUN ("window-old-pixel-height", Fwindow_old_pixel_height, + Swindow_old_pixel_height, 0, 1, 0, + doc: /* Return old total pixel height of WINDOW. 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. */) +The return value is the total pixel height of WINDOW after the last +time window change functions found WINDOW live on its frame. It is +zero if WINDOW was created after that. */) (Lisp_Object window) { - return (make_number - (decode_valid_window (window)->pixel_height_before_size_change)); + return (make_fixnum + (decode_valid_window (window)->old_pixel_height)); } DEFUN ("window-total-height", Fwindow_total_height, Swindow_total_height, 0, 2, 0, @@ -778,12 +861,12 @@ total height of WINDOW. */) struct window *w = decode_valid_window (window); if (! EQ (round, Qfloor) && ! EQ (round, Qceiling)) - return make_number (w->total_lines); + return make_fixnum (w->total_lines); else { int unit = FRAME_LINE_HEIGHT (WINDOW_XFRAME (w)); - return make_number (EQ (round, Qceiling) + return make_fixnum (EQ (round, Qceiling) ? ((w->pixel_height + unit - 1) /unit) : (w->pixel_height / unit)); } @@ -815,12 +898,12 @@ total width of WINDOW. */) struct window *w = decode_valid_window (window); if (! EQ (round, Qfloor) && ! EQ (round, Qceiling)) - return make_number (w->total_cols); + return make_fixnum (w->total_cols); else { int unit = FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w)); - return make_number (EQ (round, Qceiling) + return make_fixnum (EQ (round, Qceiling) ? ((w->pixel_width + unit - 1) /unit) : (w->pixel_width / unit)); } @@ -898,7 +981,7 @@ DEFUN ("window-pixel-left", Fwindow_pixel_left, Swindow_pixel_left, 0, 1, 0, WINDOW must be a valid window and defaults to the selected one. */) (Lisp_Object window) { - return make_number (decode_valid_window (window)->pixel_left); + return make_fixnum (decode_valid_window (window)->pixel_left); } DEFUN ("window-pixel-top", Fwindow_pixel_top, Swindow_pixel_top, 0, 1, 0, @@ -906,7 +989,7 @@ DEFUN ("window-pixel-top", Fwindow_pixel_top, Swindow_pixel_top, 0, 1, 0, WINDOW must be a valid window and defaults to the selected one. */) (Lisp_Object window) { - return make_number (decode_valid_window (window)->pixel_top); + return make_fixnum (decode_valid_window (window)->pixel_top); } DEFUN ("window-left-column", Fwindow_left_column, Swindow_left_column, 0, 1, 0, @@ -918,7 +1001,7 @@ value is 0 if there is no window to the left of WINDOW. WINDOW must be a valid window and defaults to the selected one. */) (Lisp_Object window) { - return make_number (decode_valid_window (window)->left_col); + return make_fixnum (decode_valid_window (window)->left_col); } DEFUN ("window-top-line", Fwindow_top_line, Swindow_top_line, 0, 1, 0, @@ -930,16 +1013,28 @@ there is no window above WINDOW. WINDOW must be a valid window and defaults to the selected one. */) (Lisp_Object window) { - return make_number (decode_valid_window (window)->top_line); + return make_fixnum (decode_valid_window (window)->top_line); +} + +static enum window_body_unit +window_body_unit_from_symbol (Lisp_Object unit) +{ + return + EQ (unit, Qremap) + ? WINDOW_BODY_IN_REMAPPED_CHARS + : (NILP (unit) + ? WINDOW_BODY_IN_CANONICAL_CHARS + : WINDOW_BODY_IN_PIXELS); } /* Return the number of lines/pixels of W's body. Don't count any mode or header line or horizontal divider of W. Rounds down to nearest integer when not working pixelwise. */ -static int -window_body_height (struct window *w, bool pixelwise) +int +window_body_height (struct window *w, enum window_body_unit pixelwise) { int height = (w->pixel_height + - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w) - (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w) ? WINDOW_SCROLL_BAR_AREA_HEIGHT (w) @@ -947,11 +1042,27 @@ window_body_height (struct window *w, bool pixelwise) - WINDOW_MODE_LINE_HEIGHT (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w)); + int denom = 1; + if (pixelwise == WINDOW_BODY_IN_REMAPPED_CHARS) + { + if (!NILP (Vface_remapping_alist)) + { + struct frame *f = XFRAME (WINDOW_FRAME (w)); + int face_id = lookup_named_face (NULL, f, Qdefault, true); + struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); + if (face && face->font && face->font->height) + denom = face->font->height; + } + /* For performance, use canonical chars if no face remapping. */ + else + pixelwise = WINDOW_BODY_IN_CANONICAL_CHARS; + } + + if (pixelwise == WINDOW_BODY_IN_CANONICAL_CHARS) + denom = FRAME_LINE_HEIGHT (WINDOW_XFRAME (w)); + /* Don't return a negative value. */ - return max (pixelwise - ? height - : height / FRAME_LINE_HEIGHT (WINDOW_XFRAME (w)), - 0); + return max (height / denom, 0); } /* Return the number of columns/pixels of W's body. Don't count columns @@ -960,7 +1071,7 @@ window_body_height (struct window *w, bool pixelwise) fringes either. Round down to nearest integer when not working pixelwise. */ int -window_body_width (struct window *w, bool pixelwise) +window_body_width (struct window *w, enum window_body_unit pixelwise) { struct frame *f = XFRAME (WINDOW_FRAME (w)); @@ -977,48 +1088,106 @@ window_body_width (struct window *w, bool pixelwise) ? WINDOW_FRINGES_WIDTH (w) : 0)); + int denom = 1; + if (pixelwise == WINDOW_BODY_IN_REMAPPED_CHARS) + { + if (!NILP (Vface_remapping_alist)) + { + int face_id = lookup_named_face (NULL, f, Qdefault, true); + struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); + if (face && face->font) + { + if (face->font->average_width) + denom = face->font->average_width; + else if (face->font->space_width) + denom = face->font->space_width; + } + } + /* For performance, use canonical chars if no face remapping. */ + else + pixelwise = WINDOW_BODY_IN_CANONICAL_CHARS; + } + + if (pixelwise == WINDOW_BODY_IN_CANONICAL_CHARS) + denom = FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w)); + /* Don't return a negative value. */ - return max (pixelwise - ? width - : width / FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w)), - 0); + return max (width / denom, 0); +} + +DEFUN ("window-body-width", Fwindow_body_width, Swindow_body_width, 0, 2, 0, + doc: /* Return the width of WINDOW's text area. +WINDOW must be a live window and defaults to the selected one. The +return value does not include any vertical dividers, fringes or +marginal areas, or scroll bars. + +The optional argument PIXELWISE defines the units to use for the +width. If nil, return the largest integer smaller than WINDOW's pixel +width in units of the character width of WINDOW's frame. If PIXELWISE +is `remap' and the default face is remapped (see +`face-remapping-alist'), use the remapped face to determine the +character width. For any other non-nil value, return the width in +pixels. + +Note that the returned value includes the column reserved for the +continuation glyph. + +Also see `window-max-chars-per-line'. */) + (Lisp_Object window, Lisp_Object pixelwise) +{ + return (make_fixnum + (window_body_width (decode_live_window (window), + window_body_unit_from_symbol (pixelwise)))); } DEFUN ("window-body-height", Fwindow_body_height, Swindow_body_height, 0, 2, 0, doc: /* Return the height of WINDOW's text area. -WINDOW must be a live window and defaults to the selected one. Optional -argument PIXELWISE non-nil means return the height of WINDOW's text area -in pixels. The return value does not include the mode line or header -line or any horizontal divider. - -If PIXELWISE is nil, return the largest integer smaller than WINDOW's -pixel height divided by the character height of WINDOW's frame. This -means that if a line at the bottom of the text area is only partially -visible, that line is not counted. */) +WINDOW must be a live window and defaults to the selected one. The +return value does not include the mode line or header line or any +horizontal divider. + +The optional argument PIXELWISE defines the units to use for the +height. If nil, return the largest integer smaller than WINDOW's +pixel height in units of the character height of WINDOW's frame. If +PIXELWISE is `remap' and the default face is remapped (see +`face-remapping-alist'), use the remapped face to determine the +character height. For any other non-nil value, return the height in +pixels. */) (Lisp_Object window, Lisp_Object pixelwise) { - return make_number (window_body_height (decode_live_window (window), - !NILP (pixelwise))); + return (make_fixnum + (window_body_height (decode_live_window (window), + window_body_unit_from_symbol (pixelwise)))); } -DEFUN ("window-body-width", Fwindow_body_width, Swindow_body_width, 0, 2, 0, - doc: /* Return the width of WINDOW's text area. -WINDOW must be a live window and defaults to the selected one. Optional -argument PIXELWISE non-nil means return the width in pixels. The return -value does not include any vertical dividers, fringes or marginal areas, -or scroll bars. +DEFUN ("window-old-body-pixel-width", + Fwindow_old_body_pixel_width, + Swindow_old_body_pixel_width, 0, 1, 0, + doc: /* Return old width of WINDOW's text area in pixels. +WINDOW must be a live window and defaults to the selected one. -If PIXELWISE is nil, return the largest integer smaller than WINDOW's -pixel width divided by the character width of WINDOW's frame. This -means that if a column at the right of the text area is only partially -visible, that column is not counted. +The return value is the pixel width of WINDOW's text area after the +last time window change functions found WINDOW live on its frame. It +is zero if WINDOW was created after that. */) + (Lisp_Object window) +{ + return (make_fixnum + (decode_live_window (window)->old_body_pixel_width)); +} -Note that the returned value includes the column reserved for the -continuation glyph. */) - (Lisp_Object window, Lisp_Object pixelwise) +DEFUN ("window-old-body-pixel-height", + Fwindow_old_body_pixel_height, + Swindow_old_body_pixel_height, 0, 1, 0, + doc: /* Return old height of WINDOW's text area in pixels. +WINDOW must be a live window and defaults to the selected one. + +The return value is the pixel height of WINDOW's text area after the +last time window change functions found WINDOW live on its frame. It +is zero if WINDOW was created after that. */) + (Lisp_Object window) { - return make_number (window_body_width (decode_live_window (window), - !NILP (pixelwise))); + return (make_fixnum + (decode_live_window (window)->old_body_pixel_height)); } DEFUN ("window-mode-line-height", Fwindow_mode_line_height, @@ -1027,7 +1196,7 @@ DEFUN ("window-mode-line-height", Fwindow_mode_line_height, WINDOW must be a live window and defaults to the selected one. */) (Lisp_Object window) { - return (make_number (WINDOW_MODE_LINE_HEIGHT (decode_live_window (window)))); + return make_fixnum (WINDOW_MODE_LINE_HEIGHT (decode_live_window (window))); } DEFUN ("window-header-line-height", Fwindow_header_line_height, @@ -1036,7 +1205,16 @@ DEFUN ("window-header-line-height", Fwindow_header_line_height, WINDOW must be a live window and defaults to the selected one. */) (Lisp_Object window) { - return (make_number (WINDOW_HEADER_LINE_HEIGHT (decode_live_window (window)))); + return make_fixnum (WINDOW_HEADER_LINE_HEIGHT (decode_live_window (window))); +} + +DEFUN ("window-tab-line-height", Fwindow_tab_line_height, + Swindow_tab_line_height, 0, 1, 0, + doc: /* Return the height in pixels of WINDOW's tab-line. +WINDOW must be a live window and defaults to the selected one. */) + (Lisp_Object window) +{ + return make_fixnum (WINDOW_TAB_LINE_HEIGHT (decode_live_window (window))); } DEFUN ("window-right-divider-width", Fwindow_right_divider_width, @@ -1045,7 +1223,7 @@ DEFUN ("window-right-divider-width", Fwindow_right_divider_width, WINDOW must be a live window and defaults to the selected one. */) (Lisp_Object window) { - return (make_number (WINDOW_RIGHT_DIVIDER_WIDTH (decode_live_window (window)))); + return make_fixnum (WINDOW_RIGHT_DIVIDER_WIDTH (decode_live_window (window))); } DEFUN ("window-bottom-divider-width", Fwindow_bottom_divider_width, @@ -1054,7 +1232,7 @@ DEFUN ("window-bottom-divider-width", Fwindow_bottom_divider_width, WINDOW must be a live window and defaults to the selected one. */) (Lisp_Object window) { - return (make_number (WINDOW_BOTTOM_DIVIDER_WIDTH (decode_live_window (window)))); + return make_fixnum (WINDOW_BOTTOM_DIVIDER_WIDTH (decode_live_window (window))); } DEFUN ("window-scroll-bar-width", Fwindow_scroll_bar_width, @@ -1063,7 +1241,7 @@ DEFUN ("window-scroll-bar-width", Fwindow_scroll_bar_width, WINDOW must be a live window and defaults to the selected one. */) (Lisp_Object window) { - return (make_number (WINDOW_SCROLL_BAR_AREA_WIDTH (decode_live_window (window)))); + return make_fixnum (WINDOW_SCROLL_BAR_AREA_WIDTH (decode_live_window (window))); } DEFUN ("window-scroll-bar-height", Fwindow_scroll_bar_height, @@ -1072,7 +1250,7 @@ DEFUN ("window-scroll-bar-height", Fwindow_scroll_bar_height, WINDOW must be a live window and defaults to the selected one. */) (Lisp_Object window) { - return (make_number (WINDOW_SCROLL_BAR_AREA_HEIGHT (decode_live_window (window)))); + return make_fixnum (WINDOW_SCROLL_BAR_AREA_HEIGHT (decode_live_window (window))); } DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0, @@ -1080,7 +1258,7 @@ DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0, WINDOW must be a live window and defaults to the selected one. */) (Lisp_Object window) { - return make_number (decode_live_window (window)->hscroll); + return make_fixnum (decode_live_window (window)->hscroll); } /* Set W's horizontal scroll amount to HSCROLL clipped to a reasonable @@ -1099,12 +1277,15 @@ set_window_hscroll (struct window *w, EMACS_INT hscroll) /* Prevent redisplay shortcuts when changing the hscroll. */ if (w->hscroll != new_hscroll) - XBUFFER (w->contents)->prevent_redisplay_optimizations_p = true; + { + XBUFFER (w->contents)->prevent_redisplay_optimizations_p = true; + wset_redisplay (w); + } w->hscroll = new_hscroll; w->suspend_auto_hscroll = true; - return make_number (new_hscroll); + return make_fixnum (new_hscroll); } DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0, @@ -1113,37 +1294,12 @@ WINDOW must be a live window and defaults to the selected one. Clip the number to a reasonable value if out of range. Return the new number. NCOL should be zero or positive. -Note that if `automatic-hscrolling' is non-nil, you cannot scroll the +Note that if `auto-hscroll-mode' is non-nil, you cannot scroll the window so that the location of point moves off-window. */) (Lisp_Object window, Lisp_Object ncol) { - CHECK_NUMBER (ncol); - return set_window_hscroll (decode_live_window (window), XINT (ncol)); -} - -DEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger, - Swindow_redisplay_end_trigger, 0, 1, 0, - doc: /* Return WINDOW's redisplay end trigger value. -WINDOW must be a live window and defaults to the selected one. -See `set-window-redisplay-end-trigger' for more information. */) - (Lisp_Object window) -{ - return decode_live_window (window)->redisplay_end_trigger; -} - -DEFUN ("set-window-redisplay-end-trigger", Fset_window_redisplay_end_trigger, - Sset_window_redisplay_end_trigger, 2, 2, 0, - doc: /* Set WINDOW's redisplay end trigger value to VALUE. -WINDOW must be a live window and defaults to the selected one. VALUE -should be a buffer position (typically a marker) or nil. If it is a -buffer position, then if redisplay in WINDOW reaches a position beyond -VALUE, the functions in `redisplay-end-trigger-functions' are called -with two arguments: WINDOW, and the end trigger value. Afterwards the -end-trigger value is reset to nil. */) - (register Lisp_Object window, Lisp_Object value) -{ - wset_redisplay_end_trigger (decode_live_window (window), value); - return value; + CHECK_FIXNUM (ncol); + return set_window_hscroll (decode_live_window (window), XFIXNUM (ncol)); } /* Test if the character at column X, row Y is within window W. @@ -1157,7 +1313,8 @@ end-trigger value is reset to nil. */) if it is on the border between the window and its right sibling, return ON_VERTICAL_BORDER; if it is on a scroll bar, return ON_SCROLL_BAR; - if it is on the window's top line, return ON_HEADER_LINE; + if it is on the window's top line, return ON_TAB_LINE; + if it is on the window's header line, return ON_HEADER_LINE; if it is in left or right fringe of the window, return ON_LEFT_FRINGE or ON_RIGHT_FRINGE; if it is in the marginal area to the left/right of the window, @@ -1207,15 +1364,21 @@ coordinates_in_window (register struct window *w, int x, int y) - CURRENT_MODE_LINE_HEIGHT (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w)))) return ON_HORIZONTAL_SCROLL_BAR; - /* On the mode or header line? */ + /* On the mode or header/tab line? */ else if ((window_wants_mode_line (w) && y >= (bottom_y - CURRENT_MODE_LINE_HEIGHT (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w)) && y <= bottom_y - WINDOW_BOTTOM_DIVIDER_WIDTH (w) && (part = ON_MODE_LINE)) + || (window_wants_tab_line (w) + && y < top_y + CURRENT_TAB_LINE_HEIGHT (w) + && (part = ON_TAB_LINE)) || (window_wants_header_line (w) && y < top_y + CURRENT_HEADER_LINE_HEIGHT (w) + + (window_wants_tab_line (w) + ? CURRENT_TAB_LINE_HEIGHT (w) + : 0) && (part = ON_HEADER_LINE))) { /* If it's under/over the scroll bar portion of the mode/header @@ -1315,6 +1478,7 @@ window_relative_x_coord (struct window *w, enum window_part part, int x) case ON_TEXT: return x - window_box_left (w, TEXT_AREA); + case ON_TAB_LINE: case ON_HEADER_LINE: case ON_MODE_LINE: case ON_LEFT_FRINGE: @@ -1365,6 +1529,7 @@ If they are in the bottom divider of WINDOW, `bottom-divider' is returned. If they are in the right divider of WINDOW, `right-divider' is returned. If they are in the mode line of WINDOW, `mode-line' is returned. If they are in the header line of WINDOW, `header-line' is returned. +If they are in the tab line of WINDOW, `tab-line' is returned. If they are in the left fringe of WINDOW, `left-fringe' is returned. If they are in the right fringe of WINDOW, `right-fringe' is returned. If they are on the border between WINDOW and its right sibling, @@ -1383,8 +1548,8 @@ If they are in the windows's left or right marginal areas, `left-margin'\n\ CHECK_CONS (coordinates); lx = Fcar (coordinates); ly = Fcdr (coordinates); - CHECK_NUMBER_OR_FLOAT (lx); - CHECK_NUMBER_OR_FLOAT (ly); + CHECK_NUMBER (lx); + CHECK_NUMBER (ly); x = FRAME_PIXEL_X_FROM_CANON_X (f, lx) + FRAME_INTERNAL_BORDER_WIDTH (f); y = FRAME_PIXEL_Y_FROM_CANON_Y (f, ly) + FRAME_INTERNAL_BORDER_WIDTH (f); @@ -1410,6 +1575,9 @@ If they are in the windows's left or right marginal areas, `left-margin'\n\ case ON_HEADER_LINE: return Qheader_line; + case ON_TAB_LINE: + return Qtab_line; + case ON_LEFT_FRINGE: return Qleft_fringe; @@ -1493,7 +1661,7 @@ check_window_containing (struct window *w, void *user_data) Lisp_Object window_from_coordinates (struct frame *f, int x, int y, - enum window_part *part, bool tool_bar_p) + enum window_part *part, bool tab_bar_p, bool tool_bar_p) { Lisp_Object window; struct check_window_data cw; @@ -1506,7 +1674,22 @@ window_from_coordinates (struct frame *f, int x, int y, cw.window = &window, cw.x = x, cw.y = y; cw.part = part; foreach_window (f, check_window_containing, &cw); -#if defined (HAVE_WINDOW_SYSTEM) && ! defined (USE_GTK) && ! defined (HAVE_NS) +#if defined (HAVE_WINDOW_SYSTEM) + /* If not found above, see if it's in the tab bar window, if a tab + bar exists. */ + if (NILP (window) + && tab_bar_p + && WINDOWP (f->tab_bar_window) + && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)) > 0 + && (coordinates_in_window (XWINDOW (f->tab_bar_window), x, y) + != ON_NOTHING)) + { + *part = ON_TEXT; + window = f->tab_bar_window; + } +#endif + +#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) /* If not found above, see if it's in the tool bar window, if a tool bar exists. */ if (NILP (window) @@ -1533,16 +1716,23 @@ column 0. */) { struct frame *f = decode_live_frame (frame); - /* Check that arguments are integers or floats. */ - CHECK_NUMBER_OR_FLOAT (x); - CHECK_NUMBER_OR_FLOAT (y); + CHECK_NUMBER (x); + CHECK_NUMBER (y); return window_from_coordinates (f, (FRAME_PIXEL_X_FROM_CANON_X (f, x) + FRAME_INTERNAL_BORDER_WIDTH (f)), (FRAME_PIXEL_Y_FROM_CANON_Y (f, y) + FRAME_INTERNAL_BORDER_WIDTH (f)), - 0, false); + 0, false, false); +} + +ptrdiff_t +window_point (struct window *w) +{ + return (w == XWINDOW (selected_window) + ? BUF_PT (XBUFFER (w->contents)) + : XMARKER (w->pointm)->charpos); } DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0, @@ -1558,12 +1748,7 @@ correct to return the top-level value of `point', outside of any `save-excursion' forms. But that is hard to define. */) (Lisp_Object window) { - register struct window *w = decode_live_window (window); - - if (w == XWINDOW (selected_window)) - return make_number (BUF_PT (XBUFFER (w->contents))); - else - return Fmarker_position (w->pointm); + return make_fixnum (window_point (decode_live_window (window))); } DEFUN ("window-old-point", Fwindow_old_point, Swindow_old_point, 0, 1, 0, @@ -1596,14 +1781,16 @@ have been if redisplay had finished, do this: DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0, doc: /* Return position at which display currently ends in WINDOW. -WINDOW must be a live window and defaults to the selected one. -This is updated by redisplay, when it runs to completion. -Simply changing the buffer text or setting `window-start' -does not update this value. +This is the position after the final character in WINDOW. + +WINDOW must be a live window and defaults to the selected one. This +is updated by redisplay, when it runs to completion. Simply changing +the buffer text or setting `window-start' does not update this value. + Return nil if there is no recorded value. (This can happen if the -last redisplay of WINDOW was preempted, and did not finish.) -If UPDATE is non-nil, compute the up-to-date position -if it isn't already recorded. */) +last redisplay of WINDOW was preempted, and did not finish.) If +UPDATE is non-nil, compute the up-to-date position if it isn't already +recorded. */) (Lisp_Object window, Lisp_Object update) { Lisp_Object value; @@ -1652,7 +1839,7 @@ if it isn't already recorded. */) move_it_vertically (&it, window_box_height (w)); if (it.current_y < it.last_visible_y) move_it_past_eol (&it); - value = make_number (IT_CHARPOS (it)); + value = make_fixnum (IT_CHARPOS (it)); bidi_unshelve_cache (itdata, false); if (old_buffer) @@ -1683,7 +1870,7 @@ Return POS. */) struct buffer *old_buffer = current_buffer; /* ... but here we want to catch type error before buffer change. */ - CHECK_NUMBER_COERCE_MARKER (pos); + CHECK_FIXNUM_COERCE_MARKER (pos); set_buffer_internal (XBUFFER (w->contents)); Fgoto_char (pos); set_buffer_internal (old_buffer); @@ -1703,8 +1890,24 @@ Return POS. */) DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0, doc: /* Make display in WINDOW start at position POS in WINDOW's buffer. WINDOW must be a live window and defaults to the selected one. Return -POS. Optional third arg NOFORCE non-nil inhibits next redisplay from -overriding motion of point in order to display at this exact start. */) +POS. + +Optional third arg NOFORCE non-nil prevents next redisplay from +moving point if displaying the window at POS makes point invisible; +redisplay will then choose the WINDOW's start position by itself in +that case, i.e. it will disregard POS if adhering to it will make +point not visible in the window. + +For reliable setting of WINDOW start position, make sure point is +at a position that will be visible when that start is in effect, +otherwise there's a chance POS will be disregarded, e.g., if point +winds up in a partially-visible line. + +The setting of the WINDOW's start position takes effect during the +next redisplay cycle, not immediately. If NOFORCE is nil or +omitted, forcing the display of WINDOW to start at POS cancels +any setting of WINDOW's vertical scroll (\"vscroll\") amount +set by `set-window-vscroll' and by scrolling functions. */) (Lisp_Object window, Lisp_Object pos, Lisp_Object noforce) { register struct window *w = decode_live_window (window); @@ -1762,10 +1965,7 @@ POS, ROWH is the visible height of that row, and VPOS is the row number if (EQ (pos, Qt)) posint = -1; else if (!NILP (pos)) - { - CHECK_NUMBER_COERCE_MARKER (pos); - posint = XINT (pos); - } + posint = fix_position (pos); else if (w == XWINDOW (selected_window)) posint = PT; else @@ -1789,8 +1989,8 @@ POS, ROWH is the visible height of that row, and VPOS is the row number Lisp_Object part = Qnil; if (!fully_p) part = list4i (rtop, rbot, rowh, vpos); - in_window = Fcons (make_number (x), - Fcons (make_number (y), part)); + in_window = Fcons (make_fixnum (x), + Fcons (make_fixnum (y), part)); } return in_window; @@ -1849,6 +2049,14 @@ Return nil if window display is not up-to-date. In that case, use goto found_row; } + if (EQ (line, Qtab_line)) + { + if (!window_wants_tab_line (w)) + return Qnil; + row = MATRIX_TAB_LINE_ROW (w->current_matrix); + return row->enabled_p ? list4i (row->height, 0, 0, 0) : Qnil; + } + if (EQ (line, Qheader_line)) { if (!window_wants_header_line (w)) @@ -1863,14 +2071,15 @@ Return nil if window display is not up-to-date. In that case, use return (row->enabled_p ? list4i (row->height, 0, /* not accurate */ - (WINDOW_HEADER_LINE_HEIGHT (w) + (WINDOW_TAB_LINE_HEIGHT (w) + + WINDOW_HEADER_LINE_HEIGHT (w) + window_text_bottom_y (w)), 0) : Qnil); } - CHECK_NUMBER (line); - n = XINT (line); + CHECK_FIXNUM (line); + n = XFIXNUM (line); row = MATRIX_FIRST_TEXT_ROW (w->current_matrix); end_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w); @@ -1948,9 +2157,11 @@ though when run from an idle timer with a delay of zero seconds. */) struct glyph_row *row, *end_row; int max_y = NILP (body) ? WINDOW_PIXEL_HEIGHT (w) : window_text_bottom_y (w); Lisp_Object rows = Qnil; - int window_width = NILP (body) ? w->pixel_width : window_body_width (w, true); + int window_width = NILP (body) + ? w->pixel_width : window_body_width (w, WINDOW_BODY_IN_PIXELS); + int tab_line_height = WINDOW_TAB_LINE_HEIGHT (w); int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); - int subtract = NILP (body) ? 0 : header_line_height; + int subtract = NILP (body) ? 0 : (tab_line_height + header_line_height); bool invert = !NILP (inverse); bool left_flag = !NILP (left); @@ -1968,30 +2179,20 @@ though when run from an idle timer with a delay of zero seconds. */) || window_outdated (w)) return Qnil; - if (NILP (first)) - row = (NILP (body) - ? MATRIX_ROW (w->current_matrix, 0) - : MATRIX_FIRST_TEXT_ROW (w->current_matrix)); - else if (NUMBERP (first)) - { - CHECK_RANGED_INTEGER (first, 0, w->current_matrix->nrows); - row = MATRIX_ROW (w->current_matrix, XINT (first)); - } - else - error ("Invalid specification of first line"); - - if (NILP (last)) - - end_row = (NILP (body) - ? MATRIX_ROW (w->current_matrix, w->current_matrix->nrows) - : MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w)); - else if (NUMBERP (last)) - { - CHECK_RANGED_INTEGER (last, 0, w->current_matrix->nrows); - end_row = MATRIX_ROW (w->current_matrix, XINT (last)); - } - else - error ("Invalid specification of last line"); + row = (!NILP (first) + ? MATRIX_ROW (w->current_matrix, + check_integer_range (first, 0, + w->current_matrix->nrows)) + : NILP (body) + ? MATRIX_ROW (w->current_matrix, 0) + : MATRIX_FIRST_TEXT_ROW (w->current_matrix)); + end_row = (!NILP (last) + ? MATRIX_ROW (w->current_matrix, + check_integer_range (last, 0, + w->current_matrix->nrows)) + : NILP (body) + ? MATRIX_ROW (w->current_matrix, w->current_matrix->nrows) + : MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w)); while (row <= end_row && row->enabled_p && row->y + row->height < max_y) @@ -2001,19 +2202,19 @@ though when run from an idle timer with a delay of zero seconds. */) { struct glyph *glyph = row->glyphs[TEXT_AREA]; - rows = Fcons (Fcons (make_number + rows = Fcons (Fcons (make_fixnum (invert ? glyph->pixel_width : window_width - glyph->pixel_width), - make_number (row->y + row->height - subtract)), + make_fixnum (row->y + row->height - subtract)), rows); } else - rows = Fcons (Fcons (make_number + rows = Fcons (Fcons (make_fixnum (invert ? window_width - row->pixel_width : row->pixel_width), - make_number (row->y + row->height - subtract)), + make_fixnum (row->y + row->height - subtract)), rows); row++; } @@ -2129,7 +2330,7 @@ return value is a list of elements of the form (PARAMETER . VALUE). */) Lisp_Object window_parameter (struct window *w, Lisp_Object parameter) { - Lisp_Object result = Fassq (parameter, w->window_parameters); + Lisp_Object result = assq_no_quit (parameter, w->window_parameters); return CDR_SAFE (result); } @@ -2425,8 +2626,13 @@ window_list (void) if (!CONSP (Vwindow_list)) { Lisp_Object tail, frame; + specpdl_ref count = SPECPDL_INDEX (); Vwindow_list = Qnil; + /* Don't allow quitting in Fnconc. Otherwise we might end up + with a too short Vwindow_list and Fkill_buffer not being able + to replace a buffer in all windows showing it (Bug#47244). */ + specbind (Qinhibit_quit, Qt); FOR_EACH_FRAME (tail, frame) { Lisp_Object arglist = Qnil; @@ -2436,8 +2642,10 @@ window_list (void) have to reverse this list at the end. */ foreach_window (XFRAME (frame), add_window_to_list, &arglist); arglist = Fnreverse (arglist); - Vwindow_list = CALLN (Fnconc, Vwindow_list, arglist); + Vwindow_list = nconc2 (Vwindow_list, arglist); } + + unbind_to (count, Qnil); } return Vwindow_list; @@ -2472,7 +2680,7 @@ candidate_window_p (Lisp_Object window, Lisp_Object owindow, candidate_p = false; else if (MINI_WINDOW_P (w) && (EQ (minibuf, Qlambda) - || (WINDOWP (minibuf) && !EQ (minibuf, window)))) + || (WINDOW_LIVE_P (minibuf) && !EQ (minibuf, window)))) { /* If MINIBUF is `lambda' don't consider any mini-windows. If it is a window, consider only that one. */ @@ -2492,7 +2700,7 @@ candidate_window_p (Lisp_Object window, Lisp_Object owindow, == FRAME_TERMINAL (XFRAME (selected_frame))); } - else if (INTEGERP (all_frames) && XINT (all_frames) == 0) + else if (FIXNUMP (all_frames) && XFIXNUM (all_frames) == 0) { candidate_p = (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f) #ifdef HAVE_X_WINDOWS @@ -2513,8 +2721,11 @@ candidate_window_p (Lisp_Object window, Lisp_Object owindow, /* To qualify as candidate, it's not sufficient for WINDOW's frame to just share the minibuffer window - it must be active as well (see Bug#24500). */ - candidate_p = (EQ (XWINDOW (all_frames)->frame, w->frame) - || EQ (XWINDOW (all_frames)->frame, FRAME_FOCUS_FRAME (f))); + candidate_p = ((EQ (XWINDOW (all_frames)->frame, w->frame) + || (EQ (f->minibuffer_window, all_frames) + && EQ (XWINDOW (all_frames)->frame, FRAME_FOCUS_FRAME (f)))) + && (EQ (minibuf, Qt) + || !is_minibuffer (0, XWINDOW (all_frames)->contents))); else if (FRAMEP (all_frames)) candidate_p = EQ (all_frames, w->frame); @@ -2530,12 +2741,15 @@ static void decode_next_window_args (Lisp_Object *window, Lisp_Object *minibuf, Lisp_Object *all_frames) { struct window *w = decode_live_window (*window); + Lisp_Object miniwin = XFRAME (w->frame)->minibuffer_window; XSETWINDOW (*window, w); - /* MINIBUF nil may or may not include minibuffers. Decide if it - does. */ - if (NILP (*minibuf)) - *minibuf = minibuf_level ? minibuf_window : Qlambda; + /* MINIBUF nil may or may not include minibuffer windows. Decide if + it does. But first make sure that this frame's minibuffer window + is live (Bug#47207). */ + if (WINDOW_LIVE_P (miniwin) && NILP (*minibuf)) + *minibuf = (this_minibuffer_depth (XWINDOW (miniwin)->contents) + ? miniwin : Qlambda); else if (!EQ (*minibuf, Qt)) *minibuf = Qlambda; @@ -2546,12 +2760,13 @@ decode_next_window_args (Lisp_Object *window, Lisp_Object *minibuf, Lisp_Object /* ALL_FRAMES nil doesn't specify which frames to include. */ if (NILP (*all_frames)) *all_frames - = (!EQ (*minibuf, Qlambda) - ? FRAME_MINIBUF_WINDOW (XFRAME (w->frame)) - : Qnil); + /* Once more make sure that this frame's minibuffer window is live + before including it (Bug#47207). */ + = ((WINDOW_LIVE_P (miniwin) && !EQ (*minibuf, Qlambda)) + ? miniwin : Qnil); else if (EQ (*all_frames, Qvisible)) ; - else if (EQ (*all_frames, make_number (0))) + else if (BASE_EQ (*all_frames, make_fixnum (0))) ; else if (FRAMEP (*all_frames)) ; @@ -2569,6 +2784,8 @@ static Lisp_Object next_window (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames, bool next_p) { + specpdl_ref count = SPECPDL_INDEX (); + decode_next_window_args (&window, &minibuf, &all_frames); /* If ALL_FRAMES is a frame, and WINDOW isn't on that frame, just @@ -2577,6 +2794,9 @@ next_window (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames, && !EQ (all_frames, XWINDOW (window)->frame)) return Fframe_first_window (all_frames); + /* Don't allow quitting in Fmemq. */ + specbind (Qinhibit_quit, Qt); + if (next_p) { Lisp_Object list; @@ -2626,6 +2846,8 @@ next_window (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames, window = candidate; } + unbind_to (count, Qnil); + return window; } @@ -2716,10 +2938,14 @@ static Lisp_Object window_list_1 (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames) { Lisp_Object tail, list, rest; + specpdl_ref count = SPECPDL_INDEX (); decode_next_window_args (&window, &minibuf, &all_frames); list = Qnil; + /* Don't allow quitting in Fmemq and Fnconc. */ + specbind (Qinhibit_quit, Qt); + for (tail = window_list (); CONSP (tail); tail = XCDR (tail)) if (candidate_window_p (XCAR (tail), window, minibuf, all_frames)) list = Fcons (XCAR (tail), list); @@ -2734,6 +2960,9 @@ window_list_1 (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames) XSETCDR (tail, Qnil); list = nconc2 (rest, list); } + + unbind_to (count, Qnil); + return list; } @@ -2834,7 +3063,7 @@ window_loop (enum window_loop type, Lisp_Object obj, bool mini, if (f) frame_arg = Qlambda; - else if (EQ (frames, make_number (0))) + else if (BASE_EQ (frames, make_fixnum (0))) frame_arg = frames; else if (EQ (frames, Qvisible)) frame_arg = frames; @@ -3002,14 +3231,6 @@ resize_root_window (Lisp_Object window, Lisp_Object delta, horizontal, ignore, pixelwise); } -void -sanitize_window_sizes (Lisp_Object horizontal) -{ - /* Don't burp in temacs -nw before window.el is loaded. */ - if (!NILP (Fsymbol_function (Qwindow__sanitize_window_sizes))) - call1 (Qwindow__sanitize_window_sizes, horizontal); -} - static Lisp_Object window_pixel_to_total (Lisp_Object frame, Lisp_Object horizontal) @@ -3035,8 +3256,10 @@ function in a program gives strange scrolling, make sure the window-start value is reasonable when this function is called. */) (Lisp_Object window, Lisp_Object root) { - struct window *w, *r, *s; - struct frame *f; + struct window *w = decode_valid_window (window); + struct window *r, *s; + Lisp_Object frame = w->frame; + struct frame *f = XFRAME (frame); Lisp_Object sibling, pwindow, delta; Lisp_Object swindow UNINIT; ptrdiff_t startpos UNINIT, startbyte UNINIT; @@ -3044,9 +3267,7 @@ window-start value is reasonable when this function is called. */) int new_top; bool resize_failed = false; - w = decode_valid_window (window); XSETWINDOW (window, w); - f = XFRAME (w->frame); if (NILP (root)) /* ROOT is the frame's root window. */ @@ -3086,9 +3307,12 @@ window-start value is reasonable when this function is called. */) /* Make sure WINDOW is the frame's selected window. */ if (!EQ (window, FRAME_SELECTED_WINDOW (f))) { - if (EQ (selected_frame, w->frame)) + if (EQ (selected_frame, frame)) Fselect_window (window, Qnil); else + /* Do not clear f->select_mini_window_flag here. If the + last selected window on F was an active minibuffer, we + want to return to it on a later Fselect_frame. */ fset_selected_window (f, window); } } @@ -3116,7 +3340,7 @@ window-start value is reasonable when this function is called. */) if (!EQ (swindow, FRAME_SELECTED_WINDOW (f))) { - if (EQ (selected_frame, w->frame)) + if (EQ (selected_frame, frame)) Fselect_window (swindow, Qnil); else fset_selected_window (f, swindow); @@ -3151,18 +3375,12 @@ window-start value is reasonable when this function is called. */) w->top_line = r->top_line; resize_root_window (window, delta, Qnil, Qnil, Qt); if (window_resize_check (w, false)) - { - window_resize_apply (w, false); - window_pixel_to_total (w->frame, Qnil); - } + window_resize_apply (w, false); else { resize_root_window (window, delta, Qnil, Qt, Qt); if (window_resize_check (w, false)) - { - window_resize_apply (w, false); - window_pixel_to_total (w->frame, Qnil); - } + window_resize_apply (w, false); else resize_failed = true; } @@ -3175,18 +3393,12 @@ window-start value is reasonable when this function is called. */) XSETINT (delta, r->pixel_width - w->pixel_width); resize_root_window (window, delta, Qt, Qnil, Qt); if (window_resize_check (w, true)) - { - window_resize_apply (w, true); - window_pixel_to_total (w->frame, Qt); - } + window_resize_apply (w, true); else { resize_root_window (window, delta, Qt, Qt, Qt); if (window_resize_check (w, true)) - { - window_resize_apply (w, true); - window_pixel_to_total (w->frame, Qt); - } + window_resize_apply (w, true); else resize_failed = true; } @@ -3228,6 +3440,12 @@ window-start value is reasonable when this function is called. */) } replace_window (root, window, true); + /* Assign new total sizes to all windows on FRAME. We can't do that + _before_ WINDOW replaces ROOT since 'window--pixel-to-total' works + on the whole frame and thus would work on the frame's old window + configuration (Bug#51007). */ + window_pixel_to_total (frame, Qnil); + window_pixel_to_total (frame, Qt); /* This must become SWINDOW anyway ....... */ if (BUFFERP (w->contents) && !resize_failed) @@ -3265,7 +3483,7 @@ window-start value is reasonable when this function is called. */) adjust_frame_glyphs (f); unblock_input (); - run_window_configuration_change_hook (f); + FRAME_WINDOW_CHANGE (f) = true; return Qnil; } @@ -3319,17 +3537,26 @@ select_frame_norecord (Lisp_Object frame) Fselect_frame (frame, Qt); } +/** + * run_window_configuration_change_hook: + * + * Run any functions on 'window-configuration-change-hook' for the + * frame specified by F. The buffer-local values are run with the + * window showing the buffer selected. The default value is run with + * the frame specified by F selected. All functions are called with + * the selected window's buffer current. + */ static void run_window_configuration_change_hook (struct frame *f) { - ptrdiff_t count = SPECPDL_INDEX (); + specpdl_ref count = SPECPDL_INDEX (); Lisp_Object frame, global_wcch = Fdefault_value (Qwindow_configuration_change_hook); XSETFRAME (frame, f); if (NILP (Vrun_hooks) - || !(f->can_x_set_window_size) - || !(f->after_make_frame)) + || !f->can_set_window_size + || !f->after_make_frame) return; /* Use the right buffer. Matters when running the local hooks. */ @@ -3355,7 +3582,7 @@ run_window_configuration_change_hook (struct frame *f) if (!NILP (Flocal_variable_p (Qwindow_configuration_change_hook, buffer))) { - ptrdiff_t inner_count = SPECPDL_INDEX (); + specpdl_ref inner_count = SPECPDL_INDEX (); record_unwind_protect (select_window_norecord, selected_window); select_window_norecord (window); run_funs (Fbuffer_local_value (Qwindow_configuration_change_hook, @@ -3372,7 +3599,10 @@ run_window_configuration_change_hook (struct frame *f) DEFUN ("run-window-configuration-change-hook", Frun_window_configuration_change_hook, Srun_window_configuration_change_hook, 0, 1, 0, doc: /* Run `window-configuration-change-hook' for FRAME. -If FRAME is omitted or nil, it defaults to the selected frame. */) +If FRAME is omitted or nil, it defaults to the selected frame. + +This function should not be needed any more and will be therefore +considered obsolete. */) (Lisp_Object frame) { run_window_configuration_change_hook (decode_live_frame (frame)); @@ -3382,93 +3612,441 @@ If FRAME is omitted or nil, it defaults to the selected frame. */) DEFUN ("run-window-scroll-functions", Frun_window_scroll_functions, Srun_window_scroll_functions, 0, 1, 0, doc: /* Run `window-scroll-functions' for WINDOW. -If WINDOW is omitted or nil, it defaults to the selected window. */) +If WINDOW is omitted or nil, it defaults to the selected window. + +This function is called by `split-window' for the new window, after it +has established the size of the new window. */) (Lisp_Object window) { - if (! NILP (Vwindow_scroll_functions)) + struct window *w = decode_live_window (window); + specpdl_ref count = SPECPDL_INDEX (); + + record_unwind_current_buffer (); + Fset_buffer (w->contents); + if (!NILP (Vwindow_scroll_functions)) run_hook_with_args_2 (Qwindow_scroll_functions, window, - Fmarker_position (decode_live_window (window)->start)); + Fmarker_position (w->start)); + unbind_to (count, Qnil); + 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. */ +/** + * window_sub_list: + * + * Return list of live windows constructed by traversing any window + * sub-tree rooted at WINDOW in preorder followed by right siblings of + * WINDOW. Called from outside with second argument WINDOWS nil. The + * returned list is in reverse order. + */ +static Lisp_Object +window_sub_list (Lisp_Object window, Lisp_Object windows) +{ -static bool -window_size_changed (struct window *w) + struct window *w = XWINDOW (window); + + while (w) + { + if (WINDOW_INTERNAL_P (w)) + windows = window_sub_list (w->contents, windows); + else + windows = Fcons (window, windows); + + window = w->next; + w = NILP (window) ? 0 : XWINDOW (window); + } + + return windows; +} + + +/** + * window_change_record_windows: + * + * Record changes for all live windows found by traversing any window + * sub-tree rooted at WINDOW in preorder followed by any right + * siblings of WINDOW. This sets the old buffer, old pixel and old + * body pixel sizes of each live window found to the respective + * current values. It also sets the change stamp of each window found + * to STAMP. Return the number of live windows found. + * + * When not called by itself recursively, WINDOW is its frame's root + * window, STAMP is the current change stamp of WINDOW's frame and + * NUMBER is 0. + */ +static ptrdiff_t +window_change_record_windows (Lisp_Object window, int stamp, ptrdiff_t number) { - if (w->pixel_width != w->pixel_width_before_size_change - || w->pixel_height != w->pixel_height_before_size_change) - return true; + struct window *w = XWINDOW (window); - if (WINDOW_INTERNAL_P (w)) + while (w) { - w = XWINDOW (w->contents); - while (w) + if (WINDOW_INTERNAL_P (w)) + number = window_change_record_windows (w->contents, stamp, number); + else { - if (window_size_changed (w)) - return true; - - w = NILP (w->next) ? 0 : XWINDOW (w->next); + number += 1; + w->change_stamp = stamp; + wset_old_buffer (w, w->contents); + w->old_pixel_width = w->pixel_width; + w->old_pixel_height = w->pixel_height; + w->old_body_pixel_width + = window_body_width (w, WINDOW_BODY_IN_PIXELS); + w->old_body_pixel_height + = window_body_height (w, WINDOW_BODY_IN_PIXELS); } + + w = NILP (w->next) ? 0 : XWINDOW (w->next); } - return false; + return number; } -/* Set before size change pixel sizes of windows in tree rooted at W to - their present pixel sizes. */ +/** + * window_change_record: + * + * For each frame that has recorded changes, record its selected + * window, update Fchange stamp, record the states of all its live + * windows via window_change_record_windows and reset its + * window_change and window_state_change flags. + * + * Record selected window in old_selected_window and selected frame in + * old_selected_frame. + */ static void -window_set_before_size_change_sizes (struct window *w) +window_change_record (void) { - w->pixel_width_before_size_change = w->pixel_width; - w->pixel_height_before_size_change = w->pixel_height; - - if (WINDOW_INTERNAL_P (w)) + if (window_change_record_frames) { - w = XWINDOW (w->contents); - while (w) + Lisp_Object tail, frame; + + FOR_EACH_FRAME (tail, frame) { - window_set_before_size_change_sizes (w); - w = NILP (w->next) ? 0 : XWINDOW (w->next); + struct frame *f = XFRAME (frame); + + /* Record FRAME's selected window. */ + fset_old_selected_window (f, FRAME_SELECTED_WINDOW (f)); + + /* Bump up FRAME's change stamp. If this wraps, make it 1 to avoid + that a new window (whose change stamp is always set to 0) gets + reported as "existing before". */ + f->change_stamp += 1; + if (f->change_stamp == 0) + f->change_stamp = 1; + + /* Bump up the change stamps of all live windows on this frame so + the next call of this function can tell whether any of them + "existed before" and record state for each of these windows. */ + f->number_of_windows + = window_change_record_windows (f->root_window, f->change_stamp, 0); + + /* Reset our flags. */ + FRAME_WINDOW_CHANGE (f) = false; + FRAME_WINDOW_STATE_CHANGE (f) = false; } } + + /* Strictly spoken we don't need old_selected_window at all - its + value is the old selected window of old_selected_frame. */ + old_selected_window = selected_window; + old_selected_frame = selected_frame; } -void -run_window_size_change_functions (Lisp_Object frame) +/** + * run_window_change_functions_1: + * + * Run window change functions specified by SYMBOL with argument + * WINDOW_OR_FRAME. If BUFFER is nil, WINDOW_OR_FRAME specifies a + * frame. In this case, run the default value of SYMBOL. Otherwise, + * WINDOW_OR_FRAME denotes a window showing BUFFER. In this case, run + * the buffer local value of SYMBOL in BUFFER, if any. + */ +static void +run_window_change_functions_1 (Lisp_Object symbol, Lisp_Object buffer, + Lisp_Object window_or_frame) { - struct frame *f = XFRAME (frame); - struct window *r = XWINDOW (FRAME_ROOT_WINDOW (f)); - Lisp_Object functions = Vwindow_size_change_functions; + Lisp_Object funs = Qnil; - if (FRAME_WINDOW_CONFIGURATION_CHANGED (f) - /* Here we implicitly exclude the possibility that the height of - FRAME and its minibuffer window both change leaving the height - of FRAME's root window alone. */ - || window_size_changed (r)) + if (NILP (buffer)) + funs = Fdefault_value (symbol); + else if (!NILP (Fassoc (symbol, BVAR (XBUFFER (buffer), local_var_alist), + Qnil))) + /* Don't run global value buffer-locally. */ + funs = buffer_local_value (symbol, buffer); + + while (CONSP (funs)) { - while (CONSP (functions)) + if (!EQ (XCAR (funs), Qt) + && (NILP (buffer) + ? FRAME_LIVE_P (XFRAME (window_or_frame)) + : WINDOW_LIVE_P (window_or_frame))) { - if (!EQ (XCAR (functions), Qt)) - safe_call1 (XCAR (functions), frame); - functions = XCDR (functions); + /* Any function called here may change the state of any + frame. Make sure to record changes for each live frame + in window_change_record later. */ + window_change_record_frames = true; + safe_call1 (XCAR (funs), window_or_frame); } - window_set_before_size_change_sizes (r); + funs = XCDR (funs); + } +} + + +/** + * run_window_change_functions: + * + * Run window change functions for each live frame. This function + * must be called from a "safe" position in redisplay_internal. + * + * Do not run any functions for a frame whose window_change flag is + * nil, where no window selection happened and whose window state + * change flag was not set since the last time this function was + * called. Never run any functions for tooltip frames. + * + * The change functions run are, in this order: + * + * 'window-buffer-change-functions' which are run for a window that + * changed its buffer or that was not shown the last time window + * change functions were run. The default value is also run when a + * window was deleted since the last time window change functions were + * run. + * + * `window-size-change-functions' run for a window that changed its + * body or total size, a window that changed its buffer or a window + * that was not shown the last time window change functions were run. + * + * `window-selected-change-functions' run for a window that was + * (de-)selected since the last time window change functions were run. + * + * `window-state-change-functions' run for a window for which any of + * the above three changes occurred. + * + * A buffer-local value of these functions is run if and only if the + * window for which the functions are run currently shows the buffer. + * Each call gets one argument - the window showing the buffer. This + * means that the buffer-local value of these functions may be called + * as many times as the buffer is shown on the frame. + * + * The default values of these functions are called only after all + * buffer-local values for all of these functions have been run. Each + * such call receives one argument - the frame for which a change + * occurred. Functions on `window-state-change-functions' are run + * also if the corresponding frame's window state change flag has been + * set. + * + * After the four change functions cited above have been run in the + * indicated way, functions on 'window-configuration-change-hook' are + * run. A buffer-local value is run if a window shows that buffer and + * has either changed its buffer or its body or total size or did not + * appear on this frame since the last time window change functions + * were run. The functions are called without argument and with the + * buffer's window selected. The default value is run without + * argument and with the frame for which the function is run selected. + * + * In a final step, functions on `window-state-change-hook' are run + * provided a window state change has occurred or the window state + * change flag has been set on at least one frame. Each of these + * functions is called without argument. + * + * This function does not save and restore match data. Any functions + * it calls are responsible for doing that themselves. + */ +void +run_window_change_functions (void) +{ + Lisp_Object tail, frame; + bool selected_frame_change = !EQ (selected_frame, old_selected_frame); + bool run_window_state_change_hook = false; + specpdl_ref count = SPECPDL_INDEX (); + + window_change_record_frames = false; + record_unwind_protect_void (window_change_record); + specbind (Qinhibit_redisplay, Qt); + + FOR_EACH_FRAME (tail, frame) + { + struct frame *f = XFRAME (frame); + Lisp_Object root = FRAME_ROOT_WINDOW (f); + bool frame_window_change = FRAME_WINDOW_CHANGE (f); + bool window_buffer_change, window_size_change; + bool frame_buffer_change = false, frame_size_change = false; + bool frame_selected_change + = (selected_frame_change + && (EQ (frame, old_selected_frame) + || EQ (frame, selected_frame))); + bool frame_selected_window_change + = !EQ (FRAME_OLD_SELECTED_WINDOW (f), FRAME_SELECTED_WINDOW (f)); + bool frame_window_state_change = FRAME_WINDOW_STATE_CHANGE (f); + bool window_deleted = false; + Lisp_Object windows; + ptrdiff_t number_of_windows; + + if (!FRAME_LIVE_P (f) + || !f->can_set_window_size + || !f->after_make_frame + || FRAME_TOOLTIP_P (f) + || !(frame_window_change + || frame_selected_change + || frame_selected_window_change + || frame_window_state_change)) + /* Either we are not allowed to run hooks for this frame or no + window change has been reported for it since the last time + we ran window change functions on it. */ + continue; + + /* Analyze windows and run buffer locals hooks in pre-order. */ + windows = Fnreverse (window_sub_list (root, Qnil)); + number_of_windows = 0; + + /* The following loop collects all data needed to tell whether + the default value of a hook shall be run and runs any buffer + local hooks right away. */ + for (; CONSP (windows); windows = XCDR (windows)) + { + Lisp_Object window = XCAR (windows); + struct window *w = XWINDOW (window); + Lisp_Object buffer = WINDOW_BUFFER (w); + + /* Count this window even if it has been deleted while + running a hook. */ + number_of_windows += 1; + + if (!WINDOW_LIVE_P (window)) + continue; + + /* A "buffer change" means either the window's buffer + changed or the window was not part of this frame the last + time window change functions were run for it. */ + window_buffer_change = + (frame_window_change + && (!EQ (buffer, w->old_buffer) + || w->change_stamp != f->change_stamp)); + /* A "size change" means either a buffer change or that the + total or body size of the window has changed. + + Note: A buffer change implies a size change because either + this window didn't show the buffer before or this window + didn't show the buffer the last time the window change + functions were run. In either case, an application + tracing size changes in a buffer-locally fashion might + want to be informed about that change. */ + window_size_change = + (frame_window_change + && (window_buffer_change + || w->pixel_width != w->old_pixel_width + || w->pixel_height != w->old_pixel_height + || (window_body_width (w, WINDOW_BODY_IN_PIXELS) + != w->old_body_pixel_width) + || (window_body_height (w, WINDOW_BODY_IN_PIXELS) + != w->old_body_pixel_height))); + + /* The following two are needed when running the default + values for this frame below. */ + frame_buffer_change = frame_buffer_change || window_buffer_change; + frame_size_change = frame_size_change || window_size_change; + + if (window_buffer_change) + run_window_change_functions_1 + (Qwindow_buffer_change_functions, buffer, window); + + if (window_size_change && WINDOW_LIVE_P (window)) + run_window_change_functions_1 + (Qwindow_size_change_functions, buffer, window); + + /* This window's selection has changed when it was + (de-)selected as its frame's or the globally selected + window. */ + if (((frame_selected_change + && (EQ (window, old_selected_window) + || EQ (window, selected_window))) + || (frame_selected_window_change + && (EQ (window, FRAME_OLD_SELECTED_WINDOW (f)) + || EQ (window, FRAME_SELECTED_WINDOW (f))))) + && WINDOW_LIVE_P (window)) + run_window_change_functions_1 + (Qwindow_selection_change_functions, buffer, window); + + /* This window's state has changed when its buffer or size + changed or it was (de-)selected as its frame's or the + globally selected window. */ + if ((window_buffer_change + || window_size_change + || ((frame_selected_change + && (EQ (window, old_selected_window) + || EQ (window, selected_window))) + || (frame_selected_window_change + && (EQ (window, FRAME_OLD_SELECTED_WINDOW (f)) + || EQ (window, FRAME_SELECTED_WINDOW (f)))))) + && WINDOW_LIVE_P (window)) + run_window_change_functions_1 + (Qwindow_state_change_functions, buffer, window); + } - if (FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f)) - /* Record size of FRAME's minibuffer window too. */ - window_set_before_size_change_sizes - (XWINDOW (FRAME_MINIBUF_WINDOW (f))); + /* When the number of windows on a frame has decreased, at least + one window of that frame was deleted. In that case, we want + to run the default buffer and configuration change hooks. The + default size change hook is not necessarily run in that case, + but usually will be unless the deletion was "compensated" by + a reduction of the frame size or an increase of a minibuffer + window size. */ + window_deleted = number_of_windows < f->number_of_windows; + /* A frame changed buffers when one of its windows has changed + its buffer or at least one window was deleted. */ + if ((frame_buffer_change || window_deleted) && FRAME_LIVE_P (f)) + run_window_change_functions_1 + (Qwindow_buffer_change_functions, Qnil, frame); + + /* A size change occurred when at least one of the frame's + windows has changed size. */ + if (frame_size_change && FRAME_LIVE_P (f)) + run_window_change_functions_1 + (Qwindow_size_change_functions, Qnil, frame); + + /* A frame has changed its window selection when its selected + window has changed or when it was (de-)selected. */ + if ((frame_selected_change || frame_selected_window_change) + && FRAME_LIVE_P (f)) + run_window_change_functions_1 + (Qwindow_selection_change_functions, Qnil, frame); + + /* A frame has changed state when a size or buffer change + occurred, its selected window has changed, when it was + (de-)selected or its window state change flag was set. */ + if ((frame_selected_change || frame_selected_window_change + || frame_buffer_change || window_deleted + || frame_size_change || frame_window_state_change) + && FRAME_LIVE_P (f)) + { + run_window_change_functions_1 + (Qwindow_state_change_functions, Qnil, frame); + /* Make sure to run 'window-state-change-hook' later. */ + run_window_state_change_hook = true; + /* Make sure to record changes for each live frame in + window_change_record later. */ + window_change_record_frames = true; + } - FRAME_WINDOW_CONFIGURATION_CHANGED (f) = false; + /* A frame's configuration changed when one of its windows has + changed buffer or size or at least one window was deleted. */ + if ((frame_size_change || window_deleted) && FRAME_LIVE_P (f)) + /* This will run any buffer local window configuration change + hook as well. */ + run_window_configuration_change_hook (f); } -} + /* Run 'window-state-change-hook' if at least one frame has changed + state. */ + if (run_window_state_change_hook && !NILP (Vwindow_state_change_hook)) + safe_run_hooks (Qwindow_state_change_hook); + + /* Record changes for all frames (if asked for), selected window and + frame. */ + unbind_to (count, Qnil); +} /* 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. @@ -3482,7 +4060,7 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer, { struct window *w = XWINDOW (window); struct buffer *b = XBUFFER (buffer); - ptrdiff_t count = SPECPDL_INDEX (); + specpdl_ref count = SPECPDL_INDEX (); bool samebuf = EQ (buffer, w->contents); wset_buffer (w, buffer); @@ -3495,7 +4073,7 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer, /* Update time stamps of buffer display. */ if (INTEGERP (BVAR (b, display_count))) - bset_display_count (b, make_number (XINT (BVAR (b, display_count)) + 1)); + bset_display_count (b, Fadd1 (BVAR (b, display_count))); bset_display_time (b, Fcurrent_time ()); w->window_end_pos = 0; @@ -3513,7 +4091,7 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer, set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b)); set_marker_both (w->old_pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b)); set_marker_restricted (w->start, - make_number (b->last_window_start), + make_fixnum (b->last_window_start), buffer); w->start_at_line_beg = false; w->force_start = false; @@ -3532,27 +4110,35 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer, if (!keep_margins_p) { - /* Set left and right marginal area width etc. from buffer. */ - set_window_fringes (w, BVAR (b, left_fringe_width), - BVAR (b, right_fringe_width), - BVAR (b, fringes_outside_margins)); - set_window_scroll_bars (w, BVAR (b, scroll_bar_width), - BVAR (b, vertical_scroll_bar_type), - BVAR (b, scroll_bar_height), - BVAR (b, horizontal_scroll_bar_type)); + /* Set fringes and scroll bars from buffer unless they have been + declared as persistent. */ + if (!w->fringes_persistent) + set_window_fringes (w, BVAR (b, left_fringe_width), + BVAR (b, right_fringe_width), + BVAR (b, fringes_outside_margins), Qnil); + if (!w->scroll_bars_persistent) + set_window_scroll_bars (w, BVAR (b, scroll_bar_width), + BVAR (b, vertical_scroll_bar_type), + BVAR (b, scroll_bar_height), + BVAR (b, horizontal_scroll_bar_type), Qnil); + /* Set left and right marginal area width from buffer. */ set_window_margins (w, BVAR (b, left_margin_cols), BVAR (b, right_margin_cols)); apply_window_adjustment (w); } - if (run_hooks_p) - { - if (!NILP (Vwindow_scroll_functions)) - run_hook_with_args_2 (Qwindow_scroll_functions, window, - Fmarker_position (w->start)); - if (!samebuf) - run_window_configuration_change_hook (XFRAME (WINDOW_FRAME (w))); - } + if (run_hooks_p && !NILP (Vwindow_scroll_functions)) + run_hook_with_args_2 (Qwindow_scroll_functions, window, + Fmarker_position (w->start)); + + /* Ensure that window change functions are run later if the buffer + differs and the window is neither a mini nor a pseudo window. + + Note: Running window change functions for the minibuffer is noisy + and was generally suppressed in the past. Is there any reason we + should run them? */ + if (!samebuf && !MINI_WINDOW_P (w) && !WINDOW_PSEUDO_P (w)) + FRAME_WINDOW_CHANGE (XFRAME (w->frame)) = true; unbind_to (count, Qnil); } @@ -3632,7 +4218,7 @@ displaying that buffer. */) return Qt; } - if (WINDOWP (object)) + if (WINDOW_LIVE_P (object)) { struct window *w = XWINDOW (object); mark_window_display_accurate (object, false); @@ -3694,7 +4280,7 @@ temp_output_buffer_show (register Lisp_Object buf) /* Run temp-buffer-show-hook, with the chosen window selected and its buffer current. */ { - ptrdiff_t count = SPECPDL_INDEX (); + specpdl_ref count = SPECPDL_INDEX (); Lisp_Object prev_window, prev_buffer; prev_window = selected_window; XSETBUFFER (prev_buffer, old); @@ -3718,8 +4304,8 @@ temp_output_buffer_show (register Lisp_Object buf) static struct window * allocate_window (void) { - return ALLOCATE_ZEROED_PSEUDOVECTOR - (struct window, current_matrix, PVEC_WINDOW); + return ALLOCATE_ZEROED_PSEUDOVECTOR (struct window, mode_line_help_echo, + PVEC_WINDOW); } /* Make new window, have it replace WINDOW in window-tree, and make @@ -3733,8 +4319,8 @@ make_parent_window (Lisp_Object window, bool horflag) o = XWINDOW (window); p = allocate_window (); - memcpy ((char *) p + sizeof (struct vectorlike_header), - (char *) o + sizeof (struct vectorlike_header), + memcpy ((char *) p + sizeof (union vectorlike_header), + (char *) o + sizeof (union vectorlike_header), word_size * VECSIZE (struct window)); /* P's buffer slot may change from nil to a buffer... */ adjust_window_count (p, 1); @@ -3769,9 +4355,9 @@ make_window (void) Lisp data to nil, so do it only for slots which should not be nil. */ wset_normal_lines (w, make_float (1.0)); wset_normal_cols (w, make_float (1.0)); - wset_new_total (w, make_number (0)); - wset_new_normal (w, make_number (0)); - wset_new_pixel (w, make_number (0)); + wset_new_total (w, make_fixnum (0)); + wset_new_normal (w, make_fixnum (0)); + wset_new_pixel (w, make_fixnum (0)); wset_start (w, Fmake_marker ()); wset_pointm (w, Fmake_marker ()); wset_old_pointm (w, Fmake_marker ()); @@ -3786,14 +4372,12 @@ make_window (void) non-Lisp data, so do it only for slots which should not be zero. */ w->nrows_scale_factor = w->ncols_scale_factor = 1; w->left_fringe_width = w->right_fringe_width = -1; - w->mode_line_height = w->header_line_height = -1; + w->mode_line_height = w->tab_line_height = w->header_line_height = -1; #ifdef HAVE_WINDOW_SYSTEM w->phys_cursor_type = NO_CURSOR; w->phys_cursor_width = -1; #endif w->sequence_number = ++sequence_number; - w->pixel_width_before_size_change = 0; - w->pixel_height_before_size_change = 0; w->scroll_bar_width = -1; w->scroll_bar_height = -1; w->column_number_displayed = -1; @@ -3820,14 +4404,14 @@ Note: This function does not operate on any child windows of WINDOW. */) (Lisp_Object window, Lisp_Object size, Lisp_Object add) { struct window *w = decode_valid_window (window); - EMACS_INT size_min = NILP (add) ? 0 : - XINT (w->new_pixel); + EMACS_INT size_min = NILP (add) ? 0 : - XFIXNUM (w->new_pixel); EMACS_INT size_max = size_min + min (INT_MAX, MOST_POSITIVE_FIXNUM); - CHECK_RANGED_INTEGER (size, size_min, size_max); + int checked_size = check_integer_range (size, size_min, size_max); if (NILP (add)) wset_new_pixel (w, size); else - wset_new_pixel (w, make_number (XINT (w->new_pixel) + XINT (size))); + wset_new_pixel (w, make_fixnum (XFIXNUM (w->new_pixel) + checked_size)); return w->new_pixel; } @@ -3849,11 +4433,11 @@ Note: This function does not operate on any child windows of WINDOW. */) { struct window *w = decode_valid_window (window); - CHECK_NUMBER (size); + CHECK_FIXNUM (size); if (NILP (add)) wset_new_total (w, size); else - wset_new_total (w, make_number (XINT (w->new_total) + XINT (size))); + wset_new_total (w, make_fixnum (XFIXNUM (w->new_total) + XFIXNUM (size))); return w->new_total; } @@ -3895,7 +4479,7 @@ window_resize_check (struct window *w, bool horflag) { while (c) { - if (XINT (c->new_pixel) != XINT (w->new_pixel) + if (XFIXNUM (c->new_pixel) != XFIXNUM (w->new_pixel) || !window_resize_check (c, horflag)) return false; @@ -3908,14 +4492,14 @@ window_resize_check (struct window *w, bool horflag) /* The sum of the heights of the child windows of W must equal W's height. */ { - int remaining_pixels = XINT (w->new_pixel); + int remaining_pixels = XFIXNUM (w->new_pixel); while (c) { if (!window_resize_check (c, horflag)) return false; - remaining_pixels -= XINT (c->new_pixel); + remaining_pixels -= XFIXNUM (c->new_pixel); if (remaining_pixels < 0) return false; c = NILP (c->next) ? 0 : XWINDOW (c->next); @@ -3932,14 +4516,14 @@ window_resize_check (struct window *w, bool horflag) /* The sum of the widths of the child windows of W must equal W's width. */ { - int remaining_pixels = XINT (w->new_pixel); + int remaining_pixels = XFIXNUM (w->new_pixel); while (c) { if (!window_resize_check (c, horflag)) return false; - remaining_pixels -= XINT (c->new_pixel); + remaining_pixels -= XFIXNUM (c->new_pixel); if (remaining_pixels < 0) return false; c = NILP (c->next) ? 0 : XWINDOW (c->next); @@ -3952,7 +4536,7 @@ window_resize_check (struct window *w, bool horflag) { while (c) { - if (XINT (c->new_pixel) != XINT (w->new_pixel) + if (XFIXNUM (c->new_pixel) != XFIXNUM (w->new_pixel) || !window_resize_check (c, horflag)) return false; @@ -3966,9 +4550,9 @@ window_resize_check (struct window *w, bool horflag) /* A leaf window. Make sure it's not too small. The following hardcodes the values of `window-safe-min-width' (2) and `window-safe-min-height' (1) which are defined in window.el. */ - return (XINT (w->new_pixel) >= (horflag - ? (2 * FRAME_COLUMN_WIDTH (f)) - : FRAME_LINE_HEIGHT (f))); + return (XFIXNUM (w->new_pixel) >= (horflag + ? 2 * FRAME_COLUMN_WIDTH (f) + : FRAME_LINE_HEIGHT (f))); } @@ -3992,7 +4576,7 @@ window_resize_apply (struct window *w, bool horflag) parent window has been set *before*. */ if (horflag) { - w->pixel_width = XFASTINT (w->new_pixel); + w->pixel_width = XFIXNAT (w->new_pixel); w->total_cols = w->pixel_width / unit; if (NUMBERP (w->new_normal)) wset_normal_cols (w, w->new_normal); @@ -4001,7 +4585,7 @@ window_resize_apply (struct window *w, bool horflag) } else { - w->pixel_height = XFASTINT (w->new_pixel); + w->pixel_height = XFIXNAT (w->new_pixel); w->total_lines = w->pixel_height / unit; if (NUMBERP (w->new_normal)) wset_normal_lines (w, w->new_normal); @@ -4059,6 +4643,9 @@ window_resize_apply (struct window *w, bool horflag) else /* Bug#15957. */ w->window_end_valid = false; + + if (!WINDOW_PSEUDO_P (w)) + FRAME_WINDOW_CHANGE (WINDOW_XFRAME (w)) = true; } @@ -4076,12 +4663,12 @@ window_resize_apply_total (struct window *w, bool horflag) parent window has been set *before*. */ if (horflag) { - w->total_cols = XFASTINT (w->new_total); + w->total_cols = XFIXNAT (w->new_total); edge = w->left_col; } else { - w->total_lines = XFASTINT (w->new_total); + w->total_lines = XFIXNAT (w->new_total); edge = w->top_line; } @@ -4149,7 +4736,7 @@ be applied on the Elisp level. */) bool horflag = !NILP (horizontal); if (!window_resize_check (r, horflag) - || (XINT (r->new_pixel) + || (XFIXNUM (r->new_pixel) != (horflag ? r->pixel_width : r->pixel_height))) return Qnil; @@ -4193,10 +4780,10 @@ values. */) if (NILP (horizontal)) { m->top_line = r->top_line + r->total_lines; - m->total_lines = XFASTINT (m->new_total); + m->total_lines = XFIXNAT (m->new_total); } else - m->total_cols = XFASTINT (m->new_total); + m->total_cols = XFIXNAT (m->new_total); } unblock_input (); @@ -4205,68 +4792,50 @@ values. */) } -/* Resize frame F's windows when F's width or height is set to SIZE. - If HORFLAG is zero, F's width was set to SIZE, otherwise its height - was set. SIZE is interpreted in F's canonical character units - (a.k.a. "columns" or "lines"), unless PIXELWISE is non-zero, which - means to interpret SIZE in pixel units. */ +/** +Resize frame F's windows when F's inner height (inner width if HORFLAG +is true) has been set to SIZE pixels. */ void -resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) +resize_frame_windows (struct frame *f, int size, bool horflag) { Lisp_Object root = f->root_window; struct window *r = XWINDOW (root); - Lisp_Object mini = f->minibuffer_window; - struct window *m; - /* old_size is the old size of the frame's root window. */ - int old_size = horflag ? r->total_cols : r->total_lines; int old_pixel_size = horflag ? r->pixel_width : r->pixel_height; - /* new_size is the new size of the frame's root window. */ int new_size, new_pixel_size; int unit = horflag ? FRAME_COLUMN_WIDTH (f) : FRAME_LINE_HEIGHT (f); + Lisp_Object mini = f->minibuffer_window; + struct window *m = WINDOWP (mini) ? XWINDOW (mini) : NULL; + int mini_height = ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f)) + ? (unit + m->pixel_height + - window_body_height (m, WINDOW_BODY_IN_PIXELS)) + : 0); - /* Don't let the size drop below one unit. This is more comforting - when we are called from x_set_tool_bar_lines since the latter may - have implicitly given us a zero or negative height. */ - if (pixelwise) - { - /* Note: This does not include the size for internal borders - since these are not part of the frame's text area. */ - new_pixel_size = max (horflag - ? size - : (size - - ((FRAME_HAS_MINIBUF_P (f) - && !FRAME_MINIBUF_ONLY_P (f)) - ? FRAME_LINE_HEIGHT (f) : 0)), - unit); - new_size = new_pixel_size / unit; - } - else - { - new_size = max (size - (!horflag - && FRAME_HAS_MINIBUF_P (f) - && !FRAME_MINIBUF_ONLY_P (f)), - 1); - new_pixel_size = new_size * unit; - } + new_pixel_size = max (horflag ? size : size - mini_height, unit); + new_size = new_pixel_size / unit; if (new_pixel_size == old_pixel_size && (horflag || r->pixel_top == FRAME_TOP_MARGIN_HEIGHT (f))) ; else if (WINDOW_LEAF_P (r)) - /* For a leaf root window just set the size. */ - if (horflag) - { - r->total_cols = new_size; - r->pixel_width = new_pixel_size; - } - else - { - r->top_line = FRAME_TOP_MARGIN (f); - r->pixel_top = FRAME_TOP_MARGIN_HEIGHT (f); + { + /* For a leaf root window just set the size. */ + if (horflag) + { + r->total_cols = new_size; + r->pixel_width = new_pixel_size; + } + else + { + r->top_line = FRAME_TOP_MARGIN (f); + r->pixel_top = FRAME_TOP_MARGIN_HEIGHT (f); - r->total_lines = new_size; - r->pixel_height = new_pixel_size; - } + r->total_lines = new_size; + r->pixel_height = new_pixel_size; + } + + FRAME_WINDOW_CHANGE (f) + = !WINDOW_PSEUDO_P (r) && new_pixel_size != old_pixel_size; + } else { Lisp_Object delta; @@ -4277,16 +4846,12 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) r->pixel_top = FRAME_TOP_MARGIN_HEIGHT (f); } - if (pixelwise) - XSETINT (delta, new_pixel_size - old_pixel_size); - else - XSETINT (delta, new_size - old_size); + XSETINT (delta, new_pixel_size - old_pixel_size); /* Try a "normal" resize first. */ - resize_root_window (root, delta, horflag ? Qt : Qnil, Qnil, - pixelwise ? Qt : Qnil); + resize_root_window (root, delta, horflag ? Qt : Qnil, Qnil, Qt); if (window_resize_check (r, horflag) - && new_pixel_size == XINT (r->new_pixel)) + && new_pixel_size == XFIXNUM (r->new_pixel)) { window_resize_apply (r, horflag); window_pixel_to_total (r->frame, horflag ? Qt : Qnil); @@ -4294,10 +4859,9 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) else { /* Try with "reasonable" minimum sizes next. */ - resize_root_window (root, delta, horflag ? Qt : Qnil, Qt, - pixelwise ? Qt : Qnil); + resize_root_window (root, delta, horflag ? Qt : Qnil, Qt, Qt); if (window_resize_check (r, horflag) - && new_pixel_size == XINT (r->new_pixel)) + && new_pixel_size == XFIXNUM (r->new_pixel)) { window_resize_apply (r, horflag); window_pixel_to_total (r->frame, horflag ? Qt : Qnil); @@ -4315,9 +4879,8 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) } else { - /* Are we sure we always want 1 line here? */ - m->total_lines = 1; - m->pixel_height = FRAME_LINE_HEIGHT (f); + m->total_lines = mini_height / unit; + m->pixel_height = mini_height; m->top_line = r->top_line + r->total_lines; m->pixel_top = r->pixel_top + r->pixel_height; } @@ -4336,7 +4899,7 @@ Third argument SIDE nil (or `below') specifies that the new window shall be located below WINDOW. SIDE `above' means the new window shall be located above WINDOW. In both cases PIXEL-SIZE specifies the pixel height of the new window including space reserved for the mode and/or -header line. +header/tab line. SIDE t (or `right') specifies that the new window shall be located on the right side of WINDOW. SIDE `left' means the new window shall be @@ -4369,9 +4932,9 @@ set correctly. See the code of `split-window' for how this is done. */) frame = WINDOW_FRAME (o); f = XFRAME (frame); - CHECK_NUMBER (pixel_size); + CHECK_FIXNUM (pixel_size); EMACS_INT total_size - = XINT (pixel_size) / (horflag + = XFIXNUM (pixel_size) / (horflag ? FRAME_COLUMN_WIDTH (f) : FRAME_LINE_HEIGHT (f)); @@ -4406,19 +4969,19 @@ set correctly. See the code of `split-window' for how this is done. */) p = XWINDOW (o->parent); /* Temporarily pretend we split the parent window. */ wset_new_pixel - (p, make_number ((horflag ? p->pixel_width : p->pixel_height) - - XINT (pixel_size))); + (p, make_fixnum ((horflag ? p->pixel_width : p->pixel_height) + - XFIXNUM (pixel_size))); if (!window_resize_check (p, horflag)) error ("Window sizes don't fit"); else /* Undo the temporary pretension. */ - wset_new_pixel (p, make_number (horflag ? p->pixel_width : p->pixel_height)); + wset_new_pixel (p, make_fixnum (horflag ? p->pixel_width : p->pixel_height)); } else { if (!window_resize_check (o, horflag)) error ("Resizing old window failed"); - else if (XINT (pixel_size) + XINT (o->new_pixel) + else if (XFIXNUM (pixel_size) + XFIXNUM (o->new_pixel) != (horflag ? o->pixel_width : o->pixel_height)) error ("Sum of sizes of old and new window don't fit"); } @@ -4440,9 +5003,9 @@ set correctly. See the code of `split-window' for how this is done. */) wset_combination_limit (p, Qt); /* These get applied below. */ wset_new_pixel - (p, make_number (horflag ? o->pixel_width : o->pixel_height)); + (p, make_fixnum (horflag ? o->pixel_width : o->pixel_height)); wset_new_total - (p, make_number (horflag ? o->total_cols : o->total_lines)); + (p, make_fixnum (horflag ? o->total_cols : o->total_lines)); wset_new_normal (p, new_normal); } else @@ -4511,10 +5074,10 @@ set correctly. See the code of `split-window' for how this is done. */) while (c) { if (c != n) - sum = sum + XINT (c->new_total); + sum = sum + XFIXNUM (c->new_total); c = NILP (c->next) ? 0 : XWINDOW (c->next); } - wset_new_total (n, make_number ((horflag + wset_new_total (n, make_fixnum ((horflag ? p->total_cols : p->total_lines) - sum)); @@ -4523,17 +5086,11 @@ set correctly. See the code of `split-window' for how this is done. */) block_input (); window_resize_apply (p, horflag); adjust_frame_glyphs (f); - /* Set buffer of NEW to buffer of reference window. Don't run - any hooks. */ - set_window_buffer (new, r->contents, false, true); + /* Set buffer of NEW to buffer of reference window. */ + set_window_buffer (new, r->contents, true, true); + FRAME_WINDOW_CHANGE (f) = true; unblock_input (); - /* Maybe we should run the scroll functions in Elisp (which already - runs the configuration change hook). */ - if (! NILP (Vwindow_scroll_functions)) - run_hook_with_args_2 (Qwindow_scroll_functions, new, - Fmarker_position (n->start)); - /* Return NEW. */ return new; } @@ -4596,7 +5153,7 @@ Signal an error when WINDOW is the only window on its frame. */) } if (window_resize_check (r, horflag) - && (XINT (r->new_pixel) + && (XFIXNUM (r->new_pixel) == (horflag ? r->pixel_width : r->pixel_height))) /* We can delete WINDOW now. */ { @@ -4654,36 +5211,24 @@ Signal an error when WINDOW is the only window on its frame. */) adjust_frame_glyphs (f); if (!WINDOW_LIVE_P (FRAME_SELECTED_WINDOW (f))) - /* We deleted the frame's selected window. */ + /* We apparently deleted the frame's selected window; use the + frame's first window as substitute but don't record it yet. + `delete-window' may have something better up its sleeves. */ { /* Use the frame's first window as fallback ... */ Lisp_Object new_selected_window = Fframe_first_window (frame); - /* ... but preferably use its most recently used window. */ - Lisp_Object mru_window; - /* `get-mru-window' might fail for some reason so play it safe - - promote the first window _without recording it_ first. */ if (EQ (FRAME_SELECTED_WINDOW (f), selected_window)) Fselect_window (new_selected_window, Qt); else - fset_selected_window (f, new_selected_window); - - unblock_input (); - - /* Now look whether `get-mru-window' gets us something. */ - mru_window = call1 (Qget_mru_window, frame); - if (WINDOW_LIVE_P (mru_window) - && EQ (XWINDOW (mru_window)->frame, frame)) - new_selected_window = mru_window; - - /* If all ended up well, we now promote the mru window. */ - if (EQ (FRAME_SELECTED_WINDOW (f), selected_window)) - Fselect_window (new_selected_window, Qnil); - else + /* Do not clear f->select_mini_window_flag here. If the + last selected window on F was an active minibuffer, we + want to return to it on a later Fselect_frame. */ fset_selected_window (f, new_selected_window); } - else - unblock_input (); + + unblock_input (); + FRAME_WINDOW_CHANGE (f) = true; } else /* We failed: Relink WINDOW into window tree. */ @@ -4709,118 +5254,116 @@ Signal an error when WINDOW is the only window on its frame. */) Resizing Mini-Windows ***********************************************************************/ -/* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we - can. */ +/** + * resize_mini_window_apply: + * + * Assign new window sizes after resizing a mini window W by DELTA + * pixels. No error checking performed. + */ +static void +resize_mini_window_apply (struct window *w, int delta) +{ + struct frame *f = XFRAME (w->frame); + Lisp_Object root = FRAME_ROOT_WINDOW (f); + struct window *r = XWINDOW (root); + + block_input (); + w->pixel_height = w->pixel_height + delta; + w->total_lines = w->pixel_height / FRAME_LINE_HEIGHT (f); + + window_resize_apply (r, false); + + w->pixel_top = r->pixel_top + r->pixel_height; + w->top_line = r->top_line + r->total_lines; + + /* Enforce full redisplay of the frame. */ + /* FIXME: Shouldn't some of the caller do it? */ + fset_redisplay (f); + adjust_frame_glyphs (f); + unblock_input (); +} + +/** + * grow_mini_window: + * + * Grow mini-window W by DELTA pixels. If DELTA is negative, this may + * shrink the minibuffer window to the minimum height to display one + * line of text. + */ void -grow_mini_window (struct window *w, int delta, bool pixelwise) +grow_mini_window (struct window *w, int delta) { struct frame *f = XFRAME (w->frame); - struct window *r; - Lisp_Object root, height; - int line_height, pixel_height; + int old_height = window_body_height (w, WINDOW_BODY_IN_PIXELS); + int min_height = FRAME_LINE_HEIGHT (f); eassert (MINI_WINDOW_P (w)); - eassert (delta >= 0); - if (delta > 0) - { - root = FRAME_ROOT_WINDOW (f); - r = XWINDOW (root); - height = call3 (Qwindow__resize_root_window_vertically, - root, make_number (- delta), pixelwise ? Qt : Qnil); - if (INTEGERP (height) && window_resize_check (r, false)) - { - block_input (); - window_resize_apply (r, false); + /* Never shrink mini-window to less than its minimum height. */ + if (old_height + delta < min_height) + delta = old_height > min_height ? min_height - old_height : 0; - if (pixelwise) - { - pixel_height = min (-XINT (height), INT_MAX - w->pixel_height); - line_height = pixel_height / FRAME_LINE_HEIGHT (f); - } - else - { - line_height = min (-XINT (height), - ((INT_MAX - w->pixel_height) - / FRAME_LINE_HEIGHT (f))); - pixel_height = line_height * FRAME_LINE_HEIGHT (f); - } + if (delta != 0) + { + Lisp_Object root = FRAME_ROOT_WINDOW (f); + struct window *r = XWINDOW (root); + Lisp_Object grow; - /* Grow the mini-window. */ - w->pixel_top = r->pixel_top + r->pixel_height; - w->top_line = r->top_line + r->total_lines; - /* Make sure the mini-window has always at least one line. */ - w->pixel_height = max (w->pixel_height + pixel_height, - FRAME_LINE_HEIGHT (f)); - w->total_lines = max (w->total_lines + line_height, 1); - - /* Enforce full redisplay of the frame. */ - /* FIXME: Shouldn't window--resize-root-window-vertically do it? */ - fset_redisplay (f); - adjust_frame_glyphs (f); - unblock_input (); - } - else - error ("Failed to grow minibuffer window"); + FRAME_WINDOWS_FROZEN (f) = true; + grow = call3 (Qwindow__resize_root_window_vertically, + root, make_fixnum (- delta), Qt); + if (FIXNUMP (grow) && window_resize_check (r, false)) + resize_mini_window_apply (w, -XFIXNUM (grow)); } } -/* Shrink mini-window W to one line. */ +/** + * shrink_mini_window: + * + * Shrink mini-window W to the minimum height needed to display one + * line of text. + */ void -shrink_mini_window (struct window *w, bool pixelwise) +shrink_mini_window (struct window *w) { struct frame *f = XFRAME (w->frame); - struct window *r; - Lisp_Object root, delta; - EMACS_INT height, unit; + int delta = (window_body_height (w, WINDOW_BODY_IN_PIXELS) + - FRAME_LINE_HEIGHT (f)); eassert (MINI_WINDOW_P (w)); - height = pixelwise ? w->pixel_height : w->total_lines; - unit = pixelwise ? FRAME_LINE_HEIGHT (f) : 1; - if (height > unit) + if (delta > 0) { - root = FRAME_ROOT_WINDOW (f); - r = XWINDOW (root); - delta = call3 (Qwindow__resize_root_window_vertically, - root, make_number (height - unit), - pixelwise ? Qt : Qnil); - if (INTEGERP (delta) && window_resize_check (r, false)) - { - block_input (); - window_resize_apply (r, false); - - /* Shrink the mini-window. */ - w->top_line = r->top_line + r->total_lines; - w->total_lines = 1; - w->pixel_top = r->pixel_top + r->pixel_height; - w->pixel_height = FRAME_LINE_HEIGHT (f); - /* Enforce full redisplay of the frame. */ - /* FIXME: Shouldn't window--resize-root-window-vertically do it? */ - fset_redisplay (f); - adjust_frame_glyphs (f); - unblock_input (); - } - /* If the above failed for whatever strange reason we must make a - one window frame here. The same routine will be needed when - shrinking the frame (and probably when making the initial - *scratch* window). For the moment leave things as they are. */ - else - error ("Failed to shrink minibuffer window"); + Lisp_Object root = FRAME_ROOT_WINDOW (f); + struct window *r = XWINDOW (root); + Lisp_Object grow; + + FRAME_WINDOWS_FROZEN (f) = false; + grow = call3 (Qwindow__resize_root_window_vertically, + root, make_fixnum (delta), Qt); + + if (FIXNUMP (grow) && window_resize_check (r, false)) + resize_mini_window_apply (w, -XFIXNUM (grow)); } + else if (delta < 0) + /* delta can be less than zero after adding horizontal scroll + bar. */ + grow_mini_window (w, -delta); + } -DEFUN ("resize-mini-window-internal", Fresize_mini_window_internal, Sresize_mini_window_internal, 1, 1, 0, - doc: /* Resize minibuffer window WINDOW. */) +DEFUN ("resize-mini-window-internal", Fresize_mini_window_internal, + Sresize_mini_window_internal, 1, 1, 0, + doc: /* Resize mini window WINDOW. */) (Lisp_Object window) { struct window *w = XWINDOW (window); struct window *r; struct frame *f; - int height; + int old_height, delta; - CHECK_WINDOW (window); + CHECK_LIVE_WINDOW (window); f = XFRAME (w->frame); if (!EQ (FRAME_MINIBUF_WINDOW (XFRAME (w->frame)), window)) @@ -4829,26 +5372,18 @@ DEFUN ("resize-mini-window-internal", Fresize_mini_window_internal, Sresize_mini error ("Cannot resize a minibuffer-only frame"); r = XWINDOW (FRAME_ROOT_WINDOW (f)); - height = r->pixel_height + w->pixel_height; + old_height = r->pixel_height + w->pixel_height; + delta = XFIXNUM (w->new_pixel) - w->pixel_height; if (window_resize_check (r, false) - && XINT (w->new_pixel) > 0 - && height == XINT (r->new_pixel) + XINT (w->new_pixel)) + && XFIXNUM (w->new_pixel) > 0 + && old_height == XFIXNUM (r->new_pixel) + XFIXNUM (w->new_pixel)) { - block_input (); - window_resize_apply (r, false); + resize_mini_window_apply (w, delta); - w->pixel_height = XFASTINT (w->new_pixel); - w->total_lines = w->pixel_height / FRAME_LINE_HEIGHT (f); - w->pixel_top = r->pixel_top + r->pixel_height; - w->top_line = r->top_line + r->total_lines; - - fset_redisplay (f); - adjust_frame_glyphs (f); - unblock_input (); return Qt; } else - error ("Failed to resize minibuffer window"); + error ("Cannot resize mini window"); } /* Mark window cursors off for all windows in the window tree rooted @@ -4889,15 +5424,13 @@ window_wants_mode_line (struct window *w) Lisp_Object window_mode_line_format = window_parameter (w, Qmode_line_format); - return ((WINDOW_LEAF_P (w) - && !MINI_WINDOW_P (w) - && !WINDOW_PSEUDO_P (w) - && !EQ (window_mode_line_format, Qnone) - && (!NILP (window_mode_line_format) - || !NILP (BVAR (XBUFFER (WINDOW_BUFFER (w)), mode_line_format))) - && WINDOW_PIXEL_HEIGHT (w) > WINDOW_FRAME_LINE_HEIGHT (w)) - ? 1 - : 0); + return (WINDOW_LEAF_P (w) + && !MINI_WINDOW_P (w) + && !WINDOW_PSEUDO_P (w) + && !EQ (window_mode_line_format, Qnone) + && (!NILP (window_mode_line_format) + || !NILP (BVAR (XBUFFER (WINDOW_BUFFER (w)), mode_line_format))) + && WINDOW_PIXEL_HEIGHT (w) > WINDOW_FRAME_LINE_HEIGHT (w)); } @@ -4920,39 +5453,70 @@ window_wants_header_line (struct window *w) Lisp_Object window_header_line_format = window_parameter (w, Qheader_line_format); - return ((WINDOW_LEAF_P (w) - && !MINI_WINDOW_P (w) - && !WINDOW_PSEUDO_P (w) - && !EQ (window_header_line_format, Qnone) - && (!NILP (window_header_line_format) - || !NILP (BVAR (XBUFFER (WINDOW_BUFFER (w)), header_line_format))) - && (WINDOW_PIXEL_HEIGHT (w) - > (window_wants_mode_line (w) - ? 2 * WINDOW_FRAME_LINE_HEIGHT (w) - : WINDOW_FRAME_LINE_HEIGHT (w)))) - ? 1 - : 0); + return (WINDOW_LEAF_P (w) + && !MINI_WINDOW_P (w) + && !WINDOW_PSEUDO_P (w) + && !EQ (window_header_line_format, Qnone) + && (!NILP (window_header_line_format) + || !NILP (BVAR (XBUFFER (WINDOW_BUFFER (w)), header_line_format))) + && (WINDOW_PIXEL_HEIGHT (w) + > (window_wants_mode_line (w) + ? 2 * WINDOW_FRAME_LINE_HEIGHT (w) + : WINDOW_FRAME_LINE_HEIGHT (w)))); } -/* Return number of lines of text (not counting mode lines) in W. */ + +/** + * window_wants_tab_line: + * + * Return 1 if window W wants a tab line and is high enough to + * accommodate it, 0 otherwise. + * + * W wants a tab line if it's a leaf window and neither a minibuffer + * nor a pseudo window. Moreover, its 'window-mode-line-format' + * parameter must not be 'none' and either that parameter or W's + * buffer's 'mode-line-format' value must be non-nil. Finally, W must + * be higher than its frame's canonical character height and be able + * to accommodate a mode line and a header line too if necessary (the + * mode line and a header line prevail). + */ + +bool +window_wants_tab_line (struct window *w) +{ + Lisp_Object window_tab_line_format = + window_parameter (w, Qtab_line_format); + + return (WINDOW_LEAF_P (w) + && !MINI_WINDOW_P (w) + && !WINDOW_PSEUDO_P (w) + && !EQ (window_tab_line_format, Qnone) + && (!NILP (window_tab_line_format) + || !NILP (BVAR (XBUFFER (WINDOW_BUFFER (w)), tab_line_format))) + && (WINDOW_PIXEL_HEIGHT (w) + > (((window_wants_mode_line (w) ? 1 : 0) + + (window_wants_header_line (w) ? 1 : 0) + + 1) * WINDOW_FRAME_LINE_HEIGHT (w)))); +} + +/* Return number of lines of text in window W, not counting the mode + line and header line, if any. Do NOT use this for windows on GUI + frames; use window_body_height instead. This function is only for + windows on TTY frames, where it is much more efficient. */ int window_internal_height (struct window *w) { int ht = w->total_lines; - if (!MINI_WINDOW_P (w)) - { - if (!NILP (w->parent) - || WINDOWP (w->contents) - || !NILP (w->next) - || !NILP (w->prev) - || window_wants_mode_line (w)) - --ht; + if (window_wants_mode_line (w)) + --ht; - if (window_wants_header_line (w)) - --ht; - } + if (window_wants_header_line (w)) + --ht; + + if (window_wants_tab_line (w)) + --ht; return ht; } @@ -4972,19 +5536,23 @@ window_internal_height (struct window *w) static void window_scroll (Lisp_Object window, EMACS_INT n, bool whole, bool noerror) { - ptrdiff_t count = SPECPDL_INDEX (); + specpdl_ref count = SPECPDL_INDEX (); n = clip_to_bounds (INT_MIN, n, INT_MAX); wset_redisplay (XWINDOW (window)); - if (whole && Vfast_but_imprecise_scrolling) + if (whole && fast_but_imprecise_scrolling) specbind (Qfontification_functions, Qnil); - /* If we must, use the pixel-based version which is much slower than - the line-based one but can handle varying line heights. */ + /* On GUI frames, use the pixel-based version which is much slower + than the line-based one but can handle varying line heights. */ if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame))) - window_scroll_pixel_based (window, n, whole, noerror); + { + record_unwind_protect_void (unwind_display_working_on_window); + display_working_on_window_p = true; + window_scroll_pixel_based (window, n, whole, noerror); + } else window_scroll_line_based (window, n, whole, noerror); @@ -5024,6 +5592,11 @@ window_scroll_margin (struct window *window, enum margin_unit unit) return 0; } +static int +sanitize_next_screen_context_lines (void) +{ + return clip_to_bounds (0, next_screen_context_lines, 1000000); +} /* Implementation of window_scroll that works based on pixel line heights. See the comment of window_scroll for parameter @@ -5094,9 +5667,11 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) height. This is important to ensure we get back to the same position when scrolling up, then down. */ if (whole) - dy = max ((window_box_height (w) / dy - - next_screen_context_lines) * dy, - dy); + { + int ht = window_box_height (w); + int nscls = sanitize_next_screen_context_lines (); + dy = max (dy, (ht / dy - nscls) * dy); + } dy *= n; if (n < 0) @@ -5105,7 +5680,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) if (w->vscroll < 0 && rtop > 0) { px = max (0, -w->vscroll - min (rtop, -dy)); - Fset_window_vscroll (window, make_number (px), Qt); + Fset_window_vscroll (window, make_fixnum (px), Qt, + Qnil); return; } } @@ -5115,7 +5691,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) if (rbot > 0 && (w->vscroll < 0 || vpos == 0)) { px = max (0, -w->vscroll + min (rbot, dy)); - Fset_window_vscroll (window, make_number (px), Qt); + Fset_window_vscroll (window, make_fixnum (px), Qt, + Qnil); return; } @@ -5124,14 +5701,15 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) { ptrdiff_t spos; - Fset_window_vscroll (window, make_number (0), Qt); + Fset_window_vscroll (window, make_fixnum (0), Qt, + Qnil); /* If there are other text lines above the current row, move window start to current row. Else to next row. */ if (rbot > 0) - spos = XINT (Fline_beginning_position (Qnil)); + spos = XFIXNUM (Fline_beginning_position (Qnil)); else - spos = min (XINT (Fline_end_position (Qnil)) + 1, ZV); - set_marker_restricted (w->start, make_number (spos), + spos = min (XFIXNUM (Fline_end_position (Qnil)) + 1, ZV); + set_marker_restricted (w->start, make_fixnum (spos), w->contents); w->start_at_line_beg = true; wset_update_mode_line (w); @@ -5143,7 +5721,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) } } /* Cancel previous vscroll. */ - Fset_window_vscroll (window, make_number (0), Qt); + Fset_window_vscroll (window, make_fixnum (0), Qt, Qnil); } itdata = bidi_shelve_cache (); @@ -5176,21 +5754,38 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) if (whole) { ptrdiff_t start_pos = IT_CHARPOS (it); - int dy = frame_line_height; + int flh = frame_line_height; + int ht = window_box_height (w); + int nscls = sanitize_next_screen_context_lines (); /* In the below we divide the window box height by the frame's line height to make the result predictable when the window box is not an integral multiple of the line height. This is important to ensure we get back to the same position when scrolling up, then down. */ - dy = max ((window_box_height (w) / dy - next_screen_context_lines) * dy, - dy) * n; + int dy = n * max (flh, (ht / flh - nscls) * flh); + int goal_y; + void *it_data; /* Note that move_it_vertically always moves the iterator to the start of a line. So, if the last line doesn't have a newline, we would end up at the start of the line ending at ZV. */ if (dy <= 0) { + goal_y = it.current_y + dy; move_it_vertically_backward (&it, -dy); + /* move_it_vertically_backward above always overshoots if DY + cannot be reached exactly, i.e. if it falls in the middle + of a screen line. But if that screen line is large + (e.g., a tall image), it might make more sense to + undershoot instead. */ + if (goal_y - it.current_y > 0.5 * flh) + { + it_data = bidi_shelve_cache (); + struct it it1 = it; + if (line_bottom_y (&it1) - goal_y < goal_y - it.current_y) + move_it_by_lines (&it, 1); + bidi_unshelve_cache (it_data, true); + } /* Ensure we actually do move, e.g. in case we are currently looking at an image that is taller that the window height. */ while (start_pos == IT_CHARPOS (it) @@ -5199,8 +5794,28 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) } else if (dy > 0) { - move_it_to (&it, ZV, -1, it.current_y + dy, -1, - MOVE_TO_POS | MOVE_TO_Y); + goal_y = it.current_y + dy; + move_it_to (&it, ZV, -1, goal_y, -1, MOVE_TO_POS | MOVE_TO_Y); + /* Extra precision for people who want us to preserve the + screen position of the cursor: effectively round DY to the + nearest screen line, instead of rounding to zero; the latter + causes point to move by one line after C-v followed by M-v, + if the buffer has lines of different height. */ + if (!NILP (Vscroll_preserve_screen_position) + && goal_y - it.current_y > 0.5 * flh) + { + it_data = bidi_shelve_cache (); + struct it it2 = it; + + move_it_by_lines (&it, 1); + if (it.current_y > goal_y + 0.5 * flh) + { + it = it2; + bidi_unshelve_cache (it_data, false); + } + else + bidi_unshelve_cache (it_data, true); + } /* Ensure we actually do move, e.g. in case we are currently looking at an image that is taller that the window height. */ while (start_pos == IT_CHARPOS (it) @@ -5303,11 +5918,13 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) /* We moved the window start towards ZV, so PT may be now in the scroll margin at the top. */ - move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); + if (IT_CHARPOS (it) < PT) + move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); if (IT_CHARPOS (it) == PT && it.current_y >= this_scroll_margin - && it.current_y <= last_y - WINDOW_HEADER_LINE_HEIGHT (w) - && (NILP (Vscroll_preserve_screen_position) + && it.current_y <= last_y - WINDOW_TAB_LINE_HEIGHT (w) + - WINDOW_HEADER_LINE_HEIGHT (w) + && (NILP (Vscroll_preserve_screen_position) || EQ (Vscroll_preserve_screen_position, Qt))) /* We found PT at a legitimate height. Leave it alone. */ ; @@ -5322,7 +5939,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) is necessary because we set it.current_y to 0, above. */ move_it_to (&it, -1, window_scroll_pixel_based_preserve_x, - goal_y - WINDOW_HEADER_LINE_HEIGHT (w), + goal_y - WINDOW_TAB_LINE_HEIGHT (w) + - WINDOW_HEADER_LINE_HEIGHT (w), -1, MOVE_TO_Y | MOVE_TO_X); } @@ -5355,8 +5973,12 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) /* We moved the window start towards BEGV, so PT may be now in the scroll margin at the bottom. */ move_it_to (&it, PT, -1, - (it.last_visible_y - WINDOW_HEADER_LINE_HEIGHT (w) - - partial_line_height (&it) - this_scroll_margin - 1), + /* We subtract WINDOW_HEADER_LINE_HEIGHT because + it.y is relative to the bottom of the header + line, see above. */ + (it.last_visible_y - WINDOW_TAB_LINE_HEIGHT (w) + - WINDOW_HEADER_LINE_HEIGHT (w) + - partial_line_height (&it) - this_scroll_margin - 1), -1, MOVE_TO_POS | MOVE_TO_Y); @@ -5392,11 +6014,17 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) /* See if point is on a partially visible line at the end. */ if (it.what == IT_EOB) - partial_p = it.current_y + it.ascent + it.descent > it.last_visible_y; + partial_p = + it.current_y + it.ascent + it.descent + > it.last_visible_y - this_scroll_margin + - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); else { move_it_by_lines (&it, 1); - partial_p = it.current_y > it.last_visible_y; + partial_p = + it.current_y + > it.last_visible_y - this_scroll_margin + - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); } if (charpos == PT && !partial_p @@ -5415,7 +6043,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) goal_y = this_scroll_margin; SET_TEXT_POS_FROM_MARKER (start, w->start); start_display (&it, w, start); - /* It would be wrong to subtract CURRENT_HEADER_LINE_HEIGHT + /* It would be wrong to subtract WINDOW_HEADER_LINE_HEIGHT here because we called start_display again and did not alter it.current_y this time. */ move_it_to (&it, -1, window_scroll_pixel_based_preserve_x, @@ -5441,7 +6069,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) if (adjust_old_pointm) Fset_marker (w->old_pointm, ((w == XWINDOW (selected_window)) - ? make_number (BUF_PT (XBUFFER (w->contents))) + ? make_fixnum (BUF_PT (XBUFFER (w->contents))) : Fmarker_position (w->pointm)), w->contents); } @@ -5474,7 +6102,10 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror) /* If scrolling screen-fulls, compute the number of lines to scroll from the window's height. */ if (whole) - n *= max (1, ht - next_screen_context_lines); + { + int nscls = sanitize_next_screen_context_lines (); + n *= max (1, ht - nscls); + } if (!NILP (Vscroll_preserve_screen_position)) { @@ -5490,8 +6121,8 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror) window_scroll_preserve_hpos = posit.hpos + w->hscroll; } - original_pos = Fcons (make_number (window_scroll_preserve_hpos), - make_number (window_scroll_preserve_vpos)); + original_pos = Fcons (make_fixnum (window_scroll_preserve_hpos), + make_fixnum (window_scroll_preserve_vpos)); } XSETFASTINT (tem, PT); @@ -5499,14 +6130,14 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror) if (NILP (tem)) { - Fvertical_motion (make_number (- (ht / 2)), window, Qnil); + Fvertical_motion (make_fixnum (- (ht / 2)), window, Qnil); startpos = PT; startbyte = PT_BYTE; } SET_PT_BOTH (startpos, startbyte); lose = n < 0 && PT == BEGV; - Fvertical_motion (make_number (n), window, Qnil); + Fvertical_motion (make_fixnum (n), window, Qnil); pos = PT; pos_byte = PT_BYTE; bolp = Fbolp (); @@ -5548,7 +6179,7 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror) if (this_scroll_margin > 0) { SET_PT_BOTH (pos, pos_byte); - Fvertical_motion (make_number (this_scroll_margin), window, Qnil); + Fvertical_motion (make_fixnum (this_scroll_margin), window, Qnil); top_margin = PT; } else @@ -5567,8 +6198,8 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror) else if (window_scroll_preserve_vpos >= w->total_lines - this_scroll_margin) nlines = w->total_lines - this_scroll_margin - 1; - Fvertical_motion (Fcons (make_number (window_scroll_preserve_hpos), - make_number (nlines)), window, Qnil); + Fvertical_motion (Fcons (make_fixnum (window_scroll_preserve_hpos), + make_fixnum (nlines)), window, Qnil); } else SET_PT (top_margin); @@ -5580,9 +6211,9 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror) /* If we scrolled backward, put point near the end of the window but not within the scroll margin. */ SET_PT_BOTH (pos, pos_byte); - tem = Fvertical_motion (make_number (ht - this_scroll_margin), window, + tem = Fvertical_motion (make_fixnum (ht - this_scroll_margin), window, Qnil); - if (XFASTINT (tem) == ht - this_scroll_margin) + if (XFIXNAT (tem) == ht - this_scroll_margin) bottom_margin = PT; else bottom_margin = PT + 1; @@ -5602,11 +6233,11 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror) else if (window_scroll_preserve_vpos >= ht - this_scroll_margin) nlines = ht - this_scroll_margin - 1; - Fvertical_motion (Fcons (make_number (window_scroll_preserve_hpos), - make_number (nlines)), window, Qnil); + Fvertical_motion (Fcons (make_fixnum (window_scroll_preserve_hpos), + make_fixnum (nlines)), window, Qnil); } else - Fvertical_motion (make_number (-1), window, Qnil); + Fvertical_motion (make_fixnum (-1), window, Qnil); } } } @@ -5621,41 +6252,65 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror) if (adjust_old_pointm) Fset_marker (w->old_pointm, ((w == XWINDOW (selected_window)) - ? make_number (BUF_PT (XBUFFER (w->contents))) + ? make_fixnum (BUF_PT (XBUFFER (w->contents))) : Fmarker_position (w->pointm)), w->contents); } -/* Scroll selected_window up or down. If N is nil, scroll a +/* Scroll WINDOW up or down. If N is nil, scroll upward by a screen-full which is defined as the height of the window minus - next_screen_context_lines. If N is the symbol `-', scroll. - DIRECTION may be 1 meaning to scroll down, or -1 meaning to scroll - up. This is the guts of Fscroll_up and Fscroll_down. */ + next_screen_context_lines. If N is the symbol `-', scroll downward + by a screen-full. DIRECTION may be 1 meaning to scroll down, or -1 + meaning to scroll up. */ static void -scroll_command (Lisp_Object n, int direction) +scroll_command (Lisp_Object window, Lisp_Object n, int direction) { - ptrdiff_t count = SPECPDL_INDEX (); + struct window *w; + bool other_window; + specpdl_ref count = SPECPDL_INDEX (); eassert (eabs (direction) == 1); - /* If selected window's buffer isn't current, make it current for - the moment. But don't screw up if window_scroll gets an error. */ - if (XBUFFER (XWINDOW (selected_window)->contents) != current_buffer) + w = XWINDOW (window); + other_window = ! EQ (window, selected_window); + + /* If given window's buffer isn't current, make it current for the + moment. If the window's buffer is the same, but it is not the + selected window, we need to save-excursion to avoid affecting + point in the selected window (which would cause the selected + window to scroll). Don't screw up if window_scroll gets an + error. */ + if (other_window || XBUFFER (w->contents) != current_buffer) { - record_unwind_protect (save_excursion_restore, save_excursion_save ()); - Fset_buffer (XWINDOW (selected_window)->contents); + record_unwind_protect_excursion (); + if (XBUFFER (w->contents) != current_buffer) + Fset_buffer (w->contents); + } + + if (other_window) + { + SET_PT_BOTH (marker_position (w->pointm), + marker_byte_position (w->pointm)); + SET_PT_BOTH (marker_position (w->old_pointm), + marker_byte_position (w->old_pointm)); } if (NILP (n)) - window_scroll (selected_window, direction, true, false); + window_scroll (window, direction, true, false); else if (EQ (n, Qminus)) - window_scroll (selected_window, -direction, true, false); + window_scroll (window, -direction, true, false); else { n = Fprefix_numeric_value (n); - window_scroll (selected_window, XINT (n) * direction, false, false); + window_scroll (window, XFIXNUM (n) * direction, false, false); + } + + if (other_window) + { + set_marker_both (w->pointm, Qnil, PT, PT_BYTE); + set_marker_both (w->old_pointm, Qnil, PT, PT_BYTE); } unbind_to (count, Qnil); @@ -5670,7 +6325,7 @@ If ARG is the atom `-', scroll downward by nearly full screen. When calling from a program, supply as argument a number, nil, or `-'. */) (Lisp_Object arg) { - scroll_command (arg, 1); + scroll_command (selected_window, arg, 1); return Qnil; } @@ -5683,17 +6338,18 @@ If ARG is the atom `-', scroll upward by nearly full screen. When calling from a program, supply as argument a number, nil, or `-'. */) (Lisp_Object arg) { - scroll_command (arg, -1); + scroll_command (selected_window, arg, -1); return Qnil; } DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0, doc: /* Return the other window for \"other window scroll\" commands. -If `other-window-scroll-buffer' is non-nil, a window -showing that buffer is used. If in the minibuffer, `minibuffer-scroll-window' if non-nil -specifies the window. This takes precedence over -`other-window-scroll-buffer'. */) +specifies the window. +Otherwise, if `other-window-scroll-buffer' is non-nil, a window +showing that buffer is used, popping the buffer up if necessary. +Finally, look for a neighboring window on the selected frame, +followed by all visible frames on the current terminal. */) (void) { Lisp_Object window; @@ -5702,27 +6358,25 @@ specifies the window. This takes precedence over && !NILP (Vminibuf_scroll_window)) window = Vminibuf_scroll_window; /* If buffer is specified and live, scroll that buffer. */ - else if (!NILP (Vother_window_scroll_buffer) - && BUFFERP (Vother_window_scroll_buffer) + else if (BUFFERP (Vother_window_scroll_buffer) && BUFFER_LIVE_P (XBUFFER (Vother_window_scroll_buffer))) { window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil); if (NILP (window)) window = display_buffer (Vother_window_scroll_buffer, Qt, Qnil); } + else if (FUNCTIONP (Vother_window_scroll_default)) + /* Nothing specified; try to get a window from the function. */ + window = call0 (Vother_window_scroll_default); else { - /* Nothing specified; look for a neighboring window on the same - frame. */ - window = Fnext_window (selected_window, Qnil, Qnil); + /* Otherwise, look for a neighboring window on the same frame. */ + window = Fnext_window (selected_window, Qlambda, Qnil); if (EQ (window, selected_window)) /* That didn't get us anywhere; look for a window on another - visible frame. */ - do - window = Fnext_window (window, Qnil, Qt); - while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window)))) - && ! EQ (window, selected_window)); + visible frame on the current terminal. */ + window = Fnext_window (window, Qlambda, Qvisible); } CHECK_LIVE_WINDOW (window); @@ -5733,53 +6387,6 @@ specifies the window. This takes precedence over return window; } -DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P", - doc: /* Scroll next window upward ARG lines; or near full screen if no ARG. -A near full screen is `next-screen-context-lines' less than a full screen. -The next window is the one below the current one; or the one at the top -if the current one is at the bottom. Negative ARG means scroll downward. -If ARG is the atom `-', scroll downward by nearly full screen. -When calling from a program, supply as argument a number, nil, or `-'. - -If `other-window-scroll-buffer' is non-nil, scroll the window -showing that buffer, popping the buffer up if necessary. -If in the minibuffer, `minibuffer-scroll-window' if non-nil -specifies the window to scroll. This takes precedence over -`other-window-scroll-buffer'. */) - (Lisp_Object arg) -{ - Lisp_Object window; - struct window *w; - ptrdiff_t count = SPECPDL_INDEX (); - - window = Fother_window_for_scrolling (); - w = XWINDOW (window); - - /* Don't screw up if window_scroll gets an error. */ - record_unwind_protect (save_excursion_restore, save_excursion_save ()); - - Fset_buffer (w->contents); - SET_PT_BOTH (marker_position (w->pointm), marker_byte_position (w->pointm)); - SET_PT_BOTH (marker_position (w->old_pointm), marker_byte_position (w->old_pointm)); - - if (NILP (arg)) - window_scroll (window, 1, true, true); - else if (EQ (arg, Qminus)) - window_scroll (window, -1, true, true); - else - { - if (CONSP (arg)) - arg = XCAR (arg); - CHECK_NUMBER (arg); - window_scroll (window, XINT (arg), false, true); - } - - set_marker_both (w->pointm, Qnil, PT, PT_BYTE); - set_marker_both (w->old_pointm, Qnil, PT, PT_BYTE); - unbind_to (count, Qnil); - - return Qnil; -} DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 2, "^P\np", doc: /* Scroll selected window display ARG columns left. @@ -5793,9 +6400,10 @@ by this function. This happens in an interactive call. */) (register Lisp_Object arg, Lisp_Object set_minimum) { struct window *w = XWINDOW (selected_window); - EMACS_INT requested_arg = (NILP (arg) - ? window_body_width (w, 0) - 2 - : XINT (Fprefix_numeric_value (arg))); + EMACS_INT requested_arg = + (NILP (arg) + ? window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) - 2 + : XFIXNUM (Fprefix_numeric_value (arg))); Lisp_Object result = set_window_hscroll (w, w->hscroll + requested_arg); if (!NILP (set_minimum)) @@ -5818,9 +6426,10 @@ by this function. This happens in an interactive call. */) (register Lisp_Object arg, Lisp_Object set_minimum) { struct window *w = XWINDOW (selected_window); - EMACS_INT requested_arg = (NILP (arg) - ? window_body_width (w, 0) - 2 - : XINT (Fprefix_numeric_value (arg))); + EMACS_INT requested_arg = + (NILP (arg) + ? window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) - 2 + : XFIXNUM (Fprefix_numeric_value (arg))); Lisp_Object result = set_window_hscroll (w, w->hscroll - requested_arg); if (!NILP (set_minimum)) @@ -5832,8 +6441,8 @@ by this function. This happens in an interactive call. */) } DEFUN ("minibuffer-selected-window", Fminibuffer_selected_window, Sminibuffer_selected_window, 0, 0, 0, - doc: /* Return the window which was selected when entering the minibuffer. -Returns nil, if selected window is not a minibuffer window. */) + doc: /* Return window selected just before minibuffer window was selected. +Return nil if the selected window is not a minibuffer window. */) (void) { if (minibuf_level > 0 @@ -5871,9 +6480,14 @@ displayed_window_lines (struct window *w) CLIP_TEXT_POS_FROM_MARKER (start, w->start); itdata = bidi_shelve_cache (); + + specpdl_ref count = SPECPDL_INDEX (); + record_unwind_protect_void (unwind_display_working_on_window); + display_working_on_window_p = true; start_display (&it, w, start); move_it_vertically (&it, height); bottom_y = line_bottom_y (&it); + unbind_to (count, Qnil); bidi_unshelve_cache (itdata, false); /* Add in empty lines at the bottom of the window. */ @@ -5892,22 +6506,23 @@ displayed_window_lines (struct window *w) } -DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P", +DEFUN ("recenter", Frecenter, Srecenter, 0, 2, "P\np", doc: /* Center point in selected window and maybe redisplay frame. With a numeric prefix argument ARG, recenter putting point on screen line ARG relative to the selected window. If ARG is negative, it counts up from the bottom of the window. (ARG should be less than the height of the window.) -If ARG is omitted or nil, then recenter with point on the middle line of -the selected window; if the variable `recenter-redisplay' is non-nil, -also erase the entire frame and redraw it (when `auto-resize-tool-bars' -is set to `grow-only', this resets the tool-bar's height to the minimum -height needed); if `recenter-redisplay' has the special value `tty', -then only tty frames are redrawn. +If ARG is omitted or nil, then recenter with point on the middle line +of the selected window; if REDISPLAY & `recenter-redisplay' are +non-nil, also erase the entire frame and redraw it (when +`auto-resize-tool-bars' is set to `grow-only', this resets the +tool-bar's height to the minimum height needed); if +`recenter-redisplay' has the special value `tty', then only tty frames +are redrawn. Interactively, REDISPLAY is always non-nil. Just C-u as prefix means put point in the center of the window and redisplay normally--don't erase and redraw the frame. */) - (register Lisp_Object arg) + (Lisp_Object arg, Lisp_Object redisplay) { struct window *w = XWINDOW (selected_window); struct buffer *buf = XBUFFER (w->contents); @@ -5916,6 +6531,9 @@ and redisplay normally--don't erase and redraw the frame. */) EMACS_INT iarg UNINIT; int this_scroll_margin; + /* For reasons why we signal an error here, see + https://lists.gnu.org/r/emacs-devel/2014-06/msg00053.html, + https://lists.gnu.org/r/emacs-devel/2014-06/msg00094.html. */ if (buf != current_buffer) error ("`recenter'ing a window that does not display current-buffer."); @@ -5924,7 +6542,8 @@ and redisplay normally--don't erase and redraw the frame. */) if (NILP (arg)) { - if (!NILP (Vrecenter_redisplay) + if (!NILP (redisplay) + && !NILP (Vrecenter_redisplay) && (!EQ (Vrecenter_redisplay, Qtty) || !NILP (Ftty_type (selected_frame)))) { @@ -5933,7 +6552,10 @@ and redisplay normally--don't erase and redraw the frame. */) /* Invalidate pixel data calculated for all compositions. */ for (i = 0; i < n_compositions; i++) composition_table[i]->font = NULL; -#if defined (HAVE_WINDOW_SYSTEM) && ! defined (USE_GTK) && ! defined (HAVE_NS) +#if defined (HAVE_WINDOW_SYSTEM) + WINDOW_XFRAME (w)->minimize_tab_bar_window_p = 1; +#endif +#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) WINDOW_XFRAME (w)->minimize_tool_bar_window_p = 1; #endif Fredraw_frame (WINDOW_FRAME (w)); @@ -5947,18 +6569,25 @@ and redisplay normally--don't erase and redraw the frame. */) else { arg = Fprefix_numeric_value (arg); - CHECK_NUMBER (arg); - iarg = XINT (arg); + CHECK_FIXNUM (arg); + iarg = XFIXNUM (arg); } /* Do this after making BUF current in case scroll_margin is buffer-local. */ this_scroll_margin = window_scroll_margin (w, MARGIN_IN_LINES); - /* Don't use redisplay code for initial frames, as the necessary - data structures might not be set up yet then. */ - if (!FRAME_INITIAL_P (XFRAME (w->frame))) + /* Don't use the display code for initial frames, as the necessary + data structures might not be set up yet then. Also don't use it + for buffers with very long lines, as it tremdously slows down + redisplay, especially when lines are truncated. */ + if (!FRAME_INITIAL_P (XFRAME (w->frame)) + && !current_buffer->long_line_optimizations_p) { + specpdl_ref count = SPECPDL_INDEX (); + + record_unwind_protect_void (unwind_display_working_on_window); + display_working_on_window_p = true; if (center_p) { struct it it; @@ -6021,6 +6650,7 @@ and redisplay normally--don't erase and redraw the frame. */) if (h <= 0) { bidi_unshelve_cache (itdata, false); + unbind_to (count, Qnil); return Qnil; } @@ -6037,7 +6667,7 @@ and redisplay normally--don't erase and redraw the frame. */) considered to be part of the visible height of the line. */ h += extra_line_spacing; - while (-it.current_y > h) + while (-it.current_y > h && it.what != IT_EOB) move_it_by_lines (&it, 1); charpos = IT_CHARPOS (it); @@ -6075,6 +6705,7 @@ and redisplay normally--don't erase and redraw the frame. */) bidi_unshelve_cache (itdata, false); } + unbind_to (count, Qnil); } else { @@ -6125,10 +6756,10 @@ pixels. */) struct window *w = decode_live_window (window); if (NILP (pixelwise)) - return make_number (window_box_width (w, TEXT_AREA) + return make_fixnum (window_box_width (w, TEXT_AREA) / FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w))); else - return make_number (window_box_width (w, TEXT_AREA)); + return make_fixnum (window_box_width (w, TEXT_AREA)); } DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height, @@ -6146,10 +6777,10 @@ pixels. */) struct window *w = decode_live_window (window); if (NILP (pixelwise)) - return make_number (window_box_height (w) + return make_fixnum (window_box_height (w) / FRAME_LINE_HEIGHT (WINDOW_XFRAME (w))); else - return make_number (window_box_height (w)); + return make_fixnum (window_box_height (w)); } DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line, @@ -6182,7 +6813,7 @@ from the top of the window. */) if (start < BEGV || start > ZV) { int height = window_internal_height (w); - Fvertical_motion (make_number (- (height / 2)), window, Qnil); + Fvertical_motion (make_fixnum (- (height / 2)), window, Qnil); set_marker_both (w->start, w->contents, PT, PT_BYTE); w->start_at_line_beg = !NILP (Fbolp ()); w->force_start = true; @@ -6196,7 +6827,7 @@ from the top of the window. */) XSETFASTINT (arg, lines / 2); else { - EMACS_INT iarg = XINT (Fprefix_numeric_value (arg)); + EMACS_INT iarg = XFIXNUM (Fprefix_numeric_value (arg)); if (iarg < 0) iarg = iarg + lines; @@ -6214,12 +6845,12 @@ from the top of the window. */) iarg = min (iarg, lines - this_scroll_margin - 1); #endif - arg = make_number (iarg); + arg = make_fixnum (iarg); } /* Skip past a partially visible first line. */ if (w->vscroll) - XSETINT (arg, XINT (arg) + 1); + XSETINT (arg, XFIXNUM (arg) + 1); return Fvertical_motion (arg, window, Qnil); } @@ -6232,7 +6863,7 @@ from the top of the window. */) struct save_window_data { - struct vectorlike_header header; + union vectorlike_header header; Lisp_Object selected_frame; Lisp_Object current_window; Lisp_Object f_current_buffer; @@ -6245,36 +6876,39 @@ struct save_window_data Lisp_Object saved_windows; /* All fields above are traced by the GC. - From `frame-cols' down, the fields are ignored by the GC. */ + After saved_windows, the fields are ignored by the GC. */ + /* We should be able to do without the following two. */ int frame_cols, frame_lines; - /* These two should get eventually replaced by their pixel + /* These three should get eventually replaced by their pixel counterparts. */ - int frame_menu_bar_lines, frame_tool_bar_lines; + int frame_menu_bar_lines, frame_tab_bar_lines, frame_tool_bar_lines; int frame_text_width, frame_text_height; /* These are currently unused. We need them as soon as we convert to pixels. */ - int frame_menu_bar_height, frame_tool_bar_height; - }; + int frame_menu_bar_height, frame_tab_bar_height, frame_tool_bar_height; + } GCALIGNED_STRUCT; /* This is saved as a Lisp_Vector. */ struct saved_window { - struct vectorlike_header header; + union vectorlike_header header; Lisp_Object window, buffer, start, pointm, old_pointm; Lisp_Object pixel_left, pixel_top, pixel_height, pixel_width; - Lisp_Object pixel_height_before_size_change, pixel_width_before_size_change; 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; + Lisp_Object vscroll; Lisp_Object parent, prev; Lisp_Object start_at_line_beg; Lisp_Object display_table; Lisp_Object left_margin_cols, right_margin_cols; - Lisp_Object left_fringe_width, right_fringe_width, fringes_outside_margins; - Lisp_Object scroll_bar_width, vertical_scroll_bar_type, dedicated; + Lisp_Object left_fringe_width, right_fringe_width; + Lisp_Object fringes_outside_margins, fringes_persistent; + Lisp_Object scroll_bar_width, vertical_scroll_bar_type; Lisp_Object scroll_bar_height, horizontal_scroll_bar_type; + Lisp_Object scroll_bars_persistent, dedicated; Lisp_Object combination_limit, window_parameters; }; @@ -6303,19 +6937,28 @@ DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_config } DEFUN ("set-window-configuration", Fset_window_configuration, - Sset_window_configuration, 1, 1, 0, + Sset_window_configuration, 1, 3, 0, doc: /* Set the configuration of windows and buffers as specified by CONFIGURATION. CONFIGURATION must be a value previously returned by `current-window-configuration' (which see). + +Normally, this function selects the frame of the CONFIGURATION, but if +DONT-SET-FRAME is non-nil, it leaves selected the frame which was +current at the start of the function. If DONT-SET-MINIWINDOW is non-nil, +the mini-window of the frame doesn't get set to the corresponding element +of CONFIGURATION. + If CONFIGURATION was made from a frame that is now deleted, only frame-independent values can be restored. In this case, the return value is nil. Otherwise the value is t. */) - (Lisp_Object configuration) + (Lisp_Object configuration, Lisp_Object dont_set_frame, + Lisp_Object dont_set_miniwindow) { register struct save_window_data *data; struct Lisp_Vector *saved_windows; Lisp_Object new_current_buffer; Lisp_Object frame; + Lisp_Object old_frame = selected_frame; struct frame *f; ptrdiff_t old_point = -1; USE_SAFE_ALLOCA; @@ -6380,12 +7023,6 @@ the return value is nil. Otherwise the value is t. */) 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 = false; - /* Records whether a window has changed its buffer wrt the - original configuration. */ - bool buffer_changed = false; /* Don't do this within the main loop below: This may call Lisp code and is thus potentially unsafe while input is blocked. */ @@ -6395,21 +7032,17 @@ the return value is nil. Otherwise the value is t. */) window = p->window; w = XWINDOW (window); - if (NILP (w->contents)) - /* A dead window that will be resurrected, the window - configuration will change. */ - window_changed = true; - if (BUFFERP (w->contents) && !EQ (w->contents, p->buffer) - && BUFFER_LIVE_P (XBUFFER (p->buffer))) + && BUFFER_LIVE_P (XBUFFER (p->buffer)) + && (NILP (Fminibufferp (p->buffer, Qnil)))) /* If a window we restore gets another buffer, record the window's old buffer. */ call1 (Qrecord_window_buffer, window); } - /* Disallow x_set_window_size, temporarily. */ - f->can_x_set_window_size = false; + /* Disallow set_window_size_hook, temporarily. */ + f->can_set_window_size = false; /* The mouse highlighting code could get screwed up if it runs during this. */ block_input (); @@ -6457,14 +7090,14 @@ the return value is nil. Otherwise the value is t. */) if (!NILP (p->parent)) wset_parent - (w, SAVED_WINDOW_N (saved_windows, XFASTINT (p->parent))->window); + (w, SAVED_WINDOW_N (saved_windows, XFIXNAT (p->parent))->window); else wset_parent (w, Qnil); if (!NILP (p->prev)) { wset_prev - (w, SAVED_WINDOW_N (saved_windows, XFASTINT (p->prev))->window); + (w, SAVED_WINDOW_N (saved_windows, XFIXNAT (p->prev))->window); wset_next (XWINDOW (w->prev), p->window); } else @@ -6472,7 +7105,7 @@ the return value is nil. Otherwise the value is t. */) wset_prev (w, Qnil); if (!NILP (w->parent)) wset_combination (XWINDOW (w->parent), - (XINT (p->total_cols) + (XFIXNUM (p->total_cols) != XWINDOW (w->parent)->total_cols), p->window); } @@ -6480,32 +7113,31 @@ the return value is nil. Otherwise the value is t. */) /* If we squirreled away the buffer, restore it now. */ if (BUFFERP (w->combination_limit)) wset_buffer (w, w->combination_limit); - w->pixel_left = XFASTINT (p->pixel_left); - w->pixel_top = XFASTINT (p->pixel_top); - w->pixel_width = XFASTINT (p->pixel_width); - w->pixel_height = XFASTINT (p->pixel_height); - w->pixel_width_before_size_change - = XFASTINT (p->pixel_width_before_size_change); - w->pixel_height_before_size_change - = XFASTINT (p->pixel_height_before_size_change); - w->left_col = XFASTINT (p->left_col); - w->top_line = XFASTINT (p->top_line); - w->total_cols = XFASTINT (p->total_cols); - w->total_lines = XFASTINT (p->total_lines); + w->pixel_left = XFIXNAT (p->pixel_left); + w->pixel_top = XFIXNAT (p->pixel_top); + w->pixel_width = XFIXNAT (p->pixel_width); + w->pixel_height = XFIXNAT (p->pixel_height); + w->left_col = XFIXNAT (p->left_col); + w->top_line = XFIXNAT (p->top_line); + w->total_cols = XFIXNAT (p->total_cols); + w->total_lines = XFIXNAT (p->total_lines); wset_normal_cols (w, p->normal_cols); wset_normal_lines (w, p->normal_lines); - w->hscroll = XFASTINT (p->hscroll); + w->hscroll = XFIXNAT (p->hscroll); w->suspend_auto_hscroll = !NILP (p->suspend_auto_hscroll); - w->min_hscroll = XFASTINT (p->min_hscroll); - w->hscroll_whole = XFASTINT (p->hscroll_whole); + w->min_hscroll = XFIXNAT (p->min_hscroll); + w->hscroll_whole = XFIXNAT (p->hscroll_whole); + w->vscroll = -XFIXNAT (p->vscroll); wset_display_table (w, p->display_table); - w->left_margin_cols = XINT (p->left_margin_cols); - w->right_margin_cols = XINT (p->right_margin_cols); - w->left_fringe_width = XINT (p->left_fringe_width); - w->right_fringe_width = XINT (p->right_fringe_width); + w->left_margin_cols = XFIXNUM (p->left_margin_cols); + w->right_margin_cols = XFIXNUM (p->right_margin_cols); + w->left_fringe_width = XFIXNUM (p->left_fringe_width); + w->right_fringe_width = XFIXNUM (p->right_fringe_width); w->fringes_outside_margins = !NILP (p->fringes_outside_margins); - w->scroll_bar_width = XINT (p->scroll_bar_width); - w->scroll_bar_height = XINT (p->scroll_bar_height); + w->fringes_persistent = !NILP (p->fringes_persistent); + w->scroll_bar_width = XFIXNUM (p->scroll_bar_width); + w->scroll_bar_height = XFIXNUM (p->scroll_bar_height); + w->scroll_bars_persistent = !NILP (p->scroll_bars_persistent); wset_vertical_scroll_bar_type (w, p->vertical_scroll_bar_type); wset_horizontal_scroll_bar_type (w, p->horizontal_scroll_bar_type); wset_dedicated (w, p->dedicated); @@ -6532,12 +7164,11 @@ 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 ((NILP (dont_set_miniwindow) || !MINI_WINDOW_P (w)) + && BUFFERP (p->buffer) && BUFFER_LIVE_P (XBUFFER (p->buffer))) + /* If saved buffer is alive, install it, unless it's a + minibuffer we explicitly prohibit. */ { - if (!EQ (w->contents, p->buffer)) - /* Record buffer configuration change. */ - buffer_changed = true; wset_buffer (w, p->buffer); w->start_at_line_beg = !NILP (p->start_at_line_beg); set_marker_restricted (w->start, p->start, w->contents); @@ -6571,8 +7202,6 @@ 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 = 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 @@ -6597,13 +7226,13 @@ the return value is nil. Otherwise the value is t. */) current when the window configuration was saved. */ if (EQ (XWINDOW (data->current_window)->contents, new_current_buffer)) set_marker_restricted (XWINDOW (data->current_window)->pointm, - make_number (old_point), + make_fixnum (old_point), XWINDOW (data->current_window)->contents); - /* In the following call to `select-window', prevent "swapping out + /* In the following call to select_window, prevent "swapping out point" in the old selected window using the buffer that has - been restored into it. We already swapped out that point from - that window's old buffer. + been restored into it. We already swapped out that point + from that window's old buffer. Do not record the buffer here. We do that in a separate call to select_window below. See also Bug#16207. */ @@ -6620,15 +7249,13 @@ the return value is nil. Otherwise the value is t. */) /* Now, free glyph matrices in windows that were not reused. */ for (i = 0; i < n_leaf_windows; i++) if (NILP (leaf_windows[i]->contents)) - { - free_window_matrices (leaf_windows[i]); - window_changed = true; - } + free_window_matrices (leaf_windows[i]); - /* Allow x_set_window_size again and apply frame size changes if - needed. */ - f->can_x_set_window_size = true; - adjust_frame_size (f, -1, -1, 1, false, Qset_window_configuration); + /* Allow set_window_size_hook again and resize frame's windows + if necessary. But change frame size only to preserve window + minimum sizes. */ + f->can_set_window_size = true; + adjust_frame_size (f, -1, -1, 4, false, Qset_window_configuration); adjust_frame_glyphs (f); unblock_input (); @@ -6646,63 +7273,58 @@ the return value is nil. Otherwise the value is t. */) 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 - selected window too, but that doesn't make the call to - Fselect_window above totally superfluous; it still sets f's + /* select_window will have made f the selected frame, so we + reselect the proper frame here. do_switch_frame will change + the selected window too, but that doesn't make the call to + select_window above totally superfluous; it still sets f's selected window. */ if (FRAME_LIVE_P (XFRAME (data->selected_frame))) - do_switch_frame (data->selected_frame, 0, 0, Qnil); - - 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 ‘set-window-configuration’ replaces them by two - 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) = 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); + do_switch_frame (NILP (dont_set_frame) + ? data->selected_frame + : old_frame + , 0, Qnil); } + FRAME_WINDOW_CHANGE (f) = true; + if (!NILP (new_current_buffer)) { Fset_buffer (new_current_buffer); /* If the new current buffer doesn't appear in the selected - window, go to its old point (see bug#12208). */ - if (!EQ (XWINDOW (data->current_window)->contents, new_current_buffer)) - Fgoto_char (make_number (old_point)); + window, go to its old point (Bug#12208). + + The original fix used data->current_window below which caused + false positives (compare Bug#31695) when data->current_window + is not on data->selected_frame. This happens, for example, + when read_minibuf restores the configuration of a stand-alone + minibuffer frame: After switching to the previously selected + "normal" frame, point of that frame's selected window jumped + unexpectedly because new_current_buffer is usually *not* + shown in data->current_window - the minibuffer frame's + selected window. Using selected_window instead fixes this + because do_switch_frame has set up selected_window already to + the "normal" frame's selected window and that window *does* + show new_current_buffer. */ + if (!EQ (XWINDOW (selected_window)->contents, new_current_buffer)) + Fgoto_char (make_fixnum (old_point)); } Vminibuf_scroll_window = data->minibuf_scroll_window; minibuf_selected_window = data->minibuf_selected_window; SAFE_FREE (); - return (FRAME_LIVE_P (f) ? Qt : Qnil); + return FRAME_LIVE_P (f) ? Qt : Qnil; } - void restore_window_configuration (Lisp_Object configuration) { - Fset_window_configuration (configuration); + if (CONSP (configuration)) + Fset_window_configuration (XCAR (configuration), + Fcar_safe (XCDR (configuration)), + Fcar_safe (Fcdr_safe (XCDR (configuration)))); + else + Fset_window_configuration (configuration, Qnil, Qnil); } @@ -6823,35 +7445,34 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, ptrdiff_t i) p = SAVED_WINDOW_N (vector, i); w = XWINDOW (window); - wset_temslot (w, make_number (i)); i++; + wset_temslot (w, make_fixnum (i)); i++; p->window = window; p->buffer = (WINDOW_LEAF_P (w) ? w->contents : Qnil); - p->pixel_left = make_number (w->pixel_left); - p->pixel_top = make_number (w->pixel_top); - p->pixel_width = make_number (w->pixel_width); - p->pixel_height = make_number (w->pixel_height); - p->pixel_width_before_size_change - = make_number (w->pixel_width_before_size_change); - p->pixel_height_before_size_change - = make_number (w->pixel_height_before_size_change); - p->left_col = make_number (w->left_col); - p->top_line = make_number (w->top_line); - p->total_cols = make_number (w->total_cols); - p->total_lines = make_number (w->total_lines); + p->pixel_left = make_fixnum (w->pixel_left); + p->pixel_top = make_fixnum (w->pixel_top); + p->pixel_width = make_fixnum (w->pixel_width); + p->pixel_height = make_fixnum (w->pixel_height); + p->left_col = make_fixnum (w->left_col); + p->top_line = make_fixnum (w->top_line); + p->total_cols = make_fixnum (w->total_cols); + p->total_lines = make_fixnum (w->total_lines); p->normal_cols = w->normal_cols; p->normal_lines = w->normal_lines; XSETFASTINT (p->hscroll, w->hscroll); p->suspend_auto_hscroll = w->suspend_auto_hscroll ? Qt : Qnil; XSETFASTINT (p->min_hscroll, w->min_hscroll); XSETFASTINT (p->hscroll_whole, w->hscroll_whole); + XSETFASTINT (p->vscroll, -w->vscroll); p->display_table = w->display_table; - p->left_margin_cols = make_number (w->left_margin_cols); - p->right_margin_cols = make_number (w->right_margin_cols); - p->left_fringe_width = make_number (w->left_fringe_width); - p->right_fringe_width = make_number (w->right_fringe_width); + p->left_margin_cols = make_fixnum (w->left_margin_cols); + p->right_margin_cols = make_fixnum (w->right_margin_cols); + p->left_fringe_width = make_fixnum (w->left_fringe_width); + p->right_fringe_width = make_fixnum (w->right_fringe_width); p->fringes_outside_margins = w->fringes_outside_margins ? Qt : Qnil; - p->scroll_bar_width = make_number (w->scroll_bar_width); - p->scroll_bar_height = make_number (w->scroll_bar_height); + p->fringes_persistent = w->fringes_persistent ? Qt : Qnil; + p->scroll_bar_width = make_fixnum (w->scroll_bar_width); + p->scroll_bar_height = make_fixnum (w->scroll_bar_height); + p->scroll_bars_persistent = w->scroll_bars_persistent ? Qt : Qnil; p->vertical_scroll_bar_type = w->vertical_scroll_bar_type; p->horizontal_scroll_bar_type = w->horizontal_scroll_bar_type; p->dedicated = w->dedicated; @@ -6873,7 +7494,7 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, ptrdiff_t i) hare = XCDR (hare); tortoise = XCDR (tortoise); - if (EQ (hare, tortoise)) + if (BASE_EQ (hare, tortoise)) /* Reset Vwindow_persistent_parameters to Qnil. */ { Vwindow_persistent_parameters = Qnil; @@ -6906,6 +7527,10 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, ptrdiff_t i) if (BUFFERP (w->contents)) { + bool window_point_insertion_type + = !NILP (buffer_local_value + (Qwindow_point_insertion_type, w->contents)); + /* Save w's value of point in the window configuration. If w is the selected window, then get the value of point from the buffer; pointm is garbage in the selected window. */ @@ -6916,12 +7541,8 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, ptrdiff_t i) else p->pointm = Fcopy_marker (w->pointm, Qnil); p->old_pointm = Fcopy_marker (w->old_pointm, Qnil); - XMARKER (p->pointm)->insertion_type - = !NILP (buffer_local_value /* Don't signal error if void. */ - (Qwindow_point_insertion_type, w->contents)); - XMARKER (p->old_pointm)->insertion_type - = !NILP (buffer_local_value /* Don't signal error if void. */ - (Qwindow_point_insertion_type, w->contents)); + XMARKER (p->pointm)->insertion_type = window_point_insertion_type; + XMARKER (p->old_pointm)->insertion_type = window_point_insertion_type; p->start = Fcopy_marker (w->start, Qnil); p->start_at_line_beg = w->start_at_line_beg ? Qt : Qnil; @@ -6958,22 +7579,20 @@ redirection (see `redirect-frame-focus'). The variable saved by this function. */) (Lisp_Object frame) { - Lisp_Object tem; - ptrdiff_t i, n_windows; - struct save_window_data *data; struct frame *f = decode_live_frame (frame); - - n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f))); - data = ALLOCATE_PSEUDOVECTOR (struct save_window_data, frame_cols, - PVEC_WINDOW_CONFIGURATION); - + ptrdiff_t n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f))); + struct save_window_data *data + = ALLOCATE_PSEUDOVECTOR (struct save_window_data, saved_windows, + PVEC_WINDOW_CONFIGURATION); data->frame_cols = FRAME_COLS (f); data->frame_lines = FRAME_LINES (f); data->frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f); + data->frame_tab_bar_lines = FRAME_TAB_BAR_LINES (f); data->frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f); data->frame_text_width = FRAME_TEXT_WIDTH (f); data->frame_text_height = FRAME_TEXT_HEIGHT (f); data->frame_menu_bar_height = FRAME_MENU_BAR_HEIGHT (f); + data->frame_tab_bar_height = FRAME_TAB_BAR_HEIGHT (f); data->frame_tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f); data->selected_frame = selected_frame; data->current_window = FRAME_SELECTED_WINDOW (f); @@ -6982,14 +7601,13 @@ saved by this function. */) data->minibuf_selected_window = minibuf_level > 0 ? minibuf_selected_window : Qnil; data->root_window = FRAME_ROOT_WINDOW (f); data->focus_frame = FRAME_FOCUS_FRAME (f); - tem = make_uninit_vector (n_windows); + Lisp_Object tem = make_nil_vector (n_windows); data->saved_windows = tem; - for (i = 0; i < n_windows; i++) - ASET (tem, i, - Fmake_vector (make_number (VECSIZE (struct saved_window)), Qnil)); + for (ptrdiff_t i = 0; i < n_windows; i++) + ASET (tem, i, make_nil_vector (VECSIZE (struct saved_window))); save_window_save (FRAME_ROOT_WINDOW (f), XVECTOR (tem), 0); XSETWINDOW_CONFIGURATION (tem, data); - return (tem); + return tem; } /* Called after W's margins, fringes or scroll bars was adjusted. */ @@ -7014,8 +7632,7 @@ extract_dimension (Lisp_Object dimension) { if (NILP (dimension)) return -1; - CHECK_RANGED_INTEGER (dimension, 0, INT_MAX); - return XINT (dimension); + return check_integer_range (dimension, 0, INT_MAX); } static struct window * @@ -7057,7 +7674,9 @@ reserve for the left marginal area. Optional third arg RIGHT-WIDTH does the same for the right marginal area. A nil width parameter means no margin. -Return t if any margin was actually changed and nil otherwise. */) +Leave margins unchanged if WINDOW is not large enough to accommodate +margins of the desired width. Return t if any margin was actually +changed and nil otherwise. */) (Lisp_Object window, Lisp_Object left_width, Lisp_Object right_width) { struct window *w = set_window_margins (decode_live_window (window), @@ -7078,9 +7697,9 @@ as nil. */) { struct window *w = decode_live_window (window); return Fcons (w->left_margin_cols - ? make_number (w->left_margin_cols) : Qnil, + ? make_fixnum (w->left_margin_cols) : Qnil, w->right_margin_cols - ? make_number (w->right_margin_cols) : Qnil); + ? make_fixnum (w->right_margin_cols) : Qnil); } @@ -7090,78 +7709,116 @@ as nil. */) ***********************************************************************/ static struct window * -set_window_fringes (struct window *w, Lisp_Object left_width, - Lisp_Object right_width, Lisp_Object outside_margins) +set_window_fringes (struct window *w, + Lisp_Object left_width, Lisp_Object right_width, + Lisp_Object outside_margins, Lisp_Object persistent) { - bool outside = !NILP (outside_margins); - int left = extract_dimension (left_width); - int right = extract_dimension (right_width); - - /* Do nothing on a tty or if nothing to actually change. */ - if (FRAME_WINDOW_P (WINDOW_XFRAME (w)) - && (w->left_fringe_width != left - || w->right_fringe_width != right - || w->fringes_outside_margins != outside)) + /* Do nothing on a tty. */ + if (!FRAME_WINDOW_P (WINDOW_XFRAME (w))) + return NULL; + else { - if (left > 0 || right > 0) + struct frame *f = XFRAME (WINDOW_FRAME (w)); + int old_left = WINDOW_LEFT_FRINGE_WIDTH (w); + int old_right = WINDOW_RIGHT_FRINGE_WIDTH (w); + int new_left = extract_dimension (left_width); + int new_right = extract_dimension (right_width); + bool outside = !NILP (outside_margins); + bool changed = false; + bool failed = false; + + /* Check dimensions of new fringes. Make changes only if they + fit the window's dimensions. */ + if ((WINDOW_PIXEL_WIDTH (w) + - WINDOW_MARGINS_WIDTH (w) + - WINDOW_SCROLL_BAR_AREA_WIDTH (w) + - WINDOW_RIGHT_DIVIDER_WIDTH (w) + - (new_left == -1 ? FRAME_LEFT_FRINGE_WIDTH (f) : new_left) + - (new_right == -1 ? FRAME_RIGHT_FRINGE_WIDTH (f) : new_right)) + >= MIN_SAFE_WINDOW_PIXEL_WIDTH (w)) + { + w->left_fringe_width = new_left; + w->right_fringe_width = new_right; + changed = new_left != old_left || new_right != old_right; + } + else + failed = true; + + /* Placing fringes outside margins. */ + if (outside != w->fringes_outside_margins) { - /* Don't change anything if new fringes don't fit. */ - if ((WINDOW_PIXEL_WIDTH (w) - - WINDOW_MARGINS_WIDTH (w) - - WINDOW_SCROLL_BAR_AREA_WIDTH (w) - - max (left, 0) - max (right, 0)) - < MIN_SAFE_WINDOW_PIXEL_WIDTH (w)) - return NULL; + w->fringes_outside_margins = outside; + changed = true; } - w->left_fringe_width = left; - w->right_fringe_width = right; - w->fringes_outside_margins = outside; + /* Make settings persistent unless we failed to apply some + changes. */ + if (!failed) + w->fringes_persistent = !NILP (persistent); - return w; + /* This is needed to trigger immediate redisplay of the window + when its fringes are changed, because fringes are redrawn + only if update_window is called, so we must trigger that even + if the window's glyph matrices did not change at all. */ + if (changed) + { + windows_or_buffers_changed = 35; + return w; + } + else + return NULL; } - else - return NULL; } DEFUN ("set-window-fringes", Fset_window_fringes, Sset_window_fringes, - 2, 4, 0, - doc: /* Set the fringe widths of window WINDOW. -WINDOW must be a live window and defaults to the selected one. + 2, 5, 0, + doc: /* Set fringes of specified WINDOW. +WINDOW must specify a live window and defaults to the selected one. Second arg LEFT-WIDTH specifies the number of pixels to reserve for the left fringe. Optional third arg RIGHT-WIDTH specifies the right fringe width. If a fringe width arg is nil, that means to use the frame's default fringe width. Default fringe widths can be set with the command `set-fringe-style'. + If optional fourth arg OUTSIDE-MARGINS is non-nil, draw the fringes outside of the display margins. By default, fringes are drawn between display marginal areas and the text area. -Return t if any fringe was actually changed and nil otherwise. */) - (Lisp_Object window, Lisp_Object left_width, - Lisp_Object right_width, Lisp_Object outside_margins) +Optional fifth argument PERSISTENT non-nil means that fringe settings +for WINDOW are persistent, i.e., remain unchanged when another buffer +is shown in WINDOW. PERSISTENT nil means that fringes are reset from +buffer local values when `set-window-buffer' is called on WINDOW with +the argument KEEP-MARGINS nil. + +Leave fringes unchanged if WINDOW is not large enough to accommodate +fringes of the desired width. Return t if any fringe was actually +changed and nil otherwise. */) + (Lisp_Object window, Lisp_Object left_width, Lisp_Object right_width, + Lisp_Object outside_margins, Lisp_Object persistent) { struct window *w - = set_window_fringes (decode_live_window (window), - left_width, right_width, outside_margins); + = set_window_fringes (decode_live_window (window), left_width, + right_width, outside_margins, persistent); return w ? (apply_window_adjustment (w), Qt) : Qnil; } DEFUN ("window-fringes", Fwindow_fringes, Swindow_fringes, 0, 1, 0, - doc: /* Get width of fringes of window WINDOW. + doc: /* Return fringe settings for specified WINDOW. WINDOW must be a live window and defaults to the selected one. -Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS). */) +Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS +PERSISTENT), see `set-window-fringes'. */) (Lisp_Object window) { struct window *w = decode_live_window (window); - return list3 (make_number (WINDOW_LEFT_FRINGE_WIDTH (w)), - make_number (WINDOW_RIGHT_FRINGE_WIDTH (w)), - WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) ? Qt : Qnil); + return list4 (make_fixnum (WINDOW_LEFT_FRINGE_WIDTH (w)), + make_fixnum (WINDOW_RIGHT_FRINGE_WIDTH (w)), + WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) ? Qt : Qnil, + w->fringes_persistent ? Qt : Qnil); } @@ -7173,97 +7830,128 @@ Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS). */) static struct window * set_window_scroll_bars (struct window *w, Lisp_Object width, Lisp_Object vertical_type, Lisp_Object height, - Lisp_Object horizontal_type) + Lisp_Object horizontal_type, Lisp_Object persistent) { - int iwidth = extract_dimension (width); - bool changed = false; - - if (iwidth == 0) - vertical_type = Qnil; - - if (!(NILP (vertical_type) - || EQ (vertical_type, Qleft) - || EQ (vertical_type, Qright) - || EQ (vertical_type, Qt))) - error ("Invalid type of vertical scroll bar"); - - if (w->scroll_bar_width != iwidth - || !EQ (w->vertical_scroll_bar_type, vertical_type)) + /* Do nothing on a tty. */ + if (!FRAME_WINDOW_P (WINDOW_XFRAME (w))) + return NULL; + else { - /* Don't change anything if new scroll bar won't fit. */ + struct frame *f = XFRAME (WINDOW_FRAME (w)); + int new_width = extract_dimension (width); + bool changed = false; + bool failed = false; + + if (new_width == 0) + vertical_type = Qnil; + else if (!(NILP (vertical_type) + || EQ (vertical_type, Qleft) + || EQ (vertical_type, Qright) + || EQ (vertical_type, Qt))) + error ("Invalid type of vertical scroll bar"); + + /* Check dimension of new scroll bar. Make changes only if it + fit the window's dimensions. */ if ((WINDOW_PIXEL_WIDTH (w) - WINDOW_MARGINS_WIDTH (w) - WINDOW_FRINGES_WIDTH (w) - - max (iwidth, 0)) + - WINDOW_RIGHT_DIVIDER_WIDTH (w) + - (new_width == -1 ? FRAME_SCROLL_BAR_AREA_WIDTH (f) : new_width)) >= MIN_SAFE_WINDOW_PIXEL_WIDTH (w)) { - w->scroll_bar_width = iwidth; + changed = (!EQ (vertical_type, w->vertical_scroll_bar_type) + || new_width != WINDOW_SCROLL_BAR_AREA_WIDTH (w)); wset_vertical_scroll_bar_type (w, vertical_type); - changed = true; + w->scroll_bar_width = new_width; } - } + else + failed = true; #if USE_HORIZONTAL_SCROLL_BARS - { - int iheight = extract_dimension (height); + int new_height = extract_dimension (height); - if (MINI_WINDOW_P (w) || iheight == 0) - horizontal_type = Qnil; + if ((MINI_WINDOW_P (w) && !EQ (horizontal_type, Qbottom)) + || new_height == 0) + horizontal_type = Qnil; - if (!(NILP (horizontal_type) - || EQ (horizontal_type, Qbottom) - || EQ (horizontal_type, Qt))) - error ("Invalid type of horizontal scroll bar"); + if (!(NILP (horizontal_type) + || EQ (horizontal_type, Qbottom) + || EQ (horizontal_type, Qt))) + error ("Invalid type of horizontal scroll bar"); - if (w->scroll_bar_height != iheight - || !EQ (w->horizontal_scroll_bar_type, horizontal_type)) - { - /* Don't change anything if new scroll bar won't fit. */ - if ((WINDOW_PIXEL_HEIGHT (w) - - WINDOW_HEADER_LINE_HEIGHT (w) - - WINDOW_MODE_LINE_HEIGHT (w) - - max (iheight, 0)) - >= MIN_SAFE_WINDOW_PIXEL_HEIGHT (w)) - { - w->scroll_bar_height = iheight; - wset_horizontal_scroll_bar_type (w, horizontal_type); - changed = true; - } - } - } + /* Don't change anything if new scroll bar won't fit. */ + if ((WINDOW_PIXEL_HEIGHT (w) + - WINDOW_TAB_LINE_HEIGHT (w) + - WINDOW_HEADER_LINE_HEIGHT (w) + - WINDOW_MODE_LINE_HEIGHT (w) + - (new_height == -1 ? FRAME_SCROLL_BAR_AREA_HEIGHT (f) : new_height)) + >= MIN_SAFE_WINDOW_PIXEL_HEIGHT (w)) + { + changed = (changed + || !EQ (horizontal_type, w->horizontal_scroll_bar_type) + || new_height != WINDOW_SCROLL_BAR_AREA_HEIGHT (w)); + wset_horizontal_scroll_bar_type (w, horizontal_type); + w->scroll_bar_height = new_height; + } + else + failed = true; #else - wset_horizontal_scroll_bar_type (w, Qnil); + wset_horizontal_scroll_bar_type (w, Qnil); #endif - return changed ? w : NULL; + /* Make settings persistent unless we failed to apply some + changes. */ + if (!failed) + w->scroll_bars_persistent = !NILP (persistent); + + /* This is needed to trigger immediate redisplay of the window when + scroll bars are changed, because scroll bars are redisplayed only + if more than a single window needs to be considered, see + redisplay_internal. */ + if (changed) + wset_redisplay (w); + + return changed ? w : NULL; + } } DEFUN ("set-window-scroll-bars", Fset_window_scroll_bars, - Sset_window_scroll_bars, 1, 5, 0, - doc: /* Set width and type of scroll bars of window WINDOW. -WINDOW must be a live window and defaults to the selected one. + Sset_window_scroll_bars, 1, 6, 0, + doc: /* Set width and type of scroll bars of specified WINDOW. +WINDOW must specify a live window and defaults to the selected one. -Second parameter WIDTH specifies the pixel width for the vertical scroll +Second argument WIDTH specifies the pixel width for the vertical scroll bar. If WIDTH is nil, use the scroll bar width of WINDOW's frame. -Third parameter VERTICAL-TYPE specifies the type of the vertical scroll +Third argument VERTICAL-TYPE specifies the type of the vertical scroll bar: left, right, nil or t where nil means to not display a vertical scroll bar on WINDOW and t means to use WINDOW frame's vertical scroll bar type. -Fourth parameter HEIGHT specifies the pixel height for the horizontal +Fourth argument HEIGHT specifies the pixel height for the horizontal scroll bar. If HEIGHT is nil, use the scroll bar height of WINDOW's -frame. Fifth parameter HORIZONTAL-TYPE specifies the type of the -horizontal scroll bar: bottom, nil, or t where nil means to not display -a horizontal scroll bar on WINDOW and t means to use WINDOW frame's -horizontal scroll bar type. - +frame. Fifth argument HORIZONTAL-TYPE specifies the type of the +horizontal scroll bar: bottom, nil, or t where nil means to not +display a horizontal scroll bar on WINDOW and t means to use WINDOW +frame's horizontal scroll bar type. If WINDOW is a mini window, t +effectively behaves like nil. HORIZONTAL-TYPE must equal bottom in +order to show a scroll bar for mini windows. + +Optional sixth argument PERSISTENT non-nil means that scroll bar +settings for WINDOW are persistent, i.e., remain unchanged when +another buffer is shown in WINDOW. PERSISTENT nil means that scroll +bars are reset from buffer local values when `set-window-buffer' is +called on WINDOW with the argument KEEP-MARGINS nil. + +If WINDOW is not large enough to accommodate a scroll bar of the +desired dimension, leave the corresponding scroll bar unchanged. Return t if scroll bars were actually changed and nil otherwise. */) (Lisp_Object window, Lisp_Object width, Lisp_Object vertical_type, - Lisp_Object height, Lisp_Object horizontal_type) + Lisp_Object height, Lisp_Object horizontal_type, Lisp_Object persistent) { struct window *w = set_window_scroll_bars (decode_live_window (window), - width, vertical_type, height, horizontal_type); + width, vertical_type, height, + horizontal_type, persistent); return w ? (apply_window_adjustment (w), Qt) : Qnil; } @@ -7274,23 +7962,24 @@ DEFUN ("window-scroll-bars", Fwindow_scroll_bars, Swindow_scroll_bars, WINDOW must be a live window and defaults to the selected one. Value is a list of the form (WIDTH COLUMNS VERTICAL-TYPE HEIGHT LINES -HORIZONTAL-TYPE). If WIDTH or HEIGHT is nil or VERTICAL-TYPE or -HORIZONTAL-TYPE is t, the window is using the frame's corresponding -value. */) +HORIZONTAL-TYPE PERSISTENT), see `set-window-scroll-bars'. If WIDTH +or HEIGHT is nil or VERTICAL-TYPE or HORIZONTAL-TYPE is t, WINDOW is +using the frame's corresponding value. */) (Lisp_Object window) { struct window *w = decode_live_window (window); return Fcons (((w->scroll_bar_width >= 0) - ? make_number (w->scroll_bar_width) + ? make_fixnum (w->scroll_bar_width) : Qnil), - list5 (make_number (WINDOW_SCROLL_BAR_COLS (w)), - w->vertical_scroll_bar_type, - ((w->scroll_bar_height >= 0) - ? make_number (w->scroll_bar_height) - : Qnil), - make_number (WINDOW_SCROLL_BAR_LINES (w)), - w->horizontal_scroll_bar_type)); + Fcons (make_fixnum (WINDOW_SCROLL_BAR_COLS (w)), + list5 (w->vertical_scroll_bar_type, + ((w->scroll_bar_height >= 0) + ? make_fixnum (w->scroll_bar_height) + : Qnil), + make_fixnum (WINDOW_SCROLL_BAR_LINES (w)), + w->horizontal_scroll_bar_type, + w->scroll_bars_persistent ? Qt : Qnil))); } /*********************************************************************** @@ -7299,6 +7988,8 @@ value. */) DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 2, 0, doc: /* Return the amount by which WINDOW is scrolled vertically. +This takes effect when displaying tall lines or images. + If WINDOW is omitted or nil, it defaults to the selected window. Normally, value is a multiple of the canonical character height of WINDOW; optional second arg PIXELS-P means value is measured in pixels. */) @@ -7311,29 +8002,35 @@ optional second arg PIXELS-P means value is measured in pixels. */) if (FRAME_WINDOW_P (f)) result = (NILP (pixels_p) ? FRAME_CANON_Y_FROM_PIXEL_Y (f, -w->vscroll) - : make_number (-w->vscroll)); + : make_fixnum (-w->vscroll)); else - result = make_number (0); + result = make_fixnum (0); return result; } DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll, - 2, 3, 0, + 2, 4, 0, doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL. +This takes effect when displaying tall lines or images. + WINDOW nil means use the selected window. Normally, VSCROLL is a non-negative multiple of the canonical character height of WINDOW; optional third arg PIXELS-P non-nil means that VSCROLL is in pixels. If PIXELS-P is nil, VSCROLL may have to be rounded so that it corresponds to an integral number of pixels. The return value is the result of this rounding. -If PIXELS-P is non-nil, the return value is VSCROLL. */) - (Lisp_Object window, Lisp_Object vscroll, Lisp_Object pixels_p) +If PIXELS-P is non-nil, the return value is VSCROLL. + +PRESERVE-VSCROLL-P makes setting the start of WINDOW preserve the +vscroll if its start is "frozen" due to a resized mini-window. */) + (Lisp_Object window, Lisp_Object vscroll, Lisp_Object pixels_p, + Lisp_Object preserve_vscroll_p) { struct window *w = decode_live_window (window); struct frame *f = XFRAME (w->frame); - CHECK_NUMBER_OR_FLOAT (vscroll); + CHECK_NUMBER (vscroll); if (FRAME_WINDOW_P (f)) { @@ -7353,7 +8050,12 @@ If PIXELS-P is non-nil, the return value is VSCROLL. */) /* Prevent redisplay shortcuts. */ XBUFFER (w->contents)->prevent_redisplay_optimizations_p = true; + + /* Mark W for redisplay. (bug#55299) */ + wset_redisplay (w); } + + w->preserve_vscroll_p = !NILP (preserve_vscroll_p); } return Fwindow_vscroll (window, pixels_p); @@ -7405,19 +8107,17 @@ foreach_window_1 (struct window *w, bool (*fn) (struct window *, void *), /* Return true if window configurations CONFIGURATION1 and CONFIGURATION2 describe the same state of affairs. This is used by Fequal. - IGNORE_POSITIONS means ignore non-matching scroll positions - and the like. + Ignore non-matching scroll positions and the like. This ignores a couple of things like the dedication status of window, combination_limit and the like. This might have to be fixed. */ -bool +static bool compare_window_configurations (Lisp_Object configuration1, - Lisp_Object configuration2, - bool ignore_positions) + Lisp_Object configuration2) { - register struct save_window_data *d1, *d2; + struct save_window_data *d1, *d2; struct Lisp_Vector *sws1, *sws2; ptrdiff_t i; @@ -7435,9 +8135,6 @@ compare_window_configurations (Lisp_Object configuration1, || d1->frame_menu_bar_lines != d2->frame_menu_bar_lines || !EQ (d1->selected_frame, d2->selected_frame) || !EQ (d1->f_current_buffer, d2->f_current_buffer) - || (!ignore_positions - && (!EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window) - || !EQ (d1->minibuf_selected_window, d2->minibuf_selected_window))) || !EQ (d1->focus_frame, d2->focus_frame) /* Verify that the two configurations have the same number of windows. */ || sws1->header.size != sws2->header.size) @@ -7470,47 +8167,92 @@ compare_window_configurations (Lisp_Object configuration1, equality. */ || !EQ (sw1->parent, sw2->parent) || !EQ (sw1->prev, sw2->prev) - || (!ignore_positions - && (!EQ (sw1->hscroll, sw2->hscroll) - || !EQ (sw1->min_hscroll, sw2->min_hscroll) - || !EQ (sw1->start_at_line_beg, sw2->start_at_line_beg) - || NILP (Fequal (sw1->start, sw2->start)) - || NILP (Fequal (sw1->pointm, sw2->pointm)))) || !EQ (sw1->left_margin_cols, sw2->left_margin_cols) || !EQ (sw1->right_margin_cols, sw2->right_margin_cols) || !EQ (sw1->left_fringe_width, sw2->left_fringe_width) || !EQ (sw1->right_fringe_width, sw2->right_fringe_width) || !EQ (sw1->fringes_outside_margins, sw2->fringes_outside_margins) + || !EQ (sw1->fringes_persistent, sw2->fringes_persistent) || !EQ (sw1->scroll_bar_width, sw2->scroll_bar_width) || !EQ (sw1->scroll_bar_height, sw2->scroll_bar_height) || !EQ (sw1->vertical_scroll_bar_type, sw2->vertical_scroll_bar_type) - || !EQ (sw1->horizontal_scroll_bar_type, sw2->horizontal_scroll_bar_type)) + || !EQ (sw1->horizontal_scroll_bar_type, sw2->horizontal_scroll_bar_type) + || !EQ (sw1->scroll_bars_persistent, sw2->scroll_bars_persistent)) return false; } return true; } -DEFUN ("compare-window-configurations", Fcompare_window_configurations, - Scompare_window_configurations, 2, 2, 0, - doc: /* Compare two window configurations as regards the structure of windows. -This function ignores details such as the values of point -and scrolling positions. */) +DEFUN ("window-configuration-equal-p", Fwindow_configuration_equal_p, + Swindow_configuration_equal_p, 2, 2, 0, + doc: /* Say whether two window configurations have the same window layout. +This function ignores details such as the values of point and +scrolling positions. */) (Lisp_Object x, Lisp_Object y) { - if (compare_window_configurations (x, y, true)) + if (compare_window_configurations (x, y)) return Qt; return Qnil; } + +static void init_window_once_for_pdumper (void); + void init_window_once (void) { + minibuf_window = Qnil; + staticpro (&minibuf_window); + + selected_window = Qnil; + staticpro (&selected_window); + + Vwindow_list = Qnil; + staticpro (&Vwindow_list); + + minibuf_selected_window = Qnil; + staticpro (&minibuf_selected_window); + + pdumper_do_now_and_after_late_load (init_window_once_for_pdumper); +} + +static void init_window_once_for_pdumper (void) +{ + window_scroll_pixel_based_preserve_x = -1; + window_scroll_pixel_based_preserve_y = -1; + window_scroll_preserve_hpos = -1; + window_scroll_preserve_vpos = -1; + PDUMPER_IGNORE (sequence_number); + + PDUMPER_RESET_LV (minibuf_window, Qnil); + PDUMPER_RESET_LV (selected_window, Qnil); + PDUMPER_RESET_LV (Vwindow_list, Qnil); + PDUMPER_RESET_LV (minibuf_selected_window, Qnil); + + /* Hack: if mode_line_in_non_selected_windows is true (which it may + be, if we're restoring from a dump) the guts of + make_initial_frame will try to access selected_window, which is + invalid at this point, and lose. For the purposes of creating + the initial frame and window, this variable must be false. */ + bool old_mode_line_in_non_selected_windows; + + /* Snapshot dumped_with_pdumper to suppress compiler warning. */ + bool saved_dumped_with_pdumper = dumped_with_pdumper_p (); + if (saved_dumped_with_pdumper) + { + old_mode_line_in_non_selected_windows + = mode_line_in_non_selected_windows; + mode_line_in_non_selected_windows = false; + } struct frame *f = make_initial_frame (); + if (saved_dumped_with_pdumper) + mode_line_in_non_selected_windows = + old_mode_line_in_non_selected_windows; XSETFRAME (selected_frame, f); - Vterminal_frame = selected_frame; + old_selected_frame = Vterminal_frame = selected_frame; minibuf_window = f->minibuffer_window; - selected_window = f->selected_window; + old_selected_window = selected_window = f->selected_window; } void @@ -7530,6 +8272,11 @@ syms_of_window (void) Fput (Qscroll_down, Qscroll_command, Qt); DEFSYM (Qwindow_configuration_change_hook, "window-configuration-change-hook"); + DEFSYM (Qwindow_state_change_hook, "window-state-change-hook"); + DEFSYM (Qwindow_state_change_functions, "window-state-change-functions"); + DEFSYM (Qwindow_size_change_functions, "window-size-change-functions"); + DEFSYM (Qwindow_buffer_change_functions, "window-buffer-change-functions"); + DEFSYM (Qwindow_selection_change_functions, "window-selection-change-functions"); DEFSYM (Qwindowp, "windowp"); DEFSYM (Qwindow_configuration_p, "window-configuration-p"); DEFSYM (Qwindow_live_p, "window-live-p"); @@ -7539,7 +8286,7 @@ syms_of_window (void) DEFSYM (Qwindow__resize_root_window, "window--resize-root-window"); DEFSYM (Qwindow__resize_root_window_vertically, "window--resize-root-window-vertically"); - DEFSYM (Qwindow__sanitize_window_sizes, "window--sanitize-window-sizes"); + DEFSYM (Qwindow__resize_mini_frame, "window--resize-mini-frame"); DEFSYM (Qwindow__pixel_to_total, "window--pixel-to-total"); DEFSYM (Qsafe, "safe"); DEFSYM (Qdisplay_buffer, "display-buffer"); @@ -7555,16 +8302,8 @@ syms_of_window (void) DEFSYM (Qmark_for_redisplay, "mark-for-redisplay"); DEFSYM (Qmode_line_format, "mode-line-format"); DEFSYM (Qheader_line_format, "header-line-format"); - - staticpro (&Vwindow_list); - - minibuf_selected_window = Qnil; - staticpro (&minibuf_selected_window); - - window_scroll_pixel_based_preserve_x = -1; - window_scroll_pixel_based_preserve_y = -1; - window_scroll_preserve_hpos = -1; - window_scroll_preserve_vpos = -1; + DEFSYM (Qtab_line_format, "tab-line-format"); + DEFSYM (Qno_other_window, "no-other-window"); DEFVAR_LISP ("temp-buffer-show-function", Vtemp_buffer_show_function, doc: /* Non-nil means call as function to display a help buffer. @@ -7588,6 +8327,14 @@ is displayed in the `mode-line' face. */); doc: /* If this is a live buffer, \\[scroll-other-window] should scroll its window. */); Vother_window_scroll_buffer = Qnil; + DEFVAR_LISP ("other-window-scroll-default", Vother_window_scroll_default, + doc: /* Function that provides the window to scroll by \\[scroll-other-window]. +The function `other-window-for-scrolling' first tries to use +`minibuffer-scroll-window' and `other-window-scroll-buffer'. +But when both are nil, then by default it uses a neighboring window. +This variable is intended to get another default instead of `next-window'. */); + Vother_window_scroll_default = Qnil; + DEFVAR_BOOL ("auto-window-vscroll", auto_window_vscroll_p, doc: /* Non-nil means to automatically adjust `window-vscroll' to view tall lines. */); auto_window_vscroll_p = true; @@ -7599,39 +8346,121 @@ is displayed in the `mode-line' face. */); DEFVAR_LISP ("scroll-preserve-screen-position", Vscroll_preserve_screen_position, doc: /* Controls if scroll commands move point to keep its screen position unchanged. + A value of nil means point does not keep its screen position except at the scroll margin or window boundary respectively. + A value of t means point keeps its screen position if the scroll command moved it vertically out of the window, e.g. when scrolling -by full screens. +by full screens. If point is within `next-screen-context-lines' lines +from the edges of the window, point will typically not keep its screen +position when doing commands like `scroll-up-command'/`scroll-down-command' +and the like. + Any other value means point always keeps its screen position. Scroll commands should have the `scroll-command' property on their symbols to be controlled by this variable. */); Vscroll_preserve_screen_position = Qnil; DEFVAR_LISP ("window-point-insertion-type", Vwindow_point_insertion_type, - doc: /* Type of marker to use for `window-point'. */); + doc: /* Insertion type of marker to use for `window-point'. +See `marker-insertion-type' for the meaning of the possible values. */); Vwindow_point_insertion_type = Qnil; - DEFSYM (Qwindow_point_insertion_type, "window_point_insertion_type"); - - DEFVAR_LISP ("window-configuration-change-hook", - Vwindow_configuration_change_hook, - doc: /* Functions to call when window configuration changes. -The buffer-local part is run once per window, with the relevant window -selected; while the global part is run only once for the modified frame, -with the relevant frame selected. */); - Vwindow_configuration_change_hook = Qnil; + DEFSYM (Qwindow_point_insertion_type, "window-point-insertion-type"); + + DEFVAR_LISP ("window-buffer-change-functions", Vwindow_buffer_change_functions, + doc: /* Functions called during redisplay when window buffers have changed. +The value should be a list of functions that take one argument. + +Functions specified buffer-locally are called for each window showing +the corresponding buffer if and only if that window has been added or +changed its buffer since the last redisplay. In this case the window +is passed as argument. + +Functions specified by the default value are called for each frame if +at least one window on that frame has been added, deleted or changed +its buffer since the last redisplay. In this case the frame is passed +as argument. */); + Vwindow_buffer_change_functions = Qnil; DEFVAR_LISP ("window-size-change-functions", Vwindow_size_change_functions, - doc: /* Functions called during redisplay, if window sizes have changed. + doc: /* Functions called during redisplay when 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. */); + +Functions specified buffer-locally are called for each window showing +the corresponding buffer if and only if that window has been added or +changed its buffer or its total or body size since the last redisplay. +In this case the window is passed as argument. + +Functions specified by the default value are called for each frame if +at least one window on that frame has been added or changed its buffer +or its total or body size since the last redisplay. In this case the +frame is passed as argument. + +For instance, to hide the title bar when the frame is maximized, you +can add `frame-hide-title-bar-when-maximized' to this variable. */); Vwindow_size_change_functions = Qnil; + DEFVAR_LISP ("window-selection-change-functions", Vwindow_selection_change_functions, + doc: /* Functions called during redisplay when the selected window has changed. +The value should be a list of functions that take one argument. + +Functions specified buffer-locally are called for each window showing +the corresponding buffer if and only if that window has been selected +or deselected since the last redisplay. In this case the window is +passed as argument. + +Functions specified by the default value are called for each frame if +the frame's selected window has changed since the last redisplay. In +this case the frame is passed as argument. */); + Vwindow_selection_change_functions = Qnil; + + DEFVAR_LISP ("window-state-change-functions", Vwindow_state_change_functions, + doc: /* Functions called during redisplay when the window state changed. +The value should be a list of functions that take one argument. + +Functions specified buffer-locally are called for each window showing +the corresponding buffer if and only if that window has been added, +resized, changed its buffer or has been (de-)selected since the last +redisplay. In this case the window is passed as argument. + +Functions specified by the default value are called for each frame if +at least one window on that frame has been added, deleted, changed its +buffer or its total or body size or the frame has been (de-)selected, +its selected window has changed or the window state change flag has +been set for this frame since the last redisplay. In this case the +frame is passed as argument. */); + Vwindow_state_change_functions = Qnil; + + DEFVAR_LISP ("window-state-change-hook", Vwindow_state_change_hook, + doc: /* Functions called during redisplay when the window state changed. +The value should be a list of functions that take no argument. + +This hook is called during redisplay when at least one window has been +added, deleted, (de-)selected, changed its buffer or its total or body +size or the window state change flag has been set for at least one +frame. This hook is called after all other window change functions +have been run and should be used only if a function should react to +changes that happened on at least two frames since last redisplay or +the function intends to change the window configuration. */); + Vwindow_state_change_hook = Qnil; + + DEFVAR_LISP ("window-configuration-change-hook", Vwindow_configuration_change_hook, + doc: /* Functions called during redisplay when window configuration has changed. +The value should be a list of functions that take no argument. + +Functions specified buffer-locally are called for each window showing +the corresponding buffer if at least one window on that frame has been +added, deleted or changed its buffer or its total or body size since +the last redisplay. Each call is performed with the window showing +the buffer temporarily selected. + +Functions specified by the default value are called for each frame if +at least one window on that frame has been added, deleted or changed +its buffer or its total or body size since the last redisplay. Each +call is performed with the frame temporarily selected. */); + Vwindow_configuration_change_hook = 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 @@ -7732,7 +8561,7 @@ pixelwise even if this option is nil. */); window_resize_pixelwise = false; DEFVAR_BOOL ("fast-but-imprecise-scrolling", - Vfast_but_imprecise_scrolling, + fast_but_imprecise_scrolling, doc: /* When non-nil, accelerate scrolling operations. This comes into play when scrolling rapidly over previously unfontified buffer regions. Only those portions of the buffer which @@ -7740,9 +8569,10 @@ are actually going to be displayed get fontified. Note that this optimization can cause the portion of the buffer displayed after a scrolling operation to be somewhat inaccurate. */); - Vfast_but_imprecise_scrolling = false; + fast_but_imprecise_scrolling = false; defsubr (&Sselected_window); + defsubr (&Sold_selected_window); defsubr (&Sminibuffer_window); defsubr (&Swindow_minibuffer_p); defsubr (&Swindowp); @@ -7752,10 +8582,12 @@ displayed after a scrolling operation to be somewhat inaccurate. */); defsubr (&Sframe_root_window); defsubr (&Sframe_first_window); defsubr (&Sframe_selected_window); + defsubr (&Sframe_old_selected_window); defsubr (&Sset_frame_selected_window); defsubr (&Spos_visible_in_window_p); defsubr (&Swindow_line_height); defsubr (&Swindow_buffer); + defsubr (&Swindow_old_buffer); defsubr (&Swindow_parent); defsubr (&Swindow_top_child); defsubr (&Swindow_left_child); @@ -7766,8 +8598,10 @@ displayed after a scrolling operation to be somewhat inaccurate. */); defsubr (&Swindow_use_time); defsubr (&Swindow_pixel_width); defsubr (&Swindow_pixel_height); - defsubr (&Swindow_pixel_width_before_size_change); - defsubr (&Swindow_pixel_height_before_size_change); + defsubr (&Swindow_old_pixel_width); + defsubr (&Swindow_old_pixel_height); + defsubr (&Swindow_old_body_pixel_width); + defsubr (&Swindow_old_body_pixel_height); defsubr (&Swindow_total_width); defsubr (&Swindow_total_height); defsubr (&Swindow_normal_size); @@ -7787,10 +8621,9 @@ displayed after a scrolling operation to be somewhat inaccurate. */); defsubr (&Swindow_body_width); defsubr (&Swindow_hscroll); defsubr (&Sset_window_hscroll); - defsubr (&Swindow_redisplay_end_trigger); - defsubr (&Sset_window_redisplay_end_trigger); defsubr (&Swindow_mode_line_height); defsubr (&Swindow_header_line_height); + defsubr (&Swindow_tab_line_height); defsubr (&Swindow_right_divider_width); defsubr (&Swindow_bottom_divider_width); defsubr (&Swindow_scroll_bar_width); @@ -7825,7 +8658,6 @@ displayed after a scrolling operation to be somewhat inaccurate. */); defsubr (&Sscroll_left); defsubr (&Sscroll_right); defsubr (&Sother_window_for_scrolling); - defsubr (&Sscroll_other_window); defsubr (&Sminibuffer_selected_window); defsubr (&Srecenter); defsubr (&Swindow_text_width); @@ -7843,7 +8675,8 @@ displayed after a scrolling operation to be somewhat inaccurate. */); defsubr (&Swindow_scroll_bars); defsubr (&Swindow_vscroll); defsubr (&Sset_window_vscroll); - defsubr (&Scompare_window_configurations); + defsubr (&Swindow_configuration_equal_p); + defsubr (&Swindow_bump_use_time); defsubr (&Swindow_list); defsubr (&Swindow_list_1); defsubr (&Swindow_prev_buffers); @@ -7854,14 +8687,3 @@ displayed after a scrolling operation to be somewhat inaccurate. */); defsubr (&Swindow_parameter); defsubr (&Sset_window_parameter); } - -void -keys_of_window (void) -{ - initial_define_key (control_x_map, '<', "scroll-left"); - initial_define_key (control_x_map, '>', "scroll-right"); - - initial_define_key (global_map, Ctl ('V'), "scroll-up-command"); - initial_define_key (meta_map, Ctl ('V'), "scroll-other-window"); - initial_define_key (meta_map, 'v', "scroll-down-command"); -} |