#include <config.h>
#include "lisp.h"
#include "buffer.h"
#include "keyboard.h"
#include "frame.h"
#include "window.h"
#include "commands.h"
#include "indent.h"
#include "termchar.h"
#include "disptab.h"
#include "dispextern.h"
#include "blockinput.h"
#include "intervals.h"
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif
#ifdef WINDOWSNT
#include "w32term.h"
#endif
#ifdef MSDOS
#include "msdos.h"
#endif
#ifdef macintosh
#include "macterm.h"
#endif
#ifndef max
#define max(a, b) ((a) < (b) ? (b) : (a))
#endif
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_fringe, Qright_fringe;
extern Lisp_Object Qheight, Qwidth;
static int displayed_window_lines P_ ((struct window *));
static struct window *decode_window P_ ((Lisp_Object));
static Lisp_Object select_window_1 P_ ((Lisp_Object, int));
static int count_windows P_ ((struct window *));
static int get_leaf_windows P_ ((struct window *, struct window **, int));
static void window_scroll P_ ((Lisp_Object, int, int, int));
static void window_scroll_pixel_based P_ ((Lisp_Object, int, int, int));
static void window_scroll_line_based P_ ((Lisp_Object, int, int, int));
static int window_min_size_1 P_ ((struct window *, int));
static int window_min_size P_ ((struct window *, int, int, int *));
static void size_window P_ ((Lisp_Object, int, int, int));
static int freeze_window_start P_ ((struct window *, void *));
static int window_fixed_size_p P_ ((struct window *, int, int));
static void enlarge_window P_ ((Lisp_Object, int, int));
static Lisp_Object window_list P_ ((void));
static int add_window_to_list P_ ((struct window *, void *));
static int candidate_window_p P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
Lisp_Object));
static Lisp_Object next_window P_ ((Lisp_Object, Lisp_Object,
Lisp_Object, int));
static void decode_next_window_args P_ ((Lisp_Object *, Lisp_Object *,
Lisp_Object *));
static int foreach_window_1 P_ ((struct window *,
int (* fn) (struct window *, void *),
void *));
static Lisp_Object window_list_1 P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
int window_size_fixed;
Lisp_Object selected_window;
Lisp_Object Vwindow_list;
Lisp_Object minibuf_window;
Lisp_Object Vminibuf_scroll_window;
Lisp_Object Vother_window_scroll_buffer;
Lisp_Object Vtemp_buffer_show_function;
int window_min_height;
int window_min_width;
int pop_up_windows;
int pop_up_frames;
int display_buffer_reuse_frames;
Lisp_Object Vpop_up_frame_function;
Lisp_Object Vdisplay_buffer_function;
Lisp_Object Veven_window_heights;
Lisp_Object Vspecial_display_buffer_names;
Lisp_Object Vspecial_display_regexps;
Lisp_Object Vspecial_display_function;
Lisp_Object Vsame_window_buffer_names;
Lisp_Object Vsame_window_regexps;
Lisp_Object Qtemp_buffer_show_hook;
int split_height_threshold;
int next_screen_context_lines;
static int sequence_number;
static int window_initialized;
Lisp_Object Qwindow_configuration_change_hook;
Lisp_Object Vwindow_configuration_change_hook;
Lisp_Object Vscroll_preserve_screen_position;
#if 0
static int inhibit_frame_unsplittable;
#endif
#define min(a, b) ((a) < (b) ? (a) : (b))
extern int scroll_margin;
extern Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
"Returns t if OBJECT is a window.")
(object)
Lisp_Object object;
{
return WINDOWP (object) ? Qt : Qnil;
}
DEFUN ("window-live-p", Fwindow_live_p, Swindow_live_p, 1, 1, 0,
"Returns t if OBJECT is a window which is currently visible.")
(object)
Lisp_Object object;
{
return WINDOW_LIVE_P (object) ? Qt : Qnil;
}
Lisp_Object
make_window ()
{
Lisp_Object val;
register struct window *p;
p = allocate_window ();
XSETFASTINT (p->sequence_number, ++sequence_number);
XSETFASTINT (p->left, 0);
XSETFASTINT (p->top, 0);
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 ();
XSETFASTINT (p->use_time, 0);
p->frame = Qnil;
p->display_table = Qnil;
p->dedicated = Qnil;
p->pseudo_window_p = 0;
bzero (&p->cursor, sizeof (p->cursor));
bzero (&p->last_cursor, sizeof (p->last_cursor));
bzero (&p->phys_cursor, sizeof (p->phys_cursor));
p->desired_matrix = p->current_matrix = 0;
p->phys_cursor_type = -1;
p->must_be_updated_p = 0;
XSETFASTINT (p->window_end_vpos, 0);
XSETFASTINT (p->window_end_pos, 0);
p->window_end_valid = Qnil;
p->vscroll = 0;
XSETWINDOW (val, p);
XSETFASTINT (p->last_point, 0);
p->frozen_window_start_p = 0;
Vwindow_list = Qnil;
return val;
}
DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0,
"Return the window that the cursor now appears in and commands apply to.")
()
{
return selected_window;
}
DEFUN ("minibuffer-window", Fminibuffer_window, Sminibuffer_window, 0, 1, 0,
"Return the window used now for minibuffers.\n\
If the optional argument FRAME is specified, return the minibuffer window\n\
used by that frame.")
(frame)
Lisp_Object frame;
{
if (NILP (frame))
frame = selected_frame;
CHECK_LIVE_FRAME (frame, 0);
return FRAME_MINIBUF_WINDOW (XFRAME (frame));
}
DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1, 0,
"Returns non-nil if WINDOW is a minibuffer window.")
(window)
Lisp_Object window;
{
struct window *w = decode_window (window);
return MINI_WINDOW_P (w) ? Qt : Qnil;
}
DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
Spos_visible_in_window_p, 0, 3, 0,
"Return t if position POS is currently on the frame in WINDOW.\n\
Return nil if that position is scrolled vertically out of view.\n\
If a character is only partially visible, nil is returned, unless the\n\
optional argument PARTIALLY is non-nil.\n\
POS defaults to point in WINDOW; WINDOW defaults to the selected window.")
(pos, window, partially)
Lisp_Object pos, window, partially;
{
register struct window *w;
register int posint;
register struct buffer *buf;
struct text_pos top;
Lisp_Object in_window;
int fully_p;
w = decode_window (window);
buf = XBUFFER (w->buffer);
SET_TEXT_POS_FROM_MARKER (top, w->start);
if (!NILP (pos))
{
CHECK_NUMBER_COERCE_MARKER (pos, 0);
posint = XINT (pos);
}
else if (w == XWINDOW (selected_window))
posint = PT;
else
posint = XMARKER (w->pointm)->charpos;
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 (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))
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;
}
return in_window;
}
static struct window *
decode_window (window)
register Lisp_Object window;
{
if (NILP (window))
return XWINDOW (selected_window);
CHECK_LIVE_WINDOW (window, 0);
return XWINDOW (window);
}
DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
"Return the buffer that WINDOW is displaying.")
(window)
Lisp_Object window;
{
return decode_window (window)->buffer;
}
DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0,
"Return the number of lines in WINDOW (including its mode line).")
(window)
Lisp_Object window;
{
return decode_window (window)->height;
}
DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
"Return the number of display columns in WINDOW.\n\
This is the width that is usable columns available for text in WINDOW.\n\
If you want to find out how many columns WINDOW takes up,\n\
use (let ((edges (window-edges))) (- (nth 2 edges) (nth 0 edges))).")
(window)
Lisp_Object window;
{
return make_number (window_internal_width (decode_window (window)));
}
DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
"Return the number of columns by which WINDOW is scrolled from left margin.")
(window)
Lisp_Object window;
{
return decode_window (window)->hscroll;
}
DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
"Set number of columns WINDOW is scrolled from left margin to NCOL.\n\
NCOL should be zero or positive.")
(window, ncol)
Lisp_Object window, ncol;
{
struct window *w = decode_window (window);
int hscroll;
CHECK_NUMBER (ncol, 1);
hscroll = max (0, XINT (ncol));
if (XINT (w->hscroll) != hscroll)
XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
w->hscroll = make_number (hscroll);
return ncol;
}
DEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger,
Swindow_redisplay_end_trigger, 0, 1, 0,
"Return WINDOW's redisplay end trigger value.\n\
See `set-window-redisplay-end-trigger' for more information.")
(window)
Lisp_Object window;
{
return decode_window (window)->redisplay_end_trigger;
}
DEFUN ("set-window-redisplay-end-trigger", Fset_window_redisplay_end_trigger,
Sset_window_redisplay_end_trigger, 2, 2, 0,
"Set WINDOW's redisplay end trigger value to VALUE.\n\
VALUE should be a buffer position (typically a marker) or nil.\n\
If it is a buffer position, then if redisplay in WINDOW reaches a position\n\
beyond VALUE, the functions in `redisplay-end-trigger-functions' are called\n\
with two arguments: WINDOW, and the end trigger value.\n\
Afterwards the end-trigger value is reset to nil.")
(window, value)
register Lisp_Object window, value;
{
register struct window *w;
w = decode_window (window);
w->redisplay_end_trigger = value;
return value;
}
DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0,
"Return a list of the edge coordinates of WINDOW.\n\
\(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.\n\
RIGHT is one more than the rightmost column used by WINDOW,\n\
and BOTTOM is one more than the bottommost row used by WINDOW\n\
and its mode-line.")
(window)
Lisp_Object window;
{
register struct window *w = decode_window (window);
return Fcons (w->left, Fcons (w->top,
Fcons (make_number (WINDOW_RIGHT_EDGE (w)),
Fcons (make_number (XFASTINT (w->top)
+ XFASTINT (w->height)),
Qnil))));
}
static enum window_part
coordinates_in_window (w, x, y)
register struct window *w;
register int *x, *y;
{
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);
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;
int grabbable_width = ux;
if (*x < x0 || *x >= x1)
return ON_NOTHING;
if (w->pseudo_window_p)
{
left_x = 0;
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);
}
else
{
left_x = (WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w)
- FRAME_INTERNAL_BORDER_WIDTH_SAFE (f));
right_x = WINDOW_DISPLAY_RIGHT_EDGE_PIXEL_X (w) - 1;
top_y = (WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w)
- FRAME_INTERNAL_BORDER_WIDTH_SAFE (f));
bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
}
if (WINDOW_WANTS_MODELINE_P (w)
&& *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w)
&& *y < bottom_y)
{
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)
{
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;
}
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))
{
part = ON_NOTHING;
}
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) < grabbable_width))
{
part = ON_VERTICAL_BORDER;
}
else if (*x < left_x || *x > right_x)
{
*x -= left_x;
*y -= top_y;
part = *x < left_x ? ON_LEFT_FRINGE : ON_RIGHT_FRINGE;
}
else
{
*x -= left_x;
*y -= top_y;
part = ON_TEXT;
}
}
else
{
if (*x < left_x || *x > right_x)
{
*x -= left_x;
*y -= top_y;
part = *x < left_x ? ON_LEFT_FRINGE : ON_RIGHT_FRINGE;
}
else if (!w->pseudo_window_p
&& !WINDOW_RIGHTMOST_P (w)
&& *x > right_x - ux)
{
part = ON_VERTICAL_BORDER;
}
else
{
*x -= left_x;
*y -= top_y;
part = 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\
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 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)
register Lisp_Object coordinates, window;
{
struct window *w;
struct frame *f;
int x, y;
Lisp_Object lx, ly;
CHECK_LIVE_WINDOW (window, 0);
w = XWINDOW (window);
f = XFRAME (w->frame);
CHECK_CONS (coordinates, 1);
lx = Fcar (coordinates);
ly = Fcdr (coordinates);
CHECK_NUMBER_OR_FLOAT (lx, 1);
CHECK_NUMBER_OR_FLOAT (ly, 1);
x = PIXEL_X_FROM_CANON_X (f, lx);
y = PIXEL_Y_FROM_CANON_Y (f, ly);
switch (coordinates_in_window (w, &x, &y))
{
case ON_NOTHING:
return Qnil;
case ON_TEXT:
return Fcons (CANON_X_FROM_PIXEL_X (f, x),
CANON_Y_FROM_PIXEL_Y (f, y));
case ON_MODE_LINE:
return Qmode_line;
case ON_VERTICAL_BORDER:
return Qvertical_line;
case ON_HEADER_LINE:
return Qheader_line;
case ON_LEFT_FRINGE:
return Qleft_fringe;
case ON_RIGHT_FRINGE:
return Qright_fringe;
default:
abort ();
}
}
struct check_window_data
{
Lisp_Object *window;
int *x, *y, *part;
};
static int
check_window_containing (w, user_data)
struct window *w;
void *user_data;
{
struct check_window_data *cw = (struct check_window_data *) user_data;
enum window_part found;
int continue_p = 1;
found = coordinates_in_window (w, cw->x, cw->y);
if (found != ON_NOTHING)
{
*cw->part = found - 1;
XSETWINDOW (*cw->window, w);
continue_p = 0;
}
return continue_p;
}
Lisp_Object
window_from_coordinates (f, x, y, part, tool_bar_p)
struct frame *f;
int x, y;
int *part;
int tool_bar_p;
{
Lisp_Object window;
struct check_window_data cw;
window = Qnil;
cw.window = &window, cw.x = &x, cw.y = &y; cw.part = part;
foreach_window (f, check_window_containing, &cw);
if (NILP (window)
&& 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)
!= ON_NOTHING))
{
*part = 0;
window = f->tool_bar_window;
}
return window;
}
DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
"Return window containing coordinates X and Y on FRAME.\n\
If omitted, FRAME defaults to the currently selected frame.\n\
The top left corner of the frame is considered to be row 0,\n\
column 0.")
(x, y, frame)
Lisp_Object x, y, frame;
{
int part;
struct frame *f;
if (NILP (frame))
frame = selected_frame;
CHECK_LIVE_FRAME (frame, 2);
f = XFRAME (frame);
CHECK_NUMBER_OR_FLOAT (x, 0);
CHECK_NUMBER_OR_FLOAT (y, 1);
return window_from_coordinates (f,
PIXEL_X_FROM_CANON_X (f, x),
PIXEL_Y_FROM_CANON_Y (f, y),
&part, 0);
}
DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
"Return current value of point in WINDOW.\n\
For a nonselected window, this is the value point would have\n\
if that window were selected.\n\
\n\
Note that, when WINDOW is the selected window and its buffer\n\
is also currently selected, the value returned is the same as (point).\n\
It would be more strictly correct to return the `top-level' value\n\
of point, outside of any save-excursion forms.\n\
But that is hard to define.")
(window)
Lisp_Object window;
{
register struct window *w = decode_window (window);
if (w == XWINDOW (selected_window)
&& current_buffer == XBUFFER (w->buffer))
return Fpoint ();
return Fmarker_position (w->pointm);
}
DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
"Return position at which display currently starts in WINDOW.\n\
This is updated by redisplay or by calling `set-window-start'.")
(window)
Lisp_Object window;
{
return Fmarker_position (decode_window (window)->start);
}
DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
"Return position at which display currently ends in WINDOW.\n\
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 UPDATE is non-nil, compute the up-to-date position\n\
if it isn't already recorded.")
(window, update)
Lisp_Object window, update;
{
Lisp_Object value;
struct window *w = decode_window (window);
Lisp_Object buf;
buf = w->buffer;
CHECK_BUFFER (buf, 0);
#if 0
if (NILP (w->window_end_valid))
return Qnil;
#endif
if (! NILP (update)
&& ! (! NILP (w->window_end_valid)
&& XFASTINT (w->last_modified) >= MODIFF))
{
struct text_pos startp;
struct it it;
struct buffer *old_buffer = NULL, *b = XBUFFER (buf);
if (XMARKER (w->start)->charpos < BEGV)
SET_TEXT_POS (startp, BEGV, BEGV_BYTE);
else if (XMARKER (w->start)->charpos > ZV)
SET_TEXT_POS (startp, ZV, ZV_BYTE);
else
SET_TEXT_POS_FROM_MARKER (startp, w->start);
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));
if (it.current_y < it.last_visible_y)
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));
return value;
}
DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
"Make point value in WINDOW be at position POS in WINDOW's buffer.")
(window, pos)
Lisp_Object window, pos;
{
register struct window *w = decode_window (window);
CHECK_NUMBER_COERCE_MARKER (pos, 1);
if (w == XWINDOW (selected_window)
&& XBUFFER (w->buffer) == current_buffer)
Fgoto_char (pos);
else
set_marker_restricted (w->pointm, pos, w->buffer);
if (!EQ (window, selected_window))
++windows_or_buffers_changed;
return pos;
}
DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
"Make display in WINDOW start at position POS in WINDOW's buffer.\n\
Optional third arg NOFORCE non-nil inhibits next redisplay\n\
from overriding motion of point in order to display at this exact start.")
(window, pos, noforce)
Lisp_Object window, pos, noforce;
{
register struct window *w = decode_window (window);
CHECK_NUMBER_COERCE_MARKER (pos, 1);
set_marker_restricted (w->start, pos, w->buffer);
w->start_at_line_beg = Qnil;
if (NILP (noforce))
w->force_start = Qt;
w->update_mode_line = Qt;
XSETFASTINT (w->last_modified, 0);
XSETFASTINT (w->last_overlay_modified, 0);
if (!EQ (window, selected_window))
windows_or_buffers_changed++;
return pos;
}
DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
1, 1, 0,
"Return WINDOW's dedicated object, usually t or nil.\n\
See also `set-window-dedicated-p'.")
(window)
Lisp_Object window;
{
return decode_window (window)->dedicated;
}
DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p,
Sset_window_dedicated_p, 2, 2, 0,
"Control whether WINDOW is dedicated to the buffer it displays.\n\
If it is dedicated, Emacs will not automatically change\n\
which buffer appears in it.\n\
The second argument is the new value for the dedication flag;\n\
non-nil means yes.")
(window, arg)
Lisp_Object window, arg;
{
register struct window *w = decode_window (window);
if (NILP (arg))
w->dedicated = Qnil;
else
w->dedicated = Qt;
return w->dedicated;
}
DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
0, 1, 0,
"Return the display-table that WINDOW is using.")
(window)
Lisp_Object window;
{
return decode_window (window)->display_table;
}
struct Lisp_Char_Table *
window_display_table (w)
struct window *w;
{
struct Lisp_Char_Table *dp = NULL;
if (DISP_TABLE_P (w->display_table))
dp = XCHAR_TABLE (w->display_table);
else if (BUFFERP (w->buffer))
{
struct buffer *b = XBUFFER (w->buffer);
if (DISP_TABLE_P (b->display_table))
dp = XCHAR_TABLE (b->display_table);
else if (DISP_TABLE_P (Vstandard_display_table))
dp = XCHAR_TABLE (Vstandard_display_table);
}
return dp;
}
DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_display_table, 2, 2, 0,
"Set WINDOW's display-table to TABLE.")
(window, table)
register Lisp_Object window, table;
{
register struct window *w;
w = decode_window (window);
w->display_table = table;
return table;
}
static void
unshow_buffer (w)
register struct window *w;
{
Lisp_Object buf;
struct buffer *b;
buf = w->buffer;
b = XBUFFER (buf);
if (b != XMARKER (w->pointm)->buffer)
abort ();
#if 0
if (w == XWINDOW (selected_window)
|| ! EQ (buf, XWINDOW (selected_window)->buffer))
#endif
b->last_window_start = marker_position (w->start);
if (! EQ (buf, XWINDOW (selected_window)->buffer)
&& !(WINDOWP (b->last_selected_window)
&& w != XWINDOW (b->last_selected_window)
&& EQ (buf, XWINDOW (b->last_selected_window)->buffer)))
temp_set_point_both (b,
clip_to_bounds (BUF_BEGV (b),
XMARKER (w->pointm)->charpos,
BUF_ZV (b)),
clip_to_bounds (BUF_BEGV_BYTE (b),
marker_byte_position (w->pointm),
BUF_ZV_BYTE (b)));
if (WINDOWP (b->last_selected_window)
&& w == XWINDOW (b->last_selected_window))
b->last_selected_window = Qnil;
}
static void
replace_window (old, replacement)
Lisp_Object old, replacement;
{
register Lisp_Object tem;
register struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
p->left = o->left;
p->top = o->top;
p->width = o->width;
p->height = o->height;
p->desired_matrix = p->current_matrix = 0;
p->vscroll = 0;
bzero (&p->cursor, sizeof (p->cursor));
bzero (&p->last_cursor, sizeof (p->last_cursor));
bzero (&p->phys_cursor, sizeof (p->phys_cursor));
p->phys_cursor_type = -1;
p->must_be_updated_p = 0;
p->pseudo_window_p = 0;
XSETFASTINT (p->window_end_vpos, 0);
XSETFASTINT (p->window_end_pos, 0);
p->window_end_valid = Qnil;
p->frozen_window_start_p = 0;
p->orig_top = p->orig_height = Qnil;
p->next = tem = o->next;
if (!NILP (tem))
XWINDOW (tem)->prev = replacement;
p->prev = tem = o->prev;
if (!NILP (tem))
XWINDOW (tem)->next = replacement;
p->parent = tem = o->parent;
if (!NILP (tem))
{
if (EQ (XWINDOW (tem)->vchild, old))
XWINDOW (tem)->vchild = replacement;
if (EQ (XWINDOW (tem)->hchild, old))
XWINDOW (tem)->hchild = replacement;
}
}
DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
"Remove WINDOW from the display. Default is selected window.")
(window)
register Lisp_Object window;
{
delete_window (window);
if (! NILP (Vwindow_configuration_change_hook)
&& ! NILP (Vrun_hooks))
call1 (Vrun_hooks, Qwindow_configuration_change_hook);
return Qnil;
}
void
delete_window (window)
register Lisp_Object window;
{
register Lisp_Object tem, parent, sib;
register struct window *p;
register struct window *par;
struct frame *f;
if (NILP (window))
window = selected_window;
else
CHECK_WINDOW (window, 0);
p = XWINDOW (window);
if (NILP (p->buffer)
&& NILP (p->hchild)
&& NILP (p->vchild))
return;
parent = p->parent;
if (NILP (parent))
error ("Attempt to delete minibuffer or sole ordinary window");
par = XWINDOW (parent);
windows_or_buffers_changed++;
Vwindow_list = Qnil;
f = XFRAME (WINDOW_FRAME (p));
FRAME_WINDOW_SIZES_CHANGED (f) = 1;
{
Lisp_Object pwindow;
pwindow = FRAME_SELECTED_WINDOW (f);
while (!NILP (pwindow))
{
if (EQ (window, pwindow))
break;
pwindow = XWINDOW (pwindow)->parent;
}
if (EQ (window, pwindow))
{
Lisp_Object alternative;
alternative = Fnext_window (window, Qlambda, Qnil);
if (EQ (window, selected_window))
Fselect_window (alternative);
else
FRAME_SELECTED_WINDOW (f) = alternative;
}
}
tem = p->buffer;
if (!NILP (tem))
{
unshow_buffer (p);
unchain_marker (p->pointm);
unchain_marker (p->start);
}
BLOCK_INPUT;
free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (f)));
tem = p->next;
if (!NILP (tem))
XWINDOW (tem)->prev = p->prev;
tem = p->prev;
if (!NILP (tem))
XWINDOW (tem)->next = p->next;
if (EQ (window, par->hchild))
par->hchild = p->next;
if (EQ (window, par->vchild))
par->vchild = p->next;
sib = p->prev;
if (NILP (sib))
{
sib = p->next;
XWINDOW (sib)->top = p->top;
XWINDOW (sib)->left = p->left;
}
if (!NILP (par->vchild))
set_window_height (sib,
XFASTINT (XWINDOW (sib)->height) + XFASTINT (p->height),
1);
if (!NILP (par->hchild))
set_window_width (sib,
XFASTINT (XWINDOW (sib)->width) + XFASTINT (p->width),
1);
tem = par->hchild;
if (NILP (tem))
tem = par->vchild;
if (NILP (XWINDOW (tem)->next))
replace_window (parent, tem);
if (! NILP (p->hchild))
delete_all_subwindows (XWINDOW (p->hchild));
else if (! NILP (p->vchild))
delete_all_subwindows (XWINDOW (p->vchild));
p->buffer = p->hchild = p->vchild = Qnil;
adjust_glyphs (f);
UNBLOCK_INPUT;
}
static int
add_window_to_list (w, user_data)
struct window *w;
void *user_data;
{
Lisp_Object *list = (Lisp_Object *) user_data;
Lisp_Object window;
XSETWINDOW (window, w);
*list = Fcons (window, *list);
return 1;
}
static Lisp_Object
window_list ()
{
if (!CONSP (Vwindow_list))
{
Lisp_Object tail;
Vwindow_list = Qnil;
for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
{
Lisp_Object args[2];
args[1] = Qnil;
foreach_window (XFRAME (XCAR (tail)), add_window_to_list, &args[1]);
args[0] = Vwindow_list;
args[1] = Fnreverse (args[1]);
Vwindow_list = Fnconc (2, args);
}
}
return Vwindow_list;
}
static int
candidate_window_p (window, owindow, minibuf, all_frames)
Lisp_Object window, owindow, minibuf, all_frames;
{
struct window *w = XWINDOW (window);
struct frame *f = XFRAME (w->frame);
int candidate_p = 1;
if (!BUFFERP (w->buffer))
candidate_p = 0;
else if (MINI_WINDOW_P (w)
&& (EQ (minibuf, Qlambda)
|| (WINDOWP (minibuf) && !EQ (minibuf, window))))
{
candidate_p = 0;
}
else if (EQ (all_frames, Qt))
candidate_p = 1;
else if (NILP (all_frames))
{
xassert (WINDOWP (owindow));
candidate_p = EQ (w->frame, XWINDOW (owindow)->frame);
}
else if (EQ (all_frames, Qvisible))
{
FRAME_SAMPLE_VISIBILITY (f);
candidate_p = FRAME_VISIBLE_P (f);
}
else if (INTEGERP (all_frames) && XINT (all_frames) == 0)
{
FRAME_SAMPLE_VISIBILITY (f);
candidate_p = FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f);
}
else if (WINDOWP (all_frames))
candidate_p = (EQ (FRAME_MINIBUF_WINDOW (f), all_frames)
|| EQ (XWINDOW (all_frames)->frame, w->frame)
|| EQ (XWINDOW (all_frames)->frame, FRAME_FOCUS_FRAME (f)));
else if (FRAMEP (all_frames))
candidate_p = EQ (all_frames, w->frame);
return candidate_p;
}
static void
decode_next_window_args (window, minibuf, all_frames)
Lisp_Object *window, *minibuf, *all_frames;
{
if (NILP (*window))
*window = selected_window;
else
CHECK_LIVE_WINDOW (*window, 0);
if (NILP (*minibuf))
*minibuf = minibuf_level ? minibuf_window : Qlambda;
else if (!EQ (*minibuf, Qt))
*minibuf = Qlambda;
if (NILP (*all_frames))
*all_frames = (!EQ (*minibuf, Qlambda)
? FRAME_MINIBUF_WINDOW (XFRAME (XWINDOW (*window)->frame))
: Qnil);
else if (EQ (*all_frames, Qvisible))
;
else if (XFASTINT (*all_frames) == 0)
;
else if (FRAMEP (*all_frames))
;
else if (!EQ (*all_frames, Qt))
*all_frames = Qnil;
}
static Lisp_Object
next_window (window, minibuf, all_frames, next_p)
Lisp_Object window, minibuf, all_frames;
int next_p;
{
decode_next_window_args (&window, &minibuf, &all_frames);
if (FRAMEP (all_frames)
&& !EQ (all_frames, XWINDOW (window)->frame))
return Fframe_first_window (all_frames);
if (next_p)
{
Lisp_Object list;
list = Fmemq (window, window_list ());
if (CONSP (list))
for (list = XCDR (list); CONSP (list); list = XCDR (list))
if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
break;
if (!CONSP (list))
for (list = Vwindow_list;
CONSP (list) && !EQ (XCAR (list), window);
list = XCDR (list))
if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
break;
if (CONSP (list))
window = XCAR (list);
}
else
{
Lisp_Object candidate, list;
candidate = Qnil;
for (list = window_list (); CONSP (list); list = XCDR (list))
{
if (EQ (XCAR (list), window))
{
if (WINDOWP (candidate))
break;
}
else if (candidate_window_p (XCAR (list), window, minibuf,
all_frames))
candidate = XCAR (list);
}
if (WINDOWP (candidate))
window = candidate;
}
return window;
}
DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
0)
(window, minibuf, all_frames)
Lisp_Object window, minibuf, all_frames;
{
return next_window (window, minibuf, all_frames, 1);
}
DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
0)
(window, minibuf, all_frames)
Lisp_Object window, minibuf, all_frames;
{
return next_window (window, minibuf, all_frames, 0);
}
DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
"Select the ARG'th different window on this frame.\n\
All windows on current frame are arranged in a cyclic order.\n\
This command selects the window ARG steps away in that order.\n\
A negative ARG moves in the opposite order. If the optional second\n\
argument ALL_FRAMES is non-nil, cycle through all frames.")
(arg, all_frames)
Lisp_Object arg, all_frames;
{
Lisp_Object window;
int i;
CHECK_NUMBER (arg, 0);
window = selected_window;
for (i = XINT (arg); i > 0; --i)
window = Fnext_window (window, Qnil, all_frames);
for (; i < 0; ++i)
window = Fprevious_window (window, Qnil, all_frames);
Fselect_window (window);
return Qnil;
}
DEFUN ("window-list", Fwindow_list, Swindow_list, 0, 3, 0,
"Return a list of windows on FRAME, starting with WINDOW.\n\
FRAME nil or omitted means use the selected frame.\n\
WINDOW nil or omitted means use the selected window.\n\
MINIBUF t means include the minibuffer window, even if it isn't active.\n\
MINIBUF nil or omitted means include the minibuffer window only\n\
if it's active.\n\
MINIBUF neither nil nor t means never include the minibuffer window.")
(frame, minibuf, window)
Lisp_Object frame, minibuf, window;
{
if (NILP (window))
window = selected_window;
if (NILP (frame))
frame = selected_frame;
if (!EQ (frame, XWINDOW (window)->frame))
error ("Window is on a different frame");
return window_list_1 (window, minibuf, frame);
}
static Lisp_Object
window_list_1 (window, minibuf, all_frames)
Lisp_Object window, minibuf, all_frames;
{
Lisp_Object tail, list;
decode_next_window_args (&window, &minibuf, &all_frames);
list = Qnil;
for (tail = window_list (); CONSP (tail); tail = XCDR (tail))
if (candidate_window_p (XCAR (tail), window, minibuf, all_frames))
list = Fcons (XCAR (tail), list);
return Fnreverse (list);
}
enum window_loop
{
WINDOW_LOOP_UNUSED,
GET_BUFFER_WINDOW,
GET_LRU_WINDOW,
DELETE_OTHER_WINDOWS,
DELETE_BUFFER_WINDOWS,
GET_LARGEST_WINDOW,
UNSHOW_BUFFER,
CHECK_ALL_WINDOWS
};
static Lisp_Object
window_loop (type, obj, mini, frames)
enum window_loop type;
Lisp_Object obj, frames;
int mini;
{
Lisp_Object window, windows, best_window, frame_arg;
struct frame *f;
struct gcpro gcpro1;
if (FRAMEP (frames))
f = XFRAME (frames);
else if (NILP (frames))
f = SELECTED_FRAME ();
else
f = NULL;
if (f)
frame_arg = Qlambda;
else if (XFASTINT (frames) == 0)
frame_arg = frames;
else if (EQ (frames, Qvisible))
frame_arg = frames;
else
frame_arg = Qt;
if (WINDOWP (obj))
window = obj;
else if (f)
window = FRAME_SELECTED_WINDOW (f);
else
window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
windows = window_list_1 (window, mini ? Qt : Qnil, frame_arg);
GCPRO1 (windows);
best_window = Qnil;
for (; CONSP (windows); windows = CDR (windows))
{
struct window *w;
window = XCAR (windows);
w = XWINDOW (window);
if (!MINI_WINDOW_P (w)
|| type == UNSHOW_BUFFER
|| (mini && minibuf_level > 0))
switch (type)
{
case GET_BUFFER_WINDOW:
if (EQ (w->buffer, obj)
&& (MINI_WINDOW_P (w)
? EQ (window, minibuf_window)
: 1))
{
if (NILP (best_window))
best_window = window;
else if (EQ (window, selected_window))
best_window = window;
}
break;
case GET_LRU_WINDOW:
if (!NILP (obj) && !WINDOW_FULL_WIDTH_P (w))
break;
if (MINI_WINDOW_P (w) || !NILP (w->dedicated))
break;
if (NILP (best_window)
|| (XFASTINT (XWINDOW (best_window)->use_time)
> XFASTINT (w->use_time)))
best_window = window;
break;
case DELETE_OTHER_WINDOWS:
if (!EQ (window, obj))
Fdelete_window (window);
break;
case DELETE_BUFFER_WINDOWS:
if (EQ (w->buffer, obj))
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
if (EQ (window, FRAME_ROOT_WINDOW (f))
&& !NILP (w->dedicated)
&& other_visible_frames (f))
{
while (CONSP (XCDR (windows))
&& EQ (XWINDOW (XCAR (windows))->frame,
XWINDOW (XCAR (XCDR (windows)))->frame))
windows = XCDR (windows);
Fdelete_frame (w->frame, Qnil);
}
else if (NILP (w->parent))
{
Lisp_Object buffer;
buffer = Fother_buffer (obj, Qnil, w->frame);
if (NILP (buffer))
buffer = Fget_buffer_create (build_string ("*scratch*"));
Fset_window_buffer (window, buffer);
if (EQ (window, selected_window))
Fset_buffer (w->buffer);
}
else
Fdelete_window (window);
}
break;
case GET_LARGEST_WINDOW:
{
if (MINI_WINDOW_P (w) || !NILP (w->dedicated))
break;
if (NILP (best_window))
best_window = window;
else
{
struct window *b = XWINDOW (best_window);
if (XFASTINT (w->height) * XFASTINT (w->width)
> XFASTINT (b->height) * XFASTINT (b->width))
best_window = window;
}
}
break;
case UNSHOW_BUFFER:
if (EQ (w->buffer, obj))
{
Lisp_Object buffer;
struct frame *f = XFRAME (w->frame);
buffer = Fother_buffer (obj, Qnil, w->frame);
if (NILP (buffer))
buffer = Fget_buffer_create (build_string ("*scratch*"));
if (EQ (window, FRAME_ROOT_WINDOW (f))
&& !NILP (w->dedicated)
&& other_visible_frames (f))
{
while (CONSP (XCDR (windows))
&& EQ (XWINDOW (XCAR (windows))->frame,
XWINDOW (XCAR (XCDR (windows)))->frame))
windows = XCDR (windows);
Fdelete_frame (w->frame, Qnil);
}
else
{
w->dedicated = Qnil;
Fset_window_buffer (window, buffer);
if (EQ (window, selected_window))
Fset_buffer (w->buffer);
}
}
break;
case CHECK_ALL_WINDOWS:
if (! NILP (w->buffer)
&& NILP (XBUFFER (w->buffer)->name))
abort ();
break;
case WINDOW_LOOP_UNUSED:
break;
}
}
UNGCPRO;
return best_window;
}
void
check_all_windows ()
{
window_loop (CHECK_ALL_WINDOWS, Qnil, 1, Qt);
}
DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
"Return the window least recently selected or used for display.\n\
If optional argument FRAME is `visible', search all visible frames.\n\
If FRAME is 0, search all visible and iconified frames.\n\
If FRAME is t, search all frames.\n\
If FRAME is nil, search only the selected frame.\n\
If FRAME is a frame, search only that frame.")
(frame)
Lisp_Object frame;
{
register Lisp_Object w;
w = window_loop (GET_LRU_WINDOW, Qt, 0, frame);
if (!NILP (w) && !EQ (w, selected_window))
return w;
return window_loop (GET_LRU_WINDOW, Qnil, 0, frame);
}
DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 1, 0,
"Return the largest window in area.\n\
If optional argument FRAME is `visible', search all visible frames.\n\
If FRAME is 0, search all visible and iconified frames.\n\
If FRAME is t, search all frames.\n\
If FRAME is nil, search only the selected frame.\n\
If FRAME is a frame, search only that frame.")
(frame)
Lisp_Object frame;
{
return window_loop (GET_LARGEST_WINDOW, Qnil, 0,
frame);
}
DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 1, 2, 0,
"Return a window currently displaying BUFFER, or nil if none.\n\
If optional argument FRAME is `visible', search all visible frames.\n\
If optional argument FRAME is 0, search all visible and iconified frames.\n\
If FRAME is t, search all frames.\n\
If FRAME is nil, search only the selected frame.\n\
If FRAME is a frame, search only that frame.")
(buffer, frame)
Lisp_Object buffer, frame;
{
buffer = Fget_buffer (buffer);
if (BUFFERP (buffer))
return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame);
else
return Qnil;
}
DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
0, 1, "",
"Make WINDOW (or the selected window) fill its frame.\n\
Only the frame WINDOW is on is affected.\n\
This function tries to reduce display jumps\n\
by keeping the text previously visible in WINDOW\n\
in the same place on the frame. Doing this depends on\n\
the value of (window-start WINDOW), so if calling this function\n\
in a program gives strange scrolling, make sure the window-start\n\
value is reasonable when this function is called.")
(window)
Lisp_Object window;
{
struct window *w;
int startpos;
int top, new_top;
if (NILP (window))
window = selected_window;
else
CHECK_LIVE_WINDOW (window, 0);
w = XWINDOW (window);
startpos = marker_position (w->start);
top = XFASTINT (w->top) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
if (MINI_WINDOW_P (w) && top > 0)
error ("Can't expand minibuffer to full frame");
window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_FRAME (w));
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;
struct buffer *obuf = current_buffer;
Fset_buffer (w->buffer);
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);
w->optional_new_start = Qt;
set_buffer_internal (obuf);
}
return Qnil;
}
DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
1, 2, "bDelete windows on (buffer): ",
"Delete all windows showing BUFFER.\n\
Optional second argument FRAME controls which frames are affected.\n\
If optional argument FRAME is `visible', search all visible frames.\n\
If FRAME is 0, search all visible and iconified frames.\n\
If FRAME is nil, search all frames.\n\
If FRAME is t, search only the selected frame.\n\
If FRAME is a frame, search only that frame.")
(buffer, frame)
Lisp_Object buffer, frame;
{
if (NILP (frame))
frame = Qt;
else if (EQ (frame, Qt))
frame = Qnil;
if (!NILP (buffer))
{
buffer = Fget_buffer (buffer);
CHECK_BUFFER (buffer, 0);
window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
}
return Qnil;
}
DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
Sreplace_buffer_in_windows,
1, 1, "bReplace buffer in windows: ",
"Replace BUFFER with some other buffer in all windows showing it.")
(buffer)
Lisp_Object buffer;
{
if (!NILP (buffer))
{
buffer = Fget_buffer (buffer);
CHECK_BUFFER (buffer, 0);
window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
}
return Qnil;
}
void
replace_buffer_in_all_windows (buffer)
Lisp_Object buffer;
{
#ifdef MULTI_KBOARD
Lisp_Object tail, frame;
FOR_EACH_FRAME (tail, frame)
window_loop (UNSHOW_BUFFER, buffer, 1, frame);
#else
window_loop (UNSHOW_BUFFER, buffer, 1, Qt);
#endif
}
#define MIN_SAFE_WINDOW_WIDTH (2)
#define MIN_SAFE_WINDOW_HEIGHT (2)
static void
check_min_window_sizes ()
{
if (window_min_width < MIN_SAFE_WINDOW_WIDTH)
window_min_width = MIN_SAFE_WINDOW_WIDTH;
if (window_min_height < MIN_SAFE_WINDOW_HEIGHT)
window_min_height = MIN_SAFE_WINDOW_HEIGHT;
}
void
check_frame_size (frame, rows, cols)
FRAME_PTR frame;
int *rows, *cols;
{
int min_height =
(FRAME_MINIBUF_ONLY_P (frame) ? MIN_SAFE_WINDOW_HEIGHT - 1
: (! FRAME_HAS_MINIBUF_P (frame)) ? MIN_SAFE_WINDOW_HEIGHT
: 2 * MIN_SAFE_WINDOW_HEIGHT - 1);
if (FRAME_TOP_MARGIN (frame) > 0)
min_height += FRAME_TOP_MARGIN (frame);
if (*rows < min_height)
*rows = min_height;
if (*cols < MIN_SAFE_WINDOW_WIDTH)
*cols = MIN_SAFE_WINDOW_WIDTH;
}
static int
window_fixed_size_p (w, width_p, check_siblings_p)
struct window *w;
int width_p, check_siblings_p;
{
int fixed_p;
struct window *c;
if (!NILP (w->hchild))
{
c = XWINDOW (w->hchild);
if (width_p)
{
while (c && window_fixed_size_p (c, width_p, 0))
c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
fixed_p = c == NULL;
}
else
{
while (c && !window_fixed_size_p (c, width_p, 0))
c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
fixed_p = c != NULL;
}
}
else if (!NILP (w->vchild))
{
c = XWINDOW (w->vchild);
if (width_p)
{
while (c && !window_fixed_size_p (c, width_p, 0))
c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
fixed_p = c != NULL;
}
else
{
while (c && window_fixed_size_p (c, width_p, 0))
c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
fixed_p = c == NULL;
}
}
else if (BUFFERP (w->buffer))
{
if (w->height_fixed_p && !width_p)
fixed_p = 1;
else
{
struct buffer *old = current_buffer;
Lisp_Object val;
current_buffer = XBUFFER (w->buffer);
val = find_symbol_value (Qwindow_size_fixed);
current_buffer = old;
fixed_p = 0;
if (!EQ (val, Qunbound))
{
fixed_p = !NILP (val);
if (fixed_p
&& ((EQ (val, Qheight) && width_p)
|| (EQ (val, Qwidth) && !width_p)))
fixed_p = 0;
}
}
if (!fixed_p && check_siblings_p && WINDOWP (w->parent))
{
Lisp_Object child;
for (child = w->prev; !NILP (child); child = XWINDOW (child)->prev)
if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
break;
if (NILP (child))
for (child = w->next; !NILP (child); child = XWINDOW (child)->next)
if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
break;
if (NILP (child))
fixed_p = 1;
}
}
else
fixed_p = 1;
return fixed_p;
}
static int
window_min_size_1 (w, width_p)
struct window *w;
int width_p;
{
struct window *c;
int size;
if (!NILP (w->hchild))
{
c = XWINDOW (w->hchild);
size = 0;
if (width_p)
{
while (c)
{
size += window_min_size_1 (c, width_p);
c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
}
}
else
{
while (c)
{
int min_size = window_min_size_1 (c, width_p);
size = max (min_size, size);
c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
}
}
}
else if (!NILP (w->vchild))
{
c = XWINDOW (w->vchild);
size = 0;
if (width_p)
{
while (c)
{
int min_size = window_min_size_1 (c, width_p);
size = max (min_size, size);
c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
}
}
else
{
while (c)
{
size += window_min_size_1 (c, width_p);
c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
}
}
}
else
{
if (width_p)
size = window_min_width;
else
{
if (MINI_WINDOW_P (w)
|| (!WINDOW_WANTS_MODELINE_P (w)
&& !WINDOW_WANTS_HEADER_LINE_P (w)))
size = 1;
else
size = window_min_height;
}
}
return size;
}
static int
window_min_size (w, width_p, ignore_fixed_p, fixed)
struct window *w;
int width_p, ignore_fixed_p, *fixed;
{
int size, fixed_p;
if (ignore_fixed_p)
fixed_p = 0;
else
fixed_p = window_fixed_size_p (w, width_p, 1);
if (fixed)
*fixed = fixed_p;
if (fixed_p)
size = width_p ? XFASTINT (w->width) : XFASTINT (w->height);
else
size = window_min_size_1 (w, width_p);
return size;
}
static void
size_window (window, size, width_p, nodelete_p)
Lisp_Object window;
int size, width_p, nodelete_p;
{
struct window *w = XWINDOW (window);
struct window *c;
Lisp_Object child, *forward, *sideward;
int old_size, min_size;
check_min_window_sizes ();
size = max (0, size);
if (width_p)
{
old_size = XINT (w->width);
min_size = window_min_width;
}
else
{
old_size = XINT (w->height);
min_size = window_min_height;
}
if (old_size < min_size)
w->too_small_ok = Qt;
if (!nodelete_p && !NILP (w->parent))
{
if (!MINI_WINDOW_P (w) && !NILP (w->too_small_ok))
min_size = width_p ? MIN_SAFE_WINDOW_WIDTH : MIN_SAFE_WINDOW_HEIGHT;
else
min_size = width_p ? window_min_width : window_min_height;
if (size < min_size)
{
delete_window (window);
return;
}
}
w->last_modified = make_number (0);
w->last_overlay_modified = make_number (0);
windows_or_buffers_changed++;
FRAME_WINDOW_SIZES_CHANGED (XFRAME (w->frame)) = 1;
if (width_p)
{
sideward = &w->vchild;
forward = &w->hchild;
w->width = make_number (size);
}
else
{
sideward = &w->hchild;
forward = &w->vchild;
w->height = make_number (size);
w->orig_height = Qnil;
}
if (!NILP (*sideward))
{
for (child = *sideward; !NILP (child); child = c->next)
{
c = XWINDOW (child);
if (width_p)
c->left = w->left;
else
c->top = w->top;
size_window (child, size, width_p, nodelete_p);
}
}
else if (!NILP (*forward))
{
int fixed_size, each, extra, n;
int resize_fixed_p, nfixed;
int last_pos, first_pos, nchildren, total;
fixed_size = nchildren = nfixed = total = 0;
for (child = *forward; !NILP (child); child = c->next, ++nchildren)
{
int child_size;
c = XWINDOW (child);
child_size = width_p ? XINT (c->width) : XINT (c->height);
total += child_size;
if (window_fixed_size_p (c, width_p, 0))
{
fixed_size += child_size;
++nfixed;
}
}
resize_fixed_p = nfixed == nchildren || size < fixed_size;
n = resize_fixed_p ? nchildren : nchildren - nfixed;
each = (size - total) / n;
extra = (size - total) - n * each;
first_pos = width_p ? XINT (w->left) : XINT (w->top);
last_pos = first_pos;
for (child = *forward; !NILP (child); child = c->next)
{
int new_size, old_size;
c = XWINDOW (child);
old_size = width_p ? XFASTINT (c->width) : XFASTINT (c->height);
new_size = old_size;
if (width_p)
c->left = make_number (last_pos);
else
c->top = make_number (last_pos);
if (resize_fixed_p || !window_fixed_size_p (c, width_p, 0))
{
new_size = old_size + each + extra;
extra = 0;
}
size_window (child, new_size, width_p, 1);
last_pos += new_size;
}
xassert (size == last_pos - first_pos);
if (!nodelete_p)
for (child = *forward; !NILP (child); child = c->next)
{
int child_size;
c = XWINDOW (child);
child_size = width_p ? XINT (c->width) : XINT (c->height);
size_window (child, child_size, width_p, 0);
}
}
}
void
set_window_height (window, height, nodelete)
Lisp_Object window;
int height;
int nodelete;
{
size_window (window, height, 0, nodelete);
}
void
set_window_width (window, width, nodelete)
Lisp_Object window;
int width;
int nodelete;
{
size_window (window, width, 1, nodelete);
}
int window_select_count;
Lisp_Object
Fset_window_buffer_unwind (obuf)
Lisp_Object obuf;
{
Fset_buffer (obuf);
return Qnil;
}
void
set_window_buffer (window, buffer, run_hooks_p)
Lisp_Object window, buffer;
int run_hooks_p;
{
struct window *w = XWINDOW (window);
struct buffer *b = XBUFFER (buffer);
int count = specpdl_ptr - specpdl;
w->buffer = buffer;
if (EQ (window, selected_window))
b->last_selected_window = window;
if (INTEGERP (b->display_count))
XSETINT (b->display_count, XINT (b->display_count) + 1);
b->display_time = Fcurrent_time ();
XSETFASTINT (w->window_end_pos, 0);
XSETFASTINT (w->window_end_vpos, 0);
bzero (&w->last_cursor, sizeof w->last_cursor);
w->window_end_valid = Qnil;
w->hscroll = w->min_hscroll = make_number (0);
w->vscroll = 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),
buffer);
w->start_at_line_beg = Qnil;
w->force_start = Qnil;
XSETFASTINT (w->last_modified, 0);
XSETFASTINT (w->last_overlay_modified, 0);
windows_or_buffers_changed++;
if (EQ (window, selected_window))
Fset_buffer (buffer);
else if (window_initialized)
{
record_unwind_protect (Fset_window_buffer_unwind, Fcurrent_buffer ());
Fset_buffer (buffer);
}
Fset_window_margins (window, b->left_margin_width, b->right_margin_width);
if (run_hooks_p)
{
if (! NILP (Vwindow_scroll_functions))
run_hook_with_args_2 (Qwindow_scroll_functions, window,
Fmarker_position (w->start));
if (! NILP (Vwindow_configuration_change_hook)
&& ! NILP (Vrun_hooks))
call1 (Vrun_hooks, Qwindow_configuration_change_hook);
}
unbind_to (count, Qnil);
}
DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 2, 0,
"Make WINDOW display BUFFER as its contents.\n\
BUFFER can be a buffer or buffer name.")
(window, buffer)
register Lisp_Object window, buffer;
{
register Lisp_Object tem;
register struct window *w = decode_window (window);
XSETWINDOW (window, w);
buffer = Fget_buffer (buffer);
CHECK_BUFFER (buffer, 1);
if (NILP (XBUFFER (buffer)->name))
error ("Attempt to display deleted buffer");
tem = w->buffer;
if (NILP (tem))
error ("Window is deleted");
else if (! EQ (tem, Qt))
{
if (!NILP (w->dedicated) && !EQ (tem, buffer))
error ("Window is dedicated to `%s'",
XSTRING (XBUFFER (tem)->name)->data);
unshow_buffer (w);
}
set_window_buffer (window, buffer, 1);
return Qnil;
}
DEFUN ("select-window", Fselect_window, Sselect_window, 1, 1, 0,
"Select WINDOW. Most editing will apply to WINDOW's buffer.\n\
If WINDOW is not already selected, also make WINDOW's buffer current.\n\
Note that the main editor command loop\n\
selects the buffer of the selected window before each command.")
(window)
register Lisp_Object window;
{
return select_window_1 (window, 1);
}
static Lisp_Object
select_window_1 (window, recordflag)
register Lisp_Object window;
int recordflag;
{
register struct window *w;
register struct window *ow;
struct frame *sf;
CHECK_LIVE_WINDOW (window, 0);
w = XWINDOW (window);
w->frozen_window_start_p = 0;
XSETFASTINT (w->use_time, ++window_select_count);
if (EQ (window, selected_window))
return window;
if (!NILP (selected_window))
{
ow = XWINDOW (selected_window);
if (! NILP (ow->buffer))
set_marker_both (ow->pointm, ow->buffer,
BUF_PT (XBUFFER (ow->buffer)),
BUF_PT_BYTE (XBUFFER (ow->buffer)));
}
selected_window = window;
sf = SELECTED_FRAME ();
if (XFRAME (WINDOW_FRAME (w)) != sf)
{
XFRAME (WINDOW_FRAME (w))->selected_window = window;
Fselect_frame (WINDOW_FRAME (w), Qnil);
}
else
sf->selected_window = window;
if (recordflag)
record_buffer (w->buffer);
Fset_buffer (w->buffer);
XBUFFER (w->buffer)->last_selected_window = window;
{
register int new_point = marker_position (w->pointm);
if (new_point < BEGV)
SET_PT (BEGV);
else if (new_point > ZV)
SET_PT (ZV);
else
SET_PT (new_point);
}
windows_or_buffers_changed++;
return window;
}
static Lisp_Object
display_buffer_1 (window)
Lisp_Object window;
{
Lisp_Object frame = XWINDOW (window)->frame;
FRAME_PTR f = XFRAME (frame);
FRAME_SAMPLE_VISIBILITY (f);
if (!EQ (frame, selected_frame))
{
if (FRAME_ICONIFIED_P (f))
Fmake_frame_visible (frame);
else if (FRAME_VISIBLE_P (f))
Fraise_frame (frame);
}
return window;
}
DEFUN ("special-display-p", Fspecial_display_p, Sspecial_display_p, 1, 1, 0,
"Returns non-nil if a buffer named BUFFER-NAME would be created specially.\n\
The value is actually t if the frame should be called with default frame\n\
parameters, and a list of frame parameters if they were specified.\n\
See `special-display-buffer-names', and `special-display-regexps'.")
(buffer_name)
Lisp_Object buffer_name;
{
Lisp_Object tem;
CHECK_STRING (buffer_name, 1);
tem = Fmember (buffer_name, Vspecial_display_buffer_names);
if (!NILP (tem))
return Qt;
tem = Fassoc (buffer_name, Vspecial_display_buffer_names);
if (!NILP (tem))
return XCDR (tem);
for (tem = Vspecial_display_regexps; CONSP (tem); tem = XCDR (tem))
{
Lisp_Object car = XCAR (tem);
if (STRINGP (car)
&& fast_string_match (car, buffer_name) >= 0)
return Qt;
else if (CONSP (car)
&& STRINGP (XCAR (car))
&& fast_string_match (XCAR (car), buffer_name) >= 0)
return XCDR (car);
}
return Qnil;
}
DEFUN ("same-window-p", Fsame_window_p, Ssame_window_p, 1, 1, 0,
"Returns non-nil if a new buffer named BUFFER-NAME would use the same window.\n\
See `same-window-buffer-names' and `same-window-regexps'.")
(buffer_name)
Lisp_Object buffer_name;
{
Lisp_Object tem;
CHECK_STRING (buffer_name, 1);
tem = Fmember (buffer_name, Vsame_window_buffer_names);
if (!NILP (tem))
return Qt;
tem = Fassoc (buffer_name, Vsame_window_buffer_names);
if (!NILP (tem))
return Qt;
for (tem = Vsame_window_regexps; CONSP (tem); tem = XCDR (tem))
{
Lisp_Object car = XCAR (tem);
if (STRINGP (car)
&& fast_string_match (car, buffer_name) >= 0)
return Qt;
else if (CONSP (car)
&& STRINGP (XCAR (car))
&& fast_string_match (XCAR (car), buffer_name) >= 0)
return Qt;
}
return Qnil;
}
DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 3,
"BDisplay buffer: \nP",
"Make BUFFER appear in some window but don't select it.\n\
BUFFER can be a buffer or a buffer name.\n\
If BUFFER is shown already in some window, just use that one,\n\
unless the window is the selected window and the optional second\n\
argument NOT-THIS-WINDOW is non-nil (interactively, with prefix arg).\n\
If `pop-up-frames' is non-nil, make a new frame if no window shows BUFFER.\n\
Returns the window displaying BUFFER.\n\
If `display-reuse-frames' is non-nil, and another frame is currently\n\
displaying BUFFER, then simply raise that frame.\n\
\n\
The variables `special-display-buffer-names', `special-display-regexps',\n\
`same-window-buffer-names', and `same-window-regexps' customize how certain\n\
buffer names are handled.\n\
\n\
If optional argument FRAME is `visible', search all visible frames.\n\
If FRAME is 0, search all visible and iconified frames.\n\
If FRAME is t, search all frames.\n\
If FRAME is a frame, search only that frame.\n\
If FRAME is nil, search only the selected frame\n\
(actually the last nonminibuffer frame),\n\
unless `pop-up-frames' or `display-buffer-reuse-frames' is non-nil,\n\
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\
displayed.")
(buffer, not_this_window, frame)
register Lisp_Object buffer, not_this_window, frame;
{
register Lisp_Object window, tem, swp;
struct frame *f;
swp = Qnil;
buffer = Fget_buffer (buffer);
CHECK_BUFFER (buffer, 0);
if (!NILP (Vdisplay_buffer_function))
return call2 (Vdisplay_buffer_function, buffer, not_this_window);
if (NILP (not_this_window)
&& XBUFFER (XWINDOW (selected_window)->buffer) == XBUFFER (buffer))
return display_buffer_1 (selected_window);
if (NILP (not_this_window))
{
swp = Fsame_window_p (XBUFFER (buffer)->name);
if (!NILP (swp) && !no_switch_window (selected_window))
{
Fswitch_to_buffer (buffer, Qnil);
return display_buffer_1 (selected_window);
}
}
if (! NILP (frame))
tem = frame;
else if (pop_up_frames
|| display_buffer_reuse_frames
|| last_nonminibuf_frame == 0)
XSETFASTINT (tem, 0);
else
XSETFRAME (tem, last_nonminibuf_frame);
window = Fget_buffer_window (buffer, tem);
if (!NILP (window)
&& (NILP (not_this_window) || !EQ (window, selected_window)))
return display_buffer_1 (window);
if (!NILP (Vspecial_display_function) && NILP (swp))
{
tem = Fspecial_display_p (XBUFFER (buffer)->name);
if (EQ (tem, Qt))
return call1 (Vspecial_display_function, buffer);
if (CONSP (tem))
return call2 (Vspecial_display_function, buffer, tem);
}
if (pop_up_frames || last_nonminibuf_frame == 0)
{
window = Fframe_selected_window (call0 (Vpop_up_frame_function));
Fset_window_buffer (window, buffer);
return display_buffer_1 (window);
}
f = SELECTED_FRAME ();
if (pop_up_windows
|| FRAME_MINIBUF_ONLY_P (f)
|| !NILP (XWINDOW (FRAME_ROOT_WINDOW (f))->dedicated))
{
Lisp_Object frames;
frames = Qnil;
if (FRAME_MINIBUF_ONLY_P (f))
XSETFRAME (frames, last_nonminibuf_frame);
if (split_height_threshold < window_min_height << 1)
split_height_threshold = window_min_height << 1;
if (FRAME_NO_SPLIT_P (NILP (frames) ? f : last_nonminibuf_frame))
{
window = Fget_largest_window (Qvisible);
if (NILP (window))
window = Fget_largest_window (make_number (0));
if (NILP (window))
window = Fget_largest_window (Qt);
}
else
window = Fget_largest_window (frames);
if (!NILP (window)
&& ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
&& window_height (window) >= split_height_threshold
&& WINDOW_FULL_WIDTH_P (XWINDOW (window)))
window = Fsplit_window (window, Qnil, Qnil);
else
{
Lisp_Object upper, lower, other;
window = Fget_lru_window (frames);
if (!NILP (window)
&& ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
&& (EQ (window, selected_window)
|| EQ (XWINDOW (window)->parent, Qnil))
&& window_height (window) >= window_min_height << 1)
window = Fsplit_window (window, Qnil, Qnil);
if (NILP (window))
window = Fget_buffer_window (buffer, Qvisible);
if (NILP (window))
window = Fget_largest_window (Qvisible);
if (NILP (window))
window = Fget_buffer_window (buffer, make_number (0));
if (NILP (window))
window = Fget_largest_window (make_number (0));
if (NILP (window))
window = Fget_buffer_window (buffer, Qt);
if (NILP (window))
window = Fget_largest_window (Qt);
if (NILP (window))
window = Fframe_selected_window (call0 (Vpop_up_frame_function));
other = upper = lower = Qnil;
if (!NILP (XWINDOW (window)->prev))
other = upper = XWINDOW (window)->prev, lower = window;
if (!NILP (XWINDOW (window)->next))
other = lower = XWINDOW (window)->next, upper = window;
if (!NILP (other)
&& !NILP (Veven_window_heights)
&& !EQ (XWINDOW (other)->top, XWINDOW (window)->top)
&& (XFASTINT (XWINDOW (other)->height)
> XFASTINT (XWINDOW (window)->height)))
{
int total = (XFASTINT (XWINDOW (other)->height)
+ XFASTINT (XWINDOW (window)->height));
enlarge_window (upper,
total / 2 - XFASTINT (XWINDOW (upper)->height),
0);
}
}
}
else
window = Fget_lru_window (Qnil);
Fset_window_buffer (window, buffer);
return display_buffer_1 (window);
}
void
temp_output_buffer_show (buf)
register Lisp_Object buf;
{
register struct buffer *old = current_buffer;
register Lisp_Object window;
register struct window *w;
XBUFFER (buf)->directory = current_buffer->directory;
Fset_buffer (buf);
BUF_SAVE_MODIFF (XBUFFER (buf)) = MODIFF;
BEGV = BEG;
ZV = Z;
SET_PT (BEG);
XBUFFER (buf)->prevent_redisplay_optimizations_p = 1;
set_buffer_internal (old);
if (!EQ (Vtemp_buffer_show_function, Qnil))
call1 (Vtemp_buffer_show_function, buf);
else
{
window = Fdisplay_buffer (buf, Qnil, Qnil);
if (!EQ (XWINDOW (window)->frame, selected_frame))
Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
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);
if (!NILP (Vrun_hooks))
{
Lisp_Object tem;
tem = Fboundp (Qtemp_buffer_show_hook);
if (!NILP (tem))
{
tem = Fsymbol_value (Qtemp_buffer_show_hook);
if (!NILP (tem))
{
int count = specpdl_ptr - specpdl;
Lisp_Object prev_window;
prev_window = selected_window;
record_unwind_protect (Fselect_window, prev_window);
select_window_1 (window, 0);
Fset_buffer (w->buffer);
call1 (Vrun_hooks, Qtemp_buffer_show_hook);
select_window_1 (prev_window, 0);
unbind_to (count, Qnil);
}
}
}
}
}
static void
make_dummy_parent (window)
Lisp_Object window;
{
Lisp_Object new;
register struct window *o, *p;
int i;
o = XWINDOW (window);
p = allocate_window ();
for (i = 0; i < VECSIZE (struct window); ++i)
((struct Lisp_Vector *) p)->contents[i]
= ((struct Lisp_Vector *)o)->contents[i];
XSETWINDOW (new, p);
XSETFASTINT (p->sequence_number, ++sequence_number);
replace_window (window, new);
o->next = Qnil;
o->prev = Qnil;
o->vchild = Qnil;
o->hchild = Qnil;
o->parent = new;
p->start = Qnil;
p->pointm = Qnil;
p->buffer = Qnil;
}
DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
"Split WINDOW, putting SIZE lines in the first of the pair.\n\
WINDOW defaults to selected one and SIZE to half its size.\n\
If optional third arg HORFLAG is non-nil, split side by side\n\
and put SIZE columns in the first of the pair. In that case,\n\
SIZE includes that window's scroll bar, or the divider column to its right.")
(window, size, horflag)
Lisp_Object window, size, horflag;
{
register Lisp_Object new;
register struct window *o, *p;
FRAME_PTR fo;
register int size_int;
if (NILP (window))
window = selected_window;
else
CHECK_LIVE_WINDOW (window, 0);
o = XWINDOW (window);
fo = XFRAME (WINDOW_FRAME (o));
if (NILP (size))
{
if (!NILP (horflag))
size_int = (XFASTINT (o->width) + 1) >> 1;
else
size_int = XFASTINT (o->height) >> 1;
}
else
{
CHECK_NUMBER (size, 1);
size_int = XINT (size);
}
if (MINI_WINDOW_P (o))
error ("Attempt to split minibuffer window");
else if (window_fixed_size_p (o, !NILP (horflag), 0))
error ("Attempt to split fixed-size window");
check_min_window_sizes ();
if (NILP (horflag))
{
if (size_int < window_min_height)
error ("Window height %d too small (after splitting)", size_int);
if (size_int + window_min_height > XFASTINT (o->height))
error ("Window height %d too small (after splitting)",
XFASTINT (o->height) - size_int);
if (NILP (o->parent)
|| NILP (XWINDOW (o->parent)->vchild))
{
make_dummy_parent (window);
new = o->parent;
XWINDOW (new)->vchild = window;
}
}
else
{
if (size_int < window_min_width)
error ("Window width %d too small (after splitting)", size_int);
if (size_int + window_min_width > XFASTINT (o->width))
error ("Window width %d too small (after splitting)",
XFASTINT (o->width) - size_int);
if (NILP (o->parent)
|| NILP (XWINDOW (o->parent)->hchild))
{
make_dummy_parent (window);
new = o->parent;
XWINDOW (new)->hchild = window;
}
}
windows_or_buffers_changed++;
FRAME_WINDOW_SIZES_CHANGED (fo) = 1;
new = make_window ();
p = XWINDOW (new);
p->frame = o->frame;
p->next = o->next;
if (!NILP (p->next))
XWINDOW (p->next)->prev = new;
p->prev = window;
o->next = new;
p->parent = o->parent;
p->buffer = Qt;
p->window_end_valid = Qnil;
bzero (&p->last_cursor, sizeof p->last_cursor);
if (!NILP (horflag))
{
p->height = o->height;
p->top = o->top;
XSETFASTINT (p->width, XFASTINT (o->width) - size_int);
XSETFASTINT (o->width, size_int);
XSETFASTINT (p->left, XFASTINT (o->left) + size_int);
}
else
{
p->left = o->left;
p->width = o->width;
XSETFASTINT (p->height, XFASTINT (o->height) - size_int);
XSETFASTINT (o->height, size_int);
XSETFASTINT (p->top, XFASTINT (o->top) + size_int);
}
adjust_glyphs (fo);
Fset_window_buffer (new, o->buffer);
return new;
}
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.\n\
Interactively, if an argument is not given, make the window one line bigger.")
(arg, side)
register Lisp_Object arg, side;
{
CHECK_NUMBER (arg, 0);
enlarge_window (selected_window, XINT (arg), !NILP (side));
if (! NILP (Vwindow_configuration_change_hook))
call1 (Vrun_hooks, Qwindow_configuration_change_hook);
return Qnil;
}
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.\n\
Interactively, if an argument is not given, make the window one line smaller.")
(arg, side)
register Lisp_Object arg, side;
{
CHECK_NUMBER (arg, 0);
enlarge_window (selected_window, -XINT (arg), !NILP (side));
if (! NILP (Vwindow_configuration_change_hook))
call1 (Vrun_hooks, Qwindow_configuration_change_hook);
return Qnil;
}
int
window_height (window)
Lisp_Object window;
{
register struct window *p = XWINDOW (window);
return XFASTINT (p->height);
}
int
window_width (window)
Lisp_Object window;
{
register struct window *p = XWINDOW (window);
return XFASTINT (p->width);
}
#define CURBEG(w) \
*(widthflag ? &(XWINDOW (w)->left) : &(XWINDOW (w)->top))
#define CURSIZE(w) \
*(widthflag ? &(XWINDOW (w)->width) : &(XWINDOW (w)->height))
static void
enlarge_window (window, delta, widthflag)
Lisp_Object window;
int delta, widthflag;
{
Lisp_Object parent, next, prev;
struct window *p;
Lisp_Object *sizep;
int maximum;
int (*sizefun) P_ ((Lisp_Object))
= widthflag ? window_width : window_height;
void (*setsizefun) P_ ((Lisp_Object, int, int))
= (widthflag ? set_window_width : set_window_height);
check_min_window_sizes ();
if (window_fixed_size_p (XWINDOW (window), widthflag, 1))
error ("Window is not resizable");
while (1)
{
p = XWINDOW (window);
parent = p->parent;
if (NILP (parent))
{
if (widthflag)
error ("No other window to side of this one");
break;
}
if (widthflag
? !NILP (XWINDOW (parent)->hchild)
: !NILP (XWINDOW (parent)->vchild))
break;
window = parent;
}
sizep = &CURSIZE (window);
{
register int maxdelta;
maxdelta = (!NILP (parent) ? (*sizefun) (parent) - XINT (*sizep)
: !NILP (p->next) ? ((*sizefun) (p->next)
- window_min_size (XWINDOW (p->next),
widthflag, 0, 0))
: !NILP (p->prev) ? ((*sizefun) (p->prev)
- window_min_size (XWINDOW (p->prev),
widthflag, 0, 0))
: (delta = 0));
if (delta > maxdelta)
delta = maxdelta;
}
if (XINT (*sizep) + delta < window_min_size (XWINDOW (window), widthflag, 0, 0))
{
delete_window (window);
return;
}
if (delta == 0)
return;
maximum = 0;
for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
widthflag, 0, 0);
for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
widthflag, 0, 0);
if (delta <= maximum)
{
Lisp_Object first_unaffected;
Lisp_Object first_affected;
int fixed_p;
next = p->next;
prev = p->prev;
first_affected = window;
while (delta != 0 && (!NILP (next) || !NILP (prev)))
{
if (! NILP (next))
{
int this_one = ((*sizefun) (next)
- window_min_size (XWINDOW (next),
widthflag, 0, &fixed_p));
if (!fixed_p)
{
if (this_one > delta)
this_one = delta;
(*setsizefun) (next, (*sizefun) (next) - this_one, 0);
(*setsizefun) (window, XINT (*sizep) + this_one, 0);
delta -= this_one;
}
next = XWINDOW (next)->next;
}
if (delta == 0)
break;
if (! NILP (prev))
{
int this_one = ((*sizefun) (prev)
- window_min_size (XWINDOW (prev),
widthflag, 0, &fixed_p));
if (!fixed_p)
{
if (this_one > delta)
this_one = delta;
first_affected = prev;
(*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
(*setsizefun) (window, XINT (*sizep) + this_one, 0);
delta -= this_one;
}
prev = XWINDOW (prev)->prev;
}
}
xassert (delta == 0);
first_unaffected = next;
prev = first_affected;
for (next = XWINDOW (prev)->next; ! EQ (next, first_unaffected);
prev = next, next = XWINDOW (next)->next)
{
XSETINT (CURBEG (next), XINT (CURBEG (prev)) + (*sizefun) (prev));
(*setsizefun) (next, (*sizefun) (next), 0);
}
}
else
{
register int delta1;
register int opht = (*sizefun) (parent);
if (opht <= XINT (*sizep) + delta)
{
Lisp_Object start, tem, next;
start = XWINDOW (parent)->vchild;
if (NILP (start))
start = XWINDOW (parent)->hchild;
tem = XWINDOW (window)->next;
while (! NILP (tem))
{
next = XWINDOW (tem)->next;
delete_window (tem);
tem = next;
}
tem = start;
while (! EQ (tem, window))
{
next = XWINDOW (tem)->next;
delete_window (tem);
tem = next;
}
}
else
{
struct window *w = XWINDOW (window);
Lisp_Object s;
int n = 1;
for (s = w->next; !NILP (s); s = XWINDOW (s)->next)
if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
++n;
for (s = w->prev; !NILP (s); s = XWINDOW (s)->prev)
if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
++n;
delta1 = n * delta;
XSETINT (CURSIZE (parent), opht + delta1);
(*setsizefun) (window, XINT (*sizep) + delta1, 0);
(*setsizefun) (parent, opht, 0);
}
}
XSETFASTINT (p->last_modified, 0);
XSETFASTINT (p->last_overlay_modified, 0);
adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
}
#undef CURBEG
#undef CURSIZE
static void shrink_window_lowest_first P_ ((struct window *, int));
enum save_restore_action
{
CHECK_ORIG_SIZES,
SAVE_ORIG_SIZES,
RESTORE_ORIG_SIZES
};
static int save_restore_orig_size P_ ((struct window *,
enum save_restore_action));
static void
shrink_window_lowest_first (w, height)
struct window *w;
int height;
{
struct window *c;
Lisp_Object child;
int old_height;
xassert (!MINI_WINDOW_P (w));
XSETFASTINT (w->last_modified, 0);
XSETFASTINT (w->last_overlay_modified, 0);
windows_or_buffers_changed++;
FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
old_height = XFASTINT (w->height);
XSETFASTINT (w->height, height);
if (!NILP (w->hchild))
{
for (child = w->hchild; !NILP (child); child = c->next)
{
c = XWINDOW (child);
c->top = w->top;
shrink_window_lowest_first (c, height);
}
}
else if (!NILP (w->vchild))
{
Lisp_Object last_child;
int delta = old_height - height;
int last_top;
last_child = Qnil;
for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
last_child = child;
for (child = last_child; delta && !NILP (child); child = c->prev)
{
int this_one;
c = XWINDOW (child);
this_one = XFASTINT (c->height) - MIN_SAFE_WINDOW_HEIGHT;
if (this_one > delta)
this_one = delta;
shrink_window_lowest_first (c, XFASTINT (c->height) - this_one);
delta -= this_one;
}
last_top = XINT (w->top);
for (child = w->vchild; !NILP (child); child = c->next)
{
c = XWINDOW (child);
c->top = make_number (last_top);
shrink_window_lowest_first (c, XFASTINT (c->height));
last_top += XFASTINT (c->height);
}
}
}
static int
save_restore_orig_size (w, action)
struct window *w;
enum save_restore_action action;
{
int success_p = 1;
while (w)
{
if (!NILP (w->hchild))
{
if (!save_restore_orig_size (XWINDOW (w->hchild), action))
success_p = 0;
}
else if (!NILP (w->vchild))
{
if (!save_restore_orig_size (XWINDOW (w->vchild), action))
success_p = 0;
}
switch (action)
{
case CHECK_ORIG_SIZES:
if (!INTEGERP (w->orig_top) || !INTEGERP (w->orig_height))
return 0;
break;
case SAVE_ORIG_SIZES:
w->orig_top = w->top;
w->orig_height = w->height;
XSETFASTINT (w->last_modified, 0);
XSETFASTINT (w->last_overlay_modified, 0);
break;
case RESTORE_ORIG_SIZES:
xassert (INTEGERP (w->orig_top) && INTEGERP (w->orig_height));
w->top = w->orig_top;
w->height = w->orig_height;
w->orig_height = w->orig_top = Qnil;
XSETFASTINT (w->last_modified, 0);
XSETFASTINT (w->last_overlay_modified, 0);
break;
default:
abort ();
}
w = NILP (w->next) ? NULL : XWINDOW (w->next);
}
return success_p;
}
void
grow_mini_window (w, delta)
struct window *w;
int delta;
{
struct frame *f = XFRAME (w->frame);
struct window *root;
xassert (MINI_WINDOW_P (w));
xassert (delta >= 0);
check_min_window_sizes ();
root = XWINDOW (FRAME_ROOT_WINDOW (f));
if (delta)
{
int min_height = window_min_size (root, 0, 0, 0);
if (XFASTINT (root->height) - delta < min_height)
delta = max (0, XFASTINT (root->height) - min_height);
}
if (delta)
{
if (!save_restore_orig_size (root, CHECK_ORIG_SIZES))
save_restore_orig_size (root, SAVE_ORIG_SIZES);
shrink_window_lowest_first (root, XFASTINT (root->height) - delta);
w->top = make_number (XFASTINT (root->top) + XFASTINT (root->height));
w->height = make_number (XFASTINT (w->height) + delta);
XSETFASTINT (w->last_modified, 0);
XSETFASTINT (w->last_overlay_modified, 0);
adjust_glyphs (f);
}
}
void
shrink_mini_window (w)
struct window *w;
{
struct frame *f = XFRAME (w->frame);
struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
if (save_restore_orig_size (root, CHECK_ORIG_SIZES))
{
save_restore_orig_size (root, RESTORE_ORIG_SIZES);
adjust_glyphs (f);
FRAME_WINDOW_SIZES_CHANGED (f) = 1;
windows_or_buffers_changed = 1;
}
else if (XFASTINT (w->height) > 1)
{
Lisp_Object window;
XSETWINDOW (window, w);
enlarge_window (window, 1 - XFASTINT (w->height), 0);
}
}
void
mark_window_cursors_off (w)
struct window *w;
{
while (w)
{
if (!NILP (w->hchild))
mark_window_cursors_off (XWINDOW (w->hchild));
else if (!NILP (w->vchild))
mark_window_cursors_off (XWINDOW (w->vchild));
else
w->phys_cursor_on_p = 0;
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
}
int
window_internal_height (w)
struct window *w;
{
int ht = XFASTINT (w->height);
if (!MINI_WINDOW_P (w))
{
if (!NILP (w->parent)
|| !NILP (w->vchild)
|| !NILP (w->hchild)
|| !NILP (w->next)
|| !NILP (w->prev)
|| WINDOW_WANTS_MODELINE_P (w))
--ht;
if (WINDOW_WANTS_HEADER_LINE_P (w))
--ht;
}
return ht;
}
int
window_internal_width (w)
struct window *w;
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
int width = XINT (w->width);
if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
width -= FRAME_SCROLL_BAR_COLS (f);
else if (!WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
width -= 1;
if (FRAME_WINDOW_P (f))
width -= FRAME_FLAGS_AREA_COLS (f);
return width;
}
static void
window_scroll (window, n, whole, noerror)
Lisp_Object window;
int n;
int whole;
int noerror;
{
if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
window_scroll_pixel_based (window, n, whole, noerror);
else
window_scroll_line_based (window, n, whole, noerror);
}
static void
window_scroll_pixel_based (window, n, whole, noerror)
Lisp_Object window;
int n;
int whole;
int noerror;
{
struct it it;
struct window *w = XWINDOW (window);
struct text_pos start;
Lisp_Object tem;
int this_scroll_margin;
int preserve_y;
int vscrolled = 0;
SET_TEXT_POS_FROM_MARKER (start, w->start);
tem = Fpos_visible_in_window_p (make_number (PT), window, Qt);
if (NILP (tem))
{
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);
if (it.current_y <= 0)
{
init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
move_it_vertically (&it, 0);
it.current_y = 0;
}
start = it.current.pos;
}
if (!NILP (Vscroll_preserve_screen_position))
{
start_display (&it, w, start);
move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
preserve_y = it.current_y;
}
else
preserve_y = -1;
start_display (&it, w, start);
if (whole)
{
int screen_full = (window_box_height (w)
- next_screen_context_lines * CANON_Y_UNIT (it.f));
int dy = n * screen_full;
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 ((n > 0 && IT_CHARPOS (it) == ZV)
|| (n < 0 && IT_CHARPOS (it) == CHARPOS (start)))
{
if (IT_CHARPOS (it) == ZV)
{
if (it.current_y + it.max_ascent + it.max_descent
> it.last_visible_y)
{
w->vscroll = (it.last_visible_y
- it.current_y + it.max_ascent + it.max_descent);
adjust_glyphs (it.f);
}
else if (noerror)
return;
else
Fsignal (Qend_of_buffer, Qnil);
}
else
{
if (w->vscroll != 0)
w->vscroll = 0;
else if (noerror)
return;
else
Fsignal (Qbeginning_of_buffer, Qnil);
}
XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
vscrolled = 1;
}
if (! vscrolled)
{
set_marker_restricted (w->start, make_number (IT_CHARPOS (it)),
w->buffer);
w->start_at_line_beg = Fbolp ();
w->update_mode_line = Qt;
XSETFASTINT (w->last_modified, 0);
XSETFASTINT (w->last_overlay_modified, 0);
w->force_start = Qt;
}
it.current_y = it.vpos = 0;
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
{
this_scroll_margin = max (0, scroll_margin);
this_scroll_margin = min (this_scroll_margin, XFASTINT (w->height) / 4);
this_scroll_margin *= CANON_Y_UNIT (it.f);
if (n > 0)
{
move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
while (it.current_y < this_scroll_margin)
move_it_by_lines (&it, 1, 1);
SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
}
else if (n < 0)
{
int charpos, bytepos;
move_it_to (&it, PT, -1,
it.last_visible_y - this_scroll_margin - 1, -1,
MOVE_TO_POS | MOVE_TO_Y);
charpos = IT_CHARPOS (it);
bytepos = IT_BYTEPOS (it);
move_it_by_lines (&it, 1, 1);
if (it.current_y > it.last_visible_y)
{
move_it_by_lines (&it, -2, 0);
SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
}
else
SET_PT_BOTH (charpos, bytepos);
}
}
}
static void
window_scroll_line_based (window, n, whole, noerror)
Lisp_Object window;
int n;
int whole;
int noerror;
{
register struct window *w = XWINDOW (window);
register int opoint = PT, opoint_byte = PT_BYTE;
register int pos, pos_byte;
register int ht = window_internal_height (w);
register Lisp_Object tem;
int lose;
Lisp_Object bolp;
int startpos;
struct position posit;
int original_vpos;
if (whole)
n *= max (1, ht - next_screen_context_lines);
startpos = marker_position (w->start);
posit = *compute_motion (startpos, 0, 0, 0,
PT, ht, 0,
window_internal_width (w), XINT (w->hscroll),
0, w);
original_vpos = posit.vpos;
XSETFASTINT (tem, PT);
tem = Fpos_visible_in_window_p (tem, window, Qnil);
if (NILP (tem))
{
Fvertical_motion (make_number (- (ht / 2)), window);
startpos = PT;
}
SET_PT (startpos);
lose = n < 0 && PT == BEGV;
Fvertical_motion (make_number (n), window);
pos = PT;
pos_byte = PT_BYTE;
bolp = Fbolp ();
SET_PT_BOTH (opoint, opoint_byte);
if (lose)
{
if (noerror)
return;
else
Fsignal (Qbeginning_of_buffer, Qnil);
}
if (pos < ZV)
{
int this_scroll_margin = scroll_margin;
if (this_scroll_margin < 0)
this_scroll_margin = 0;
if (XINT (w->height) < 4 * scroll_margin)
this_scroll_margin = XINT (w->height) / 4;
set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
w->start_at_line_beg = bolp;
w->update_mode_line = Qt;
XSETFASTINT (w->last_modified, 0);
XSETFASTINT (w->last_overlay_modified, 0);
w->force_start = Qt;
if (whole && !NILP (Vscroll_preserve_screen_position))
{
SET_PT_BOTH (pos, pos_byte);
Fvertical_motion (make_number (original_vpos), window);
}
else if (n > 0)
{
int top_margin;
if (this_scroll_margin > 0)
{
SET_PT_BOTH (pos, pos_byte);
Fvertical_motion (make_number (this_scroll_margin), window);
top_margin = PT;
}
else
top_margin = pos;
if (top_margin <= opoint)
SET_PT_BOTH (opoint, opoint_byte);
else if (!NILP (Vscroll_preserve_screen_position))
{
SET_PT_BOTH (pos, pos_byte);
Fvertical_motion (make_number (original_vpos), window);
}
else
SET_PT (top_margin);
}
else if (n < 0)
{
int bottom_margin;
SET_PT_BOTH (pos, pos_byte);
tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
if (XFASTINT (tem) == ht - this_scroll_margin)
bottom_margin = PT;
else
bottom_margin = PT + 1;
if (bottom_margin > opoint)
SET_PT_BOTH (opoint, opoint_byte);
else
{
if (!NILP (Vscroll_preserve_screen_position))
{
SET_PT_BOTH (pos, pos_byte);
Fvertical_motion (make_number (original_vpos), window);
}
else
Fvertical_motion (make_number (-1), window);
}
}
}
else
{
if (noerror)
return;
else
Fsignal (Qend_of_buffer, Qnil);
}
}
static void
scroll_command (n, direction)
Lisp_Object n;
int direction;
{
int count = BINDING_STACK_SIZE ();
xassert (abs (direction) == 1);
if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
{
record_unwind_protect (save_excursion_restore, save_excursion_save ());
Fset_buffer (XWINDOW (selected_window)->buffer);
++windows_or_buffers_changed;
}
if (NILP (n))
window_scroll (selected_window, direction, 1, 0);
else if (EQ (n, Qminus))
window_scroll (selected_window, -direction, 1, 0);
else
{
n = Fprefix_numeric_value (n);
window_scroll (selected_window, XINT (n) * direction, 0, 0);
}
unbind_to (count, Qnil);
}
DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
"Scroll text of current window upward ARG lines; or near full screen if no ARG.\n\
A near full screen is `next-screen-context-lines' less than a full screen.\n\
Negative ARG means scroll downward.\n\
If ARG is the atom `-', scroll downward by nearly full screen.\n\
When calling from a program, supply as argument a number, nil, or `-'.")
(arg)
Lisp_Object arg;
{
scroll_command (arg, 1);
return Qnil;
}
DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
"Scroll text of current window down ARG lines; or near full screen if no ARG.\n\
A near full screen is `next-screen-context-lines' less than a full screen.\n\
Negative ARG means scroll upward.\n\
If ARG is the atom `-', scroll upward by nearly full screen.\n\
When calling from a program, supply as argument a number, nil, or `-'.")
(arg)
Lisp_Object arg;
{
scroll_command (arg, -1);
return Qnil;
}
DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0,
"Return the other window for \"other window scroll\" commands.\n\
If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
specifies the window.\n\
If `other-window-scroll-buffer' is non-nil, a window\n\
showing that buffer is used.")
()
{
Lisp_Object window;
if (MINI_WINDOW_P (XWINDOW (selected_window))
&& !NILP (Vminibuf_scroll_window))
window = Vminibuf_scroll_window;
else if (!NILP (Vother_window_scroll_buffer))
{
window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
if (NILP (window))
window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt, Qnil);
}
else
{
window = Fnext_window (selected_window, Qnil, Qnil);
if (EQ (window, selected_window))
do
window = Fnext_window (window, Qnil, Qt);
while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
&& ! EQ (window, selected_window));
}
CHECK_LIVE_WINDOW (window, 0);
if (EQ (window, selected_window))
error ("There is no other window");
return window;
}
DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
"Scroll next window upward ARG lines; or near full screen if no ARG.\n\
A near full screen is `next-screen-context-lines' less than a full screen.\n\
The next window is the one below the current one; or the one at the top\n\
if the current one is at the bottom. Negative ARG means scroll downward.\n\
If ARG is the atom `-', scroll downward by nearly full screen.\n\
When calling from a program, supply as argument a number, nil, or `-'.\n\
\n\
If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
specifies the window to scroll.\n\
If `other-window-scroll-buffer' is non-nil, scroll the window\n\
showing that buffer, popping the buffer up if necessary.")
(arg)
Lisp_Object arg;
{
Lisp_Object window;
struct window *w;
int count = BINDING_STACK_SIZE ();
window = Fother_window_for_scrolling ();
w = XWINDOW (window);
record_unwind_protect (save_excursion_restore, save_excursion_save ());
++windows_or_buffers_changed;
Fset_buffer (w->buffer);
SET_PT (marker_position (w->pointm));
if (NILP (arg))
window_scroll (window, 1, 1, 1);
else if (EQ (arg, Qminus))
window_scroll (window, -1, 1, 1);
else
{
if (CONSP (arg))
arg = Fcar (arg);
CHECK_NUMBER (arg, 0);
window_scroll (window, XINT (arg), 0, 1);
}
set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
unbind_to (count, Qnil);
return Qnil;
}
DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 1, "P",
"Scroll selected window display ARG columns left.\n\
Default for ARG is window width minus 2.\n\
Value is the total amount of leftward horizontal scrolling in\n\
effect after the change.\n\
If `automatic-hscrolling' is non-nil, the argument ARG modifies\n\
a lower bound for automatic scrolling, i.e. automatic scrolling\n\
will not scroll a window to a column less than the value returned\n\
by this function.")
(arg)
register Lisp_Object arg;
{
Lisp_Object result;
int hscroll;
struct window *w = XWINDOW (selected_window);
if (NILP (arg))
XSETFASTINT (arg, window_internal_width (w) - 2);
else
arg = Fprefix_numeric_value (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",
"Scroll selected window display ARG columns right.\n\
Default for ARG is window width minus 2.\n\
Value is the total amount of leftward horizontal scrolling in\n\
effect after the change.\n\
If `automatic-hscrolling' is non-nil, the argument ARG modifies\n\
a lower bound for automatic scrolling, i.e. automatic scrolling\n\
will not scroll a window to a column less than the value returned\n\
by this function.")
(arg)
register Lisp_Object arg;
{
Lisp_Object result;
int hscroll;
struct window *w = XWINDOW (selected_window);
if (NILP (arg))
XSETFASTINT (arg, window_internal_width (w) - 2);
else
arg = Fprefix_numeric_value (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;
}
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;
if (XMARKER (w->start)->charpos < BEGV)
SET_TEXT_POS (start, BEGV, BEGV_BYTE);
else if (XMARKER (w->start)->charpos > ZV)
SET_TEXT_POS (start, ZV, ZV_BYTE);
else
SET_TEXT_POS_FROM_MARKER (start, w->start);
start_display (&it, w, start);
move_it_vertically (&it, height);
bottom_y = line_bottom_y (&it);
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.\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;
{
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))
{
int i;
for (i = 0; i < n_compositions; i++)
composition_table[i]->font = NULL;
Fredraw_frame (w->frame);
SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
center_p = 1;
}
else if (CONSP (arg))
center_p = 1;
else
{
arg = Fprefix_numeric_value (arg);
CHECK_NUMBER (arg, 0);
}
set_buffer_internal (buf);
if (FRAME_WINDOW_P (XFRAME (w->frame)))
{
if (center_p)
{
struct it it;
struct text_pos pt;
SET_TEXT_POS (pt, PT, PT_BYTE);
start_display (&it, w, pt);
move_it_vertically (&it, - window_box_height (w) / 2);
charpos = IT_CHARPOS (it);
bytepos = IT_BYTEPOS (it);
}
else if (XINT (arg) < 0)
{
struct it it;
struct text_pos pt;
int y0, y1, h, nlines;
SET_TEXT_POS (pt, PT, PT_BYTE);
start_display (&it, w, pt);
y0 = it.current_y;
nlines = - XINT (arg) - 1;
move_it_by_lines (&it, nlines, 1);
y1 = line_bottom_y (&it);
if (it.vpos < nlines)
y1 += (nlines - it.vpos) * CANON_Y_UNIT (it.f);
h = window_box_height (w) - (y1 - y0);
start_display (&it, w, pt);
move_it_vertically (&it, - h);
charpos = IT_CHARPOS (it);
bytepos = IT_BYTEPOS (it);
}
else
{
struct position pos;
pos = *vmotion (PT, - XINT (arg), w);
charpos = pos.bufpos;
bytepos = pos.bytepos;
}
}
else
{
struct position pos;
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);
pos = *vmotion (PT, - XINT (arg), w);
charpos = pos.bufpos;
bytepos = pos.bytepos;
}
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;
}
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 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);
}
DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
1, 1, "P",
"Position point relative to window.\n\
With no argument, position point at center of window.\n\
An argument specifies vertical position within the window;\n\
zero means top of window, negative means relative to bottom of window.")
(arg)
Lisp_Object arg;
{
struct window *w = XWINDOW (selected_window);
int lines, start;
Lisp_Object window;
window = selected_window;
start = marker_position (w->start);
if (start < BEGV || start > ZV)
{
int height = window_internal_height (w);
Fvertical_motion (make_number (- (height / 2)), window);
set_marker_both (w->start, w->buffer, PT, PT_BYTE);
w->start_at_line_beg = Fbolp ();
w->force_start = Qt;
}
else
Fgoto_char (w->start);
lines = displayed_window_lines (w);
if (NILP (arg))
XSETFASTINT (arg, lines / 2);
else
{
arg = Fprefix_numeric_value (arg);
if (XINT (arg) < 0)
XSETINT (arg, XINT (arg) + lines);
}
if (w->vscroll)
XSETINT (arg, XINT (arg) + 1);
return Fvertical_motion (arg, window);
}
struct save_window_data
{
EMACS_INT size_from_Lisp_Vector_struct;
struct Lisp_Vector *next_from_Lisp_Vector_struct;
Lisp_Object frame_width, frame_height, frame_menu_bar_lines;
Lisp_Object frame_tool_bar_lines;
Lisp_Object selected_frame;
Lisp_Object current_window;
Lisp_Object current_buffer;
Lisp_Object minibuf_scroll_window;
Lisp_Object root_window;
Lisp_Object focus_frame;
Lisp_Object min_width, min_height;
Lisp_Object saved_windows;
};
struct saved_window
{
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, 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
#define SAVED_WINDOW_N(swv,n) \
((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
"Return t if OBJECT is a window-configuration object.")
(object)
Lisp_Object object;
{
if (WINDOW_CONFIGURATIONP (object))
return Qt;
return Qnil;
}
DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
"Return the frame that CONFIG, a window-configuration object, is about.")
(config)
Lisp_Object config;
{
register struct save_window_data *data;
struct Lisp_Vector *saved_windows;
if (! WINDOW_CONFIGURATIONP (config))
wrong_type_argument (Qwindow_configuration_p, config);
data = (struct save_window_data *) XVECTOR (config);
saved_windows = XVECTOR (data->saved_windows);
return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
}
DEFUN ("set-window-configuration", Fset_window_configuration,
Sset_window_configuration, 1, 1, 0,
"Set the configuration of windows and buffers as specified by CONFIGURATION.\n\
CONFIGURATION must be a value previously returned\n\
by `current-window-configuration' (which see).\n\
If CONFIGURATION was made from a frame that is now deleted,\n\
only frame-independent values can be restored. In this case,\n\
the return value is nil. Otherwise the value is t.")
(configuration)
Lisp_Object configuration;
{
register struct save_window_data *data;
struct Lisp_Vector *saved_windows;
Lisp_Object new_current_buffer;
Lisp_Object frame;
FRAME_PTR f;
int old_point = -1;
while (!WINDOW_CONFIGURATIONP (configuration))
wrong_type_argument (Qwindow_configuration_p, configuration);
data = (struct save_window_data *) XVECTOR (configuration);
saved_windows = XVECTOR (data->saved_windows);
new_current_buffer = data->current_buffer;
if (NILP (XBUFFER (new_current_buffer)->name))
new_current_buffer = Qnil;
else
{
if (XBUFFER (new_current_buffer) == current_buffer)
old_point = PT;
}
frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
f = XFRAME (frame);
if (FRAME_LIVE_P (f))
{
register struct window *w;
register struct saved_window *p;
struct window *root_window;
struct window **leaf_windows;
int n_leaf_windows;
int k, i, n;
int previous_frame_height = FRAME_HEIGHT (f);
int previous_frame_width = FRAME_WIDTH (f);
int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
BLOCK_INPUT;
if (XFASTINT (data->frame_height) != previous_frame_height
|| XFASTINT (data->frame_width) != previous_frame_width)
change_frame_size (f, XFASTINT (data->frame_height),
XFASTINT (data->frame_width), 0, 0, 0);
#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
if (XFASTINT (data->frame_menu_bar_lines)
!= previous_frame_menu_bar_lines)
x_set_menu_bar_lines (f, data->frame_menu_bar_lines, make_number (0));
#ifdef HAVE_WINDOW_SYSTEM
if (XFASTINT (data->frame_tool_bar_lines)
!= previous_frame_tool_bar_lines)
x_set_tool_bar_lines (f, data->frame_tool_bar_lines, make_number (0));
#endif
#endif
if (! NILP (XWINDOW (selected_window)->buffer))
{
w = XWINDOW (selected_window);
set_marker_both (w->pointm,
w->buffer,
BUF_PT (XBUFFER (w->buffer)),
BUF_PT_BYTE (XBUFFER (w->buffer)));
}
windows_or_buffers_changed++;
FRAME_WINDOW_SIZES_CHANGED (f) = 1;
root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
leaf_windows
= (struct window **) alloca (count_windows (root_window)
* sizeof (struct window *));
n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
window_min_height = 1;
window_min_width = 1;
delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
for (k = 0; k < saved_windows->size; k++)
{
p = SAVED_WINDOW_N (saved_windows, k);
w = XWINDOW (p->window);
w->next = Qnil;
if (!NILP (p->parent))
w->parent = SAVED_WINDOW_N (saved_windows,
XFASTINT (p->parent))->window;
else
w->parent = Qnil;
if (!NILP (p->prev))
{
w->prev = SAVED_WINDOW_N (saved_windows,
XFASTINT (p->prev))->window;
XWINDOW (w->prev)->next = p->window;
}
else
{
w->prev = Qnil;
if (!NILP (w->parent))
{
if (EQ (p->width, XWINDOW (w->parent)->width))
{
XWINDOW (w->parent)->vchild = p->window;
XWINDOW (w->parent)->hchild = Qnil;
}
else
{
XWINDOW (w->parent)->hchild = p->window;
XWINDOW (w->parent)->vchild = Qnil;
}
}
}
if (BUFFERP (w->height))
w->buffer = w->height;
w->left = p->left;
w->top = p->top;
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;
XSETFASTINT (w->last_modified, 0);
XSETFASTINT (w->last_overlay_modified, 0);
if (NILP (p->buffer))
w->buffer = p->buffer;
else
{
if (!NILP (XBUFFER (p->buffer)->name))
{
w->buffer = p->buffer;
w->start_at_line_beg = p->start_at_line_beg;
set_marker_restricted (w->start, p->start, w->buffer);
set_marker_restricted (w->pointm, p->pointm, w->buffer);
Fset_marker (XBUFFER (w->buffer)->mark,
p->mark, w->buffer);
if (!EQ (p->buffer, new_current_buffer)
&& XBUFFER (p->buffer) == current_buffer)
Fgoto_char (w->pointm);
}
else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
{
w->buffer = Fcdr (Fcar (Vbuffer_alist));
set_marker_restricted (w->start, make_number (0), w->buffer);
set_marker_restricted (w->pointm, make_number (0),w->buffer);
w->start_at_line_beg = Qt;
}
else
{
if (XMARKER (w->start)->buffer == 0)
set_marker_restricted (w->start, make_number (0),
w->buffer);
if (XMARKER (w->pointm)->buffer == 0)
set_marker_restricted_both (w->pointm, w->buffer,
BUF_PT (XBUFFER (w->buffer)),
BUF_PT_BYTE (XBUFFER (w->buffer)));
w->start_at_line_beg = Qt;
}
}
}
FRAME_ROOT_WINDOW (f) = data->root_window;
selected_window = Qnil;
Fselect_window (data->current_window);
XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
= selected_window;
if (NILP (data->focus_frame)
|| (FRAMEP (data->focus_frame)
&& FRAME_LIVE_P (XFRAME (data->focus_frame))))
Fredirect_frame_focus (frame, data->focus_frame);
#if 0
if (f != selected_frame && FRAME_WINDOW_P (f))
do_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)),
0, 0);
#endif
if (previous_frame_height != FRAME_HEIGHT (f)
|| previous_frame_width != FRAME_WIDTH (f))
change_frame_size (f, previous_frame_height, previous_frame_width,
0, 0, 0);
#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
make_number (0));
#ifdef HAVE_WINDOW_SYSTEM
if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
make_number (0));
#endif
#endif
for (i = n = 0; i < n_leaf_windows; ++i)
{
if (NILP (leaf_windows[i]->buffer))
{
xassert (NILP (leaf_windows[i]->hchild)
&& NILP (leaf_windows[i]->vchild));
free_window_matrices (leaf_windows[i]);
}
else if (EQ (leaf_windows[i]->buffer, new_current_buffer))
++n;
}
if (old_point > 0 && n > 1)
old_point = -1;
adjust_glyphs (f);
UNBLOCK_INPUT;
if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
do_switch_frame (data->selected_frame, 0, 0);
if (! NILP (Vwindow_configuration_change_hook)
&& ! NILP (Vrun_hooks))
call1 (Vrun_hooks, Qwindow_configuration_change_hook);
}
if (!NILP (new_current_buffer))
{
Fset_buffer (new_current_buffer);
if (old_point >= 0)
SET_PT (old_point);
}
window_min_height = XINT (data->min_height);
window_min_width = XINT (data->min_width);
Vminibuf_scroll_window = data->minibuf_scroll_window;
return (FRAME_LIVE_P (f) ? Qt : Qnil);
}
void
delete_all_subwindows (w)
register struct window *w;
{
if (!NILP (w->next))
delete_all_subwindows (XWINDOW (w->next));
if (!NILP (w->vchild))
delete_all_subwindows (XWINDOW (w->vchild));
if (!NILP (w->hchild))
delete_all_subwindows (XWINDOW (w->hchild));
w->height = w->buffer;
if (!NILP (w->buffer))
unshow_buffer (w);
w->buffer = Qnil;
w->vchild = Qnil;
w->hchild = Qnil;
Vwindow_list = Qnil;
}
static int
count_windows (window)
register struct window *window;
{
register int count = 1;
if (!NILP (window->next))
count += count_windows (XWINDOW (window->next));
if (!NILP (window->vchild))
count += count_windows (XWINDOW (window->vchild));
if (!NILP (window->hchild))
count += count_windows (XWINDOW (window->hchild));
return count;
}
static int
get_leaf_windows (w, flat, i)
struct window *w;
struct window **flat;
int i;
{
while (w)
{
if (!NILP (w->hchild))
i = get_leaf_windows (XWINDOW (w->hchild), flat, i);
else if (!NILP (w->vchild))
i = get_leaf_windows (XWINDOW (w->vchild), flat, i);
else
flat[i++] = w;
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
return i;
}
struct glyph *
get_phys_cursor_glyph (w)
struct window *w;
{
struct glyph_row *row;
struct glyph *glyph;
if (w->phys_cursor.vpos >= 0
&& w->phys_cursor.vpos < w->current_matrix->nrows
&& (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
row->enabled_p)
&& row->used[TEXT_AREA] > w->phys_cursor.hpos)
glyph = row->glyphs[TEXT_AREA] + w->phys_cursor.hpos;
else
glyph = NULL;
return glyph;
}
static int
save_window_save (window, vector, i)
Lisp_Object window;
struct Lisp_Vector *vector;
int i;
{
register struct saved_window *p;
register struct window *w;
register Lisp_Object tem;
for (;!NILP (window); window = w->next)
{
p = SAVED_WINDOW_N (vector, i);
w = XWINDOW (window);
XSETFASTINT (w->temslot, i++);
p->window = window;
p->buffer = w->buffer;
p->left = w->left;
p->top = w->top;
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 (!NILP (w->buffer))
{
if (EQ (window, selected_window))
{
p->pointm = Fmake_marker ();
set_marker_both (p->pointm, w->buffer,
BUF_PT (XBUFFER (w->buffer)),
BUF_PT_BYTE (XBUFFER (w->buffer)));
}
else
p->pointm = Fcopy_marker (w->pointm, Qnil);
p->start = Fcopy_marker (w->start, Qnil);
p->start_at_line_beg = w->start_at_line_beg;
tem = XBUFFER (w->buffer)->mark;
p->mark = Fcopy_marker (tem, Qnil);
}
else
{
p->pointm = Qnil;
p->start = Qnil;
p->mark = Qnil;
p->start_at_line_beg = Qnil;
}
if (NILP (w->parent))
p->parent = Qnil;
else
p->parent = XWINDOW (w->parent)->temslot;
if (NILP (w->prev))
p->prev = Qnil;
else
p->prev = XWINDOW (w->prev)->temslot;
if (!NILP (w->vchild))
i = save_window_save (w->vchild, vector, i);
if (!NILP (w->hchild))
i = save_window_save (w->hchild, vector, i);
}
return i;
}
DEFUN ("current-window-configuration", Fcurrent_window_configuration,
Scurrent_window_configuration, 0, 1, 0,
"Return an object representing the current window configuration of FRAME.\n\
If FRAME is nil or omitted, use the selected frame.\n\
This describes the number of windows, their sizes and current buffers,\n\
and for each displayed buffer, where display starts, and the positions of\n\
point and mark. An exception is made for point in the current buffer:\n\
its value is -not- saved.\n\
This also records the currently selected frame, and FRAME's focus\n\
redirection (see `redirect-frame-focus').")
(frame)
Lisp_Object frame;
{
register Lisp_Object tem;
register int n_windows;
register struct save_window_data *data;
register struct Lisp_Vector *vec;
register int i;
FRAME_PTR f;
if (NILP (frame))
frame = selected_frame;
CHECK_LIVE_FRAME (frame, 0);
f = XFRAME (frame);
n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
vec = allocate_other_vector (VECSIZE (struct save_window_data));
data = (struct save_window_data *)vec;
XSETFASTINT (data->frame_width, FRAME_WIDTH (f));
XSETFASTINT (data->frame_height, FRAME_HEIGHT (f));
XSETFASTINT (data->frame_menu_bar_lines, FRAME_MENU_BAR_LINES (f));
XSETFASTINT (data->frame_tool_bar_lines, FRAME_TOOL_BAR_LINES (f));
data->selected_frame = selected_frame;
data->current_window = FRAME_SELECTED_WINDOW (f);
XSETBUFFER (data->current_buffer, current_buffer);
data->minibuf_scroll_window = Vminibuf_scroll_window;
data->root_window = FRAME_ROOT_WINDOW (f);
data->focus_frame = FRAME_FOCUS_FRAME (f);
XSETINT (data->min_height, window_min_height);
XSETINT (data->min_width, window_min_width);
tem = Fmake_vector (make_number (n_windows), Qnil);
data->saved_windows = tem;
for (i = 0; i < n_windows; i++)
XVECTOR (tem)->contents[i]
= Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), 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,
"Execute body, preserving window sizes and contents.\n\
Restore which buffer appears in which window, where display starts,\n\
and the value of point and mark for each window.\n\
Also restore the choice of selected window.\n\
Also restore which buffer is current.\n\
Does not restore the value of point in current buffer.")
(args)
Lisp_Object args;
{
register Lisp_Object val;
register int count = specpdl_ptr - specpdl;
record_unwind_protect (Fset_window_configuration,
Fcurrent_window_configuration (Qnil));
val = Fprogn (args);
return unbind_to (count, val);
}
DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
2, 3, 0,
"Set width of marginal areas of window WINDOW.\n\
If window is nil, set margins of the currently selected window.\n\
First parameter LEFT-WIDTH specifies the number of character\n\
cells to reserve for the left marginal area. Second parameter\n\
RIGHT-WIDTH does the same for the right marginal area.\n\
A nil width parameter means no margin.")
(window, left, right)
Lisp_Object window, left, right;
{
struct window *w = decode_window (window);
if (!NILP (left))
CHECK_NUMBER_OR_FLOAT (left, 1);
if (!NILP (right))
CHECK_NUMBER_OR_FLOAT (right, 2);
if ((INTEGERP (left) && XINT (left) < 0)
|| (FLOATP (left) && XFLOAT_DATA (left) <= 0))
XSETFASTINT (left, 0);
if (INTEGERP (left) && XFASTINT (left) == 0)
left = Qnil;
if ((INTEGERP (right) && XINT (right) < 0)
|| (FLOATP (right) && XFLOAT_DATA (right) <= 0))
XSETFASTINT (right, 0);
if (INTEGERP (right) && XFASTINT (right) == 0)
right = Qnil;
w->left_margin_width = left;
w->right_margin_width = right;
++windows_or_buffers_changed;
adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
return Qnil;
}
DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
0, 1, 0,
"Get width of marginal areas of window WINDOW.\n\
If WINDOW is omitted or nil, use the currently selected window.\n\
Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).\n\
If a marginal area does not exist, its width will be returned\n\
as nil.")
(window)
Lisp_Object window;
{
struct window *w = decode_window (window);
return Fcons (w->left_margin_width, w->right_margin_width);
}
DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 1, 0,
"Return the amount by which WINDOW is scrolled vertically.\n\
Use the selected window if WINDOW is nil or omitted.\n\
Value is a multiple of the canonical character height of WINDOW.")
(window)
Lisp_Object window;
{
Lisp_Object result;
struct frame *f;
struct window *w;
if (NILP (window))
window = selected_window;
else
CHECK_WINDOW (window, 0);
w = XWINDOW (window);
f = XFRAME (w->frame);
if (FRAME_WINDOW_P (f))
result = CANON_Y_FROM_PIXEL_Y (f, -w->vscroll);
else
result = make_number (0);
return result;
}
DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
2, 2, 0,
"Set amount by which WINDOW should be scrolled vertically to VSCROLL.\n\
WINDOW nil means use the selected window. VSCROLL is a non-negative\n\
multiple of the canonical character height of WINDOW.")
(window, vscroll)
Lisp_Object window, vscroll;
{
struct window *w;
struct frame *f;
if (NILP (window))
window = selected_window;
else
CHECK_WINDOW (window, 0);
CHECK_NUMBER_OR_FLOAT (vscroll, 1);
w = XWINDOW (window);
f = XFRAME (w->frame);
if (FRAME_WINDOW_P (f))
{
int old_dy = w->vscroll;
w->vscroll = - CANON_Y_UNIT (f) * XFLOATINT (vscroll);
w->vscroll = min (w->vscroll, 0);
if (w->vscroll < 0 && w->vscroll < old_dy)
adjust_glyphs (f);
XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
}
return Fwindow_vscroll (window);
}
void
foreach_window (f, fn, user_data)
struct frame *f;
int (* fn) P_ ((struct window *, void *));
void *user_data;
{
foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data);
}
static int
foreach_window_1 (w, fn, user_data)
struct window *w;
int (* fn) P_ ((struct window *, void *));
void *user_data;
{
int cont;
for (cont = 1; w && cont;)
{
if (!NILP (w->hchild))
cont = foreach_window_1 (XWINDOW (w->hchild), fn, user_data);
else if (!NILP (w->vchild))
cont = foreach_window_1 (XWINDOW (w->vchild), fn, user_data);
else
cont = fn (w, user_data);
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
return cont;
}
static int
freeze_window_start (w, freeze_p)
struct window *w;
void *freeze_p;
{
if (w == XWINDOW (selected_window)
|| MINI_WINDOW_P (w)
|| (MINI_WINDOW_P (XWINDOW (selected_window))
&& ! NILP (Vminibuf_scroll_window)
&& w == XWINDOW (Vminibuf_scroll_window)))
freeze_p = NULL;
w->frozen_window_start_p = freeze_p != NULL;
return 1;
}
void
freeze_window_starts (f, freeze_p)
struct frame *f;
int freeze_p;
{
foreach_window (f, freeze_window_start, (void *) (freeze_p ? f : 0));
}
int
compare_window_configurations (c1, c2, ignore_positions)
Lisp_Object c1, c2;
int ignore_positions;
{
register struct save_window_data *d1, *d2;
struct Lisp_Vector *sw1, *sw2;
int i;
if (!WINDOW_CONFIGURATIONP (c1))
wrong_type_argument (Qwindow_configuration_p, c1);
if (!WINDOW_CONFIGURATIONP (c2))
wrong_type_argument (Qwindow_configuration_p, c2);
d1 = (struct save_window_data *) XVECTOR (c1);
d2 = (struct save_window_data *) XVECTOR (c2);
sw1 = XVECTOR (d1->saved_windows);
sw2 = XVECTOR (d2->saved_windows);
if (! EQ (d1->frame_width, d2->frame_width))
return 0;
if (! EQ (d1->frame_height, d2->frame_height))
return 0;
if (! EQ (d1->frame_menu_bar_lines, d2->frame_menu_bar_lines))
return 0;
if (! EQ (d1->selected_frame, d2->selected_frame))
return 0;
if (! EQ (d1->current_buffer, d2->current_buffer))
return 0;
if (! ignore_positions)
if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
return 0;
if (! EQ (d1->focus_frame, d2->focus_frame))
return 0;
if (! EQ (d1->min_width, d2->min_width))
return 0;
if (! EQ (d1->min_height, d2->min_height))
return 0;
if (sw1->size != sw2->size)
return 0;
for (i = 0; i < sw1->size; i++)
{
struct saved_window *p1, *p2;
int w1_is_current, w2_is_current;
p1 = SAVED_WINDOW_N (sw1, i);
p2 = SAVED_WINDOW_N (sw2, i);
w1_is_current = EQ (d1->current_window, p1->window);
w2_is_current = EQ (d2->current_window, p2->window);
if (w1_is_current != w2_is_current)
return 0;
if (! EQ (p1->buffer, p2->buffer))
return 0;
if (! EQ (p1->left, p2->left))
return 0;
if (! EQ (p1->top, p2->top))
return 0;
if (! EQ (p1->width, p2->width))
return 0;
if (! EQ (p1->height, p2->height))
return 0;
if (! EQ (p1->display_table, p2->display_table))
return 0;
if (! EQ (p1->parent, p2->parent))
return 0;
if (! EQ (p1->prev, p2->prev))
return 0;
if (! ignore_positions)
{
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)))
return 0;
if (NILP (Fequal (p1->pointm, p2->pointm)))
return 0;
if (NILP (Fequal (p1->mark, p2->mark)))
return 0;
}
}
return 1;
}
DEFUN ("compare-window-configurations", Fcompare_window_configurations,
Scompare_window_configurations, 2, 2, 0,
"Compare two window configurations as regards the structure of windows.\n\
This function ignores details such as the values of point and mark\n\
and scrolling positions.")
(x, y)
Lisp_Object x, y;
{
if (compare_window_configurations (x, y, 1))
return Qt;
return Qnil;
}
void
init_window_once ()
{
struct frame *f = make_terminal_frame ();
XSETFRAME (selected_frame, f);
Vterminal_frame = selected_frame;
minibuf_window = f->minibuffer_window;
selected_window = f->selected_window;
last_nonminibuf_frame = f;
window_initialized = 1;
}
void
init_window ()
{
Vwindow_list = Qnil;
}
void
syms_of_window ()
{
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);
staticpro (&Qwindow_configuration_change_hook);
Qwindow_configuration_change_hook
= intern ("window-configuration-change-hook");
Qwindowp = intern ("windowp");
staticpro (&Qwindowp);
Qwindow_configuration_p = intern ("window-configuration-p");
staticpro (&Qwindow_configuration_p);
Qwindow_live_p = intern ("window-live-p");
staticpro (&Qwindow_live_p);
Qtemp_buffer_show_hook = intern ("temp-buffer-show-hook");
staticpro (&Qtemp_buffer_show_hook);
staticpro (&Vwindow_list);
DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
"Non-nil means call as function to display a help buffer.\n\
The function is called with one argument, the buffer to be displayed.\n\
Used by `with-output-to-temp-buffer'.\n\
If this function is used, then it must do the entire job of showing\n\
the buffer; `temp-buffer-show-hook' is not run unless this function runs it.");
Vtemp_buffer_show_function = Qnil;
DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
"If non-nil, function to call to handle `display-buffer'.\n\
It will receive two args, the buffer and a flag which if non-nil means\n\
that the currently selected window is not acceptable.\n\
Commands such as `switch-to-buffer-other-window' and `find-file-other-window'\n\
work using this function.");
Vdisplay_buffer_function = Qnil;
DEFVAR_LISP ("even-window-heights", &Veven_window_heights,
"*If non-nil, `display-buffer' should even the window heights.\n\
If nil, `display-buffer' will leave the window configuration alone.");
Veven_window_heights = Qt;
DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
"Non-nil means it is the window that C-M-v in minibuffer should scroll.");
Vminibuf_scroll_window = Qnil;
DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
"If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.");
Vother_window_scroll_buffer = Qnil;
DEFVAR_BOOL ("pop-up-frames", &pop_up_frames,
"*Non-nil means `display-buffer' should make a separate frame.");
pop_up_frames = 0;
DEFVAR_BOOL ("display-buffer-reuse-frames", &display_buffer_reuse_frames,
"*Non-nil means `display-buffer' should reuse frames.\n\
If the buffer in question is already displayed in a frame, raise that frame.");
display_buffer_reuse_frames = 0;
DEFVAR_LISP ("pop-up-frame-function", &Vpop_up_frame_function,
"Function to call to handle automatic new frame creation.\n\
It is called with no arguments and should return a newly created frame.\n\
\n\
A typical value might be `(lambda () (new-frame pop-up-frame-alist))'\n\
where `pop-up-frame-alist' would hold the default frame parameters.");
Vpop_up_frame_function = Qnil;
DEFVAR_LISP ("special-display-buffer-names", &Vspecial_display_buffer_names,
"*List of buffer names that should have their own special frames.\n\
Displaying a buffer whose name is in this list makes a special frame for it\n\
using `special-display-function'. See also `special-display-regexps'.\n\
\n\
An element of the list can be a list instead of just a string.\n\
There are two ways to use a list as an element:\n\
(BUFFER FRAME-PARAMETERS...) (BUFFER FUNCTION OTHER-ARGS...)\n\
In the first case, FRAME-PARAMETERS are used to create the frame.\n\
In the latter case, FUNCTION is called with BUFFER as the first argument,\n\
followed by OTHER-ARGS--it can display BUFFER in any way it likes.\n\
All this is done by the function found in `special-display-function'.\n\
\n\
If this variable appears \"not to work\", because you add a name to it\n\
but that buffer still appears in the selected window, look at the\n\
values of `same-window-buffer-names' and `same-window-regexps'.\n\
Those variables take precedence over this one.");
Vspecial_display_buffer_names = Qnil;
DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
"*List of regexps saying which buffers should have their own special frames.\n\
If a buffer name matches one of these regexps, it gets its own frame.\n\
Displaying a buffer whose name is in this list makes a special frame for it\n\
using `special-display-function'.\n\
\n\
An element of the list can be a list instead of just a string.\n\
There are two ways to use a list as an element:\n\
(REGEXP FRAME-PARAMETERS...) (REGEXP FUNCTION OTHER-ARGS...)\n\
In the first case, FRAME-PARAMETERS are used to create the frame.\n\
In the latter case, FUNCTION is called with the buffer as first argument,\n\
followed by OTHER-ARGS--it can display the buffer in any way it likes.\n\
All this is done by the function found in `special-display-function'.\n\
\n\
If this variable appears \"not to work\", because you add a regexp to it\n\
but the matching buffers still appear in the selected window, look at the\n\
values of `same-window-buffer-names' and `same-window-regexps'.\n\
Those variables take precedence over this one.");
Vspecial_display_regexps = Qnil;
DEFVAR_LISP ("special-display-function", &Vspecial_display_function,
"Function to call to make a new frame for a special buffer.\n\
It is called with two arguments, the buffer and optional buffer specific\n\
data, and should return a window displaying that buffer.\n\
The default value makes a separate frame for the buffer,\n\
using `special-display-frame-alist' to specify the frame parameters.\n\
\n\
A buffer is special if its is listed in `special-display-buffer-names'\n\
or matches a regexp in `special-display-regexps'.");
Vspecial_display_function = Qnil;
DEFVAR_LISP ("same-window-buffer-names", &Vsame_window_buffer_names,
"*List of buffer names that should appear in the selected window.\n\
Displaying one of these buffers using `display-buffer' or `pop-to-buffer'\n\
switches to it in the selected window, rather than making it appear\n\
in some other window.\n\
\n\
An element of the list can be a cons cell instead of just a string.\n\
Then the car must be a string, which specifies the buffer name.\n\
This is for compatibility with `special-display-buffer-names';\n\
the cdr of the cons cell is ignored.\n\
\n\
See also `same-window-regexps'.");
Vsame_window_buffer_names = Qnil;
DEFVAR_LISP ("same-window-regexps", &Vsame_window_regexps,
"*List of regexps saying which buffers should appear in the selected window.\n\
If a buffer name matches one of these regexps, then displaying it\n\
using `display-buffer' or `pop-to-buffer' switches to it\n\
in the selected window, rather than making it appear in some other window.\n\
\n\
An element of the list can be a cons cell instead of just a string.\n\
Then the car must be a string, which specifies the buffer name.\n\
This is for compatibility with `special-display-buffer-names';\n\
the cdr of the cons cell is ignored.\n\
\n\
See also `same-window-buffer-names'.");
Vsame_window_regexps = Qnil;
DEFVAR_BOOL ("pop-up-windows", &pop_up_windows,
"*Non-nil means display-buffer should make new windows.");
pop_up_windows = 1;
DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
"*Number of lines of continuity when scrolling by screenfuls.");
next_screen_context_lines = 2;
DEFVAR_INT ("split-height-threshold", &split_height_threshold,
"*display-buffer would prefer to split the largest window if this large.\n\
If there is only one window, it is split regardless of this value.");
split_height_threshold = 500;
DEFVAR_INT ("window-min-height", &window_min_height,
"*Delete any window less than this tall (including its mode line).");
window_min_height = 4;
DEFVAR_INT ("window-min-width", &window_min_width,
"*Delete any window less than this wide.");
window_min_width = 10;
DEFVAR_LISP ("scroll-preserve-screen-position",
&Vscroll_preserve_screen_position,
"*Non-nil means scroll commands move point to keep its screen line unchanged.");
Vscroll_preserve_screen_position = Qnil;
DEFVAR_LISP ("window-configuration-change-hook",
&Vwindow_configuration_change_hook,
"Functions to call when window configuration changes.\n\
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 (&Swindowp);
defsubr (&Swindow_live_p);
defsubr (&Spos_visible_in_window_p);
defsubr (&Swindow_buffer);
defsubr (&Swindow_height);
defsubr (&Swindow_width);
defsubr (&Swindow_hscroll);
defsubr (&Sset_window_hscroll);
defsubr (&Swindow_redisplay_end_trigger);
defsubr (&Sset_window_redisplay_end_trigger);
defsubr (&Swindow_edges);
defsubr (&Scoordinates_in_window_p);
defsubr (&Swindow_at);
defsubr (&Swindow_point);
defsubr (&Swindow_start);
defsubr (&Swindow_end);
defsubr (&Sset_window_point);
defsubr (&Sset_window_start);
defsubr (&Swindow_dedicated_p);
defsubr (&Sset_window_dedicated_p);
defsubr (&Swindow_display_table);
defsubr (&Sset_window_display_table);
defsubr (&Snext_window);
defsubr (&Sprevious_window);
defsubr (&Sother_window);
defsubr (&Sget_lru_window);
defsubr (&Sget_largest_window);
defsubr (&Sget_buffer_window);
defsubr (&Sdelete_other_windows);
defsubr (&Sdelete_windows_on);
defsubr (&Sreplace_buffer_in_windows);
defsubr (&Sdelete_window);
defsubr (&Sset_window_buffer);
defsubr (&Sselect_window);
defsubr (&Sspecial_display_p);
defsubr (&Ssame_window_p);
defsubr (&Sdisplay_buffer);
defsubr (&Ssplit_window);
defsubr (&Senlarge_window);
defsubr (&Sshrink_window);
defsubr (&Sscroll_up);
defsubr (&Sscroll_down);
defsubr (&Sscroll_left);
defsubr (&Sscroll_right);
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);
defsubr (&Sset_window_configuration);
defsubr (&Scurrent_window_configuration);
defsubr (&Ssave_window_excursion);
defsubr (&Sset_window_margins);
defsubr (&Swindow_margins);
defsubr (&Swindow_vscroll);
defsubr (&Sset_window_vscroll);
defsubr (&Scompare_window_configurations);
defsubr (&Swindow_list);
}
void
keys_of_window ()
{
initial_define_key (control_x_map, '1', "delete-other-windows");
initial_define_key (control_x_map, '2', "split-window");
initial_define_key (control_x_map, '0', "delete-window");
initial_define_key (control_x_map, 'o', "other-window");
initial_define_key (control_x_map, '^', "enlarge-window");
initial_define_key (control_x_map, '<', "scroll-left");
initial_define_key (control_x_map, '>', "scroll-right");
initial_define_key (global_map, Ctl ('V'), "scroll-up");
initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
initial_define_key (meta_map, 'v', "scroll-down");
initial_define_key (global_map, Ctl('L'), "recenter");
initial_define_key (meta_map, 'r', "move-to-window-line");
}