X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/2d3c9015c70fd05ac1bec42cc59d57c3fb6b82b5..bf90e9ac7caec15b0f111e0bb67e311233f3a795:/src/window.c diff --git a/src/window.c b/src/window.c index 8a608433ed..45dfb9ea1c 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-2014 Free Software + Copyright (C) 1985-1987, 1993-1998, 2000-2015 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -52,6 +52,7 @@ static Lisp_Object Qrecord_window_buffer; static Lisp_Object Qwindow_deletable_p, Qdelete_window, Qdisplay_buffer; static Lisp_Object Qreplace_buffer_in_windows, Qget_mru_window; static Lisp_Object Qwindow_resize_root_window, Qwindow_resize_root_window_vertically; +static Lisp_Object Qwindow_sanitize_window_sizes; static Lisp_Object Qwindow_pixel_to_total; static Lisp_Object Qscroll_up, Qscroll_down, Qscroll_command; static Lisp_Object Qsafe, Qabove, Qbelow, Qwindow_size, Qclone_of; @@ -87,7 +88,7 @@ static struct window *set_window_fringes (struct window *, 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 @@ -143,66 +144,85 @@ wset_combination_limit (struct window *w, Lisp_Object val) { w->combination_limit = val; } + static void wset_dedicated (struct window *w, Lisp_Object val) { w->dedicated = val; } + static void wset_display_table (struct window *w, Lisp_Object val) { w->display_table = val; } + static void wset_new_normal (struct window *w, Lisp_Object val) { w->new_normal = val; } + static void wset_new_total (struct window *w, Lisp_Object val) { w->new_total = val; } + static void wset_normal_cols (struct window *w, Lisp_Object val) { w->normal_cols = val; } + static void wset_normal_lines (struct window *w, Lisp_Object val) { w->normal_lines = val; } + static void wset_parent (struct window *w, Lisp_Object val) { w->parent = val; } + static void wset_pointm (struct window *w, Lisp_Object val) { w->pointm = val; } + +static void +wset_old_pointm (struct window *w, Lisp_Object val) +{ + w->old_pointm = val; +} + static void wset_start (struct window *w, Lisp_Object val) { w->start = val; } + static void wset_temslot (struct window *w, Lisp_Object val) { w->temslot = val; } + static void wset_vertical_scroll_bar_type (struct window *w, Lisp_Object val) { w->vertical_scroll_bar_type = val; } + static void wset_window_parameters (struct window *w, Lisp_Object val) { w->window_parameters = val; } + static void wset_combination (struct window *w, bool horflag, Lisp_Object val) { @@ -309,7 +329,7 @@ DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0, DEFUN ("window-valid-p", Fwindow_valid_p, Swindow_valid_p, 1, 1, 0, doc: /* Return t if OBJECT is a valid window and nil otherwise. A valid window is either a window that displays a buffer or an internal -window. Deleted windows are not live. */) +window. Windows that have been deleted are not valid. */) (Lisp_Object object) { return WINDOW_VALID_P (object) ? Qt : Qnil; @@ -790,7 +810,12 @@ total width of WINDOW. */) DEFUN ("window-new-total", Fwindow_new_total, Swindow_new_total, 0, 1, 0, doc: /* Return the new total size of window WINDOW. -WINDOW must be a valid window and defaults to the selected one. */) +WINDOW must be a valid window and defaults to the selected one. + +The new total size of WINDOW is the value set by the last call of +`set-window-new-total' for WINDOW. If it is valid, it will be shortly +installed as WINDOW's total height (see `window-total-height') or total +width (see `window-total-width'). */) (Lisp_Object window) { return decode_valid_window (window)->new_total; @@ -799,7 +824,25 @@ WINDOW must be a valid window and defaults to the selected one. */) DEFUN ("window-normal-size", Fwindow_normal_size, Swindow_normal_size, 0, 2, 0, doc: /* Return the normal height of window WINDOW. WINDOW must be a valid window and defaults to the selected one. -If HORIZONTAL is non-nil, return the normal width of WINDOW. */) +If HORIZONTAL is non-nil, return the normal width of WINDOW. + +The normal height of a frame's root window or a window that is +horizontally combined (a window that has a left or right sibling) is +1.0. The normal height of a window that is vertically combined (has a +sibling above or below) is the fraction of the window's height with +respect to its parent. The sum of the normal heights of all windows in a +vertical combination equals 1.0. + +Similarly, the normal width of a frame's root window or a window that is +vertically combined equals 1.0. The normal width of a window that is +horizontally combined is the fraction of the window's width with respect +to its parent. The sum of the normal widths of all windows in a +horizontal combination equals 1.0. + +The normal sizes of windows are used to restore the proportional sizes +of windows after they have been shrunk to their minimum sizes; for +example when a frame is temporarily made very small and afterwards gets +re-enlarged to its previous size. */) (Lisp_Object window, Lisp_Object horizontal) { struct window *w = decode_valid_window (window); @@ -809,7 +852,11 @@ If HORIZONTAL is non-nil, return the normal width of WINDOW. */) DEFUN ("window-new-normal", Fwindow_new_normal, Swindow_new_normal, 0, 1, 0, doc: /* Return new normal size of window WINDOW. -WINDOW must be a valid window and defaults to the selected one. */) +WINDOW must be a valid window and defaults to the selected one. + +The new normal size of WINDOW is the value set by the last call of +`set-window-new-normal' for WINDOW. If valid, it will be shortly +installed as WINDOW's normal size (see `window-normal-size'). */) (Lisp_Object window) { return decode_valid_window (window)->new_normal; @@ -817,7 +864,12 @@ WINDOW must be a valid window and defaults to the selected one. */) DEFUN ("window-new-pixel", Fwindow_new_pixel, Swindow_new_pixel, 0, 1, 0, doc: /* Return new pixel size of window WINDOW. -WINDOW must be a valid window and defaults to the selected one. */) +WINDOW must be a valid window and defaults to the selected one. + +The new pixel size of WINDOW is the value set by the last call of +`set-window-new-pixel' for WINDOW. If it is valid, it will be shortly +installed as WINDOW's pixel height (see `window-pixel-height') or pixel +width (see `window-pixel-width'). */) (Lisp_Object window) { return decode_valid_window (window)->new_pixel; @@ -871,6 +923,9 @@ window_body_height (struct window *w, bool pixelwise) { int height = (w->pixel_height - WINDOW_HEADER_LINE_HEIGHT (w) + - (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w) + ? WINDOW_SCROLL_BAR_AREA_HEIGHT (w) + : 0) - WINDOW_MODE_LINE_HEIGHT (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w)); @@ -991,6 +1046,15 @@ WINDOW must be a live window and defaults to the selected one. */) return (make_number (WINDOW_SCROLL_BAR_AREA_WIDTH (decode_live_window (window)))); } +DEFUN ("window-scroll-bar-height", Fwindow_scroll_bar_height, + Swindow_scroll_bar_height, 0, 1, 0, + doc: /* Return the height in pixels of WINDOW's horizontal scrollbar. +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)))); +} + DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0, doc: /* Return the number of columns by which WINDOW is scrolled from left margin. WINDOW must be a live window and defaults to the selected one. */) @@ -1018,6 +1082,8 @@ set_window_hscroll (struct window *w, EMACS_INT hscroll) XBUFFER (w->contents)->prevent_redisplay_optimizations_p = 1; w->hscroll = new_hscroll; + w->suspend_auto_hscroll = 1; + return make_number (new_hscroll); } @@ -1167,12 +1233,16 @@ display margins, fringes, header line, and/or mode line. */) return list4i ((WINDOW_BOX_LEFT_EDGE_COL (w) + WINDOW_LEFT_MARGIN_COLS (w) - + WINDOW_LEFT_FRINGE_COLS (w)), + + ((WINDOW_LEFT_FRINGE_WIDTH (w) + + WINDOW_FRAME_COLUMN_WIDTH (w) - 1) + / WINDOW_FRAME_COLUMN_WIDTH (w))), (WINDOW_TOP_EDGE_LINE (w) + WINDOW_HEADER_LINE_LINES (w)), (WINDOW_BOX_RIGHT_EDGE_COL (w) - WINDOW_RIGHT_MARGIN_COLS (w) - - WINDOW_RIGHT_FRINGE_COLS (w)), + - ((WINDOW_RIGHT_FRINGE_WIDTH (w) + + WINDOW_FRAME_COLUMN_WIDTH (w) - 1) + / WINDOW_FRAME_COLUMN_WIDTH (w))), (WINDOW_BOTTOM_EDGE_LINE (w) - WINDOW_MODE_LINE_LINES (w))); } @@ -1286,6 +1356,17 @@ coordinates_in_window (register struct window *w, int x, int y) && x >= right_x - WINDOW_RIGHT_DIVIDER_WIDTH (w) && x <= right_x) return ON_RIGHT_DIVIDER; + /* On the horizontal scroll bar? (Including the empty space at its + right!) */ + else if ((WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w) + && y >= (bottom_y + - WINDOW_SCROLL_BAR_AREA_HEIGHT (w) + - CURRENT_MODE_LINE_HEIGHT (w) + - WINDOW_BOTTOM_DIVIDER_WIDTH (w)) + && y <= (bottom_y + - CURRENT_MODE_LINE_HEIGHT (w) + - WINDOW_BOTTOM_DIVIDER_WIDTH (w)))) + return ON_HORIZONTAL_SCROLL_BAR; /* On the mode or header line? */ else if ((WINDOW_WANTS_MODELINE_P (w) && y >= (bottom_y @@ -1329,7 +1410,7 @@ coordinates_in_window (register struct window *w, int x, int y) /* Outside any interesting column? */ if (x < left_x || x > right_x) - return ON_SCROLL_BAR; + return ON_VERTICAL_SCROLL_BAR; lmargin_width = window_box_width (w, LEFT_MARGIN_AREA); rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA); @@ -1493,10 +1574,13 @@ If they are in the windows's left or right marginal areas, `left-margin'\n\ case ON_RIGHT_MARGIN: return Qright_margin; - case ON_SCROLL_BAR: + case ON_VERTICAL_SCROLL_BAR: /* Historically we are supposed to return nil in this case. */ return Qnil; + case ON_HORIZONTAL_SCROLL_BAR: + return Qnil; + case ON_RIGHT_DIVIDER: return Qright_divider; @@ -1637,6 +1721,14 @@ correct to return the top-level value of `point', outside of any return Fmarker_position (w->pointm); } +DEFUN ("window-old-point", Fwindow_old_point, Swindow_old_point, 0, 1, 0, + doc: /* Return old value of point in WINDOW. +WINDOW must be a live window and defaults to the selected one. */) + (Lisp_Object window) +{ + return Fmarker_position (decode_live_window (window)->old_pointm); +} + DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0, doc: /* Return position at which display currently starts in WINDOW. WINDOW must be a live window and defaults to the selected one. @@ -2915,17 +3007,33 @@ selected frame and no others. */) return Qnil; } + static Lisp_Object resize_root_window (Lisp_Object window, Lisp_Object delta, Lisp_Object horizontal, Lisp_Object ignore, Lisp_Object pixelwise) { return call5 (Qwindow_resize_root_window, window, delta, horizontal, ignore, pixelwise); } +/* Placeholder used by temacs -nw before window.el is loaded. */ +DEFUN ("window--sanitize-window-sizes", Fwindow__sanitize_window_sizes, + Swindow__sanitize_window_sizes, 2, 2, 0, + doc: /* */) + (Lisp_Object frame, Lisp_Object horizontal) +{ + return Qnil; +} + +Lisp_Object +sanitize_window_sizes (Lisp_Object frame, Lisp_Object horizontal) +{ + return call2 (Qwindow_sanitize_window_sizes, frame, horizontal); +} + static Lisp_Object window_pixel_to_total (Lisp_Object frame, Lisp_Object horizontal) { - return call2(Qwindow_pixel_to_total, frame, horizontal); + return call2 (Qwindow_pixel_to_total, frame, horizontal); } @@ -3204,89 +3312,6 @@ replace_buffer_in_windows_safely (Lisp_Object buffer) window_loop (REPLACE_BUFFER_IN_WINDOWS_SAFELY, buffer, 1, frame); } } - -/* If *HEIGHT or *WIDTH are too small a size for FRAME, set them to the - minimum allowable size. PIXELWISE means interpret these as pixel - sizes. */ - -void -check_frame_size (struct frame *frame, int *width, int *height, bool pixelwise) -{ - /* For height, we have to see: - how many windows the frame has at minimum (one or two), - and whether it has a menu bar or other special stuff at the top. */ - if (pixelwise) - { - int min_height = MIN_SAFE_WINDOW_HEIGHT * FRAME_LINE_HEIGHT (frame); - int min_width = MIN_SAFE_WINDOW_WIDTH * FRAME_COLUMN_WIDTH (frame); - - if (!FRAME_MINIBUF_ONLY_P (frame) && FRAME_HAS_MINIBUF_P (frame)) - min_height = 2 * min_height; - - min_height += FRAME_TOP_MARGIN_HEIGHT (frame); - min_height += FRAME_INTERNAL_BORDER_WIDTH (frame); - - if (*height < min_height) - *height = min_height; - if (*width < min_width) - *width = min_width; - } - else - { - int min_height - = ((FRAME_MINIBUF_ONLY_P (frame) || ! FRAME_HAS_MINIBUF_P (frame)) - ? MIN_SAFE_WINDOW_HEIGHT - : 2 * MIN_SAFE_WINDOW_HEIGHT); - - if (FRAME_TOP_MARGIN (frame) > 0) - min_height += FRAME_TOP_MARGIN (frame); - - if (*height < min_height) - *height = min_height; - if (*width < MIN_SAFE_WINDOW_WIDTH) - *width = MIN_SAFE_WINDOW_WIDTH; - } -} - -/* Adjust the margins of window W if text area is too small. - Return 1 if window width is ok after adjustment; 0 if window - is still too narrow. */ - -static int -adjust_window_margins (struct window *w) -{ - int box_width = (WINDOW_PIXEL_WIDTH (w) - - WINDOW_FRINGES_WIDTH (w) - - WINDOW_SCROLL_BAR_AREA_WIDTH (w)); - int margin_width = WINDOW_MARGINS_WIDTH (w); - - if (box_width - margin_width >= MIN_SAFE_WINDOW_PIXEL_WIDTH (w)) - return 1; - - if (margin_width < 0 || box_width < MIN_SAFE_WINDOW_PIXEL_WIDTH (w)) - return 0; - else - /* Window's text area is too narrow, but reducing the window - margins will fix that. */ - { - int unit = WINDOW_FRAME_COLUMN_WIDTH (w); - - margin_width = box_width - MIN_SAFE_WINDOW_PIXEL_WIDTH (w); - - if (WINDOW_RIGHT_MARGIN_WIDTH (w) > 0) - { - if (WINDOW_LEFT_MARGIN_WIDTH (w) > 0) - w->left_margin_cols = w->right_margin_cols = - margin_width / (2 * unit); - else - w->right_margin_cols = margin_width / unit; - } - else - w->left_margin_cols = margin_width / unit; - - return 1; - } -} /* The following three routines are needed for running a window's configuration change hook. */ @@ -3320,7 +3345,9 @@ run_window_configuration_change_hook (struct frame *f) = Fdefault_value (Qwindow_configuration_change_hook); XSETFRAME (frame, f); - if (NILP (Vrun_hooks) || !NILP (inhibit_lisp_code)) + if (NILP (Vrun_hooks) + || !(f->can_x_set_window_size) + || !(f->can_run_window_configuration_change_hook)) return; /* Use the right buffer. Matters when running the local hooks. */ @@ -3415,17 +3442,21 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer, w->last_cursor_vpos = 0; if (!(keep_margins_p && samebuf)) - { /* If we're not actually changing the buffer, don't reset hscroll and - vscroll. This case happens for example when called from + { /* If we're not actually changing the buffer, don't reset hscroll + and vscroll. This case happens for example when called from change_frame_size_1, where we use a dummy call to - Fset_window_buffer on the frame's selected window (and no other) - just in order to run window-configuration-change-hook. - Resetting hscroll and vscroll here is problematic for things like - image-mode and doc-view-mode since it resets the image's position - whenever we resize the frame. */ - w->hscroll = w->min_hscroll = 0; + Fset_window_buffer on the frame's selected window (and no + other) just in order to run window-configuration-change-hook + (no longer true since change_frame_size_1 directly calls + run_window_configuration_change_hook). Resetting hscroll and + vscroll here is problematic for things like image-mode and + doc-view-mode since it resets the image's position whenever we + resize the frame. */ + w->hscroll = w->min_hscroll = w->hscroll_whole = 0; + w->suspend_auto_hscroll = 0; w->vscroll = 0; 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), buffer); @@ -3443,6 +3474,7 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer, Fset_buffer (buffer); XMARKER (w->pointm)->insertion_type = !NILP (Vwindow_point_insertion_type); + XMARKER (w->old_pointm)->insertion_type = !NILP (Vwindow_point_insertion_type); if (!keep_margins_p) { @@ -3451,7 +3483,9 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer, 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), Qnil); + BVAR (b, vertical_scroll_bar_type), + BVAR (b, scroll_bar_height), + BVAR (b, horizontal_scroll_bar_type)); set_window_margins (w, BVAR (b, left_margin_cols), BVAR (b, right_margin_cols)); apply_window_adjustment (w); @@ -3597,10 +3631,11 @@ temp_output_buffer_show (register Lisp_Object buf) Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window))); Vminibuf_scroll_window = window; w = XWINDOW (window); - w->hscroll = 0; - w->min_hscroll = 0; + w->hscroll = w->min_hscroll = w->hscroll_whole = 0; + w->suspend_auto_hscroll = 0; set_marker_restricted_both (w->start, buf, BEG, BEG); set_marker_restricted_both (w->pointm, buf, BEG, BEG); + set_marker_restricted_both (w->old_pointm, buf, BEG, BEG); /* Run temp-buffer-show-hook, with the chosen window selected and its buffer current. */ @@ -3652,6 +3687,7 @@ make_parent_window (Lisp_Object window, bool horflag) /* ...but now P becomes an internal window. */ wset_start (p, Qnil); wset_pointm (p, Qnil); + wset_old_pointm (p, Qnil); wset_buffer (p, Qnil); wset_combination (p, horflag, window); wset_combination_limit (p, Qnil); @@ -3675,7 +3711,9 @@ make_window (void) wset_new_pixel (w, make_number (0)); wset_start (w, Fmake_marker ()); wset_pointm (w, Fmake_marker ()); + wset_old_pointm (w, Fmake_marker ()); wset_vertical_scroll_bar_type (w, Qt); + wset_horizontal_scroll_bar_type (w, Qt); /* These Lisp fields are marked specially so they're not set to nil by allocate_window. */ wset_prev_buffers (w, Qnil); @@ -3692,8 +3730,8 @@ make_window (void) #endif w->sequence_number = ++sequence_number; w->scroll_bar_width = -1; + w->scroll_bar_height = -1; w->column_number_displayed = -1; - /* Reset window_list. */ Vwindow_list = Qnil; /* Return window. */ @@ -3709,6 +3747,10 @@ Return SIZE. Optional argument ADD non-nil means add SIZE to the new pixel size of WINDOW and return the sum. +The new pixel size of WINDOW, if valid, will be shortly installed as +WINDOW's pixel height (see `window-pixel-height') or pixel width (see +`window-pixel-width'). + Note: This function does not operate on any child windows of WINDOW. */) (Lisp_Object window, Lisp_Object size, Lisp_Object add) { @@ -3733,6 +3775,10 @@ Return SIZE. Optional argument ADD non-nil means add SIZE to the new total size of WINDOW and return the sum. +The new total size of WINDOW, if valid, will be shortly installed as +WINDOW's total height (see `window-total-height') or total width (see +`window-total-width'). + Note: This function does not operate on any child windows of WINDOW. */) (Lisp_Object window, Lisp_Object size, Lisp_Object add) { @@ -3752,6 +3798,9 @@ DEFUN ("set-window-new-normal", Fset_window_new_normal, Sset_window_new_normal, WINDOW must be a valid window and defaults to the selected one. Return SIZE. +The new normal size of WINDOW, if valid, will be shortly installed as +WINDOW's normal size (see `window-normal-size'). + Note: This function does not operate on any child windows of WINDOW. */) (Lisp_Object window, Lisp_Object size) { @@ -3858,7 +3907,7 @@ window_resize_check (struct window *w, bool horflag) } -/* Set w->pixel_height (w->pixel_height if HORIZONTAL is non-zero) to +/* Set w->pixel_height (w->pixel_width if HORFLAG is non-zero) to w->new_pixel for window W and recursively all child windows of W. Also calculate and assign the new vertical (horizontal) pixel start positions of each of these windows. @@ -3943,15 +3992,12 @@ window_resize_apply (struct window *w, bool horflag) } } else - { - adjust_window_margins (w); - /* Bug#15957. */ - w->window_end_valid = 0; - } + /* Bug#15957. */ + w->window_end_valid = 0; } -/* Set w->total_lines (w->total_cols if HORIZONTAL is non-zero) to +/* Set w->total_lines (w->total_cols if HORFLAG is non-zero) to w->new_total for window W and recursively all child windows of W. Also calculate and assign the new vertical (horizontal) start positions of each of these windows. */ @@ -4019,9 +4065,14 @@ If FRAME is omitted or nil, it defaults to the selected frame. Optional argument HORIZONTAL omitted or nil means apply requested height values. HORIZONTAL non-nil means apply requested width values. -This function checks whether the requested values sum up to a valid -window layout, recursively assigns the new sizes of all child windows -and calculates and assigns the new start positions of these windows. +The requested size values are those set by `set-window-new-pixel' and +`set-window-new-normal'. This function checks whether the requested +values sum up to a valid window layout, recursively assigns the new +sizes of all child windows and calculates and assigns the new start +positions of these windows. + +Return t if the requested values have been applied correctly, nil +otherwise. Note: This function does not check any of `window-fixed-size-p', `window-min-height' or `window-min-width'. All these checks have to @@ -4092,11 +4143,7 @@ values. */) /* Resize frame F's windows when number of lines of F is set to SIZE. HORFLAG 1 means resize windows when number of columns of F is set to - SIZE. PIXELWISE 1 means to interpret SIZE as pixels. - - This function can delete all windows but the selected one in order to - satisfy the request. The result will be meaningful if and only if - F's windows have meaningful sizes when you call this. */ + SIZE. PIXELWISE 1 means to interpret SIZE as pixels. */ void resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) { @@ -4107,6 +4154,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) /* 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; + int old_pixel_top = r->pixel_top; /* 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); @@ -4121,7 +4169,6 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) new_pixel_size = max (horflag ? size : (size - - FRAME_TOP_MARGIN_HEIGHT (f) - ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f)) ? FRAME_LINE_HEIGHT (f) : 0)), @@ -4133,7 +4180,6 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) new_size = max (horflag ? size : (size - - FRAME_TOP_MARGIN (f) - ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f)) ? 1 : 0)), @@ -4144,7 +4190,8 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) r->top_line = FRAME_TOP_MARGIN (f); r->pixel_top = FRAME_TOP_MARGIN_HEIGHT (f); - if (new_pixel_size == old_pixel_size) + if (new_pixel_size == old_pixel_size + && r->pixel_top == old_pixel_top) ; else if (WINDOW_LEAF_P (r)) /* For a leaf root window just set the size. */ @@ -4186,6 +4233,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) { window_resize_apply (r, horflag); window_pixel_to_total (r->frame, horflag ? Qt : Qnil); +#if 0 /* Let's try without safe sizes and/or killing other windows. */ } else { @@ -4198,7 +4246,6 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) window_resize_apply (r, horflag); window_pixel_to_total (r->frame, horflag ? Qt : Qnil); } -#if 0 /* Let's try without killing other windows. */ else { /* We lost. Delete all windows but the frame's @@ -4402,7 +4449,9 @@ set correctly. See the code of `split-window' for how this is done. */) n->right_fringe_width = r->right_fringe_width; n->fringes_outside_margins = r->fringes_outside_margins; n->scroll_bar_width = r->scroll_bar_width; + n->scroll_bar_height = r->scroll_bar_height; wset_vertical_scroll_bar_type (n, r->vertical_scroll_bar_type); + wset_horizontal_scroll_bar_type (n, r->horizontal_scroll_bar_type); /* Directly assign orthogonal coordinates and sizes. */ if (horflag) @@ -4546,6 +4595,7 @@ Signal an error when WINDOW is the only window on its frame. */) { unshow_buffer (w); unchain_marker (XMARKER (w->pointm)); + unchain_marker (XMARKER (w->old_pointm)); unchain_marker (XMARKER (w->start)); wset_buffer (w, Qnil); } @@ -4750,10 +4800,10 @@ DEFUN ("resize-mini-window-internal", Fresize_mini_window_internal, Sresize_mini block_input (); window_resize_apply (r, 0); - w->total_lines = XFASTINT (w->new_total); - w->top_line = r->top_line + r->total_lines; 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); FRAME_WINDOW_SIZES_CHANGED (f) = 1; @@ -4807,6 +4857,7 @@ window_internal_height (struct window *w) return ht; } + /************************************************************************ Window Scrolling @@ -4822,11 +4873,16 @@ window_internal_height (struct window *w) static void window_scroll (Lisp_Object window, EMACS_INT n, bool whole, int noerror) { + ptrdiff_t count = SPECPDL_INDEX (); + immediate_quit = 1; n = clip_to_bounds (INT_MIN, n, INT_MAX); wset_redisplay (XWINDOW (window)); + if (whole && Vfast_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. */ if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame))) @@ -4834,6 +4890,8 @@ window_scroll (Lisp_Object window, EMACS_INT n, bool whole, int noerror) else window_scroll_line_based (window, n, whole, noerror); + unbind_to (count, Qnil); + /* Bug#15957. */ XWINDOW (window)->window_end_valid = 0; immediate_quit = 0; @@ -4857,6 +4915,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror) void *itdata = NULL; int window_total_lines; int frame_line_height = default_line_pixel_height (w); + bool adjust_old_pointm = !NILP (Fequal (Fwindow_point (window), + Fwindow_old_point (window))); SET_TEXT_POS_FROM_MARKER (start, w->start); /* Scrolling a minibuffer window via scroll bar when the echo area @@ -4883,8 +4943,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror) /* The function move_iterator_vertically may move over more than the specified y-distance. If it->w is small, e.g. a mini-buffer window, we may end up in front of the window's - display area. This is the case when Start displaying at the - start of the line containing PT in this case. */ + display area. Start displaying at the start of the line + containing PT in this case. */ if (it.current_y <= 0) { init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID); @@ -4901,9 +4961,14 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror) { int px; int dy = frame_line_height; + /* 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. */ if (whole) - dy = max ((window_box_height (w) - - next_screen_context_lines * dy), + dy = max ((window_box_height (w) / dy + - next_screen_context_lines) * dy, dy); dy *= n; @@ -4985,8 +5050,12 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror) { ptrdiff_t start_pos = IT_CHARPOS (it); int dy = frame_line_height; - dy = max ((window_box_height (w) - - next_screen_context_lines * dy), + /* 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; /* Note that move_it_vertically always moves the iterator to the @@ -5161,6 +5230,32 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror) charpos = IT_CHARPOS (it); bytepos = IT_BYTEPOS (it); + /* If PT is in the screen line at the last fully visible line, + move_it_to will stop at X = 0 in that line, because the + required Y coordinate is reached there. See if we can get to + PT without descending lower in Y, and if we can, it means we + reached PT before the scroll margin. */ + if (charpos != PT) + { + struct it it2; + void *it_data; + + it2 = it; + it_data = bidi_shelve_cache (); + move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); + if (IT_CHARPOS (it) == PT && it.current_y == it2.current_y) + { + charpos = IT_CHARPOS (it); + bytepos = IT_BYTEPOS (it); + bidi_unshelve_cache (it_data, 1); + } + else + { + it = it2; + bidi_unshelve_cache (it_data, 0); + } + } + /* 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; @@ -5202,6 +5297,13 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror) } } bidi_unshelve_cache (itdata, 0); + + if (adjust_old_pointm) + Fset_marker (w->old_pointm, + ((w == XWINDOW (selected_window)) + ? make_number (BUF_PT (XBUFFER (w->contents))) + : Fmarker_position (w->pointm)), + w->contents); } @@ -5226,6 +5328,8 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror) ptrdiff_t startpos = marker_position (w->start); ptrdiff_t startbyte = marker_byte_position (w->start); Lisp_Object original_pos = Qnil; + bool adjust_old_pointm = !NILP (Fequal (Fwindow_point (window), + Fwindow_old_point (window))); /* If scrolling screen-fulls, compute the number of lines to scroll from the window's height. */ @@ -5241,6 +5345,7 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror) struct position posit = *compute_motion (startpos, startbyte, 0, 0, 0, PT, ht, 0, -1, w->hscroll, 0, w); + window_scroll_preserve_vpos = posit.vpos; window_scroll_preserve_hpos = posit.hpos + w->hscroll; } @@ -5356,6 +5461,13 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror) else xsignal0 (Qend_of_buffer); } + + if (adjust_old_pointm) + Fset_marker (w->old_pointm, + ((w == XWINDOW (selected_window)) + ? make_number (BUF_PT (XBUFFER (w->contents))) + : Fmarker_position (w->pointm)), + w->contents); } @@ -5492,6 +5604,7 @@ specifies the window to scroll. This takes precedence over 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, 1, 1); @@ -5506,6 +5619,7 @@ specifies the window to scroll. This takes precedence over } 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; @@ -5531,6 +5645,8 @@ by this function. This happens in an interactive call. */) if (!NILP (set_minimum)) w->min_hscroll = w->hscroll; + w->suspend_auto_hscroll = 1; + return result; } @@ -5554,6 +5670,8 @@ by this function. This happens in an interactive call. */) if (!NILP (set_minimum)) w->min_hscroll = w->hscroll; + w->suspend_auto_hscroll = 1; + return result; } @@ -5651,7 +5769,7 @@ and redisplay normally--don't erase and redraw the frame. */) if (buf != current_buffer) error ("`recenter'ing a window that does not display current-buffer."); - + /* If redisplay is suppressed due to an error, try again. */ buf->display_error_modiff = 0; @@ -5817,38 +5935,52 @@ and redisplay normally--don't erase and redraw the frame. */) w->start_at_line_beg = (bytepos == BEGV_BYTE || FETCH_BYTE (bytepos - 1) == '\n'); + wset_redisplay (w); + return Qnil; } DEFUN ("window-text-width", Fwindow_text_width, Swindow_text_width, - 0, 1, 0, + 0, 2, 0, doc: /* Return the width in columns of the text display area of WINDOW. WINDOW must be a live window and defaults to the selected one. The returned width does not include dividers, scrollbars, margins, fringes, nor any partial-width columns at the right of the text -area. */) - (Lisp_Object window) +area. + +Optional argument PIXELWISE non-nil, means to return the width in +pixels. */) + (Lisp_Object window, Lisp_Object pixelwise) { struct window *w = decode_live_window (window); - return make_number (window_box_width (w, TEXT_AREA) - / FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w))); + if (NILP (pixelwise)) + return make_number (window_box_width (w, TEXT_AREA) + / FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w))); + else + return make_number (window_box_width (w, TEXT_AREA)); } DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height, - 0, 1, 0, + 0, 2, 0, doc: /* Return the height in lines of the text display area of WINDOW. WINDOW must be a live window and defaults to the selected one. The returned height does not include dividers, the mode line, any header -line, nor any partial-height lines at the bottom of the text area. */) - (Lisp_Object window) +line, nor any partial-height lines at the bottom of the text area. + +Optional argument PIXELWISE non-nil, means to return the height in +pixels. */) + (Lisp_Object window, Lisp_Object pixelwise) { struct window *w = decode_live_window (window); - return make_number (window_box_height (w) - / FRAME_LINE_HEIGHT (WINDOW_XFRAME (w))); + if (NILP (pixelwise)) + return make_number (window_box_height (w) + / FRAME_LINE_HEIGHT (WINDOW_XFRAME (w))); + else + return make_number (window_box_height (w)); } DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line, @@ -5958,17 +6090,18 @@ struct saved_window { struct vectorlike_header header; - Lisp_Object window, buffer, start, pointm; + Lisp_Object window, buffer, start, pointm, old_pointm; Lisp_Object pixel_left, pixel_top, pixel_height, pixel_width; Lisp_Object left_col, top_line, total_cols, total_lines; Lisp_Object normal_cols, normal_lines; - Lisp_Object hscroll, min_hscroll; + Lisp_Object hscroll, min_hscroll, hscroll_whole, suspend_auto_hscroll; 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 scroll_bar_height, horizontal_scroll_bar_type; Lisp_Object combination_limit, window_parameters; }; @@ -5996,13 +6129,6 @@ DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_config return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame; } -/* From Chong's unwind_create_frame_1. */ -static void -unwind_change_frame (Lisp_Object val) -{ - inhibit_lisp_code = val; -} - DEFUN ("set-window-configuration", Fset_window_configuration, Sset_window_configuration, 1, 1, 0, doc: /* Set the configuration of windows and buffers as specified by CONFIGURATION. @@ -6019,6 +6145,7 @@ the return value is nil. Otherwise the value is t. */) Lisp_Object frame; struct frame *f; ptrdiff_t old_point = -1; + USE_SAFE_ALLOCA; CHECK_WINDOW_CONFIGURATION (configuration); @@ -6082,19 +6209,6 @@ the return value is nil. Otherwise the value is t. */) int n_leaf_windows; ptrdiff_t k; int i, n; - ptrdiff_t count = SPECPDL_INDEX (); - /* If the frame has been resized since this window configuration was - made, we change the frame to the size specified in the - configuration, restore the configuration, and then resize it - back. We keep track of the prevailing height in these variables. */ - int previous_frame_text_height = FRAME_TEXT_HEIGHT (f); - int previous_frame_text_width = FRAME_TEXT_WIDTH (f); - /* int previous_frame_menu_bar_height = FRAME_MENU_BAR_HEIGHT (f); */ - /* int previous_frame_tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f); */ - /* int previous_frame_lines = FRAME_LINES (f); */ - /* int previous_frame_cols = FRAME_COLS (f); */ - int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f); - int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f); /* Don't do this within the main loop below: This may call Lisp code and is thus potentially unsafe while input is blocked. */ @@ -6111,36 +6225,12 @@ the return value is nil. Otherwise the value is t. */) call1 (Qrecord_window_buffer, window); } - /* Don't run lisp in the following segment since the frame is in a - completely inconsistent state. See Bug#16207. */ - record_unwind_protect (unwind_change_frame, inhibit_lisp_code); - inhibit_lisp_code = Qt; + /* Disallow x_set_window_size, temporarily. */ + f->can_x_set_window_size = false; /* The mouse highlighting code could get screwed up if it runs during this. */ block_input (); - if (data->frame_text_width != previous_frame_text_width - || data->frame_text_height != previous_frame_text_height) - change_frame_size (f, data->frame_text_width, - data->frame_text_height, 0, 0, 0, 1); - - if (data->frame_menu_bar_lines != previous_frame_menu_bar_lines) - { -#ifdef HAVE_WINDOW_SYSTEM - if (FRAME_WINDOW_P (f)) - x_set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines), - make_number (0)); - else /* TTY or MSDOS */ -#endif - set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines), - make_number (0)); - } -#ifdef HAVE_WINDOW_SYSTEM - if (data->frame_tool_bar_lines != previous_frame_tool_bar_lines) - x_set_tool_bar_lines (f, make_number (data->frame_tool_bar_lines), - make_number (0)); -#endif - /* "Swap out" point from the selected window's buffer into the window itself. (Normally the pointm of the selected window holds garbage.) We do this now, before @@ -6163,8 +6253,8 @@ the return value is nil. Otherwise the value is t. */) really like to do is to free only those matrices not reused below. */ root_window = XWINDOW (FRAME_ROOT_WINDOW (f)); - leaf_windows = alloca (count_windows (root_window) - * sizeof *leaf_windows); + int nwindows = count_windows (root_window); + SAFE_NALLOCA (leaf_windows, 1, nwindows); n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0); /* Kludge Alert! @@ -6219,7 +6309,9 @@ the return value is nil. Otherwise the value is t. */) wset_normal_cols (w, p->normal_cols); wset_normal_lines (w, p->normal_lines); w->hscroll = XFASTINT (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); 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); @@ -6227,7 +6319,9 @@ the return value is nil. Otherwise the value is t. */) w->right_fringe_width = XINT (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); 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); wset_combination_limit (w, p->combination_limit); /* Restore any window parameters that have been saved. @@ -6258,16 +6352,15 @@ the return value is nil. Otherwise the value is t. */) 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); - set_marker_restricted (w->pointm, p->pointm, - w->contents); - + set_marker_restricted (w->pointm, p->pointm, w->contents); + set_marker_restricted (w->old_pointm, p->old_pointm, w->contents); /* As documented in Fcurrent_window_configuration, don't restore the location of point in the buffer which was current when the window configuration was recorded. */ if (!EQ (p->buffer, new_current_buffer) && XBUFFER (p->buffer) == current_buffer) Fgoto_char (w->pointm); - } + } else if (BUFFERP (w->contents) && BUFFER_LIVE_P (XBUFFER (w->contents))) /* Keep window's old buffer; make sure the markers are real. */ { @@ -6279,20 +6372,26 @@ the return value is nil. Otherwise the value is t. */) (w->pointm, w->contents, BUF_PT (XBUFFER (w->contents)), BUF_PT_BYTE (XBUFFER (w->contents))); + if (XMARKER (w->old_pointm)->buffer == 0) + set_marker_restricted_both + (w->old_pointm, w->contents, + BUF_PT (XBUFFER (w->contents)), + BUF_PT_BYTE (XBUFFER (w->contents))); w->start_at_line_beg = 1; } else if (!NILP (w->start)) /* Leaf window has no live buffer, get one. */ { /* 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 - scenario from March 2011). */ + avoid showing an unimportant buffer and, if necessary, to + recreate *scratch* in the course (part of Juanma's bs-show + scenario from March 2011). */ wset_buffer (w, other_buffer_safely (Fcurrent_buffer ())); /* This will set the markers to beginning of visible range. */ set_marker_restricted_both (w->start, w->contents, 0, 0); set_marker_restricted_both (w->pointm, w->contents, 0, 0); + set_marker_restricted_both (w->old_pointm, w->contents, 0, 0); w->start_at_line_beg = 1; if (!NILP (w->dedicated)) /* Record this window as dead. */ @@ -6327,30 +6426,6 @@ the return value is nil. Otherwise the value is t. */) && FRAME_LIVE_P (XFRAME (data->focus_frame)))) Fredirect_frame_focus (frame, data->focus_frame); - /* Set the frame size to the value it had before this function. */ - if (previous_frame_text_width != FRAME_TEXT_WIDTH (f) - || previous_frame_text_height != FRAME_TEXT_HEIGHT (f)) - change_frame_size (f, previous_frame_text_width, - previous_frame_text_height, 0, 0, 0, 1); - - if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f)) - { -#ifdef HAVE_WINDOW_SYSTEM - if (FRAME_WINDOW_P (f)) - x_set_menu_bar_lines (f, - make_number (previous_frame_menu_bar_lines), - make_number (0)); - else /* TTY or MSDOS */ -#endif - set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines), - make_number (0)); - } -#ifdef HAVE_WINDOW_SYSTEM - if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f)) - x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines), - make_number (0)); -#endif - /* Now, free glyph matrices in windows that were not reused. */ for (i = n = 0; i < n_leaf_windows; ++i) { @@ -6360,9 +6435,13 @@ the return value is nil. Otherwise the value is t. */) ++n; } + /* 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, 0, Qnil); + adjust_frame_glyphs (f); unblock_input (); - unbind_to (count, Qnil); /* Scan dead buffer windows. */ for (; CONSP (dead_windows); dead_windows = XCDR (dead_windows)) @@ -6399,9 +6478,11 @@ the return value is nil. Otherwise the value is t. */) Vminibuf_scroll_window = data->minibuf_scroll_window; minibuf_selected_window = data->minibuf_selected_window; + SAFE_FREE (); return (FRAME_LIVE_P (f) ? Qt : Qnil); } + void restore_window_configuration (Lisp_Object configuration) { @@ -6433,6 +6514,7 @@ delete_all_child_windows (Lisp_Object window) { unshow_buffer (w); unchain_marker (XMARKER (w->pointm)); + unchain_marker (XMARKER (w->old_pointm)); unchain_marker (XMARKER (w->start)); /* Since combination limit makes sense for an internal windows only, we use this slot to save the buffer for the sake of @@ -6539,7 +6621,9 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i) 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); 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); @@ -6547,7 +6631,9 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i) p->right_fringe_width = make_number (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->vertical_scroll_bar_type = w->vertical_scroll_bar_type; + p->horizontal_scroll_bar_type = w->horizontal_scroll_bar_type; p->dedicated = w->dedicated; p->combination_limit = w->combination_limit; p->window_parameters = Qnil; @@ -6609,9 +6695,13 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i) BUF_PT_BYTE (XBUFFER (w->contents))); 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)); p->start = Fcopy_marker (w->start, Qnil); p->start_at_line_beg = w->start_at_line_beg ? Qt : Qnil; @@ -6619,6 +6709,7 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i) else { p->pointm = Qnil; + p->old_pointm = Qnil; p->start = Qnil; p->start_at_line_beg = Qnil; } @@ -6688,7 +6779,6 @@ static void apply_window_adjustment (struct window *w) { eassert (w); - adjust_window_margins (w); clear_glyph_matrix (w->current_matrix); w->window_end_valid = 0; windows_or_buffers_changed = 30; @@ -6706,8 +6796,8 @@ set_window_margins (struct window *w, Lisp_Object left_width, Lisp_Object right_width) { int left, right; + int unit = WINDOW_FRAME_COLUMN_WIDTH (w); - /* FIXME: what about margins that are too wide? */ left = (NILP (left_width) ? 0 : (CHECK_NATNUM (left_width), XINT (left_width))); right = (NILP (right_width) ? 0 @@ -6715,11 +6805,23 @@ set_window_margins (struct window *w, Lisp_Object left_width, if (w->left_margin_cols != left || w->right_margin_cols != right) { - w->left_margin_cols = left; - w->right_margin_cols = right; - return w; + /* Don't change anything if new margins won't fit. */ + if ((WINDOW_PIXEL_WIDTH (w) + - WINDOW_FRINGES_WIDTH (w) + - WINDOW_SCROLL_BAR_AREA_WIDTH (w) + - (left + right) * unit) + >= MIN_SAFE_WINDOW_PIXEL_WIDTH (w)) + { + w->left_margin_cols = left; + w->right_margin_cols = right; + + return w; + } + else + return NULL; } - return NULL; + else + return NULL; } DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins, @@ -6781,12 +6883,25 @@ set_window_fringes (struct window *w, Lisp_Object left_width, || w->right_fringe_width != right || w->fringes_outside_margins != outside)) { + if (left > 0 || right > 0) + { + /* 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->left_fringe_width = left; w->right_fringe_width = right; w->fringes_outside_margins = outside; + return w; } - return NULL; + else + return NULL; } DEFUN ("set-window-fringes", Fset_window_fringes, Sset_window_fringes, @@ -6837,9 +6952,11 @@ 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 horizontal_type) + Lisp_Object vertical_type, Lisp_Object height, + Lisp_Object horizontal_type) { int iwidth = (NILP (width) ? -1 : (CHECK_NATNUM (width), XINT (width))); + bool changed = 0; if (iwidth == 0) vertical_type = Qnil; @@ -6853,32 +6970,78 @@ set_window_scroll_bars (struct window *w, Lisp_Object width, if (w->scroll_bar_width != iwidth || !EQ (w->vertical_scroll_bar_type, vertical_type)) { - w->scroll_bar_width = iwidth; - wset_vertical_scroll_bar_type (w, vertical_type); - return w; + /* Don't change anything if new scroll bar won't fit. */ + if ((WINDOW_PIXEL_WIDTH (w) + - WINDOW_MARGINS_WIDTH (w) + - WINDOW_FRINGES_WIDTH (w) + - max (iwidth, 0)) + >= MIN_SAFE_WINDOW_PIXEL_WIDTH (w)) + { + w->scroll_bar_width = iwidth; + wset_vertical_scroll_bar_type (w, vertical_type); + changed = 1; + } } - return NULL; + +#if USE_HORIZONTAL_SCROLL_BARS + { + int iheight = (NILP (height) ? -1 : (CHECK_NATNUM (height), XINT (height))); + + if (MINI_WINDOW_P (w) || iheight == 0) + horizontal_type = Qnil; + + 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 = 1; + } + } + } +#else + wset_horizontal_scroll_bar_type (w, Qnil); +#endif + + return changed ? w : NULL; } DEFUN ("set-window-scroll-bars", Fset_window_scroll_bars, - Sset_window_scroll_bars, 2, 4, 0, + 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. -Second parameter WIDTH specifies the pixel width for the scroll bar. +Second parameter 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 -bar: left, right, or nil. -If WIDTH is nil, use the frame's scroll-bar width. -If VERTICAL-TYPE is t, use the frame's scroll-bar type. -Fourth parameter HORIZONTAL-TYPE is currently unused. +bar: left, right, or nil. If VERTICAL-TYPE is t, this means use the +frame's scroll-bar type. + +Fourth parameter 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: nil, bottom, or t. If HORIZONTAL-TYPE is t, this +means to use the frame's horizontal scroll-bar type. Return t if scroll bars were actually changed and nil otherwise. */) - (Lisp_Object window, Lisp_Object width, - Lisp_Object vertical_type, Lisp_Object horizontal_type) + (Lisp_Object window, Lisp_Object width, Lisp_Object vertical_type, + Lisp_Object height, Lisp_Object horizontal_type) { struct window *w = set_window_scroll_bars (decode_live_window (window), - width, vertical_type, horizontal_type); + width, vertical_type, height, horizontal_type); return w ? (apply_window_adjustment (w), Qt) : Qnil; } @@ -6888,19 +7051,25 @@ DEFUN ("window-scroll-bars", Fwindow_scroll_bars, Swindow_scroll_bars, doc: /* Get width and type of scroll bars of window WINDOW. WINDOW must be a live window and defaults to the selected one. -Value is a list of the form (WIDTH COLS VERTICAL-TYPE HORIZONTAL-TYPE). -If WIDTH is nil or TYPE is t, the window is using the frame's corresponding +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. */) (Lisp_Object window) { struct window *w = decode_live_window (window); - return list4 (make_number (WINDOW_SCROLL_BAR_AREA_WIDTH (w)), - make_number (WINDOW_SCROLL_BAR_COLS (w)), - w->vertical_scroll_bar_type, Qnil); + return Fcons (((w->scroll_bar_width >= 0) + ? make_number (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)); } - - /*********************************************************************** Smooth scrolling @@ -7090,7 +7259,9 @@ compare_window_configurations (Lisp_Object configuration1, || !EQ (sw1->right_fringe_width, sw2->right_fringe_width) || !EQ (sw1->fringes_outside_margins, sw2->fringes_outside_margins) || !EQ (sw1->scroll_bar_width, sw2->scroll_bar_width) - || !EQ (sw1->vertical_scroll_bar_type, sw2->vertical_scroll_bar_type)) + || !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)) return 0; } @@ -7144,6 +7315,7 @@ syms_of_window (void) DEFSYM (Qdelete_window, "delete-window"); 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_pixel_to_total, "window--pixel-to-total"); DEFSYM (Qsafe, "safe"); DEFSYM (Qdisplay_buffer, "display-buffer"); @@ -7184,7 +7356,7 @@ the buffer; `temp-buffer-show-hook' is not run unless this function runs it. */ doc: /* Non-nil means to use `mode-line-inactive' face in non-selected windows. If the minibuffer is active, the `minibuffer-scroll-window' mode line is displayed in the `mode-line' face. */); - mode_line_in_non_selected_windows = 1; + mode_line_in_non_selected_windows = true; DEFVAR_LISP ("other-window-scroll-buffer", Vother_window_scroll_buffer, doc: /* If this is a live buffer, \\[scroll-other-window] should scroll its window. */); @@ -7192,7 +7364,7 @@ is displayed in the `mode-line' face. */); 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 = 1; + auto_window_vscroll_p = true; DEFVAR_INT ("next-screen-context-lines", next_screen_context_lines, doc: /* Number of lines of continuity when scrolling by screenfuls. */); @@ -7315,7 +7487,18 @@ all functions that symmetrically resize a parent window. Note that when a frame's pixel size is not a multiple of the frame's character size, at least one window may get resized pixelwise even if this option is nil. */); - window_resize_pixelwise = 0; + window_resize_pixelwise = false; + + DEFVAR_BOOL ("fast-but-imprecise-scrolling", + Vfast_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 +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; defsubr (&Sselected_window); defsubr (&Sminibuffer_window); @@ -7370,12 +7553,14 @@ pixelwise even if this option is nil. */); defsubr (&Swindow_right_divider_width); defsubr (&Swindow_bottom_divider_width); defsubr (&Swindow_scroll_bar_width); + defsubr (&Swindow_scroll_bar_height); defsubr (&Swindow_inside_edges); defsubr (&Swindow_inside_pixel_edges); defsubr (&Swindow_inside_absolute_pixel_edges); defsubr (&Scoordinates_in_window_p); defsubr (&Swindow_at); defsubr (&Swindow_point); + defsubr (&Swindow_old_point); defsubr (&Swindow_start); defsubr (&Swindow_end); defsubr (&Sset_window_point); @@ -7386,6 +7571,7 @@ pixelwise even if this option is nil. */); defsubr (&Sset_window_display_table); defsubr (&Snext_window); defsubr (&Sprevious_window); + defsubr (&Swindow__sanitize_window_sizes); defsubr (&Sget_buffer_window); defsubr (&Sdelete_other_windows_internal); defsubr (&Sdelete_window_internal);