X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/20b69789f39002044bb4618e0d97179d5498659a..506d2f9a542b2dcdc4dc918abd0524f29e22a2a6:/src/window.c diff --git a/src/window.c b/src/window.c index cb6767c5c9..69643ec669 100644 --- a/src/window.c +++ b/src/window.c @@ -1,7 +1,7 @@ /* Window creation, deletion and examination for GNU Emacs. Does not include redisplay. Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1996, 1997, 1998, 2000, - 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -50,6 +50,7 @@ Boston, MA 02110-1301, USA. */ Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p; +Lisp_Object Qscroll_up, Qscroll_down; Lisp_Object Qwindow_size_fixed; extern Lisp_Object Qleft_margin, Qright_margin; @@ -62,10 +63,10 @@ static void window_scroll_pixel_based P_ ((Lisp_Object, int, int, int)); static void window_scroll_line_based P_ ((Lisp_Object, int, int, int)); static int window_min_size_1 P_ ((struct window *, int)); static int window_min_size P_ ((struct window *, int, int, int *)); -static void size_window P_ ((Lisp_Object, int, int, int)); +static void size_window P_ ((Lisp_Object, int, int, int, int, int)); static int freeze_window_start P_ ((struct window *, void *)); static int window_fixed_size_p P_ ((struct window *, int, int)); -static void enlarge_window P_ ((Lisp_Object, int, int, int)); +static void enlarge_window P_ ((Lisp_Object, int, int)); static Lisp_Object window_list P_ ((void)); static int add_window_to_list P_ ((struct window *, void *)); static int candidate_window_p P_ ((Lisp_Object, Lisp_Object, Lisp_Object, @@ -210,6 +211,14 @@ Lisp_Object Vwindow_configuration_change_hook; Lisp_Object Vscroll_preserve_screen_position; +/* Incremented by 1 whenever a window is deleted. */ + +int window_deletion_count; + +/* Used by the function window_scroll_pixel_based */ + +static int window_scroll_pixel_based_preserve_y; + #if 0 /* This isn't used anywhere. */ /* Nonzero means we can split a frame even if it is "unsplittable". */ static int inhibit_frame_unsplittable; @@ -652,12 +661,24 @@ coordinates_in_window (w, x, y) || WINDOW_RIGHTMOST_P (w)) { if (!WINDOW_LEFTMOST_P (w) && abs (*x - x0) < grabbable_width) - return ON_VERTICAL_BORDER; + { + /* Convert X and Y to window relative coordinates. + Vertical border is at the left edge of window. */ + *x = max (0, *x - x0); + *y -= top_y; + return ON_VERTICAL_BORDER; + } } else { if (abs (*x - x1) < grabbable_width) - return ON_VERTICAL_BORDER; + { + /* Convert X and Y to window relative coordinates. + Vertical border is at the right edge of window. */ + *x = min (x1, *x) - x0; + *y -= top_y; + return ON_VERTICAL_BORDER; + } } if (*x < x0 || *x >= x1) @@ -699,7 +720,13 @@ coordinates_in_window (w, x, y) && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w) && !WINDOW_RIGHTMOST_P (w) && (abs (*x - right_x) < grabbable_width)) - return ON_VERTICAL_BORDER; + { + /* Convert X and Y to window relative coordinates. + Vertical border is at the right edge of window. */ + *x = min (right_x, *x) - left_x; + *y -= top_y; + return ON_VERTICAL_BORDER; + } } else { @@ -711,6 +738,8 @@ coordinates_in_window (w, x, y) { /* On the border on the right side of the window? Assume that this area begins at RIGHT_X minus a canonical char width. */ + *x = min (right_x, *x) - left_x; + *y -= top_y; return ON_VERTICAL_BORDER; } } @@ -1333,7 +1362,7 @@ delete_window (window) CHECK_WINDOW (window); p = XWINDOW (window); - /* It's okay to delete an already-deleted window. */ + /* It's a no-op to delete an already-deleted window. */ if (NILP (p->buffer) && NILP (p->hchild) && NILP (p->vchild)) @@ -1397,6 +1426,9 @@ delete_window (window) } } + /* Now we know we can delete this one. */ + window_deletion_count++; + tem = p->buffer; /* tem is null for dummy parent windows (which have inferiors but not any contents themselves) */ @@ -1822,7 +1854,7 @@ DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p", All windows on current frame are arranged in a cyclic order. This command selects the window ARG steps away in that order. A negative ARG moves in the opposite order. The optional second -argument ALL_FRAMES has the same meaning as in `next-window', which see. */) +argument ALL-FRAMES has the same meaning as in `next-window', which see. */) (arg, all_frames) Lisp_Object arg, all_frames; { @@ -1854,7 +1886,8 @@ MINIBUF neither nil nor t means never include the minibuffer window. */) Lisp_Object frame, minibuf, window; { if (NILP (window)) - window = selected_window; + window = FRAMEP (frame) ? XFRAME (frame)->selected_window : selected_window; + CHECK_WINDOW (window); if (NILP (frame)) frame = selected_frame; @@ -1962,7 +1995,7 @@ window_loop (type, obj, mini, frames) GCPRO1 (windows); best_window = Qnil; - for (; CONSP (windows); windows = CDR (windows)) + for (; CONSP (windows); windows = XCDR (windows)) { struct window *w; @@ -2000,7 +2033,7 @@ window_loop (type, obj, mini, frames) `obj & 1' means consider only full-width windows. `obj & 2' means consider also dedicated windows. */ if (((XINT (obj) & 1) && !WINDOW_FULL_WIDTH_P (w)) - || (!(XINT (obj) & 2) && EQ (w->dedicated, Qt)) + || (!(XINT (obj) & 2) && !NILP (w->dedicated)) /* Minibuffer windows are always ignored. */ || MINI_WINDOW_P (w)) break; @@ -2055,7 +2088,7 @@ window_loop (type, obj, mini, frames) case GET_LARGEST_WINDOW: { /* nil `obj' means to ignore dedicated windows. */ /* Ignore dedicated windows and minibuffers. */ - if (MINI_WINDOW_P (w) || (NILP (obj) && EQ (w->dedicated, Qt))) + if (MINI_WINDOW_P (w) || (NILP (obj) && !NILP (w->dedicated))) break; if (NILP (best_window)) @@ -2561,7 +2594,10 @@ window_min_size_1 (w, width_p) else { if (width_p) - size = window_min_width; + size = max (window_min_width, + (MIN_SAFE_WINDOW_WIDTH + + WINDOW_FRINGE_COLS (w) + + WINDOW_SCROLL_BAR_COLS (w))); else { if (MINI_WINDOW_P (w) @@ -2790,17 +2826,23 @@ shrink_windows (total, size, nchildren, shrinkable, /* Set WINDOW's height or width to SIZE. WIDTH_P non-zero means set WINDOW's width. Resize WINDOW's children, if any, so that they - keep their proportionate size relative to WINDOW. Propagate - WINDOW's top or left edge position to children. Delete windows - that become too small unless NODELETE_P is non-zero. + keep their proportionate size relative to WINDOW. + + If FIRST_ONLY is 1, change only the first of WINDOW's children when + they are in series. If LAST_ONLY is 1, change only the last of + WINDOW's children when they are in series. + + Propagate WINDOW's top or left edge position to children. Delete + windows that become too small unless NODELETE_P is non-zero. If NODELETE_P is 2, that means we do delete windows that are too small, even if they were too small before! */ static void -size_window (window, size, width_p, nodelete_p) +size_window (window, size, width_p, nodelete_p, first_only, last_only) Lisp_Object window; int size, width_p, nodelete_p; + int first_only, last_only; { struct window *w = XWINDOW (window); struct window *c; @@ -2875,6 +2917,7 @@ size_window (window, size, width_p, nodelete_p) if (!NILP (*sideward)) { + /* We have a chain of parallel siblings whose size should all change. */ for (child = *sideward; !NILP (child); child = c->next) { c = XWINDOW (child); @@ -2882,9 +2925,45 @@ size_window (window, size, width_p, nodelete_p) c->left_col = w->left_col; else c->top_line = w->top_line; - size_window (child, size, width_p, nodelete_p); + size_window (child, size, width_p, nodelete_p, + first_only, last_only); } } + else if (!NILP (*forward) && last_only) + { + /* Change the last in a series of siblings. */ + Lisp_Object last_child; + int child_size; + + for (child = *forward; !NILP (child); child = c->next) + { + c = XWINDOW (child); + last_child = child; + } + + child_size = XINT (width_p ? c->total_cols : c->total_lines); + size_window (last_child, + size - old_size + child_size, + width_p, nodelete_p, first_only, last_only); + } + else if (!NILP (*forward) && first_only) + { + /* Change the first in a series of siblings. */ + int child_size; + + child = *forward; + c = XWINDOW (child); + + if (width_p) + c->left_col = w->left_col; + else + c->top_line = w->top_line; + + child_size = XINT (width_p ? c->total_cols : c->total_lines); + size_window (child, + size - old_size + child_size, + width_p, nodelete_p, first_only, last_only); + } else if (!NILP (*forward)) { int fixed_size, each, extra, n; @@ -2892,7 +2971,7 @@ size_window (window, size, width_p, nodelete_p) int last_pos, first_pos, nchildren, total; int *new_sizes = NULL; - /* Determine the fixed-size portion of the this window, and the + /* Determine the fixed-size portion of this window, and the number of child windows. */ fixed_size = nchildren = nfixed = total = 0; for (child = *forward; !NILP (child); child = c->next, ++nchildren) @@ -2955,7 +3034,7 @@ size_window (window, size, width_p, nodelete_p) /* Set new height. Note that size_window also propagates edge positions to children, so it's not a no-op if we didn't change the child's size. */ - size_window (child, new_size, width_p, 1); + size_window (child, new_size, width_p, 1, first_only, last_only); /* Remember the bottom/right edge position of this child; it will be used to set the top/left edge of the next child. */ @@ -2974,7 +3053,7 @@ size_window (window, size, width_p, nodelete_p) int child_size; c = XWINDOW (child); child_size = width_p ? XINT (c->total_cols) : XINT (c->total_lines); - size_window (child, child_size, width_p, 2); + size_window (child, child_size, width_p, 2, first_only, last_only); } } } @@ -2990,7 +3069,7 @@ set_window_height (window, height, nodelete) int height; int nodelete; { - size_window (window, height, 0, nodelete); + size_window (window, height, 0, nodelete, 0, 0); } @@ -3005,7 +3084,7 @@ set_window_width (window, width, nodelete) int width; int nodelete; { - size_window (window, width, 1, nodelete); + size_window (window, width, 1, nodelete, 0, 0); } /* Change window heights in windows rooted in WINDOW by N lines. */ @@ -3401,7 +3480,7 @@ displaying BUFFER, then simply raise that frame. The variables `special-display-buffer-names', `special-display-regexps', `same-window-buffer-names', and `same-window-regexps' customize how certain buffer names are handled. -The latter two take effect only if NOT-THIS-WINDOW is t. +The latter two take effect only if NOT-THIS-WINDOW is nil. If optional argument FRAME is `visible', search all visible frames. If FRAME is 0, search all visible and iconified frames. @@ -3583,7 +3662,7 @@ displayed. */) + XFASTINT (XWINDOW (window)->total_lines)); enlarge_window (upper, total / 2 - XFASTINT (XWINDOW (upper)->total_lines), - 0, 0); + 0); } } } @@ -3660,7 +3739,7 @@ temp_output_buffer_show (buf) #endif set_buffer_internal (old); - if (!EQ (Vtemp_buffer_show_function, Qnil)) + if (!NILP (Vtemp_buffer_show_function)) call1 (Vtemp_buffer_show_function, buf); else { @@ -3742,7 +3821,9 @@ SIZE includes that window's scroll bar, or the divider column to its right. Interactively, all arguments are nil. Returns the newly created window (which is the lower or rightmost one). -The upper or leftmost window is the original one and remains selected. +The upper or leftmost window is the original one, and remains selected +if it was selected before. + See Info node `(elisp)Splitting Windows' for more details and examples.*/) (window, size, horflag) Lisp_Object window, size, horflag; @@ -3874,21 +3955,18 @@ See Info node `(elisp)Splitting Windows' for more details and examples.*/) return new; } -DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 3, "p", +DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p", doc: /* Make current window ARG lines bigger. From program, optional second arg non-nil means grow sideways ARG columns. Interactively, if an argument is not given, make the window one line bigger. If HORIZONTAL is non-nil, enlarge horizontally instead of vertically. - -Optional third arg PRESERVE-BEFORE, if non-nil, means do not change the size -of the siblings above or to the left of the selected window. Only -siblings to the right or below are changed. */) - (arg, horizontal, preserve_before) - register Lisp_Object arg, horizontal, preserve_before; +This function can delete windows, even the second window, if they get +too small. */) + (arg, horizontal) + Lisp_Object arg, horizontal; { CHECK_NUMBER (arg); - enlarge_window (selected_window, XINT (arg), !NILP (horizontal), - !NILP (preserve_before)); + enlarge_window (selected_window, XINT (arg), !NILP (horizontal)); if (! NILP (Vwindow_configuration_change_hook)) call1 (Vrun_hooks, Qwindow_configuration_change_hook); @@ -3896,20 +3974,16 @@ siblings to the right or below are changed. */) return Qnil; } -DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 3, "p", +DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p", doc: /* Make current window ARG lines smaller. From program, optional second arg non-nil means shrink sideways arg columns. -Interactively, if an argument is not given, make the window one line smaller. - -Optional third arg PRESERVE-BEFORE, if non-nil, means do not change the size -of the siblings above or to the left of the selected window. Only +Interactively, if an argument is not given, make the window one line smaller. Only siblings to the right or below are changed. */) - (arg, side, preserve_before) - register Lisp_Object arg, side, preserve_before; + (arg, side) + Lisp_Object arg, side; { CHECK_NUMBER (arg); - enlarge_window (selected_window, -XINT (arg), !NILP (side), - !NILP (preserve_before)); + enlarge_window (selected_window, -XINT (arg), !NILP (side)); if (! NILP (Vwindow_configuration_change_hook)) call1 (Vrun_hooks, Qwindow_configuration_change_hook); @@ -3947,15 +4021,12 @@ window_width (window) Siblings of the selected window are resized to fulfill the size request. If they become too small in the process, they will be - deleted. - - If PRESERVE_BEFORE is nonzero, that means don't alter - the siblings to the left or above WINDOW. */ + deleted. */ static void -enlarge_window (window, delta, horiz_flag, preserve_before) +enlarge_window (window, delta, horiz_flag) Lisp_Object window; - int delta, horiz_flag, preserve_before; + int delta, horiz_flag; { Lisp_Object parent, next, prev; struct window *p; @@ -4002,33 +4073,18 @@ enlarge_window (window, delta, horiz_flag, preserve_before) /* Compute the maximum size increment this window can have. */ - if (preserve_before) - { - if (!NILP (parent)) - { - maxdelta = (*sizefun) (parent) - XINT (*sizep); - /* Subtract size of siblings before, since we can't take that. */ - maxdelta -= XINT (CURBEG (window)) - XINT (CURBEG (parent)); - } - else - maxdelta = (!NILP (p->next) ? ((*sizefun) (p->next) - - window_min_size (XWINDOW (p->next), - horiz_flag, 0, 0)) - : (delta = 0)); - } - else - maxdelta = (!NILP (parent) ? (*sizefun) (parent) - XINT (*sizep) - /* This is a main window followed by a minibuffer. */ - : !NILP (p->next) ? ((*sizefun) (p->next) - - window_min_size (XWINDOW (p->next), - horiz_flag, 0, 0)) - /* This is a minibuffer following a main window. */ - : !NILP (p->prev) ? ((*sizefun) (p->prev) - - window_min_size (XWINDOW (p->prev), - horiz_flag, 0, 0)) - /* This is a frame with only one window, a minibuffer-only - or a minibufferless frame. */ - : (delta = 0)); + maxdelta = (!NILP (parent) ? (*sizefun) (parent) - XINT (*sizep) + /* This is a main window followed by a minibuffer. */ + : !NILP (p->next) ? ((*sizefun) (p->next) + - window_min_size (XWINDOW (p->next), + horiz_flag, 0, 0)) + /* This is a minibuffer following a main window. */ + : !NILP (p->prev) ? ((*sizefun) (p->prev) + - window_min_size (XWINDOW (p->prev), + horiz_flag, 0, 0)) + /* This is a frame with only one window, a minibuffer-only + or a minibufferless frame. */ + : (delta = 0)); if (delta > maxdelta) /* This case traps trying to make the minibuffer @@ -4051,10 +4107,9 @@ enlarge_window (window, delta, horiz_flag, preserve_before) for (next = p->next; ! NILP (next); next = XWINDOW (next)->next) maximum += (*sizefun) (next) - window_min_size (XWINDOW (next), horiz_flag, 0, 0); - if (! preserve_before) - for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev) - maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev), - horiz_flag, 0, 0); + for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev) + maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev), + horiz_flag, 0, 0); /* If we can get it all from them without deleting them, do so. */ if (delta <= maximum) @@ -4070,7 +4125,7 @@ enlarge_window (window, delta, horiz_flag, preserve_before) moving away from this window in both directions alternately, and take as much as we can get without deleting that sibling. */ while (delta != 0 - && (!NILP (next) || (!preserve_before && !NILP (prev)))) + && (!NILP (next) || !NILP (prev))) { if (! NILP (next)) { @@ -4094,7 +4149,7 @@ enlarge_window (window, delta, horiz_flag, preserve_before) if (delta == 0) break; - if (!preserve_before && ! NILP (prev)) + if (! NILP (prev)) { int this_one = ((*sizefun) (prev) - window_min_size (XWINDOW (prev), @@ -4231,9 +4286,173 @@ enlarge_window (window, delta, horiz_flag, preserve_before) adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window)))); } + +/* Adjust the size of WINDOW by DELTA, moving only its trailing edge. + HORIZ_FLAG nonzero means adjust the width, moving the right edge. + zero means adjust the height, moving the bottom edge. + + Following siblings of the selected window are resized to fulfill + the size request. If they become too small in the process, they + are not deleted; instead, we signal an error. */ + +static void +adjust_window_trailing_edge (window, delta, horiz_flag) + Lisp_Object window; + int delta, horiz_flag; +{ + Lisp_Object parent, child; + struct window *p; + Lisp_Object old_config = Fcurrent_window_configuration (Qnil); + int delcount = window_deletion_count; + + /* Check values of window_min_width and window_min_height for + validity. */ + check_min_window_sizes (); + + if (NILP (window)) + window = Fselected_window (); + + CHECK_WINDOW (window); + + /* Give up if this window cannot be resized. */ + if (window_fixed_size_p (XWINDOW (window), horiz_flag, 1)) + error ("Window is not resizable"); + + while (1) + { + Lisp_Object first_parallel = Qnil; + + if (NILP (window)) + { + /* This happens if WINDOW on the previous iteration was + at top level of the window tree. */ + Fset_window_configuration (old_config); + error ("Specified window edge is fixed"); + } + + p = XWINDOW (window); + parent = p->parent; + + /* See if this level has windows in parallel in the specified + direction. If so, set FIRST_PARALLEL to the first one. */ + if (horiz_flag) + { + if (! NILP (parent) && !NILP (XWINDOW (parent)->vchild)) + first_parallel = XWINDOW (parent)->vchild; + else if (NILP (parent) && !NILP (p->next)) + { + /* Handle the vertical chain of main window and minibuffer + which has no parent. */ + first_parallel = window; + while (! NILP (XWINDOW (first_parallel)->prev)) + first_parallel = XWINDOW (first_parallel)->prev; + } + } + else + { + if (! NILP (parent) && !NILP (XWINDOW (parent)->hchild)) + first_parallel = XWINDOW (parent)->hchild; + } + + /* If this level's succession is in the desired dimension, + and this window is the last one, and there is no higher level, + its trailing edge is fixed. */ + if (NILP (XWINDOW (window)->next) && NILP (first_parallel) + && NILP (parent)) + { + Fset_window_configuration (old_config); + error ("Specified window edge is fixed"); + } + + /* Don't make this window too small. */ + if (XINT (CURSIZE (window)) + delta + < (horiz_flag ? window_min_width : window_min_height)) + { + Fset_window_configuration (old_config); + error ("Cannot adjust window size as specified"); + } + + /* Clear out some redisplay caches. */ + XSETFASTINT (p->last_modified, 0); + XSETFASTINT (p->last_overlay_modified, 0); + + /* Adjust this window's edge. */ + XSETINT (CURSIZE (window), + XINT (CURSIZE (window)) + delta); + + /* If this window has following siblings in the desired dimension, + make them smaller, and exit the loop. + + (If we reach the top of the tree and can never do this, + we will fail and report an error, above.) */ + if (NILP (first_parallel)) + { + if (!NILP (p->next)) + { + /* This may happen for the minibuffer. In that case + the window_deletion_count check below does not work. */ + if (XINT (CURSIZE (p->next)) - delta <= 0) + { + Fset_window_configuration (old_config); + error ("Cannot adjust window size as specified"); + } + + XSETINT (CURBEG (p->next), + XINT (CURBEG (p->next)) + delta); + size_window (p->next, XINT (CURSIZE (p->next)) - delta, + horiz_flag, 0, 1, 0); + break; + } + } + else + /* Here we have a chain of parallel siblings, in the other dimension. + Change the size of the other siblings. */ + for (child = first_parallel; + ! NILP (child); + child = XWINDOW (child)->next) + if (! EQ (child, window)) + size_window (child, XINT (CURSIZE (child)) + delta, + horiz_flag, 0, 0, 1); + + window = parent; + } + + /* If we made a window so small it got deleted, + we failed. Report failure. */ + if (delcount != window_deletion_count) + { + Fset_window_configuration (old_config); + error ("Cannot adjust window size as specified"); + } + + /* Adjust glyph matrices. */ + adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window)))); +} + #undef CURBEG #undef CURSIZE +DEFUN ("adjust-window-trailing-edge", Fadjust_window_trailing_edge, + Sadjust_window_trailing_edge, 3, 3, 0, + doc: /* Adjust the bottom or right edge of WINDOW by DELTA. +If HORIZONTAL is non-nil, that means adjust the width, moving the right edge. +Otherwise, adjust the height, moving the bottom edge. + +Following siblings of the selected window are resized to fulfill +the size request. If they become too small in the process, they +are not deleted; instead, we signal an error. */) + (window, delta, horizontal) + Lisp_Object window, delta, horizontal; +{ + CHECK_NUMBER (delta); + adjust_window_trailing_edge (window, XINT (delta), !NILP (horizontal)); + + if (! NILP (Vwindow_configuration_change_hook)) + call1 (Vrun_hooks, Qwindow_configuration_change_hook); + + return Qnil; +} + /*********************************************************************** @@ -4468,7 +4687,7 @@ shrink_mini_window (w) among the other windows. */ Lisp_Object window; XSETWINDOW (window, w); - enlarge_window (window, 1 - XFASTINT (w->total_lines), 0, 0); + enlarge_window (window, 1 - XFASTINT (w->total_lines), 0); } } @@ -4601,7 +4820,6 @@ window_scroll_pixel_based (window, n, whole, noerror) struct text_pos start; Lisp_Object tem; int this_scroll_margin; - int preserve_y; /* True if we fiddled the window vscroll field without really scrolling. */ int vscrolled = 0; @@ -4667,12 +4885,21 @@ window_scroll_pixel_based (window, n, whole, noerror) point in the same window line as it is now, so get that line. */ if (!NILP (Vscroll_preserve_screen_position)) { - start_display (&it, w, start); - move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); - preserve_y = it.current_y; + /* We preserve the goal pixel coordinate across consecutive + calls to scroll-up or scroll-down. This avoids the + possibility of point becoming "stuck" on a tall line when + scrolling by one line. */ + if (window_scroll_pixel_based_preserve_y < 0 + || (!EQ (current_kboard->Vlast_command, Qscroll_up) + && !EQ (current_kboard->Vlast_command, Qscroll_down))) + { + start_display (&it, w, start); + move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); + window_scroll_pixel_based_preserve_y = it.current_y; + } } else - preserve_y = -1; + window_scroll_pixel_based_preserve_y = -1; /* Move iterator it from start the specified distance forward or backward. The result is the new window start. */ @@ -4721,7 +4948,7 @@ window_scroll_pixel_based (window, n, whole, noerror) { if (it.current_y < it.last_visible_y && (it.current_y + it.max_ascent + it.max_descent - >= it.last_visible_y)) + > it.last_visible_y)) { /* The last line was only partially visible, make it fully visible. */ @@ -4731,6 +4958,8 @@ window_scroll_pixel_based (window, n, whole, noerror) } else if (noerror) return; + else if (n < 0) /* could happen with empty buffers */ + Fsignal (Qbeginning_of_buffer, Qnil); else Fsignal (Qend_of_buffer, Qnil); } @@ -4802,14 +5031,14 @@ window_scroll_pixel_based (window, n, whole, noerror) || EQ (Vscroll_preserve_screen_position, Qt))) /* We found PT at a legitimate height. Leave it alone. */ ; - else if (preserve_y >= 0) + else if (window_scroll_pixel_based_preserve_y >= 0) { /* If we have a header line, take account of it. This is necessary because we set it.current_y to 0, above. */ - if (WINDOW_WANTS_HEADER_LINE_P (w)) - preserve_y -= CURRENT_HEADER_LINE_HEIGHT (w); - - move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y); + move_it_to (&it, -1, -1, + window_scroll_pixel_based_preserve_y + - (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0 ), + -1, MOVE_TO_Y); SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it)); } else @@ -4829,7 +5058,8 @@ window_scroll_pixel_based (window, n, whole, noerror) int charpos, bytepos; int partial_p; - /* Save our position, for the preserve_y case. */ + /* Save our position, for the + window_scroll_pixel_based_preserve_y case. */ charpos = IT_CHARPOS (it); bytepos = IT_BYTEPOS (it); @@ -4859,20 +5089,15 @@ window_scroll_pixel_based (window, n, whole, noerror) || EQ (Vscroll_preserve_screen_position, Qt))) /* We found PT before we found the display margin, so PT is ok. */ ; - else if (preserve_y >= 0) + else if (window_scroll_pixel_based_preserve_y >= 0) { SET_TEXT_POS_FROM_MARKER (start, w->start); start_display (&it, w, start); -#if 0 /* It's wrong to subtract this here - because we called start_display again - and did not alter it.current_y this time. */ - - /* If we have a header line, take account of it. */ - if (WINDOW_WANTS_HEADER_LINE_P (w)) - preserve_y -= CURRENT_HEADER_LINE_HEIGHT (w); -#endif - - move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y); + /* It would be wrong to subtract CURRENT_HEADER_LINE_HEIGHT + here because we called start_display again and did not + alter it.current_y this time. */ + move_it_to (&it, -1, -1, window_scroll_pixel_based_preserve_y, -1, + MOVE_TO_Y); SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it)); } else @@ -5636,6 +5861,7 @@ struct saved_window 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; + Lisp_Object dedicated; }; #define SAVED_WINDOW_N(swv,n) \ @@ -5646,9 +5872,7 @@ DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_ (object) Lisp_Object object; { - if (WINDOW_CONFIGURATIONP (object)) - return Qt; - return Qnil; + return WINDOW_CONFIGURATIONP (object) ? Qt : Qnil; } DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0, @@ -5697,7 +5921,23 @@ the return value is nil. Otherwise the value is t. */) else { if (XBUFFER (new_current_buffer) == current_buffer) - old_point = PT; + /* The code further down "preserves point" by saving here PT in + old_point and then setting it later back into PT. When the + current-selected-window and the final-selected-window both show + the current buffer, this suffers from the problem that the + current PT is the window-point of the current-selected-window, + while the final PT is the point of the final-selected-window, so + this copy from one PT to the other would end up moving the + window-point of the final-selected-window to the window-point of + the current-selected-window. So we have to be careful which + point of the current-buffer we copy into old_point. */ + if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer) + && WINDOWP (selected_window) + && EQ (XWINDOW (selected_window)->buffer, new_current_buffer) + && !EQ (selected_window, data->current_window)) + old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos; + else + old_point = PT; else /* BUF_PT (XBUFFER (new_current_buffer)) gives us the position of point in new_current_buffer as of the last time this buffer was @@ -5854,6 +6094,7 @@ the return value is nil. Otherwise the value is t. */) w->fringes_outside_margins = p->fringes_outside_margins; w->scroll_bar_width = p->scroll_bar_width; w->vertical_scroll_bar_type = p->vertical_scroll_bar_type; + w->dedicated = p->dedicated; XSETFASTINT (w->last_modified, 0); XSETFASTINT (w->last_overlay_modified, 0); @@ -6123,6 +6364,7 @@ save_window_save (window, vector, i) p->fringes_outside_margins = w->fringes_outside_margins; p->scroll_bar_width = w->scroll_bar_width; p->vertical_scroll_bar_type = w->vertical_scroll_bar_type; + p->dedicated = w->dedicated; if (!NILP (w->buffer)) { /* Save w's value of point in the window configuration. @@ -6468,7 +6710,8 @@ this is automatically adjusted to a multiple of the frame column width. 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 TYPE is t, use the frame's scroll-bar type. */) +If VERTICAL-TYPE is t, use the frame's scroll-bar type. +Fourth parameter HORIZONTAL-TYPE is currently unused. */) (window, width, vertical_type, horizontal_type) Lisp_Object window, width, vertical_type, horizontal_type; { @@ -6536,7 +6779,7 @@ DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 2, 0, doc: /* Return the amount by which WINDOW is scrolled vertically. Use the selected window if WINDOW is nil or omitted. Normally, value is a multiple of the canonical character height of WINDOW; -optional second arg PIXELS_P means value is measured in pixels. */) +optional second arg PIXELS-P means value is measured in pixels. */) (window, pixels_p) Lisp_Object window, pixels_p; { @@ -6566,7 +6809,7 @@ DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll, doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL. 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. +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. @@ -6621,7 +6864,9 @@ foreach_window (f, fn, user_data) int (* fn) P_ ((struct window *, void *)); void *user_data; { - foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data); + /* Fdelete_frame may set FRAME_ROOT_WINDOW (f) to Qnil. */ + if (WINDOWP (FRAME_ROOT_WINDOW (f))) + foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data); } @@ -6851,6 +7096,12 @@ init_window () void syms_of_window () { + Qscroll_up = intern ("scroll-up"); + staticpro (&Qscroll_up); + + Qscroll_down = intern ("scroll-down"); + staticpro (&Qscroll_down); + Qwindow_size_fixed = intern ("window-size-fixed"); staticpro (&Qwindow_size_fixed); Fset (Qwindow_size_fixed, Qnil); @@ -6876,6 +7127,8 @@ syms_of_window () minibuf_selected_window = Qnil; staticpro (&minibuf_selected_window); + window_scroll_pixel_based_preserve_y = -1; + DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function, doc: /* Non-nil means call as function to display a help buffer. The function is called with one argument, the buffer to be displayed. @@ -7114,6 +7367,7 @@ The selected frame is the one whose configuration has changed. */); defsubr (&Ssplit_window); defsubr (&Senlarge_window); defsubr (&Sshrink_window); + defsubr (&Sadjust_window_trailing_edge); defsubr (&Sscroll_up); defsubr (&Sscroll_down); defsubr (&Sscroll_left);