/* Window creation, deletion and examination for GNU Emacs.
Does not include redisplay.
- Copyright (C) 1985,86,87,93,94,95,96,97,1998,2000, 2001, 2002, 2003
- 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);
bzero (&p->last_cursor, sizeof (p->last_cursor));
bzero (&p->phys_cursor, sizeof (p->phys_cursor));
p->desired_matrix = p->current_matrix = 0;
+ p->nrows_scale_factor = p->ncols_scale_factor = 1;
p->phys_cursor_type = -1;
p->phys_cursor_width = -1;
p->must_be_updated_p = 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;
DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
Spos_visible_in_window_p, 0, 3, 0,
- doc: /* Return t if position POS is currently on the frame in WINDOW.
+ doc: /* Return non-nil if position POS is currently on the frame in WINDOW.
Return nil if that position is scrolled vertically out of view.
If a character is only partially visible, nil is returned, unless the
optional argument PARTIALLY is non-nil.
-POS defaults to point in WINDOW; WINDOW defaults to the selected window. */)
+If POS is only out of view because of horizontal scrolling, return non-nil.
+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 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 int posint;
register struct buffer *buf;
struct text_pos top;
- Lisp_Object in_window;
- int fully_p;
+ Lisp_Object in_window = Qnil;
+ int rtop, rbot, fully_p = 1;
+ int x, y;
w = decode_window (window);
buf = XBUFFER (w->buffer);
else
posint = XMARKER (w->pointm)->charpos;
- /* If position is above window start, it's not visible. */
- if (posint < CHARPOS (top))
- in_window = Qnil;
- else if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf)
- && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (buf)
- && posint < BUF_Z (buf) - XFASTINT (w->window_end_pos))
- {
- /* If frame is up-to-date, and POSINT is < window end pos, use
- that info. This doesn't work for POSINT == end pos, because
- the window end pos is actually the position _after_ the last
- char in the window. */
- if (NILP (partially))
- {
- pos_visible_p (w, posint, &fully_p, NILP (partially));
- in_window = fully_p ? Qt : Qnil;
- }
- else
- in_window = Qt;
- }
- else if (posint > BUF_ZV (buf))
- in_window = Qnil;
- else if (CHARPOS (top) < BUF_BEGV (buf) || CHARPOS (top) > BUF_ZV (buf))
- /* If window start is out of range, do something reasonable. */
- in_window = Qnil;
- else
- {
- if (pos_visible_p (w, posint, &fully_p, NILP (partially)))
- in_window = !NILP (partially) || fully_p ? Qt : Qnil;
- else
- in_window = Qnil;
- }
-
+ /* If position is above window start or outside buffer boundaries,
+ or if window start is out of range, position is not visible. */
+ if (posint >= CHARPOS (top)
+ && posint <= BUF_ZV (buf)
+ && CHARPOS (top) >= BUF_BEGV (buf)
+ && CHARPOS (top) <= BUF_ZV (buf)
+ && 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 ? Qnil
+ : Fcons (make_number (rtop),
+ make_number (rbot))),
+ Qnil)));
return in_window;
}
}
DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
- doc: /* Return the buffer that WINDOW is displaying. */)
+ doc: /* Return the buffer that WINDOW is displaying.
+WINDOW defaults to the selected window. */)
(window)
Lisp_Object window;
{
DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
doc: /* Set number of columns WINDOW is scrolled from left margin to NCOL.
-NCOL should be zero or positive.
+Return NCOL. NCOL should be zero or positive.
Note that if `automatic-hscrolling' is non-nil, you cannot scroll the
window so that the location of point becomes invisible. */)
+ 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)
}
DEFUN ("window-inside-pixel-edges", Fwindow_inside_pixel_edges, Swindow_inside_pixel_edges, 0, 1, 0,
- doc: /* Return a list of the edge coordinates of WINDOW.
+ doc: /* Return a list of the edge pixel coordinates of WINDOW.
\(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.
RIGHT is one more than the rightmost x position used by text in WINDOW,
and BOTTOM is one more than the bottommost y position used by text in WINDOW.
+ 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)
if it is on the window's modeline, return ON_MODE_LINE;
if it is on the border between the window and its right sibling,
return ON_VERTICAL_BORDER.
+ if it is on a scroll bar,
+ return ON_SCROLL_BAR.
if it is on the window's top line, return ON_HEADER_LINE;
if it is in left or right fringe of the window,
return ON_LEFT_FRINGE or ON_RIGHT_FRINGE, and convert *X and *Y
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_NOTHING;
+ return ON_SCROLL_BAR;
lmargin_width = window_box_width (w, LEFT_MARGIN_AREA);
rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA);
ly = Fcdr (coordinates);
CHECK_NUMBER_OR_FLOAT (lx);
CHECK_NUMBER_OR_FLOAT (ly);
- x = FRAME_PIXEL_X_FROM_CANON_X (f, lx);
- y = FRAME_PIXEL_Y_FROM_CANON_Y (f, ly);
+ x = FRAME_PIXEL_X_FROM_CANON_X (f, lx) + FRAME_INTERNAL_BORDER_WIDTH (f);
+ y = FRAME_PIXEL_Y_FROM_CANON_Y (f, ly) + FRAME_INTERNAL_BORDER_WIDTH (f);
switch (coordinates_in_window (w, &x, &y))
{
case ON_RIGHT_MARGIN:
return Qright_margin;
+ case ON_SCROLL_BAR:
+ /* Historically we are supposed to return nil in this case. */
+ return Qnil;
+
default:
abort ();
}
CHECK_NUMBER_OR_FLOAT (y);
return window_from_coordinates (f,
- FRAME_PIXEL_X_FROM_CANON_X (f, x),
- FRAME_PIXEL_Y_FROM_CANON_Y (f, y),
+ (FRAME_PIXEL_X_FROM_CANON_X (f, x)
+ + FRAME_INTERNAL_BORDER_WIDTH (f)),
+ (FRAME_PIXEL_Y_FROM_CANON_Y (f, y)
+ + FRAME_INTERNAL_BORDER_WIDTH (f)),
0, 0, 0, 0);
}
This is updated by redisplay, when it runs to completion.
Simply changing the buffer text or setting `window-start'
does not update this value.
+Return nil if there is no recorded value. \(This can happen if the
+last redisplay of WINDOW was preempted, and did not finish.)
If UPDATE is non-nil, compute the up-to-date position
if it isn't already recorded. */)
(window, update)
}
DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
- doc: /* Make point value in WINDOW be at position POS in WINDOW's buffer. */)
+ doc: /* Make point value in WINDOW be at position POS in WINDOW's buffer.
+Return POS. */)
(window, pos)
Lisp_Object window, pos;
{
DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
doc: /* Make display in WINDOW start at position POS in WINDOW's buffer.
+Return POS.
Optional third arg NOFORCE non-nil inhibits next redisplay
from overriding motion of point in order to display at this exact start. */)
(window, pos, noforce)
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))
;
doc: /* Select the ARG'th different window on this frame.
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. If the optional second
-argument ALL_FRAMES is non-nil, cycle through all frames. */)
+A negative ARG moves in the opposite order. The optional second
+argument ALL_FRAMES has the same meaning as in `next-window', which see. */)
(arg, all_frames)
Lisp_Object arg, all_frames;
{
window_list_1 (window, minibuf, all_frames)
Lisp_Object window, minibuf, all_frames;
{
- Lisp_Object tail, list;
+ Lisp_Object tail, list, rest;
decode_next_window_args (&window, &minibuf, &all_frames);
list = Qnil;
if (candidate_window_p (XCAR (tail), window, minibuf, all_frames))
list = Fcons (XCAR (tail), list);
- return Fnreverse (list);
+ /* Rotate the list to start with WINDOW. */
+ list = Fnreverse (list);
+ rest = Fmemq (window, list);
+ if (!NILP (rest) && !EQ (rest, list))
+ {
+ for (tail = list; !EQ (XCDR (tail), rest); tail = XCDR (tail))
+ ;
+ XSETCDR (tail, Qnil);
+ list = nconc2 (rest, list);
+ }
+ return list;
}
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;
DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
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.
DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 1, 2, 0,
doc: /* Return a window currently displaying BUFFER, or nil if none.
+BUFFER can be a buffer or a buffer name.
If optional argument FRAME is `visible', search all visible frames.
If optional argument FRAME is 0, search all visible and iconified frames.
If FRAME is t, search all frames.
DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
1, 2, "bDelete windows on (buffer): ",
doc: /* Delete all windows showing BUFFER.
+BUFFER must be a buffer or the name of an existing buffer.
Optional second argument FRAME controls which frames are affected.
If optional argument FRAME is `visible', search all visible frames.
If FRAME is 0, search all visible and iconified frames.
DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
Sreplace_buffer_in_windows,
1, 1, "bReplace buffer in windows: ",
- doc: /* Replace BUFFER with some other buffer in all windows showing it. */)
+ doc: /* Replace BUFFER with some other buffer in all windows showing it.
+BUFFER may be a buffer or the name of an existing buffer. */)
(buffer)
Lisp_Object buffer;
{
--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);
DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 3, 0,
doc: /* Make WINDOW display BUFFER as its contents.
-BUFFER can be a buffer or buffer name.
-Optional third arg KEEP_MARGINS non-nil means that WINDOW's current
+BUFFER can be a buffer or the name of an existing buffer.
+Optional third arg KEEP-MARGINS non-nil means that WINDOW's current
display margins, fringe widths, and scroll bar settings are maintained;
the default is to reset these from BUFFER's local settings or the frame
-defaults. */)
+defaults.
+
+This function runs the hook `window-scroll-functions'. */)
(window, buffer, keep_margins)
register Lisp_Object window, buffer, keep_margins;
{
DEFUN ("select-window", Fselect_window, Sselect_window, 1, 2, 0,
doc: /* Select WINDOW. Most editing will apply to WINDOW's buffer.
-If WINDOW is not already selected, also make WINDOW's buffer current.
-Also make WINDOW the frame's selected window.
+If WINDOW is not already selected, make WINDOW's buffer current
+and make WINDOW the frame's selected window. Return WINDOW.
Optional second arg NORECORD non-nil means
do not put this buffer at the front of the list of recently selected ones.
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;
DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 3,
"BDisplay buffer: \nP",
doc: /* Make BUFFER appear in some window but don't select it.
-BUFFER can be a buffer or a buffer name.
+BUFFER must be the name of an existing buffer, or, when called from Lisp,
+a buffer.
If BUFFER is shown already in some window, just use that one,
unless the window is the selected window and the optional second
argument NOT-THIS-WINDOW is non-nil (interactively, with prefix arg).
unless `pop-up-frames' or `display-buffer-reuse-frames' is non-nil,
which means search visible and iconified frames.
+If a full-width window on a splittable frame is available to display
+the buffer, it may be split, subject to the value of the variable
+`split-height-threshold'.
+
If `even-window-heights' is non-nil, window heights will be evened out
if displaying the buffer causes two vertically adjacent windows to be
displayed. */)
0, 1, 0,
doc: /* Force redisplay of all windows.
If optional arg OBJECT is a window, force redisplay of that window only.
-If OBJECT is a buffer or buffer name, force redisplay of all windows
+If OBJECT is a buffer or buffer name, force redisplay of all windows
displaying that buffer. */)
(object)
Lisp_Object object;
++update_mode_lines;
return Qt;
}
-
+
if (STRINGP (object))
object = Fget_buffer (object);
if (BUFFERP (object) && !NILP (XBUFFER (object)->name))
Lisp_Object prev_window, prev_buffer;
prev_window = selected_window;
XSETBUFFER (prev_buffer, old);
-
+
/* Select the window that was chosen, for running the hook.
Note: Both Fselect_window and select_window_norecord may
set-buffer to the buffer displayed in the window,
= ((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);
WINDOW defaults to selected one and SIZE to half its size.
If optional third arg HORFLAG is non-nil, split side by side
and put SIZE columns in the first of the pair. In that case,
-SIZE includes that window's scroll bar, or the divider column to its right. */)
+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.
+See Info node `(elisp)Splitting Windows' for more details and examples.*/)
(window, size, horflag)
Lisp_Object window, size, horflag;
{
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. */
{
posit = *compute_motion (startpos, 0, 0, 0,
PT, ht, 0,
- window_box_text_cols (w), XINT (w->hscroll),
+ -1, XINT (w->hscroll),
0, w);
original_vpos = posit.vpos;
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);
}
DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
- doc: /* Scroll text of current window upward ARG lines; or near full screen if no ARG.
+ doc: /* Scroll text of current window upward ARG lines.
+If ARG is omitted or nil, scroll upward by a near full screen.
A near full screen is `next-screen-context-lines' less than a full screen.
Negative ARG means scroll downward.
If ARG is the atom `-', scroll downward by nearly full screen.
}
DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
- doc: /* Scroll text of current window down ARG lines; or near full screen if no ARG.
+ doc: /* Scroll text of current window down ARG lines.
+If ARG is omitted or nil, scroll down by a near full screen.
A near full screen is `next-screen-context-lines' less than a full screen.
Negative ARG means scroll upward.
If ARG is the atom `-', scroll upward by nearly full screen.
\f
DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0,
doc: /* Return the other window for \"other window scroll\" commands.
-If in the minibuffer, `minibuffer-scroll-window' if non-nil
-specifies the window.
If `other-window-scroll-buffer' is non-nil, a window
-showing that buffer is used. */)
+showing that buffer is used.
+If in the minibuffer, `minibuffer-scroll-window' if non-nil
+specifies the window. This takes precedence over
+`other-window-scroll-buffer'. */)
()
{
Lisp_Object window;
If ARG is the atom `-', scroll downward by nearly full screen.
When calling from a program, supply as argument a number, nil, or `-'.
-If in the minibuffer, `minibuffer-scroll-window' if non-nil
-specifies the window to scroll.
If `other-window-scroll-buffer' is non-nil, scroll the window
-showing that buffer, popping the buffer up if necessary. */)
+showing that buffer, popping the buffer up if necessary.
+If in the minibuffer, `minibuffer-scroll-window' if non-nil
+specifies the window to scroll. This takes precedence over
+`other-window-scroll-buffer'. */)
(arg)
Lisp_Object arg;
{
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);
DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
0, UNEVALLED, 0,
- doc: /* Execute body, preserving window sizes and contents.
+ doc: /* Execute BODY, preserving window sizes and contents.
+Return the value of the last form in BODY.
Restore which buffer appears in which window, where display starts,
and the value of point and mark for each window.
Also restore the choice of selected window.
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)
+ || EQ (vertical_type, Qleft)
|| EQ (vertical_type, Qright)
|| EQ (vertical_type, Qt)))
error ("Invalid type of vertical scroll bar");
Smooth scrolling
***********************************************************************/
-DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 1, 0,
+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.
-Value is a multiple of the canonical character height of WINDOW. */)
- (window)
- Lisp_Object window;
+Normally, value is a multiple of the canonical character height of WINDOW;
+optional second arg PIXELS_P means value is measured in pixels. */)
+ (window, pixels_p)
+ Lisp_Object window, pixels_p;
{
Lisp_Object result;
struct frame *f;
f = XFRAME (w->frame);
if (FRAME_WINDOW_P (f))
- result = FRAME_CANON_Y_FROM_PIXEL_Y (f, -w->vscroll);
+ result = (NILP (pixels_p)
+ ? FRAME_CANON_Y_FROM_PIXEL_Y (f, -w->vscroll)
+ : make_number (-w->vscroll));
else
result = make_number (0);
return result;
DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
- 2, 2, 0,
+ 2, 3, 0,
doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL.
-WINDOW nil means use the selected window. VSCROLL is a non-negative
-multiple of the canonical character height of WINDOW. */)
- (window, vscroll)
- Lisp_Object window, 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.
+If PIXELS-P is nil, VSCROLL may have to be rounded so that it
+corresponds to an integral number of pixels. The return value is the
+result of this rounding.
+If PIXELS-P is non-nil, the return value is VSCROLL. */)
+ (window, vscroll, pixels_p)
+ Lisp_Object window, vscroll, pixels_p;
{
struct window *w;
struct frame *f;
{
int old_dy = w->vscroll;
- w->vscroll = - FRAME_LINE_HEIGHT (f) * XFLOATINT (vscroll);
+ w->vscroll = - (NILP (pixels_p)
+ ? FRAME_LINE_HEIGHT (f) * XFLOATINT (vscroll)
+ : 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);
+ return Fwindow_vscroll (window, pixels_p);
}
\f
{
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
DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
doc: /* If non-nil, function to call to handle `display-buffer'.
It will receive two args, the buffer and a flag which if non-nil means
- that the currently selected window is not acceptable.
+that the currently selected window is not acceptable.
+It should choose or create a window, display the specified buffer in it,
+and return the window.
Commands such as `switch-to-buffer-other-window' and `find-file-other-window'
work using this function. */);
Vdisplay_buffer_function = Qnil;
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.
There are two ways to use a list as an element:
(BUFFER FRAME-PARAMETERS...) (BUFFER FUNCTION OTHER-ARGS...)
-In the first case, FRAME-PARAMETERS are used to create the frame.
-In the latter case, FUNCTION is called with BUFFER as the first argument,
-followed by OTHER-ARGS--it can display BUFFER in any way it likes.
+In the first case, the FRAME-PARAMETERS are pairs of the form
+\(PARAMETER . VALUE); these parameter values are used to create the frame.
+In the second case, FUNCTION is called with BUFFER as the first argument,
+followed by the OTHER-ARGS--it can display BUFFER in any way it likes.
All this is done by the function found in `special-display-function'.
If the specified frame parameters include (same-buffer . t), the
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:
(REGEXP FRAME-PARAMETERS...) (REGEXP FUNCTION OTHER-ARGS...)
-In the first case, FRAME-PARAMETERS are used to create the frame.
-In the latter case, FUNCTION is called with the buffer as first argument,
-followed by OTHER-ARGS--it can display the buffer in any way it likes.
+In the first case, the FRAME-PARAMETERS are pairs of the form
+\(PARAMETER . VALUE); these parameter values are used to create the frame.
+In the second case, FUNCTION is called with BUFFER as the first argument,
+followed by the OTHER-ARGS--it can display the buffer in any way it likes.
All this is done by the function found in `special-display-function'.
If the specified frame parameters include (same-buffer . t), the
next_screen_context_lines = 2;
DEFVAR_INT ("split-height-threshold", &split_height_threshold,
- doc: /* *display-buffer would prefer to split the largest window if this large.
+ doc: /* *A window must be at least this tall to be eligible for splitting by `display-buffer'.
If there is only one window, it is split regardless of this value. */);
split_height_threshold = 500;
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.
-Emacs won't change the size of any window displaying that buffer,
-unless you explicitly change the size, or Emacs has no other choice.
-This variable automatically becomes buffer-local when set. */);
- Fmake_variable_buffer_local (Qwindow_size_fixed);
- window_size_fixed = 0;
-
defsubr (&Sselected_window);
defsubr (&Sminibuffer_window);
defsubr (&Swindow_minibuffer_p);