/* Window creation, deletion and examination for GNU Emacs.
Does not include redisplay.
- Copyright (C) 1985,86,87, 1993,94,95,96,97,98, 2000,01,02,03,04
- Free Software Foundation, Inc.
+ Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1996, 1997, 1998, 2000,
+ 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GNU Emacs.
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#include <config.h>
#include "lisp.h"
void *));
static Lisp_Object window_list_1 P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
-/* The value of `window-size-fixed'. */
-
-int window_size_fixed;
-
/* This is the window in which the terminal's cursor should
be left when nothing is being done with it. This must
always be a leaf window, and its buffer is selected by
Lisp_Object Vtemp_buffer_show_function;
+/* Non-zero means line and page scrolling on tall lines (with images)
+ does partial scrolling by modifying window-vscroll. */
+
+int auto_window_vscroll_p;
+
/* Non-zero means to use mode-line-inactive face in all windows but the
selected-window and the minibuffer-scroll-window when the
minibuffer is active. */
Lisp_Object Qwindow_configuration_change_hook;
Lisp_Object Vwindow_configuration_change_hook;
-/* Nonzero means scroll commands try to put point
+/* Non-nil means scroll commands try to put point
at the same screen height as previously. */
Lisp_Object Vscroll_preserve_screen_position;
register struct window *p;
p = allocate_window ();
- XSETFASTINT (p->sequence_number, ++sequence_number);
+ ++sequence_number;
+ XSETFASTINT (p->sequence_number, sequence_number);
XSETFASTINT (p->left_col, 0);
XSETFASTINT (p->top_line, 0);
XSETFASTINT (p->total_lines, 0);
p->fringes_outside_margins = Qnil;
p->scroll_bar_width = Qnil;
p->vertical_scroll_bar_type = Qt;
- p->overlay_arrow_bitmap = 0;
Vwindow_list = Qnil;
return val;
POS defaults to point in WINDOW; WINDOW defaults to the selected window.
If POS is visible, return t if PARTIALLY is nil; if PARTIALLY is non-nil,
-return value is a list (X Y FULLY) where X and Y are the pixel coordinates
-relative to the top left corner of the window, and FULLY is t if the
-character after POS is fully visible and nil otherwise. */)
+return value is a list (X Y PARTIAL) where X and Y are the pixel coordinates
+relative to the top left corner of the window. PARTIAL is nil if the character
+after POS is fully visible; otherwise it is a cons (RTOP . RBOT) where RTOP
+and RBOT are the number of pixels invisible at the top and bottom of the row. */)
(pos, window, partially)
Lisp_Object pos, window, partially;
{
register struct buffer *buf;
struct text_pos top;
Lisp_Object in_window = Qnil;
- int fully_p = 1;
+ int rtop, rbot, fully_p = 1;
int x, y;
w = decode_window (window);
&& posint <= BUF_ZV (buf)
&& CHARPOS (top) >= BUF_BEGV (buf)
&& CHARPOS (top) <= BUF_ZV (buf)
- && pos_visible_p (w, posint, &fully_p, &x, &y, NILP (partially))
- && (!NILP (partially) || fully_p))
+ && pos_visible_p (w, posint, &x, &y, &rtop, &rbot, NILP (partially))
+ && (fully_p = !rtop && !rbot, (!NILP (partially) || fully_p)))
in_window = Qt;
if (!NILP (in_window) && !NILP (partially))
in_window = Fcons (make_number (x),
Fcons (make_number (y),
- Fcons (fully_p ? Qt : Qnil, Qnil)));
+ Fcons ((fully_p ? Qnil
+ : Fcons (make_number (rtop),
+ make_number (rbot))),
+ Qnil)));
return in_window;
}
+ WINDOW_LEFT_FRINGE_COLS (w)),
make_number (WINDOW_TOP_EDGE_LINE (w)
+ WINDOW_HEADER_LINE_LINES (w)),
- make_number (WINDOW_RIGHT_EDGE_COL (w)
+ make_number (WINDOW_BOX_RIGHT_EDGE_COL (w)
- WINDOW_RIGHT_MARGIN_COLS (w)
- WINDOW_RIGHT_FRINGE_COLS (w)),
make_number (WINDOW_BOTTOM_EDGE_LINE (w)
+ WINDOW_LEFT_FRINGE_WIDTH (w)),
make_number (WINDOW_TOP_EDGE_Y (w)
+ WINDOW_HEADER_LINE_HEIGHT (w)),
- make_number (WINDOW_RIGHT_EDGE_X (w)
+ make_number (WINDOW_BOX_RIGHT_EDGE_X (w)
- WINDOW_RIGHT_MARGIN_WIDTH (w)
- WINDOW_RIGHT_FRINGE_WIDTH (w)),
make_number (WINDOW_BOTTOM_EDGE_Y (w)
int grabbable_width = ux;
int lmargin_width, rmargin_width, text_left, text_right;
- if (*x < x0 || *x >= x1)
- return ON_NOTHING;
-
/* In what's below, we subtract 1 when computing right_x because we
want the rightmost pixel, which is given by left_pixel+width-1. */
if (w->pseudo_window_p)
return ON_VERTICAL_BORDER;
}
+ if (*x < x0 || *x >= x1)
+ return ON_NOTHING;
+
/* Convert X and Y to window relative coordinates.
Mode line starts at left edge of window. */
*x -= x0;
goto header_vertical_border_check;
}
+ if (*x < x0 || *x >= x1)
+ return ON_NOTHING;
+
/* Outside any interesting column? */
if (*x < left_x || *x > right_x)
return ON_SCROLL_BAR;
tem = par->hchild;
if (NILP (tem))
tem = par->vchild;
- if (NILP (XWINDOW (tem)->next))
+ if (NILP (XWINDOW (tem)->next)) {
replace_window (parent, tem);
+ par = XWINDOW (tem);
+ }
/* Since we may be deleting combination windows, we must make sure that
not only p but all its children have been marked as deleted. */
/* Mark this window as deleted. */
p->buffer = p->hchild = p->vchild = Qnil;
+ if (! NILP (par->parent))
+ par = XWINDOW (par->parent);
+
+ /* Check if we have a v/hchild with a v/hchild. In that case remove
+ one of them. */
+
+ if (! NILP (par->vchild) && ! NILP (XWINDOW (par->vchild)->vchild))
+ {
+ p = XWINDOW (par->vchild);
+ par->vchild = p->vchild;
+ tem = p->vchild;
+ }
+ else if (! NILP (par->hchild) && ! NILP (XWINDOW (par->hchild)->hchild))
+ {
+ p = XWINDOW (par->hchild);
+ par->hchild = p->hchild;
+ tem = p->hchild;
+ }
+ else
+ p = 0;
+
+ if (p)
+ {
+ while (! NILP (tem)) {
+ XWINDOW (tem)->parent = p->parent;
+ if (NILP (XWINDOW (tem)->next))
+ break;
+ tem = XWINDOW (tem)->next;
+ }
+ if (! NILP (tem)) {
+ /* The next of the v/hchild we are removing is now the next of the
+ last child for the v/hchild:
+ Before v/hchild -> v/hchild -> next1 -> next2
+ |
+ -> next3
+ After: v/hchild -> next1 -> next2 -> next3
+ */
+ XWINDOW (tem)->next = p->next;
+ if (! NILP (p->next))
+ XWINDOW (p->next)->prev = tem;
+ }
+ p->next = p->prev = p->vchild = p->hchild = p->buffer = Qnil;
+ }
+
+
/* Adjust glyph matrices. */
adjust_glyphs (f);
UNBLOCK_INPUT;
: Qnil);
else if (EQ (*all_frames, Qvisible))
;
- else if (XFASTINT (*all_frames) == 0)
+ else if (EQ (*all_frames, make_number (0)))
;
else if (FRAMEP (*all_frames))
;
if (f)
frame_arg = Qlambda;
- else if (XFASTINT (frames) == 0)
+ else if (EQ (frames, make_number (0)))
frame_arg = frames;
else if (EQ (frames, Qvisible))
frame_arg = frames;
doc: /* Return the window least recently selected or used for display.
Return a full-width window if possible.
A minibuffer window is never a candidate.
+A dedicated window is never a candidate, so if all windows are dedicated,
+the value is nil.
If optional argument FRAME is `visible', search all visible frames.
If FRAME is 0, search all visible and iconified frames.
If FRAME is t, search all frames.
DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 1, 0,
doc: /* Return the largest window in area.
A minibuffer window is never a candidate.
+A dedicated window is never a candidate, so if all windows are dedicated,
+the value is nil.
If optional argument FRAME is `visible', search all visible frames.
If FRAME is 0, search all visible and iconified frames.
If FRAME is t, search all frames.
--shrinkable;
total_removed += smallest;
+ /* We don't know what the smallest is now. */
+ smallest = total;
+
/* Out of for, just remove one window at the time and
check again if we have enough space. */
break;
that are left and still can be shrunk. */
while (total_shrink > total_removed)
{
+ int nonzero_sizes = 0;
+ int nonzero_idx = -1;
+
+ for (i = 0; i < nchildren; ++i)
+ if (new_sizes[i] > 0)
+ {
+ ++nonzero_sizes;
+ nonzero_idx = i;
+ }
+
for (i = 0; i < nchildren; ++i)
if (new_sizes[i] > min_size)
{
check again if we have enough space. */
break;
}
+
+
+ /* Special case, only one window left. */
+ if (nonzero_sizes == 1)
+ break;
+ }
+
+ /* Any surplus due to rounding, we add to windows that are left. */
+ while (total_shrink < total_removed)
+ {
+ for (i = 0; i < nchildren; ++i)
+ {
+ if (new_sizes[i] != 0 && total_shrink < total_removed)
+ {
+ ++new_sizes[i];
+ --total_removed;
+ break;
+ }
+ }
}
return new_sizes;
if (EQ (window, selected_window))
b->last_selected_window = window;
+ /* Let redisplay errors through. */
+ b->display_error_modiff = 0;
+
/* Update time stamps of buffer display. */
if (INTEGERP (b->display_count))
XSETINT (b->display_count, XINT (b->display_count) + 1);
w = XWINDOW (window);
w->frozen_window_start_p = 0;
- XSETFASTINT (w->use_time, ++window_select_count);
+ ++window_select_count;
+ XSETFASTINT (w->use_time, window_select_count);
if (EQ (window, selected_window))
return window;
+ /* Store the current buffer's actual point into the
+ old selected window. It belongs to that window,
+ and when the window is not selected, must be in the window. */
if (!NILP (selected_window))
{
ow = XWINDOW (selected_window);
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), Qnil);
+ Fselect_frame (WINDOW_FRAME (w));
}
else
sf->selected_window = window;
}
DEFUN ("special-display-p", Fspecial_display_p, Sspecial_display_p, 1, 1, 0,
- doc: /* Returns non-nil if a buffer named BUFFER-NAME would be created specially.
-The value is actually t if the frame should be called with default frame
-parameters, and a list of frame parameters if they were specified.
-See `special-display-buffer-names', and `special-display-regexps'. */)
+ doc: /* Returns non-nil if a buffer named BUFFER-NAME gets a special frame.
+If the value is t, `display-buffer' or `pop-to-buffer' would create a
+special frame for that buffer using the default frame parameters.
+
+If the value is a list, it is a list of frame parameters that would be used
+to make a frame for that buffer.
+The variables `special-display-buffer-names'
+and `special-display-regexps' control this. */)
(buffer_name)
Lisp_Object buffer_name;
{
}
DEFUN ("same-window-p", Fsame_window_p, Ssame_window_p, 1, 1, 0,
- doc: /* Returns non-nil if a new buffer named BUFFER-NAME would use the same window.
+ doc: /* Returns non-nil if a buffer named BUFFER-NAME would use the same window.
+More precisely, if `display-buffer' or `pop-to-buffer' would display
+that buffer in the selected window rather than (as usual) in some other window.
See `same-window-buffer-names' and `same-window-regexps'. */)
(buffer_name)
Lisp_Object buffer_name;
= ((struct Lisp_Vector *)o)->contents[i];
XSETWINDOW (new, p);
- XSETFASTINT (p->sequence_number, ++sequence_number);
+ ++sequence_number;
+ XSETFASTINT (p->sequence_number, sequence_number);
/* Put new into window structure in place of window */
replace_window (window, new);
The number of children n equals the number of resizable
children of this window + 1 because we know window itself
- is resizable (otherwise we would have signalled an error. */
+ is resizable (otherwise we would have signalled an error). */
struct window *w = XWINDOW (window);
Lisp_Object s;
results for variable height lines. */
init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
it.current_y = it.last_visible_y;
- move_it_vertically (&it, - window_box_height (w) / 2);
+ move_it_vertically_backward (&it, window_box_height (w) / 2);
/* The function move_iterator_vertically may move over more than
the specified y-distance. If it->w is small, e.g. a
if (it.current_y <= 0)
{
init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
- move_it_vertically (&it, 0);
+ move_it_vertically_backward (&it, 0);
it.current_y = 0;
}
start = it.current.pos;
}
+ else if (auto_window_vscroll_p)
+ {
+ if (tem = XCAR (XCDR (XCDR (tem))), CONSP (tem))
+ {
+ int px;
+ int dy = WINDOW_FRAME_LINE_HEIGHT (w);
+ if (whole)
+ dy = max ((window_box_height (w)
+ - next_screen_context_lines * dy),
+ dy);
+ dy *= n;
+
+ if (n < 0 && (px = XINT (XCAR (tem))) > 0)
+ {
+ px = max (0, -w->vscroll - min (px, -dy));
+ Fset_window_vscroll (window, make_number (px), Qt);
+ return;
+ }
+ if (n > 0 && (px = XINT (XCDR (tem))) > 0)
+ {
+ px = max (0, -w->vscroll + min (px, dy));
+ Fset_window_vscroll (window, make_number (px), Qt);
+ return;
+ }
+ }
+ Fset_window_vscroll (window, make_number (0), Qt);
+ }
- /* If scroll_preserve_screen_position is non-zero, we try to set
+ /* If scroll_preserve_screen_position is non-nil, we try to set
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);
if (whole)
{
- int screen_full = (window_box_height (w)
- - next_screen_context_lines * FRAME_LINE_HEIGHT (it.f));
- int dy = n * screen_full;
+ int start_pos = IT_CHARPOS (it);
+ int dy = WINDOW_FRAME_LINE_HEIGHT (w);
+ dy = max ((window_box_height (w)
+ - next_screen_context_lines * dy),
+ dy) * n;
/* 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)
- move_it_vertically_backward (&it, -dy);
+ {
+ move_it_vertically_backward (&it, -dy);
+ /* Ensure we actually does 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)
+ && start_pos > BEGV)
+ move_it_by_lines (&it, -1, 1);
+ }
else if (dy > 0)
- move_it_to (&it, ZV, -1, it.current_y + dy, -1,
- MOVE_TO_POS | MOVE_TO_Y);
+ {
+ move_it_to (&it, ZV, -1, it.current_y + dy, -1,
+ MOVE_TO_POS | MOVE_TO_Y);
+ /* Ensure we actually does 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)
+ && start_pos < ZV)
+ move_it_by_lines (&it, 1, 1);
+ }
}
else
move_it_by_lines (&it, n, 1);
w->force_start = Qt;
}
+ /* The rest of this function uses current_y in a nonstandard way,
+ not including the height of the header line if any. */
it.current_y = it.vpos = 0;
- /* Preserve the screen position if we must. */
- if (preserve_y >= 0)
- {
- move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
- SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
- }
- else
+ /* Move PT out of scroll margins.
+ This code wants current_y to be zero at the window start position
+ even if there is a header line. */
+ this_scroll_margin = max (0, scroll_margin);
+ this_scroll_margin = min (this_scroll_margin, XFASTINT (w->total_lines) / 4);
+ this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
+
+ if (n > 0)
{
- /* Move PT out of scroll margins. */
- this_scroll_margin = max (0, scroll_margin);
- this_scroll_margin = min (this_scroll_margin, XFASTINT (w->total_lines) / 4);
- this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
+ /* 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 && it.current_y >= this_scroll_margin
+ && (NILP (Vscroll_preserve_screen_position)
+ || EQ (Vscroll_preserve_screen_position, Qt)))
+ /* We found PT at a legitimate height. Leave it alone. */
+ ;
+ else if (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);
- if (n > 0)
+ move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
+ SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+ }
+ else
{
- /* 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);
while (it.current_y < this_scroll_margin)
{
int prev = it.current_y;
}
SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
}
- else if (n < 0)
+ }
+ else if (n < 0)
+ {
+ int charpos, bytepos;
+ int partial_p;
+
+ /* Save our position, for the preserve_y case. */
+ charpos = IT_CHARPOS (it);
+ bytepos = IT_BYTEPOS (it);
+
+ /* 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 - CURRENT_HEADER_LINE_HEIGHT (w)
+ - this_scroll_margin - 1),
+ -1,
+ MOVE_TO_POS | MOVE_TO_Y);
+
+ /* Save our position, in case it's correct. */
+ charpos = IT_CHARPOS (it);
+ bytepos = IT_BYTEPOS (it);
+
+ /* 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;
+ else
{
- int charpos, bytepos;
-
- /* 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 - this_scroll_margin - 1, -1,
- MOVE_TO_POS | MOVE_TO_Y);
+ move_it_by_lines (&it, 1, 1);
+ partial_p = it.current_y > it.last_visible_y;
+ }
- /* Save our position, in case it's correct. */
- charpos = IT_CHARPOS (it);
- bytepos = IT_BYTEPOS (it);
+ if (charpos == PT && !partial_p
+ && (NILP (Vscroll_preserve_screen_position)
+ || EQ (Vscroll_preserve_screen_position, Qt)))
+ /* We found PT before we found the display margin, so PT is ok. */
+ ;
+ else if (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
- /* See if point is on a partially visible line at the end. */
- move_it_by_lines (&it, 1, 1);
- if (it.current_y > it.last_visible_y)
+ move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
+ SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+ }
+ else
+ {
+ if (partial_p)
/* The last line was only partially visible, so back up two
lines to make sure we're on a fully visible line. */
{
the window-scroll-functions. */
w->force_start = Qt;
- if (whole && !NILP (Vscroll_preserve_screen_position))
+ if (!NILP (Vscroll_preserve_screen_position)
+ && (whole || !EQ (Vscroll_preserve_screen_position, Qt)))
{
SET_PT_BOTH (pos, pos_byte);
Fvertical_motion (make_number (original_vpos), window);
return Qnil;
}
\f
-DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 1, "P",
+DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 2, "P\np",
doc: /* Scroll selected window display ARG columns left.
Default for ARG is window width minus 2.
Value is the total amount of leftward horizontal scrolling in
effect after the change.
-If `automatic-hscrolling' is non-nil, the argument ARG modifies
-a lower bound for automatic scrolling, i.e. automatic scrolling
+If SET_MINIMUM is non-nil, the new scroll amount becomes the
+lower bound for automatic scrolling, i.e. automatic scrolling
will not scroll a window to a column less than the value returned
-by this function. */)
- (arg)
- register Lisp_Object arg;
+by this function. This happens in an interactive call. */)
+ (arg, set_minimum)
+ register Lisp_Object arg, set_minimum;
{
Lisp_Object result;
int hscroll;
hscroll = XINT (w->hscroll) + XINT (arg);
result = Fset_window_hscroll (selected_window, make_number (hscroll));
- if (interactive_p (0))
+ if (!NILP (set_minimum))
w->min_hscroll = w->hscroll;
return result;
}
-DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 1, "P",
+DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 2, "P\np",
doc: /* Scroll selected window display ARG columns right.
Default for ARG is window width minus 2.
Value is the total amount of leftward horizontal scrolling in
effect after the change.
-If `automatic-hscrolling' is non-nil, the argument ARG modifies
-a lower bound for automatic scrolling, i.e. automatic scrolling
+If SET_MINIMUM is non-nil, the new scroll amount becomes the
+lower bound for automatic scrolling, i.e. automatic scrolling
will not scroll a window to a column less than the value returned
-by this function. */)
- (arg)
- register Lisp_Object arg;
+by this function. This happens in an interactive call. */)
+ (arg, set_minimum)
+ register Lisp_Object arg, set_minimum;
{
Lisp_Object result;
int hscroll;
hscroll = XINT (w->hscroll) - XINT (arg);
result = Fset_window_hscroll (selected_window, make_number (hscroll));
- if (interactive_p (0))
+ if (!NILP (set_minimum))
w->min_hscroll = w->hscroll;
return result;
struct buffer *obuf = current_buffer;
int center_p = 0;
int charpos, bytepos;
+ int iarg;
+ int this_scroll_margin;
/* If redisplay is suppressed due to an error, try again. */
obuf->display_error_modiff = 0;
{
arg = Fprefix_numeric_value (arg);
CHECK_NUMBER (arg);
+ iarg = XINT (arg);
}
set_buffer_internal (buf);
+ /* Do this after making BUF current
+ in case scroll_margin is buffer-local. */
+ this_scroll_margin = max (0, scroll_margin);
+ this_scroll_margin = min (this_scroll_margin,
+ XFASTINT (w->total_lines) / 4);
+
/* Handle centering on a graphical frame specially. Such frames can
have variable-height lines and centering point on the basis of
line counts would lead to strange effects. */
SET_TEXT_POS (pt, PT, PT_BYTE);
start_display (&it, w, pt);
- move_it_vertically (&it, - window_box_height (w) / 2);
+ move_it_vertically_backward (&it, window_box_height (w) / 2);
charpos = IT_CHARPOS (it);
bytepos = IT_BYTEPOS (it);
}
- else if (XINT (arg) < 0)
+ else if (iarg < 0)
{
struct it it;
struct text_pos pt;
- int y0, y1, h, nlines;
+ int nlines = -iarg;
+ int extra_line_spacing;
+ int h = window_box_height (w);
+
+ iarg = - max (-iarg, this_scroll_margin);
SET_TEXT_POS (pt, PT, PT_BYTE);
start_display (&it, w, pt);
- y0 = it.current_y;
+
+ /* Be sure we have the exact height of the full line containing PT. */
+ move_it_by_lines (&it, 0, 1);
/* The amount of pixels we have to move back is the window
height minus what's displayed in the line containing PT,
and the lines below. */
- nlines = - XINT (arg) - 1;
+ it.current_y = 0;
+ it.vpos = 0;
move_it_by_lines (&it, nlines, 1);
- y1 = line_bottom_y (&it);
+ if (it.vpos == nlines)
+ h -= it.current_y;
+ else
+ {
+ /* Last line has no newline */
+ h -= line_bottom_y (&it);
+ it.vpos++;
+ }
+
+ /* Don't reserve space for extra line spacing of last line. */
+ extra_line_spacing = it.max_extra_line_spacing;
/* If we can't move down NLINES lines because we hit
the end of the buffer, count in some empty lines. */
if (it.vpos < nlines)
- y1 += (nlines - it.vpos) * FRAME_LINE_HEIGHT (it.f);
-
- h = window_box_height (w) - (y1 - y0);
+ {
+ nlines -= it.vpos;
+ extra_line_spacing = it.extra_line_spacing;
+ h -= nlines * (FRAME_LINE_HEIGHT (it.f) + extra_line_spacing);
+ }
+ if (h <= 0)
+ return Qnil;
+ /* Now find the new top line (starting position) of the window. */
start_display (&it, w, pt);
- move_it_vertically (&it, - h);
+ it.current_y = 0;
+ move_it_vertically_backward (&it, h);
+
+ /* If extra line spacing is present, we may move too far
+ back. This causes the last line to be only partially
+ visible (which triggers redisplay to recenter that line
+ in the middle), so move forward.
+ But ignore extra line spacing on last line, as it is not
+ considered to be part of the visible height of the line.
+ */
+ h += extra_line_spacing;
+ while (-it.current_y > h)
+ move_it_by_lines (&it, 1, 1);
+
charpos = IT_CHARPOS (it);
bytepos = IT_BYTEPOS (it);
}
else
{
struct position pos;
- pos = *vmotion (PT, - XINT (arg), w);
+
+ iarg = max (iarg, this_scroll_margin);
+
+ pos = *vmotion (PT, -iarg, w);
charpos = pos.bufpos;
bytepos = pos.bytepos;
}
int ht = window_internal_height (w);
if (center_p)
- arg = make_number (ht / 2);
- else if (XINT (arg) < 0)
- arg = make_number (XINT (arg) + ht);
+ iarg = ht / 2;
+ else if (iarg < 0)
+ iarg += ht;
+
+ /* Don't let it get into the margin at either top or bottom. */
+ iarg = max (iarg, this_scroll_margin);
+ iarg = min (iarg, ht - this_scroll_margin - 1);
- pos = *vmotion (PT, - XINT (arg), w);
+ pos = *vmotion (PT, - iarg, w);
charpos = pos.bufpos;
bytepos = pos.bytepos;
}
struct window *w = XWINDOW (selected_window);
int lines, start;
Lisp_Object window;
+#if 0
+ int this_scroll_margin;
+#endif
window = selected_window;
start = marker_position (w->start);
Fgoto_char (w->start);
lines = displayed_window_lines (w);
+
+#if 0
+ this_scroll_margin = max (0, scroll_margin);
+ this_scroll_margin = min (this_scroll_margin, lines / 4);
+#endif
+
if (NILP (arg))
XSETFASTINT (arg, lines / 2);
else
{
- arg = Fprefix_numeric_value (arg);
- if (XINT (arg) < 0)
- XSETINT (arg, XINT (arg) + lines);
+ int iarg = XINT (Fprefix_numeric_value (arg));
+
+ if (iarg < 0)
+ iarg = iarg + lines;
+
+#if 0 /* This code would prevent move-to-window-line from moving point
+ to a place inside the scroll margins (which would cause the
+ next redisplay to scroll). I wrote this code, but then concluded
+ it is probably better not to install it. However, it is here
+ inside #if 0 so as not to lose it. -- rms. */
+
+ /* Don't let it get into the margin at either top or bottom. */
+ iarg = max (iarg, this_scroll_margin);
+ iarg = min (iarg, lines - this_scroll_margin - 1);
+#endif
+
+ arg = make_number (iarg);
}
/* Skip past a partially visible first line. */
Lisp_Object scroll_bar_width, vertical_scroll_bar_type;
};
-#define SAVED_WINDOW_VECTOR_SIZE 24 /* Arg to Fmake_vector */
-
#define SAVED_WINDOW_N(swv,n) \
((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
if (XBUFFER (new_current_buffer) == current_buffer)
old_point = PT;
else
- old_point = BUF_PT (XBUFFER (new_current_buffer));
+ /* BUF_PT (XBUFFER (new_current_buffer)) gives us the position of
+ point in new_current_buffer as of the last time this buffer was
+ used. This can be non-deterministic since it can be changed by
+ things like jit-lock by mere temporary selection of some random
+ window that happens to show this buffer.
+ So if possible we want this arbitrary choice of "which point" to
+ be the one from the to-be-selected-window so as to prevent this
+ window's cursor from being copied from another window. */
+ if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer)
+ /* If current_window = selected_window, its point is in BUF_PT. */
+ && !EQ (selected_window, data->current_window))
+ old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos;
+ else
+ old_point = BUF_PT (XBUFFER (new_current_buffer));
}
frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
#endif
#endif
- /* "Swap out" point from the selected window
- into its buffer. We do this now, before
+ /* "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
restoring the window contents, and prevent it from
being done later on when we select a new window. */
if (! NILP (XWINDOW (selected_window)->buffer))
FRAME_ROOT_WINDOW (f) = data->root_window;
/* Prevent "swapping out point" in the old selected window
using the buffer that has been restored into it.
- Use the point value from the beginning of this function
- since unshow_buffer (called from delete_all_subwindows)
- could have altered it. */
+ We already swapped out point that from that window's old buffer. */
selected_window = Qnil;
+
+ /* Arrange *not* to restore point in the buffer that was
+ current when the window configuration was saved. */
if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer))
set_marker_restricted (XWINDOW (data->current_window)->pointm,
make_number (old_point),
p = SAVED_WINDOW_N (vector, i);
w = XWINDOW (window);
- XSETFASTINT (w->temslot, i++);
+ XSETFASTINT (w->temslot, i); i++;
p->window = window;
p->buffer = w->buffer;
p->left_col = w->left_col;
data->saved_windows = tem;
for (i = 0; i < n_windows; i++)
XVECTOR (tem)->contents[i]
- = Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil);
+ = Fmake_vector (make_number (VECSIZE (struct saved_window)), Qnil);
save_window_save (FRAME_ROOT_WINDOW (f), XVECTOR (tem), 0);
XSETWINDOW_CONFIGURATION (tem, data);
return (tem);
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. */)
- (window, left, right)
- Lisp_Object window, left, right;
+ (window, left_width, right_width)
+ Lisp_Object window, left_width, right_width;
{
struct window *w = decode_window (window);
/* Translate negative or zero widths to nil.
Margins that are too wide have to be checked elsewhere. */
- if (!NILP (left))
+ if (!NILP (left_width))
{
- CHECK_NUMBER (left);
- if (XINT (left) <= 0)
- left = Qnil;
+ CHECK_NUMBER (left_width);
+ if (XINT (left_width) <= 0)
+ left_width = Qnil;
}
- if (!NILP (right))
+ if (!NILP (right_width))
{
- CHECK_NUMBER (right);
- if (XINT (right) <= 0)
- right = Qnil;
+ CHECK_NUMBER (right_width);
+ if (XINT (right_width) <= 0)
+ right_width = Qnil;
}
- if (!EQ (w->left_margin_cols, left)
- || !EQ (w->right_margin_cols, right))
+ if (!EQ (w->left_margin_cols, left_width)
+ || !EQ (w->right_margin_cols, right_width))
{
- w->left_margin_cols = left;
- w->right_margin_cols = right;
+ w->left_margin_cols = left_width;
+ w->right_margin_cols = right_width;
adjust_window_margins (w);
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. */)
- (window, left, right, outside_margins)
- Lisp_Object window, left, right, outside_margins;
+ (window, left_width, right_width, outside_margins)
+ Lisp_Object window, left_width, right_width, outside_margins;
{
struct window *w = decode_window (window);
- if (!NILP (left))
- CHECK_NUMBER (left);
- if (!NILP (right))
- CHECK_NUMBER (right);
+ if (!NILP (left_width))
+ CHECK_NATNUM (left_width);
+ if (!NILP (right_width))
+ CHECK_NATNUM (right_width);
- if (!EQ (w->left_fringe_width, left)
- || !EQ (w->right_fringe_width, right)
+ if (!EQ (w->left_fringe_width, left_width)
+ || !EQ (w->right_fringe_width, right_width)
|| !EQ (w->fringes_outside_margins, outside_margins))
{
- w->left_fringe_width = left;
- w->right_fringe_width = right;
+ w->left_fringe_width = left_width;
+ w->right_fringe_width = right_width;
w->fringes_outside_margins = outside_margins;
adjust_window_margins (w);
struct window *w = decode_window (window);
if (!NILP (width))
- CHECK_NUMBER (width);
+ {
+ CHECK_NATNUM (width);
- if (XINT (width) == 0)
- vertical_type = Qnil;
+ if (XINT (width) == 0)
+ vertical_type = Qnil;
+ }
if (!(EQ (vertical_type, Qnil)
|| EQ (vertical_type, Qleft)
: XFLOATINT (vscroll));
w->vscroll = min (w->vscroll, 0);
- /* Adjust glyph matrix of the frame if the virtual display
- area becomes larger than before. */
- if (w->vscroll < 0 && w->vscroll < old_dy)
- adjust_glyphs (f);
+ if (w->vscroll != old_dy)
+ {
+ /* Adjust glyph matrix of the frame if the virtual display
+ area becomes larger than before. */
+ if (w->vscroll < 0 && w->vscroll < old_dy)
+ adjust_glyphs (f);
- /* Prevent redisplay shortcuts. */
- XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+ /* Prevent redisplay shortcuts. */
+ XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+ }
}
return Fwindow_vscroll (window, pixels_p);
{
Qwindow_size_fixed = intern ("window-size-fixed");
staticpro (&Qwindow_size_fixed);
+ Fset (Qwindow_size_fixed, Qnil);
staticpro (&Qwindow_configuration_change_hook);
Qwindow_configuration_change_hook
doc: /* *Non-nil means `display-buffer' should make a separate frame. */);
pop_up_frames = 0;
+ 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;
+
DEFVAR_BOOL ("display-buffer-reuse-frames", &display_buffer_reuse_frames,
doc: /* *Non-nil means `display-buffer' should reuse frames.
If the buffer in question is already displayed in a frame, raise that frame. */);
DEFVAR_LISP ("special-display-buffer-names", &Vspecial_display_buffer_names,
doc: /* *List of buffer names that should have their own special frames.
-Displaying a buffer whose name is in this list makes a special frame for it
+Displaying a buffer with `display-buffer' or `pop-to-buffer',
+if its name is in this list, makes a special frame for it
using `special-display-function'. See also `special-display-regexps'.
An element of the list can be a list instead of just a string.
DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
doc: /* *List of regexps saying which buffers should have their own special frames.
-If a buffer name matches one of these regexps, it gets its own frame.
-Displaying a buffer whose name is in this list makes a special frame for it
-using `special-display-function'.
+When displaying a buffer with `display-buffer' or `pop-to-buffer',
+if any regexp in this list matches the buffer name, it makes a
+special frame for the buffer by calling `special-display-function'.
An element of the list can be a list instead of just a string.
There are two ways to use a list as an element:
DEFVAR_LISP ("scroll-preserve-screen-position",
&Vscroll_preserve_screen_position,
- doc: /* *Non-nil means scroll commands move point to keep its screen line unchanged. */);
+ doc: /* *Controls if scroll commands move point to keep its screen line 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.
+Any other value means point always keeps its screen position. */);
Vscroll_preserve_screen_position = Qnil;
DEFVAR_LISP ("window-configuration-change-hook",
The selected frame is the one whose configuration has changed. */);
Vwindow_configuration_change_hook = Qnil;
- DEFVAR_BOOL ("window-size-fixed", &window_size_fixed,
- doc: /* Non-nil in a buffer means windows displaying the buffer are fixed-size.
-If the value is`height', then only the window's height is fixed.
-If the value is `width', then only the window's width is fixed.
-Any other non-nil value fixes both the width and the height.
-Emacs won't change the size of any window displaying that buffer,
-unless you explicitly change the size, or Emacs has no other choice. */);
- Fmake_variable_buffer_local (Qwindow_size_fixed);
- window_size_fixed = 0;
-
defsubr (&Sselected_window);
defsubr (&Sminibuffer_window);
defsubr (&Swindow_minibuffer_p);