/* Window creation, deletion and examination for GNU Emacs.
Does not include redisplay.
- Copyright (C) 1985,86,87,93,94,95,96,97,1998,2000
+ Copyright (C) 1985,86,87,93,94,95,96,97,1998,2000, 2001
Free Software Foundation, Inc.
This file is part of GNU Emacs.
#define max(a, b) ((a) < (b) ? (b) : (a))
#endif
+/* Values returned from coordinates_in_window. */
+
+enum window_part
+{
+ ON_NOTHING,
+ ON_TEXT,
+ ON_MODE_LINE,
+ ON_VERTICAL_BORDER,
+ ON_HEADER_LINE,
+ ON_LEFT_FRINGE,
+ ON_RIGHT_FRINGE
+};
+
Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
-Lisp_Object Qwindow_size_fixed, Qleft_bitmap_area, Qright_bitmap_area;
+Lisp_Object Qwindow_size_fixed, Qleft_fringe, Qright_fringe;
extern Lisp_Object Qheight, Qwidth;
static struct window *decode_window P_ ((Lisp_Object));
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
(object)
Lisp_Object object;
{
- return (WINDOWP (object) && ! NILP (XWINDOW (object)->buffer) ? Qt : Qnil);
+ return WINDOW_LIVE_P (object) ? Qt : Qnil;
}
Lisp_Object
XSETFASTINT (p->height, 0);
XSETFASTINT (p->width, 0);
XSETFASTINT (p->hscroll, 0);
+ XSETFASTINT (p->min_hscroll, 0);
p->orig_top = p->orig_height = Qnil;
p->start = Fmake_marker ();
p->pointm = Fmake_marker ();
"Set number of columns WINDOW is scrolled from left margin to NCOL.\n\
NCOL should be zero or positive.")
(window, ncol)
- register Lisp_Object window, ncol;
+ Lisp_Object window, ncol;
{
- register struct window *w;
+ struct window *w = decode_window (window);
+ int hscroll;
CHECK_NUMBER (ncol, 1);
- if (XINT (ncol) < 0) XSETFASTINT (ncol, 0);
- w = decode_window (window);
- if (XINT (w->hscroll) != XINT (ncol))
- /* Prevent redisplay shortcuts */
+ hscroll = max (0, XINT (ncol));
+
+ /* Prevent redisplay shortcuts when changing the hscroll. */
+ if (XINT (w->hscroll) != hscroll)
XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
- w->hscroll = ncol;
+
+ w->hscroll = make_number (hscroll);
return ncol;
}
X and Y are frame relative pixel coordinates. */
-static int
+static enum window_part
coordinates_in_window (w, x, y)
register struct window *w;
register int *x, *y;
{
+ /* Let's make this a global enum later, instead of using numbers
+ everywhere. */
struct frame *f = XFRAME (WINDOW_FRAME (w));
int left_x, right_x, top_y, bottom_y;
int flags_area_width = FRAME_LEFT_FLAGS_AREA_WIDTH (f);
-
- /* Let's make this a global enum later, instead of using numbers
- everywhere. */
- enum {ON_NOTHING, ON_TEXT, ON_MODE_LINE, ON_VERTICAL_BORDER,
- ON_HEADER_LINE, ON_LEFT_FRINGE, ON_RIGHT_FRINGE};
-
+ enum window_part part;
+ int ux = CANON_X_UNIT (f), uy = CANON_Y_UNIT (f);
+ int x0 = XFASTINT (w->left) * ux;
+ int x1 = x0 + XFASTINT (w->width) * ux;
+ /* The width of the area where the vertical line can be dragged.
+ (Between mode lines for instance. */
+ int grabbable_width = ux;
+
+ 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)
{
left_x = 0;
- right_x = XFASTINT (w->width) * CANON_Y_UNIT (f) - 1;
+ right_x = XFASTINT (w->width) * CANON_X_UNIT (f) - 1;
top_y = WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
}
sibling, say it's on the vertical line. That's to be able
to resize windows horizontally in case we're using toolkit
scroll bars. */
-
+
if (WINDOW_WANTS_MODELINE_P (w)
- && *y < bottom_y
- && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
+ && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w)
+ && *y < bottom_y)
+ {
+ /* We're somewhere on the mode line. We consider the place
+ between mode lines of horizontally adjacent mode lines
+ as the vertical border. If scroll bars on the left,
+ return the right window. */
+ part = ON_MODE_LINE;
+
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
+ {
+ if (abs (*x - x0) < grabbable_width)
+ part = ON_VERTICAL_BORDER;
+ }
+ else if (!WINDOW_RIGHTMOST_P (w) && abs (*x - x1) < grabbable_width)
+ part = ON_VERTICAL_BORDER;
+ }
+ else if (WINDOW_WANTS_HEADER_LINE_P (w)
+ && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w)
+ && *y >= top_y)
{
- if (!WINDOW_RIGHTMOST_P (w)
- && (abs (*x - ((XFASTINT (w->left) + XFASTINT (w->width))
- * CANON_X_UNIT (f)))
- < CANON_X_UNIT (f) / 2))
- return ON_VERTICAL_BORDER;
- return ON_MODE_LINE;
+ part = ON_HEADER_LINE;
+
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
+ {
+ if (abs (*x - x0) < grabbable_width)
+ part = ON_VERTICAL_BORDER;
+ }
+ else if (!WINDOW_RIGHTMOST_P (w) && abs (*x - x1) < grabbable_width)
+ part = ON_VERTICAL_BORDER;
}
-
- if (WINDOW_WANTS_HEADER_LINE_P (w)
- && *y >= top_y
- && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
+ /* Outside anything interesting? */
+ else if (*y < top_y
+ || *y >= bottom_y
+ || *x < (left_x
+ - flags_area_width
+ - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * ux)
+ || *x > (right_x
+ + flags_area_width
+ + FRAME_RIGHT_SCROLL_BAR_WIDTH (f) * ux))
{
- if (!WINDOW_RIGHTMOST_P (w)
- && (abs (*x - ((XFASTINT (w->left) + XFASTINT (w->width))
- * CANON_X_UNIT (f)))
- < CANON_X_UNIT (f) / 2))
- return ON_VERTICAL_BORDER;
- return ON_HEADER_LINE;
+ part = ON_NOTHING;
}
-
- /* Completely outside anything interesting? */
- if (*y < top_y
- || *y >= bottom_y
- || *x < (left_x
- - flags_area_width
- - (FRAME_LEFT_SCROLL_BAR_WIDTH (f)
- * CANON_X_UNIT (f)))
- || *x > right_x + flags_area_width)
- return ON_NOTHING;
-
- if (FRAME_WINDOW_P (f))
+ else if (FRAME_WINDOW_P (f))
{
if (!w->pseudo_window_p
&& !FRAME_HAS_VERTICAL_SCROLL_BARS (f)
&& !WINDOW_RIGHTMOST_P (w)
- && (abs (*x - right_x - flags_area_width) < CANON_X_UNIT (f) / 2))
- return ON_VERTICAL_BORDER;
-
- if (*x < left_x || *x > right_x)
+ && (abs (*x - right_x - flags_area_width) < grabbable_width))
+ {
+ part = ON_VERTICAL_BORDER;
+ }
+ else if (*x < left_x || *x > right_x)
{
/* Other lines than the mode line don't include flags areas and
scroll bars on the left. */
/* Convert X and Y to window-relative pixel coordinates. */
*x -= left_x;
*y -= top_y;
- return *x < left_x ? ON_LEFT_FRINGE : ON_RIGHT_FRINGE;
+ part = *x < left_x ? ON_LEFT_FRINGE : ON_RIGHT_FRINGE;
+ }
+ else
+ {
+ *x -= left_x;
+ *y -= top_y;
+ part = ON_TEXT;
}
}
else
/* Convert X and Y to window-relative pixel coordinates. */
*x -= left_x;
*y -= top_y;
- return *x < left_x ? ON_LEFT_FRINGE : ON_RIGHT_FRINGE;
+ part = *x < left_x ? ON_LEFT_FRINGE : ON_RIGHT_FRINGE;
}
-
/* Here, too, "*x > right_x" is because of character terminals. */
- if (!w->pseudo_window_p
- && !WINDOW_RIGHTMOST_P (w)
- && *x > right_x - CANON_X_UNIT (f))
- /* On the border on the right side of the window? Assume that
- this area begins at RIGHT_X minus a canonical char width. */
- return ON_VERTICAL_BORDER;
+ else if (!w->pseudo_window_p
+ && !WINDOW_RIGHTMOST_P (w)
+ && *x > right_x - ux)
+ {
+ /* On the border on the right side of the window? Assume that
+ this area begins at RIGHT_X minus a canonical char width. */
+ part = ON_VERTICAL_BORDER;
+ }
+ else
+ {
+ /* Convert X and Y to window-relative pixel coordinates. */
+ *x -= left_x;
+ *y -= top_y;
+ part = ON_TEXT;
+ }
}
-
- /* Convert X and Y to window-relative pixel coordinates. */
- *x -= left_x;
- *y -= top_y;
- return ON_TEXT;
+
+ return part;
}
+
DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
Scoordinates_in_window_p, 2, 2, 0,
"Return non-nil if COORDINATES are in WINDOW.\n\
COORDINATES is a cons of the form (X . Y), X and Y being distances\n\
measured in characters from the upper-left corner of the frame.\n\
-(0 . 0) denotes the character in the upper left corner of the\n\
+\(0 . 0) denotes the character in the upper left corner of the\n\
frame.\n\
If COORDINATES are in the text portion of WINDOW,\n\
the coordinates relative to the window are returned.\n\
If they are in the mode line of WINDOW, `mode-line' is returned.\n\
If they are in the top mode line of WINDOW, `header-line' is returned.\n\
-If they are in the bitmap-area to the left of the window,\n\
- `left-bitmap-area' is returned, if they are in the area on the right of\n\
- the window, `right-bitmap-area' is returned.\n\
+If they are in the fringe to the left of the window,\n\
+ `left-fringe' is returned, if they are in the area on the right of\n\
+ the window, `right-fringe' is returned.\n\
If they are on the border between WINDOW and its right sibling,\n\
`vertical-line' is returned.")
(coordinates, window)
switch (coordinates_in_window (w, &x, &y))
{
- case 0: /* NOT in window at all. */
+ case ON_NOTHING:
return Qnil;
- case 1: /* In text part of window. */
- /* X and Y are now window relative pixel coordinates.
- Convert them to canonical char units before returning
- them. */
+ case ON_TEXT:
+ /* X and Y are now window relative pixel coordinates. Convert
+ them to canonical char units before returning them. */
return Fcons (CANON_X_FROM_PIXEL_X (f, x),
CANON_Y_FROM_PIXEL_Y (f, y));
- case 2: /* In mode line of window. */
+ case ON_MODE_LINE:
return Qmode_line;
- case 3: /* On right border of window. */
+ case ON_VERTICAL_BORDER:
return Qvertical_line;
- case 4:
+ case ON_HEADER_LINE:
return Qheader_line;
- case 5:
- return Qleft_bitmap_area;
+ case ON_LEFT_FRINGE:
+ return Qleft_fringe;
- case 6:
- return Qright_bitmap_area;
+ case ON_RIGHT_FRINGE:
+ return Qright_fringe;
default:
abort ();
void *user_data;
{
struct check_window_data *cw = (struct check_window_data *) user_data;
- int found;
+ enum window_part found;
+ int continue_p = 1;
found = coordinates_in_window (w, cw->x, cw->y);
- if (found)
+ if (found != ON_NOTHING)
{
*cw->part = found - 1;
XSETWINDOW (*cw->window, w);
+ continue_p = 0;
}
- return !found;
+ return continue_p;
}
&& tool_bar_p
&& WINDOWP (f->tool_bar_window)
&& XINT (XWINDOW (f->tool_bar_window)->height) > 0
- && coordinates_in_window (XWINDOW (f->tool_bar_window), &x, &y))
+ && (coordinates_in_window (XWINDOW (f->tool_bar_window), &x, &y)
+ != ON_NOTHING))
{
*part = 0;
window = f->tool_bar_window;
This is updated by redisplay, when it runs to completion.\n\
Simply changing the buffer text or setting `window-start'\n\
does not update this value.\n\
-If UP-TO-DATE is non-nil, compute the up-to-date position\n\
+If UPDATE is non-nil, compute the up-to-date position\n\
if it isn't already recorded.")
(window, update)
Lisp_Object window, update;
{
struct text_pos startp;
struct it it;
+ struct buffer *old_buffer = NULL, *b = XBUFFER (buf);
/* In case W->start is out of the range, use something
reasonable. This situation occured when loading a file with
/* Cannot use Fvertical_motion because that function doesn't
cope with variable-height lines. */
+ if (b != current_buffer)
+ {
+ old_buffer = current_buffer;
+ set_buffer_internal (b);
+ }
+
start_display (&it, w, startp);
move_it_vertically (&it, window_box_height (w));
+ move_it_past_eol (&it);
value = make_number (IT_CHARPOS (it));
+
+ if (old_buffer)
+ set_buffer_internal (old_buffer);
}
else
XSETINT (value, BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
Fgoto_char (pos);
else
set_marker_restricted (w->pointm, pos, w->buffer);
+
+ /* We have to make sure that redisplay updates the window to show
+ the new value of point. */
+ if (!EQ (window, selected_window))
+ ++windows_or_buffers_changed;
return pos;
}
register Lisp_Object tem, parent, sib;
register struct window *p;
register struct window *par;
- FRAME_PTR frame;
+ struct frame *f;
/* Because this function is called by other C code on non-leaf
windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
windows_or_buffers_changed++;
Vwindow_list = Qnil;
- frame = XFRAME (WINDOW_FRAME (p));
- FRAME_WINDOW_SIZES_CHANGED (frame) = 1;
+ f = XFRAME (WINDOW_FRAME (p));
+ FRAME_WINDOW_SIZES_CHANGED (f) = 1;
/* Are we trying to delete any frame's selected window? */
{
- Lisp_Object frame, pwindow;
+ Lisp_Object pwindow;
/* See if the frame's selected window is either WINDOW
or any subwindow of it, by finding all that window's parents
and comparing each one with WINDOW. */
- frame = WINDOW_FRAME (XWINDOW (window));
- pwindow = FRAME_SELECTED_WINDOW (XFRAME (frame));
+ pwindow = FRAME_SELECTED_WINDOW (f);
while (!NILP (pwindow))
{
if (EQ (window, selected_window))
Fselect_window (alternative);
else
- FRAME_SELECTED_WINDOW (XFRAME (frame)) = alternative;
+ FRAME_SELECTED_WINDOW (f) = alternative;
}
}
events and other events that access glyph matrices are not
processed while we are changing them. */
BLOCK_INPUT;
- free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (frame)));
+ free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (f)));
tem = p->next;
if (!NILP (tem))
p->buffer = p->hchild = p->vchild = Qnil;
/* Adjust glyph matrices. */
- adjust_glyphs (frame);
+ adjust_glyphs (f);
UNBLOCK_INPUT;
}
(frame, minibuf, window)
Lisp_Object frame, minibuf, window;
{
- Lisp_Object list;
-
if (NILP (window))
window = selected_window;
if (NILP (frame))
Qnil, look at just the selected frame;
Qvisible, look at visible frames;
a frame, just look at windows on that frame.
- If MINI is non-zero, perform the operation on minibuffer windows too.
-*/
+ If MINI is non-zero, perform the operation on minibuffer windows too. */
enum window_loop
{
else
window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
- /* Figure out the last window we're going to mess with. Since
- Fnext_window, given the same options, is guaranteed to go in a
- ring, we can just use Fprevious_window to find the last one.
-
- We can't just wait until we hit the first window again, because
- it might be deleted. */
-
windows = window_list_1 (window, mini ? Qt : Qnil, frame_arg);
GCPRO1 (windows);
best_window = Qnil;
? EQ (window, minibuf_window)
: 1))
{
- UNGCPRO;
- return window;
+ if (NILP (best_window))
+ best_window = window;
+ else if (EQ (window, selected_window))
+ /* For compatibility with 20.x, prefer to return
+ selected-window. */
+ best_window = window;
}
break;
{
struct window *w;
int startpos;
- int top;
+ int top, new_top;
if (NILP (window))
window = selected_window;
else
CHECK_LIVE_WINDOW (window, 0);
-
w = XWINDOW (window);
startpos = marker_position (w->start);
on the frame. But don't try to do this if the window start is
outside the visible portion (as might happen when the display is
not current, due to typeahead). */
- if (startpos >= BUF_BEGV (XBUFFER (w->buffer))
+ new_top = XFASTINT (w->top) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
+ if (new_top != top
+ && startpos >= BUF_BEGV (XBUFFER (w->buffer))
&& startpos <= BUF_ZV (XBUFFER (w->buffer)))
{
struct position pos;
pos = *vmotion (startpos, -top, w);
set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
+ w->window_end_valid = Qnil;
w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
|| FETCH_BYTE (pos.bytepos - 1) == '\n') ? Qt
: Qnil);
min_size = window_min_height;
}
- if (old_size < window_min_width)
+ if (old_size < min_size)
w->too_small_ok = Qt;
/* Maybe delete WINDOW if it's too small. */
if (!nodelete_p && !NILP (w->parent))
{
- int min_size;
-
if (!MINI_WINDOW_P (w) && !NILP (w->too_small_ok))
min_size = width_p ? MIN_SAFE_WINDOW_WIDTH : MIN_SAFE_WINDOW_HEIGHT;
else
sideward = &w->hchild;
forward = &w->vchild;
w->height = make_number (size);
+ w->orig_height = Qnil;
}
if (!NILP (*sideward))
XSETFASTINT (w->window_end_vpos, 0);
bzero (&w->last_cursor, sizeof w->last_cursor);
w->window_end_valid = Qnil;
- XSETFASTINT (w->hscroll, 0);
+ w->hscroll = w->min_hscroll = make_number (0);
+ w->vscroll = make_number (0);
set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
set_marker_restricted (w->start,
make_number (b->last_window_start),
which means search visible and iconified frames.\n\
\n\
If `even-window-heights' is non-nil, window heights will be evened out\n\
-if displaying the buffer causes two vertically\ adjacent windows to be\n\
+if displaying the buffer causes two vertically adjacent windows to be\n\
displayed.")
(buffer, not_this_window, frame)
register Lisp_Object buffer, not_this_window, frame;
Vminibuf_scroll_window = window;
w = XWINDOW (window);
XSETFASTINT (w->hscroll, 0);
+ XSETFASTINT (w->min_hscroll, 0);
set_marker_restricted_both (w->start, buf, 1, 1);
set_marker_restricted_both (w->pointm, buf, 1, 1);
\f
DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
"Make current window ARG lines bigger.\n\
-From program, optional second arg non-nil means grow sideways ARG columns.")
+From program, optional second arg non-nil means grow sideways ARG columns.\n\
+Interactively, if an argument is not given, make the window one line bigger.")
(arg, side)
register Lisp_Object arg, side;
{
DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
"Make current window ARG lines smaller.\n\
-From program, optional second arg non-nil means shrink sideways arg columns.")
+From program, optional second arg non-nil means shrink sideways arg columns.\n\
+Interactively, if an argument is not given, make the window one line smaller.")
(arg, side)
register Lisp_Object arg, side;
{
}
else if (XFASTINT (w->height) > 1)
{
+ /* Distribute the additional lines of the mini-window
+ among the other windows. */
Lisp_Object window;
XSETWINDOW (window, w);
enlarge_window (window, 1 - XFASTINT (w->height), 0);
/* If PT is not visible in WINDOW, move back one half of
the screen. */
- XSETFASTINT (tem, PT);
- tem = Fpos_visible_in_window_p (tem, window, Qnil);
+ tem = Fpos_visible_in_window_p (make_number (PT), window, Qnil);
if (NILP (tem))
{
/* Move backward half the height of the window. Performance note:
int screen_full = (it.last_visible_y
- next_screen_context_lines * CANON_Y_UNIT (it.f));
int direction = n < 0 ? -1 : 1;
- move_it_vertically (&it, direction * screen_full);
+ int dy = direction * screen_full;
+
+ /* 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);
+ else if (dy > 0)
+ move_it_to (&it, ZV, -1, it.current_y + dy, -1,
+ MOVE_TO_POS | MOVE_TO_Y);
}
else
move_it_by_lines (&it, n, 1);
{
if (it.current_y + it.max_ascent + it.max_descent
> it.last_visible_y)
- /* The last line was only partially visible, make it fully
- visible. */
- w->vscroll =
- it.last_visible_y
- - it.current_y + it.max_ascent + it.max_descent;
+ {
+ /* The last line was only partially visible, make it fully
+ visible. */
+ w->vscroll = (it.last_visible_y
+ - it.current_y + it.max_ascent + it.max_descent);
+ adjust_glyphs (it.f);
+ }
else if (noerror)
return;
else
(arg)
register Lisp_Object arg;
{
-
+ Lisp_Object result;
+ int hscroll;
+ struct window *w = XWINDOW (selected_window);
+
if (NILP (arg))
- XSETFASTINT (arg, window_internal_width (XWINDOW (selected_window)) - 2);
+ XSETFASTINT (arg, window_internal_width (w) - 2);
else
arg = Fprefix_numeric_value (arg);
- return
- Fset_window_hscroll (selected_window,
- make_number (XINT (XWINDOW (selected_window)->hscroll)
- + XINT (arg)));
+ hscroll = XINT (w->hscroll) + XINT (arg);
+ result = Fset_window_hscroll (selected_window, make_number (hscroll));
+
+ if (interactive_p (0))
+ w->min_hscroll = w->hscroll;
+
+ return result;
}
DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 1, "P",
(arg)
register Lisp_Object arg;
{
+ Lisp_Object result;
+ int hscroll;
+ struct window *w = XWINDOW (selected_window);
+
if (NILP (arg))
- XSETFASTINT (arg, window_internal_width (XWINDOW (selected_window)) - 2);
+ XSETFASTINT (arg, window_internal_width (w) - 2);
else
arg = Fprefix_numeric_value (arg);
- return
- Fset_window_hscroll (selected_window,
- make_number (XINT (XWINDOW (selected_window)->hscroll)
- - XINT (arg)));
+ hscroll = XINT (w->hscroll) - XINT (arg);
+ result = Fset_window_hscroll (selected_window, make_number (hscroll));
+
+ if (interactive_p (0))
+ w->min_hscroll = w->hscroll;
+
+ return result;
+}
+
+/* Value is the number of lines actually displayed in window W,
+ as opposed to its height. */
+
+static int
+displayed_window_lines (w)
+ struct window *w;
+{
+ struct it it;
+ struct text_pos start;
+ int height = window_box_height (w);
+ struct buffer *old_buffer;
+ int bottom_y;
+
+ if (XBUFFER (w->buffer) != current_buffer)
+ {
+ old_buffer = current_buffer;
+ set_buffer_internal (XBUFFER (w->buffer));
+ }
+ else
+ old_buffer = NULL;
+
+ SET_TEXT_POS_FROM_MARKER (start, w->start);
+ start_display (&it, w, start);
+ move_it_vertically (&it, height);
+ bottom_y = line_bottom_y (&it);
+
+ /* Add in empty lines at the bottom of the window. */
+ if (bottom_y < height)
+ {
+ int uy = CANON_Y_UNIT (it.f);
+ it.vpos += (height - bottom_y + uy - 1) / uy;
+ }
+
+ if (old_buffer)
+ set_buffer_internal (old_buffer);
+
+ return it.vpos;
}
+
DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
- "Center point in window and redisplay frame. With ARG, put point on line ARG.\n\
-The desired position of point is always relative to the current window.\n\
-Just C-u as prefix means put point in the center of the window.\n\
-If ARG is omitted or nil, erases the entire frame and then\n\
-redraws with point in the center of the current window.")
+ "Center point in window and redisplay frame.\n\
+With prefix argument ARG, recenter putting point on screen line ARG\n\
+relative to the current window. If ARG is negative, it counts up from the\n\
+bottom of the window. (ARG should be less than the height of the window.)\n\
+\n\
+If ARG is omitted or nil, erase the entire frame and then\n\
+redraw with point in the center of the current window.\n\
+Just C-u as prefix means put point in the center of the window\n\
+and redisplay normally--don't erase and redraw the frame.")
(arg)
register Lisp_Object arg;
{
- register struct window *w = XWINDOW (selected_window);
- register int ht = window_internal_height (w);
- struct position pos;
+ struct window *w = XWINDOW (selected_window);
struct buffer *buf = XBUFFER (w->buffer);
struct buffer *obuf = current_buffer;
+ int center_p = 0;
+ int charpos, bytepos;
if (NILP (arg))
{
- extern int frame_garbaged;
int i;
/* Invalidate pixel data calculated for all compositions. */
Fredraw_frame (w->frame);
SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
- XSETFASTINT (arg, ht / 2);
+ center_p = 1;
}
else if (CONSP (arg)) /* Just C-u. */
- {
- XSETFASTINT (arg, ht / 2);
- }
+ center_p = 1;
else
{
arg = Fprefix_numeric_value (arg);
CHECK_NUMBER (arg, 0);
}
- if (XINT (arg) < 0)
- XSETINT (arg, XINT (arg) + ht);
-
set_buffer_internal (buf);
- pos = *vmotion (PT, - XINT (arg), w);
- set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
- w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
- || FETCH_BYTE (pos.bytepos - 1) == '\n')
- ? Qt : Qnil);
+ /* Handle centering on a gfaphical frame specially. Such frames can
+ have variable-height lines and centering point on the basis of
+ line counts would lead to strange effects. */
+ if (center_p && FRAME_WINDOW_P (XFRAME (w->frame)))
+ {
+ struct it it;
+ struct text_pos pt;
+
+ SET_TEXT_POS (pt, PT, PT_BYTE);
+ start_display (&it, w, pt);
+ move_it_vertically (&it, - it.last_visible_y / 2);
+ charpos = IT_CHARPOS (it);
+ bytepos = IT_BYTEPOS (it);
+ }
+ else
+ {
+ struct position pos;
+
+ if (center_p)
+ {
+ int ht = displayed_window_lines (w);
+ arg = make_number (ht / 2);
+ }
+ else if (XINT (arg) < 0)
+ {
+ int ht = displayed_window_lines (w);
+ XSETINT (arg, XINT (arg) + ht);
+ }
+
+ pos = *vmotion (PT, - XINT (arg), w);
+ charpos = pos.bufpos;
+ bytepos = pos.bytepos;
+ }
+
+ /* Set the new window start. */
+ set_marker_both (w->start, w->buffer, charpos, bytepos);
+ w->window_end_valid = Qnil;
w->force_start = Qt;
+ if (bytepos == BEGV_BYTE || FETCH_BYTE (bytepos - 1) == '\n')
+ w->start_at_line_beg = Qt;
+ else
+ w->start_at_line_beg = Qnil;
+
set_buffer_internal (obuf);
-
return Qnil;
}
-/* Value is the number of lines actually displayed in window W,
- as opposed to its height. */
-
-static int
-displayed_window_lines (w)
- struct window *w;
+DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height,
+ 0, 1, 0,
+ "Return the height in lines of the text display area of WINDOW.\n\
+This doesn't include the mode-line (or header-line if any) or any\n\
+partial-height lines in the text display area.")
+ (window)
+ Lisp_Object window;
{
- struct it it;
- struct text_pos start;
- int height = window_box_height (w);
- struct buffer *old_buffer;
- int bottom_y;
-
- if (XBUFFER (w->buffer) != current_buffer)
- {
- old_buffer = current_buffer;
- set_buffer_internal (XBUFFER (w->buffer));
- }
- else
- old_buffer = NULL;
-
- SET_TEXT_POS_FROM_MARKER (start, w->start);
- start_display (&it, w, start);
- move_it_vertically (&it, height);
-
- if (old_buffer)
- set_buffer_internal (old_buffer);
-
- /* Add in empty lines at the bottom of the window. */
- bottom_y = it.current_y + it.max_ascent + it.max_descent;
- if (bottom_y < height)
- {
- struct frame *f = XFRAME (w->frame);
- int rest = height - bottom_y;
- int lines = (rest + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
- it.vpos += lines;
- }
-#if 0
- else if (it.current_y < height && bottom_y > height)
- /* Partially visible line at the bottom. */
- ++it.vpos;
-#endif
-
- return it.vpos;
+ struct window *w = decode_window (window);
+ int pixel_height = window_box_height (w);
+ int line_height = pixel_height / CANON_Y_UNIT (XFRAME (w->frame));
+ return make_number (line_height);
}
XSETINT (arg, XINT (arg) + lines);
}
+ /* Skip past a partially visible first line. */
+ if (w->vscroll)
+ XSETINT (arg, XINT (arg) + 1);
+
return Fvertical_motion (arg, window);
}
/* This is saved as a Lisp_Vector */
struct saved_window
- {
- /* these first two must agree with struct Lisp_Vector in lisp.h */
- EMACS_INT size_from_Lisp_Vector_struct;
- struct Lisp_Vector *next_from_Lisp_Vector_struct;
+{
+ /* these first two must agree with struct Lisp_Vector in lisp.h */
+ EMACS_INT size_from_Lisp_Vector_struct;
+ struct Lisp_Vector *next_from_Lisp_Vector_struct;
- Lisp_Object window;
- Lisp_Object buffer, start, pointm, mark;
- Lisp_Object left, top, width, height, hscroll;
- Lisp_Object parent, prev;
- Lisp_Object start_at_line_beg;
- Lisp_Object display_table;
- Lisp_Object orig_top, orig_height;
- };
-#define SAVED_WINDOW_VECTOR_SIZE 16 /* Arg to Fmake_vector */
+ Lisp_Object window;
+ Lisp_Object buffer, start, pointm, mark;
+ Lisp_Object left, top, width, height, hscroll, min_hscroll;
+ Lisp_Object parent, prev;
+ Lisp_Object start_at_line_beg;
+ Lisp_Object display_table;
+ Lisp_Object orig_top, orig_height;
+};
+
+#define SAVED_WINDOW_VECTOR_SIZE 17 /* Arg to Fmake_vector */
#define SAVED_WINDOW_N(swv,n) \
((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
f = XFRAME (frame);
-
+
/* If f is a dead frame, don't bother rebuilding its window tree.
However, there is other stuff we should still try to do below. */
if (FRAME_LIVE_P (f))
w->width = p->width;
w->height = p->height;
w->hscroll = p->hscroll;
+ w->min_hscroll = p->min_hscroll;
w->display_table = p->display_table;
w->orig_top = p->orig_top;
w->orig_height = p->orig_height;
xassert (NILP (leaf_windows[i]->hchild)
&& NILP (leaf_windows[i]->vchild));
free_window_matrices (leaf_windows[i]);
- SET_FRAME_GARBAGED (f);
}
else if (EQ (leaf_windows[i]->buffer, new_current_buffer))
++n;
p->width = w->width;
p->height = w->height;
p->hscroll = w->hscroll;
+ p->min_hscroll = w->min_hscroll;
p->display_table = w->display_table;
p->orig_top = w->orig_top;
p->orig_height = w->orig_height;
{
if (! EQ (p1->hscroll, p2->hscroll))
return 0;
+ if (!EQ (p1->min_hscroll, p2->min_hscroll))
+ return 0;
if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
return 0;
if (NILP (Fequal (p1->start, p2->start)))
void
syms_of_window ()
{
- Qleft_bitmap_area = intern ("left-bitmap-area");
- staticpro (&Qleft_bitmap_area);
- Qright_bitmap_area = intern ("right-bitmap-area");
- staticpro (&Qright_bitmap_area);
+ Qleft_fringe = intern ("left-fringe");
+ staticpro (&Qleft_fringe);
+ Qright_fringe = intern ("right-fringe");
+ staticpro (&Qright_fringe);
Qwindow_size_fixed = intern ("window-size-fixed");
staticpro (&Qwindow_size_fixed);
DEFVAR_LISP ("scroll-preserve-screen-position",
&Vscroll_preserve_screen_position,
- "*Nonzero means scroll commands move point to keep its screen line unchanged.");
+ "*Non-nil means scroll commands move point to keep its screen line unchanged.");
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,
+ "Non-nil in a buffer means windows displaying the buffer are fixed-size.\n\
+Emacs won't change the size of any window displaying that buffer,\n\
+unless you explicitly change the size, or Emacs has no other choice.\n\
+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);
defsubr (&Sother_window_for_scrolling);
defsubr (&Sscroll_other_window);
defsubr (&Srecenter);
+ defsubr (&Swindow_text_height);
defsubr (&Smove_to_window_line);
defsubr (&Swindow_configuration_p);
defsubr (&Swindow_configuration_frame);