/* Window creation, deletion and examination for GNU Emacs.
Does not include redisplay.
- Copyright (C) 1985, 86, 87, 93, 94, 95, 96 Free Software Foundation, Inc.
+ Copyright (C) 1985,86,87,93,94,95,96,97,1998 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include "termchar.h"
#include "disptab.h"
#include "keyboard.h"
+#include "dispextern.h"
+#include "blockinput.h"
+#include "intervals.h"
+
+#ifdef HAVE_X_WINDOWS
+#include "xterm.h"
+#endif /* HAVE_X_WINDOWS */
+#ifdef WINDOWSNT
+#include "w32term.h"
+#endif
+
+#ifndef max
+#define max(a, b) ((a) < (b) ? (b) : (a))
+#endif
+
-Lisp_Object Qwindowp, Qwindow_live_p;
+Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
+Lisp_Object Qwindow_size_fixed, Qleft_bitmap_area, Qright_bitmap_area;
+extern Lisp_Object Qheight, Qwidth;
-Lisp_Object Fnext_window (), Fdelete_window (), Fselect_window ();
-Lisp_Object Fset_window_buffer (), Fsplit_window (), Frecenter ();
+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 void foreach_window_1 P_ ((struct window *, void (*fn) (), int, int,
+ int, int));
+static void freeze_window_start P_ ((struct window *, int));
+static int window_fixed_size_p P_ ((struct window *, int, int));
+static void enlarge_window P_ ((Lisp_Object, int, int));
-void delete_all_subwindows ();
-static struct window *decode_window();
/* This is the window in which the terminal's cursor should
be left when nothing is being done with it. This must
Lisp_Object selected_window;
-/* The minibuffer window of the selected frame.
- Note that you cannot test for minibufferness of an arbitrary window
- by comparing against this; but you can test for minibufferness of
+/* The mini-buffer window of the selected frame.
+ Note that you cannot test for mini-bufferness of an arbitrary window
+ by comparing against this; but you can test for mini-bufferness of
the selected window. */
+
Lisp_Object minibuf_window;
/* Non-nil means it is the window for C-M-v to scroll
- when the minibuffer is selected. */
+ when the mini-buffer is selected. */
+
Lisp_Object Vminibuf_scroll_window;
/* Non-nil means this is the buffer whose window C-M-v should scroll. */
+
Lisp_Object Vother_window_scroll_buffer;
/* Non-nil means it's function to call to display temp buffers. */
+
Lisp_Object Vtemp_buffer_show_function;
/* If a window gets smaller than either of these, it is removed. */
+
int window_min_height;
int window_min_width;
/* Nonzero implies Fdisplay_buffer should create windows. */
+
int pop_up_windows;
/* Nonzero implies make new frames for Fdisplay_buffer. */
+
int pop_up_frames;
/* Non-nil means use this function instead of default */
+
Lisp_Object Vpop_up_frame_function;
/* Function to call to handle Fdisplay_buffer. */
+
Lisp_Object Vdisplay_buffer_function;
/* List of buffer *names* for buffers that should have their own frames. */
+
Lisp_Object Vspecial_display_buffer_names;
/* List of regexps for buffer names that should have their own frames. */
+
Lisp_Object Vspecial_display_regexps;
/* Function to pop up a special frame. */
+
Lisp_Object Vspecial_display_function;
/* List of buffer *names* for buffers to appear in selected window. */
+
Lisp_Object Vsame_window_buffer_names;
/* List of regexps for buffer names to appear in selected window. */
+
Lisp_Object Vsame_window_regexps;
/* Hook run at end of temp_output_buffer_show. */
+
Lisp_Object Qtemp_buffer_show_hook;
/* Fdisplay_buffer always splits the largest window
if that window is more than this high. */
+
int split_height_threshold;
/* Number of lines of continuity in scrolling by screenfuls. */
+
int next_screen_context_lines;
/* Incremented for each window created. */
+
static int sequence_number;
/* Nonzero after init_window_once has finished. */
+
static int window_initialized;
/* Hook to run when window config changes. */
+
Lisp_Object Qwindow_configuration_change_hook;
Lisp_Object Vwindow_configuration_change_hook;
/* Nonzero means scroll commands try to put point
at the same screen height as previously. */
-static int scroll_preserve_screen_position;
-/* Non-nil means we can split a frame even if it is "unsplittable". */
-static int frame_override_unsplittable;
+Lisp_Object Vscroll_preserve_screen_position;
+
+#if 0 /* This isn't used anywhere. */
+/* Nonzero means we can split a frame even if it is "unsplittable". */
+static int inhibit_frame_unsplittable;
+#endif /* 0 */
#define min(a, b) ((a) < (b) ? (a) : (b))
for (i = 0; i < VECSIZE (struct window); i++)
vec->contents[i] = Qnil;
vec->size = VECSIZE (struct window);
- p = (struct window *)vec;
+ p = (struct window *) vec;
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->last_point_x, 0);
- XSETFASTINT (p->last_point_y, 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;
return val;
}
Lisp_Object frame;
{
if (NILP (frame))
- XSETFRAME (frame, selected_frame);
- else
- CHECK_LIVE_FRAME (frame, 0);
-
+ frame = selected_frame;
+ CHECK_LIVE_FRAME (frame, 0);
return FRAME_MINIBUF_WINDOW (XFRAME (frame));
}
Lisp_Object pos, window;
{
register struct window *w;
- register int top;
- register int height;
register int posint;
register struct buffer *buf;
- struct position posval;
- int hscroll;
+ struct text_pos top;
+ Lisp_Object in_window;
if (NILP (pos))
posint = PT;
}
w = decode_window (window);
- top = marker_position (w->start);
- hscroll = XINT (w->hscroll);
-
- if (posint < top)
- return Qnil;
-
- height = XFASTINT (w->height) - ! MINI_WINDOW_P (w);
-
buf = XBUFFER (w->buffer);
- if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf)
- && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (buf))
- {
- /* If frame is up to date,
- use the info recorded about how much text fit on it. */
- if (posint < BUF_Z (buf) - XFASTINT (w->window_end_pos)
- || (XFASTINT (w->window_end_vpos) < height))
- return Qt;
- return Qnil;
- }
+ SET_TEXT_POS_FROM_MARKER (top, w->start);
+
+ /* If position above window, it's not visible. */
+ if (posint < CHARPOS (top))
+ in_window = Qnil;
+ else if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf)
+ && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (buf)
+ && posint < BUF_Z (buf) - XFASTINT (w->window_end_pos))
+ /* If frame is up to date, and POSINT is < window end pos, use
+ that info. This doesn't work for POSINT == end pos, because
+ the window end pos is actually the position _after_ the last
+ char in the window. */
+ in_window = Qt;
+ else if (posint > BUF_ZV (buf))
+ in_window = Qnil;
+ else if (CHARPOS (top) < BUF_BEGV (buf) || CHARPOS (top) > BUF_ZV (buf))
+ /* If window start is out of range, do something reasonable. */
+ in_window = Qnil;
else
{
- if (posint > BUF_ZV (buf))
- return Qnil;
-
- /* w->start can be out of range. If it is, do something reasonable. */
- if (top < BUF_BEGV (buf) || top > BUF_ZV (buf))
- return Qnil;
-
- /* If that info is not correct, calculate afresh */
- /* BUG FIX for the 7th arg (TOHPOS).
-
- '0' is harmless, however, ' - (1 << (BITS_PER_SHORT - 1))' is
- more appropriate here. In case of HSCROLL > 0, this can avoid
- needless calculation done until (HPOS == 0).
-
- We want to determine if the position POSINT is in HEIGHT or
- not. We don't have to do calculation until (HPOS == 0). We
- can stop it when VPOS goes beyond HEIGHT. */
- posval = *compute_motion (top, 0, (hscroll ? 1 - hscroll : 0), 0,
- posint, height, - (1 << (BITS_PER_SHORT - 1)),
- window_internal_width (w) - 1,
- hscroll, 0, w);
-
- return posval.vpos < height ? Qt : Qnil;
+ struct it it;
+ start_display (&it, w, top);
+ move_it_to (&it, posint, 0, it.last_visible_y, -1,
+ MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+ in_window = IT_CHARPOS (it) == posint ? Qt : Qnil;
}
+
+ return in_window;
}
\f
static struct window *
if (XINT (ncol) < 0) XSETFASTINT (ncol, 0);
w = decode_window (window);
if (XINT (w->hscroll) != XINT (ncol))
- XBUFFER (w->buffer)->clip_changed = 1; /* Prevent redisplay shortcuts */
+ /* Prevent redisplay shortcuts */
+ XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
w->hscroll = ncol;
return ncol;
}
Qnil))));
}
-/* Test if the character at column *x, row *y is within window *w.
+/* Test if the character at column *X, row *Y is within window W.
If it is not, return 0;
if it is in the window's text area,
set *x and *y to its location relative to the upper left corner
return 1;
if it is on the window's modeline, return 2;
if it is on the border between the window and its right sibling,
- return 3. */
+ return 3.
+ if it is on the window's top line, return 4;
+ if it is in the bitmap area to the left/right of the window,
+ return 5 or 6, and convert *X and *Y to window-relative corrdinates.
+
+ X and Y are frame relative pixel coordinates. */
+
static int
coordinates_in_window (w, x, y)
register struct window *w;
register int *x, *y;
{
- register int left = XINT (w->left);
- register int right_edge = WINDOW_RIGHT_EDGE (w);
- register int left_margin = WINDOW_LEFT_MARGIN (w);
- register int right_margin = WINDOW_RIGHT_MARGIN (w);
- register int window_height = XINT (w->height);
- register int top = XFASTINT (w->top);
-
- if ( *x < left || *x >= right_edge
- || *y < top || *y >= top + window_height)
- return 0;
+ 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);
- if (left_margin != left && *x < left_margin && *x >= left)
- return 3;
-
- if (right_margin != right_edge && *x >= right_margin && *x < right_edge)
- return 3;
-
- /* Is the character is the mode line? */
- if (*y == top + window_height - 1
- && ! MINI_WINDOW_P (w))
- return 2;
+ if (w->pseudo_window_p)
+ {
+ left_x = 0;
+ right_x = XFASTINT (w->width) * CANON_Y_UNIT (f);
+ 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 (f));
+ right_x = WINDOW_DISPLAY_RIGHT_EDGE_PIXEL_X (w);
+ top_y = (WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w)
+ - FRAME_INTERNAL_BORDER_WIDTH (f));
+ bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
+ }
- *x -= WINDOW_LEFT_MARGIN (w);
- *y -= top;
- return 1;
+ if (*y < top_y
+ || *y >= bottom_y
+ || *x < (left_x
+ - flags_area_width
+ - (FRAME_LEFT_SCROLL_BAR_WIDTH (f)
+ * CANON_X_UNIT (f)))
+ || *x > right_x + flags_area_width)
+ /* Completely outside anything interesting. */
+ return 0;
+ else if (WINDOW_WANTS_MODELINE_P (w)
+ && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
+ /* On the mode line. */
+ return 2;
+ else if (WINDOW_WANTS_HEADER_LINE_P (w)
+ && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
+ /* On the top line. */
+ return 4;
+ else if (*x < left_x || *x >= right_x)
+ {
+ /* Other lines than the mode line don't include flags areas and
+ scroll bars on the left. */
+
+ /* Convert X and Y to window-relative pixel coordinates. */
+ *x -= left_x;
+ *y -= top_y;
+ return *x < left_x ? 5 : 6;
+ }
+ else if (!w->pseudo_window_p
+ && !WINDOW_RIGHTMOST_P (w)
+ && *x >= right_x - CANON_X_UNIT (f))
+ /* On the border on the right side of the window? Assume that
+ this area begins at RIGHT_X minus a canonical char width. */
+ return 3;
+ else
+ {
+ /* Convert X and Y to window-relative pixel coordinates. */
+ *x -= left_x;
+ *y -= top_y;
+ return 1;
+ }
}
DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
If COORDINATES are in the text portion of WINDOW,\n\
the coordinates relative to the window are returned.\n\
If they are in the mode line of WINDOW, `mode-line' is returned.\n\
+If they are in the top mode line of WINDOW, `header-line' is returned.\n\
+If they are in the bitmap-area to the left of the window,\n\
+ `left-bitmap-area' is returned, if they are in the area on the right of\n\
+ the window, `right-bitmap-area' is returned.\n\
If they are 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);
- x = XINT (Fcar (coordinates));
- y = XINT (Fcdr (coordinates));
-
- switch (coordinates_in_window (XWINDOW (window), &x, &y))
+ 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 0: /* NOT in window at all. */
return Qnil;
case 1: /* In text part of window. */
- return Fcons (x, y);
+ /* X and Y are now window relative pixel coordinates.
+ Convert them to canonical char units before returning
+ them. */
+ return Fcons (CANON_X_FROM_PIXEL_X (f, x),
+ CANON_Y_FROM_PIXEL_Y (f, y));
case 2: /* In mode line of window. */
return Qmode_line;
case 3: /* On right border of window. */
return Qvertical_line;
+ case 4:
+ return Qheader_line;
+
+ case 5:
+ return Qleft_bitmap_area;
+
+ case 6:
+ return Qright_bitmap_area;
+
default:
abort ();
}
}
-/* Find the window containing column x, row y, and return it as a
- Lisp_Object. If x, y is on the window's modeline, set *part
- to 1; if it is on the separating line between the window and its
- right sibling, set it to 2; otherwise set it to 0. If there is no
- window under x, y return nil and leave *part unmodified. */
+/* Find the window containing frame-relative pixel position X/Y and
+ return it as a Lisp_Object. If X, Y is on the window's modeline,
+ set *PART to 1; if it is on the separating line between the window
+ and its right sibling, set it to 2; otherwise set it to 0. If
+ there is no window under X, Y return nil and leave *PART
+ unmodified. TOOL_BAR_P non-zero means detect tool-bar windows. */
+
Lisp_Object
-window_from_coordinates (frame, x, y, part)
+window_from_coordinates (frame, x, y, part, tool_bar_p)
FRAME_PTR frame;
int x, y;
int *part;
+ int tool_bar_p;
{
register Lisp_Object tem, first;
+ int found;
tem = first = FRAME_SELECTED_WINDOW (frame);
do
{
- int found = coordinates_in_window (XWINDOW (tem), &x, &y);
+ found = coordinates_in_window (XWINDOW (tem), &x, &y);
if (found)
{
tem = Fnext_window (tem, Qt, Qlambda);
}
- while (! EQ (tem, first));
+ while (!EQ (tem, first));
+
+ /* See if it's in the tool bar window, if a tool bar exists. */
+ if (tool_bar_p
+ && WINDOWP (frame->tool_bar_window)
+ && XFASTINT (XWINDOW (frame->tool_bar_window)->height)
+ && coordinates_in_window (XWINDOW (frame->tool_bar_window), &x, &y))
+ {
+ *part = 0;
+ return frame->tool_bar_window;
+ }
return Qnil;
}
Lisp_Object x, y, frame;
{
int part;
+ struct frame *f;
if (NILP (frame))
- XSETFRAME (frame, selected_frame);
- else
- CHECK_LIVE_FRAME (frame, 2);
- CHECK_NUMBER (x, 0);
- CHECK_NUMBER (y, 1);
+ frame = selected_frame;
+ CHECK_LIVE_FRAME (frame, 2);
+ f = XFRAME (frame);
+
+ /* Check that arguments are integers or floats. */
+ CHECK_NUMBER_OR_FLOAT (x, 0);
+ CHECK_NUMBER_OR_FLOAT (y, 1);
- return window_from_coordinates (XFRAME (frame),
- XINT (x), XINT (y),
- &part);
+ 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,
(vertical-motion (1- (window-height window)) window)\n\
(point))") */
-DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 1, 0,
+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.")
- (window)
- Lisp_Object window;
+does not update this value.\n\
+If UP-TO-DATE 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);
return Qnil;
#endif
- XSETINT (value,
- BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
+ if (! NILP (update)
+ && ! (! NILP (w->window_end_valid)
+ && XFASTINT (w->last_modified) >= MODIFF))
+ {
+ int opoint = PT, opoint_byte = PT_BYTE;
+
+ /* In case W->start is out of the range, use something
+ reasonable. This situation occured when loading a file with
+ `-l' containing a call to `rmail' with subsequent other
+ commands. At the end, W->start happened to be BEG, while
+ rmail had already narrowed the buffer. This leads to an
+ abort in temp_set_pt_both. */
+ if (XMARKER (w->start)->charpos < BEGV)
+ TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
+ else if (XMARKER (w->start)->charpos > ZV)
+ TEMP_SET_PT_BOTH (ZV, ZV_BYTE);
+ else
+ TEMP_SET_PT_BOTH (XMARKER (w->start)->charpos,
+ XMARKER (w->start)->bytepos);
+
+ Fvertical_motion (make_number (window_internal_height (w)), Qnil);
+ XSETINT (value, PT);
+ TEMP_SET_PT_BOTH (opoint, opoint_byte);
+ }
+ else
+ XSETINT (value,
+ BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
return value;
}
register struct window *w = decode_window (window);
CHECK_NUMBER_COERCE_MARKER (pos, 1);
- if (w == XWINDOW (selected_window))
+ if (w == XWINDOW (selected_window)
+ && XBUFFER (w->buffer) == current_buffer)
Fgoto_char (pos);
else
set_marker_restricted (w->pointm, pos, w->buffer);
-
+
return pos;
}
XSETFASTINT (w->last_overlay_modified, 0);
if (!EQ (window, selected_window))
windows_or_buffers_changed++;
+
return pos;
}
return decode_window (window)->display_table;
}
-/* Get the display table for use currently on window W.
- This is either W's display table or W's buffer's display table.
- Ignore the specified tables if they are not valid;
- if no valid table is specified, return 0. */
+/* Get the display table for use on window W. This is either W's
+ display table or W's buffer's display table. Ignore the specified
+ tables if they are not valid; if no valid table is specified,
+ return 0. */
struct Lisp_Char_Table *
window_display_table (w)
tem = w->display_table;
if (DISP_TABLE_P (tem))
return XCHAR_TABLE (tem);
+ if (NILP (w->buffer))
+ return 0;
+
tem = XBUFFER (w->buffer)->display_table;
if (DISP_TABLE_P (tem))
return XCHAR_TABLE (tem);
register Lisp_Object window, table;
{
register struct window *w;
- register Lisp_Object z; /* Return value. */
w = decode_window (window);
w->display_table = table;
\f
/* Record info on buffer window w is displaying
when it is about to cease to display that buffer. */
-static
+static void
unshow_buffer (w)
register struct window *w;
{
Lisp_Object buf;
+ struct buffer *b;
buf = w->buffer;
- if (XBUFFER (buf) != XMARKER (w->pointm)->buffer)
+ b = XBUFFER (buf);
+ if (b != XMARKER (w->pointm)->buffer)
abort ();
- if (w == XWINDOW (XBUFFER (buf)->last_selected_window))
- XBUFFER (buf)->last_selected_window = Qnil;
+ if (w == XWINDOW (b->last_selected_window))
+ b->last_selected_window = Qnil;
#if 0
if (w == XWINDOW (selected_window)
selected window, while last_window_start reflects another
window which was recently showing the same buffer.
Some people might say that might be a good thing. Let's see. */
- XBUFFER (buf)->last_window_start = marker_position (w->start);
+ b->last_window_start = marker_position (w->start);
/* Point in the selected window's buffer
is actually stored in that buffer, and the window's pointm isn't used.
So don't clobber point in that buffer. */
if (! EQ (buf, XWINDOW (selected_window)->buffer))
- BUF_PT (XBUFFER (buf))
- = clip_to_bounds (BUF_BEGV (XBUFFER (buf)),
- marker_position (w->pointm),
- BUF_ZV (XBUFFER (buf)));
+ 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)));
}
/* Put replacement into the window structure in place of old. */
-static
+static void
replace_window (old, replacement)
Lisp_Object old, replacement;
{
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))
return Qnil;
}
+void
delete_window (window)
register Lisp_Object window;
{
register Lisp_Object tem, parent, sib;
register struct window *p;
register struct window *par;
+ FRAME_PTR frame;
/* Because this function is called by other C code on non-leaf
windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
par = XWINDOW (parent);
windows_or_buffers_changed++;
- FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (p))) = 1;
+ frame = XFRAME (WINDOW_FRAME (p));
+ FRAME_WINDOW_SIZES_CHANGED (frame) = 1;
/* Are we trying to delete any frame's selected window? */
{
unchain_marker (p->start);
}
+ /* Free window glyph matrices. It is sure that they are allocated
+ again when ADJUST_GLYPHS is called. Block input so that expose
+ events and other events that access glyph matrices are not
+ processed while we are changing them. */
+ BLOCK_INPUT;
+ free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (frame)));
+
tem = p->next;
if (!NILP (tem))
XWINDOW (tem)->prev = p->prev;
/* Mark this window as deleted. */
p->buffer = p->hchild = p->vchild = Qnil;
+
+ /* Adjust glyph matrices. */
+ adjust_glyphs (frame);
+ UNBLOCK_INPUT;
}
\f
If that happens, go back to the selected frame
so we can complete the cycle. */
if (EQ (tem, tem1))
- XSETFRAME (tem, selected_frame);
+ tem = selected_frame;
}
tem = FRAME_ROOT_WINDOW (XFRAME (tem));
window = XWINDOW (window)->vchild;
else break;
}
+
+ QUIT;
}
/* Which windows are acceptable?
Exit the loop and accept this window if
If that happens, go back to the selected frame
so we can complete the cycle. */
if (EQ (tem, tem1))
- XSETFRAME (tem, selected_frame);
+ tem = selected_frame;
}
/* If this frame has a minibuffer, find that window first,
because it is conceptually the last window in that frame. */
DELETE_OTHER_WINDOWS, /* Arg is window not to delete */
DELETE_BUFFER_WINDOWS, /* Arg is buffer */
GET_LARGEST_WINDOW,
- UNSHOW_BUFFER /* Arg is buffer */
+ UNSHOW_BUFFER, /* Arg is buffer */
+ CHECK_ALL_WINDOWS
};
static Lisp_Object
if (FRAMEP (frames))
frame = XFRAME (frames);
else if (NILP (frames))
- frame = selected_frame;
+ frame = SELECTED_FRAME ();
else
frame = 0;
if (frame)
else if (frame)
w = FRAME_SELECTED_WINDOW (frame);
else
- w = FRAME_SELECTED_WINDOW (selected_frame);
+ w = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
/* Figure out the last window we're going to mess with. Since
Fnext_window, given the same options, is guaranteed to go in a
best_window = Qnil;
for (;;)
{
- FRAME_PTR w_frame = XFRAME (WINDOW_FRAME (XWINDOW (w)));
-
/* Pick the next window now, since some operations will delete
the current window. */
next_window = Fnext_window (w, mini ? Qt : Qnil, frame_arg);
the frame is visible, since Fnext_window skips non-visible frames
if that is desired, under the control of frame_arg. */
if (! MINI_WINDOW_P (XWINDOW (w))
+ /* For UNSHOW_BUFFER, we must always consider all windows. */
+ || type == UNSHOW_BUFFER
|| (mini && minibuf_level > 0))
switch (type)
{
if (NILP (XWINDOW (w)->parent))
{
Lisp_Object new_buffer;
- new_buffer = Fother_buffer (obj, Qnil);
+ new_buffer = Fother_buffer (obj, Qnil,
+ XWINDOW (w)->frame);
if (NILP (new_buffer))
new_buffer
= Fget_buffer_create (build_string ("*scratch*"));
/* Find another buffer to show in this window. */
Lisp_Object another_buffer;
FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
- another_buffer = Fother_buffer (obj, Qnil);
+ another_buffer = Fother_buffer (obj, Qnil, XWINDOW (w)->frame);
if (NILP (another_buffer))
another_buffer
= Fget_buffer_create (build_string ("*scratch*"));
}
}
break;
+
+ /* Check for a window that has a killed buffer. */
+ case CHECK_ALL_WINDOWS:
+ if (! NILP (XWINDOW (w)->buffer)
+ && NILP (XBUFFER (XWINDOW (w)->buffer)->name))
+ abort ();
}
if (EQ (w, last_window))
return best_window;
}
+/* Used for debugging. Abort if any window has a dead buffer. */
+
+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\
w = XWINDOW (window);
startpos = marker_position (w->start);
- top = XFASTINT (w->top) - FRAME_MENU_BAR_LINES (XFRAME (WINDOW_FRAME (w)));
+ 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");
have unwanted side effects due to text properties. */
pos = *vmotion (startpos, -top, w);
- Fset_marker (w->start, make_number (pos.bufpos), w->buffer);
- w->start_at_line_beg = ((pos.bufpos == BEGV
- || FETCH_BYTE (pos.bufpos - 1) == '\n') ? Qt
+ set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
+ w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
+ || FETCH_BYTE (pos.bytepos - 1) == '\n') ? Qt
: Qnil);
/* We need to do this, so that the window-scroll-functions
get called. */
set_buffer_internal (obuf);
}
+
return Qnil;
}
1, 2, "bDelete windows on (buffer): ",
"Delete all windows showing BUFFER.\n\
Optional second argument FRAME controls which frames are affected.\n\
-If nil or omitted, delete all windows showing BUFFER in any frame.\n\
-If t, delete only windows showing BUFFER in the selected frame.\n\
-If `visible', delete all windows showing BUFFER in any visible frame.\n\
-If a frame, delete only windows showing BUFFER in that frame.")
+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;
{
/* FRAME uses t and nil to mean the opposite of what window_loop
expects. */
- if (! FRAMEP (frame))
- frame = NILP (frame) ? Qt : Qnil;
+ if (NILP (frame))
+ frame = Qt;
+ else if (EQ (frame, Qt))
+ frame = Qnil;
if (!NILP (buffer))
{
CHECK_BUFFER (buffer, 0);
window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
}
+
return Qnil;
}
because it only considers frames on the current keyboard.
So loop manually over frames, and handle each one. */
FOR_EACH_FRAME (tail, frame)
- window_loop (UNSHOW_BUFFER, buffer, 0, frame);
+ window_loop (UNSHOW_BUFFER, buffer, 1, frame);
#else
- window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
+ window_loop (UNSHOW_BUFFER, buffer, 1, Qt);
#endif
}
\f
/* The smallest acceptable dimensions for a window. Anything smaller
might crash Emacs. */
+
#define MIN_SAFE_WINDOW_WIDTH (2)
#define MIN_SAFE_WINDOW_HEIGHT (2)
/* If *ROWS or *COLS are too small a size for FRAME, set them to the
minimum allowable size. */
+
void
check_frame_size (frame, rows, cols)
FRAME_PTR frame;
(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_MENU_BAR_LINES (frame) > 0)
- min_height += FRAME_MENU_BAR_LINES (frame);
+
+ if (FRAME_TOP_MARGIN (frame) > 0)
+ min_height += FRAME_TOP_MARGIN (frame);
if (*rows < min_height)
*rows = min_height;
*cols = MIN_SAFE_WINDOW_WIDTH;
}
-/* Normally the window is deleted if it gets too small.
- nodelete nonzero means do not do this.
- (The caller should check later and do so if appropriate) */
-set_window_height (window, height, nodelete)
- Lisp_Object window;
- int height;
- int nodelete;
+/* Value is non-zero if window W is fixed-size. WIDTH_P non-zero means
+ check if W's width can be changed, otherwise check W's height.
+ CHECK_SIBLINGS_P non-zero means check resizablity of WINDOW's
+ siblings, too. If none of the siblings is resizable, WINDOW isn't
+ either. */
+
+static int
+window_fixed_size_p (w, width_p, check_siblings_p)
+ struct window *w;
+ int width_p, check_siblings_p;
{
- register struct window *w = XWINDOW (window);
- register struct window *c;
- int oheight = XFASTINT (w->height);
- int top, pos, lastbot, opos, lastobot;
- Lisp_Object child;
+ int fixed_p;
+ struct window *c;
+
+ if (!NILP (w->hchild))
+ {
+ c = XWINDOW (w->hchild);
+
+ if (width_p)
+ {
+ /* A horiz. combination is fixed-width if all of if its
+ children are. */
+ while (c && window_fixed_size_p (c, width_p, 0))
+ c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+ fixed_p = c == NULL;
+ }
+ else
+ {
+ /* A horiz. combination is fixed-height if one of if its
+ children is. */
+ 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)
+ {
+ /* A vert. combination is fixed-width if one of if its
+ children is. */
+ while (c && !window_fixed_size_p (c, width_p, 0))
+ c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+ fixed_p = c != NULL;
+ }
+ else
+ {
+ /* A vert. combination is fixed-height if all of if its
+ children are. */
+ 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;
+ }
+ }
- check_min_window_sizes ();
+ /* Can't tell if this one is resizable without looking at
+ siblings. If all siblings are fixed-size this one is too. */
+ 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 (!nodelete
- && ! NILP (w->parent)
- && height < window_min_height)
- {
- delete_window (window);
- return;
+ 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;
- XSETFASTINT (w->last_modified, 0);
- XSETFASTINT (w->last_overlay_modified, 0);
- windows_or_buffers_changed++;
- FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
+ return fixed_p;
+}
+
- XSETFASTINT (w->height, height);
+/* Return the minimum size of window W, not taking fixed-width windows
+ into account. WIDTH_P non-zero means return the minimum width,
+ otherwise return the minimum height. If W is a combination window,
+ compute the minimum size from the minimum sizes of W's children. */
+
+static int
+window_min_size_1 (w, width_p)
+ struct window *w;
+ int width_p;
+{
+ struct window *c;
+ int size;
+
if (!NILP (w->hchild))
{
- for (child = w->hchild; !NILP (child); child = XWINDOW (child)->next)
+ c = XWINDOW (w->hchild);
+ size = 0;
+
+ if (width_p)
+ {
+ /* The min width of a horizontal combination is
+ the sum of the min widths of its children. */
+ while (c)
+ {
+ size += window_min_size_1 (c, width_p);
+ c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+ }
+ }
+ else
{
- XWINDOW (child)->top = w->top;
- set_window_height (child, height, nodelete);
+ /* The min height a horizontal combination equals
+ the maximum of all min height of its children. */
+ 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))
{
- lastbot = top = XFASTINT (w->top);
- lastobot = 0;
- for (child = w->vchild; !NILP (child); child = c->next)
+ c = XWINDOW (w->vchild);
+ size = 0;
+
+ if (width_p)
{
- c = XWINDOW (child);
+ /* The min width of a vertical combination is
+ the maximum of the min widths of its children. */
+ 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
+ {
+ /* The min height of a vertical combination equals
+ the sum of the min height of its children. */
+ 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;
+ }
+ }
- opos = lastobot + XFASTINT (c->height);
+ return size;
+}
- XSETFASTINT (c->top, lastbot);
- pos = (((opos * height) << 1) + oheight) / (oheight << 1);
+/* Return the minimum size of window W, taking fixed-size windows into
+ account. WIDTH_P non-zero means return the minimum width,
+ otherwise return the minimum height. IGNORE_FIXED_P non-zero means
+ ignore if W is fixed-size. Set *FIXED to 1 if W is fixed-size
+ unless FIXED is null. */
- /* Avoid confusion: inhibit deletion of child if becomes too small */
- set_window_height (child, pos + top - lastbot, 1);
+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;
- /* Now advance child to next window,
- and set lastbot if child was not just deleted. */
- lastbot = pos + top;
- lastobot = opos;
- }
- /* Now delete any children that became too small. */
- if (!nodelete)
- for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
- {
- set_window_height (child, XINT (XWINDOW (child)->height), 0);
- }
- }
+ 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;
}
-/* Recursively set width of WINDOW and its inferiors. */
-set_window_width (window, width, nodelete)
+/* Set WINDOW's height or width to SIZE. WIDTH_P non-zero means set
+ WINDOW's width. Resize WINDOW's children, if any, so that they
+ keep their proportionate size relative to WINDOW. Propagate
+ WINDOW's top or left edge position to children. Delete windows
+ that become too small unless NODELETE_P is non-zero. */
+
+static void
+size_window (window, size, width_p, nodelete_p)
Lisp_Object window;
- int width;
- int nodelete;
+ int size, width_p, nodelete_p;
{
- register struct window *w = XWINDOW (window);
- register struct window *c;
- int owidth = XFASTINT (w->width);
- int left, pos, lastright, opos, lastoright;
- Lisp_Object child;
+ struct window *w = XWINDOW (window);
+ struct window *c;
+ Lisp_Object child, *forward, *sideward;
+ int old_size, min_size;
- if (!nodelete && width < window_min_width && !NILP (w->parent))
+ check_min_window_sizes ();
+
+ /* If the window has been "too small" at one point,
+ don't delete it for being "too small" in the future.
+ Preserve it as long as that is at all possible. */
+ if (width_p)
{
- delete_window (window);
- return;
+ old_size = XFASTINT (w->width);
+ min_size = window_min_width;
+ }
+ else
+ {
+ old_size = XFASTINT (w->height);
+ min_size = window_min_height;
+ }
+
+ if (old_size < window_min_width)
+ w->too_small_ok = Qt;
+
+ /* Maybe delete WINDOW if it's too small. */
+ if (!nodelete_p && !NILP (w->parent))
+ {
+ int min_size;
+
+ if (!MINI_WINDOW_P (w) && !NILP (w->too_small_ok))
+ min_size = width_p ? MIN_SAFE_WINDOW_WIDTH : MIN_SAFE_WINDOW_HEIGHT;
+ else
+ min_size = width_p ? window_min_width : window_min_height;
+
+ if (size < min_size)
+ {
+ delete_window (window);
+ return;
+ }
}
+ /* Set redisplay hints. */
XSETFASTINT (w->last_modified, 0);
XSETFASTINT (w->last_overlay_modified, 0);
windows_or_buffers_changed++;
FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
- XSETFASTINT (w->width, width);
- if (!NILP (w->vchild))
+ if (width_p)
{
- for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
+ sideward = &w->vchild;
+ forward = &w->hchild;
+ XSETFASTINT (w->width, size);
+ }
+ else
+ {
+ sideward = &w->hchild;
+ forward = &w->vchild;
+ XSETFASTINT (w->height, size);
+ }
+
+ if (!NILP (*sideward))
+ {
+ for (child = *sideward; !NILP (child); child = c->next)
{
- XWINDOW (child)->left = w->left;
- set_window_width (child, width, nodelete);
+ 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 (w->hchild))
+ else if (!NILP (*forward))
{
- lastright = left = XFASTINT (w->left);
- lastoright = 0;
- for (child = w->hchild; !NILP (child); child = c->next)
+ int fixed_size, each, extra, n;
+ int resize_fixed_p, nfixed;
+ int last_pos, first_pos, nchildren;
+
+ /* Determine the fixed-size portion of the this window, and the
+ number of child windows. */
+ fixed_size = nchildren = nfixed = 0;
+ for (child = *forward; !NILP (child); child = c->next, ++nchildren)
{
c = XWINDOW (child);
+ if (window_fixed_size_p (c, width_p, 0))
+ {
+ fixed_size += (width_p
+ ? XFASTINT (c->width) : XFASTINT (c->height));
+ ++nfixed;
+ }
+ }
- opos = lastoright + XFASTINT (c->width);
-
- XSETFASTINT (c->left, lastright);
-
- pos = (((opos * width) << 1) + owidth) / (owidth << 1);
+ /* If the new size is smaller than fixed_size, or if there
+ aren't any resizable windows, allow resizing fixed-size
+ windows. */
+ resize_fixed_p = nfixed == nchildren || size < fixed_size;
+
+ /* Compute how many lines/columns to add to each child. The
+ value of extra takes care of rounding errors. */
+ n = resize_fixed_p ? nchildren : nchildren - nfixed;
+ each = (size - old_size) / n;
+ extra = (size - old_size) - n * each;
+
+ /* Compute new children heights and edge positions. */
+ first_pos = width_p ? XFASTINT (w->left) : XFASTINT (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;
- /* Inhibit deletion for becoming too small */
- set_window_width (child, pos + left - lastright, 1);
+ /* The top or left edge position of this child equals the
+ bottom or right edge of its predecessor. */
+ if (width_p)
+ c->left = make_number (last_pos);
+ else
+ c->top = make_number (last_pos);
- /* Now advance child to next window,
- and set lastright if child was not just deleted. */
- lastright = pos + left, lastoright = opos;
+ /* If this child can be resized, do it. */
+ if (resize_fixed_p || !window_fixed_size_p (c, width_p, 0))
+ {
+ new_size = old_size + each + extra;
+ extra = 0;
+ }
+
+ /* Set new height. Note that size_window also propagates
+ edge positions to children, so it's not a no-op if we
+ didn't change the child's size. */
+ size_window (child, new_size, width_p, 1);
+
+ /* Remember the bottom/right edge position of this child; it
+ will be used to set the top/left edge of the next child. */
+ last_pos += new_size;
}
- /* Delete children that became too small */
- if (!nodelete)
- for (child = w->hchild; !NILP (child); child = XWINDOW (child)->next)
+
+ /* We should have covered the parent exactly with child windows. */
+ xassert (size == last_pos - first_pos);
+
+ /* Now delete any children that became too small. */
+ if (!nodelete_p)
+ for (child = *forward; !NILP (child); child = c->next)
{
- set_window_width (child, XINT (XWINDOW (child)->width), 0);
+ int child_size;
+ c = XWINDOW (child);
+ child_size = width_p ? XFASTINT (c->width) : XFASTINT (c->height);
+ size_window (child, child_size, width_p, 0);
}
}
}
-\f
-int window_select_count;
-Lisp_Object
+/* Set WINDOW's height to HEIGHT, and recursively change the height of
+ WINDOW's children. NODELETE non-zero means don't delete windows
+ that become too small in the process. (The caller should check
+ later and do so if appropriate.) */
+
+void
+set_window_height (window, height, nodelete)
+ Lisp_Object window;
+ int height;
+ int nodelete;
+{
+ size_window (window, height, 0, nodelete);
+}
+
+
+/* Set WINDOW's width to WIDTH, and recursively change the width of
+ WINDOW's children. NODELETE non-zero means don't delete windows
+ that become too small in the process. (The caller should check
+ later and do so if appropriate.) */
+
+void
+set_window_width (window, width, nodelete)
+ Lisp_Object window;
+ int width;
+ int nodelete;
+{
+ size_window (window, width, 1, nodelete);
+}
+
+\f
+int window_select_count;
+
+Lisp_Object
Fset_window_buffer_unwind (obuf)
Lisp_Object obuf;
{
return 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);
- int count = specpdl_ptr - specpdl;
-
- 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)) /* w->buffer is t when the window
- is first being set up. */
- {
- if (!NILP (w->dedicated) && !EQ (tem, buffer))
- error ("Window is dedicated to `%s'",
- XSTRING (XBUFFER (tem)->name)->data);
+/* Make WINDOW display BUFFER as its contents. RUN_HOOKS_P non-zero
+ means it's allowed to run hooks. See make_frame for a case where
+ it's not allowed. */
- unshow_buffer (w);
- }
+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))
- XBUFFER (w->buffer)->last_selected_window = window;
- if (INTEGERP (XBUFFER (buffer)->display_count))
- XSETINT (XBUFFER (buffer)->display_count,
- XINT (XBUFFER (buffer)->display_count) + 1);
+ b->last_selected_window = window;
+
+ /* Update time stamps of buffer display. */
+ 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;
XSETFASTINT (w->hscroll, 0);
- Fset_marker (w->pointm,
- make_number (BUF_PT (XBUFFER (buffer))),
- buffer);
+ set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
set_marker_restricted (w->start,
- make_number (XBUFFER (buffer)->last_window_start),
+ make_number (b->last_window_start),
buffer);
w->start_at_line_beg = Qnil;
w->force_start = Qnil;
Fset_buffer (buffer);
}
- if (! NILP (Vwindow_scroll_functions))
- run_hook_with_args_2 (Qwindow_scroll_functions, window,
- Fmarker_position (w->start));
+ /* Set left and right marginal area width from buffer. */
+ Fset_window_margins (window, b->left_margin_width, b->right_margin_width);
- if (! NILP (Vwindow_configuration_change_hook)
- && ! NILP (Vrun_hooks))
- call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+ 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)) /* w->buffer is t when the window
+ is first being set up. */
+ {
+ 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\
-The main editor command loop selects the buffer of the selected window\n\
-before each command.")
+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);
+}
+\f
+static Lisp_Object
+select_window_1 (window, recordflag)
+ register Lisp_Object window;
+ int recordflag;
{
register struct window *w;
register struct window *ow = XWINDOW (selected_window);
+ struct frame *sf;
CHECK_LIVE_WINDOW (window, 0);
if (EQ (window, selected_window))
return window;
- Fset_marker (ow->pointm, make_number (BUF_PT (XBUFFER (ow->buffer))),
- ow->buffer);
+ 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;
- if (XFRAME (WINDOW_FRAME (w)) != selected_frame)
+ sf = SELECTED_FRAME ();
+ if (XFRAME (WINDOW_FRAME (w)) != sf)
{
XFRAME (WINDOW_FRAME (w))->selected_window = window;
/* Use this rather than Fhandle_switch_frame
Fselect_frame (WINDOW_FRAME (w), Qnil);
}
else
- selected_frame->selected_window = window;
+ sf->selected_window = window;
- record_buffer (w->buffer);
+ if (recordflag)
+ record_buffer (w->buffer);
Fset_buffer (w->buffer);
XBUFFER (w->buffer)->last_selected_window = window;
windows_or_buffers_changed++;
return window;
}
-
+\f
/* Deiconify the frame containing the window WINDOW,
unless it is the selected frame;
then return WINDOW.
display_buffer_1 (window)
Lisp_Object window;
{
- FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
+ Lisp_Object frame = XWINDOW (window)->frame;
+ FRAME_PTR f = XFRAME (frame);
+
FRAME_SAMPLE_VISIBILITY (f);
- if (f != selected_frame)
+
+ if (!EQ (frame, selected_frame))
{
if (FRAME_ICONIFIED_P (f))
- Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
+ Fmake_frame_visible (frame);
else if (FRAME_VISIBLE_P (f))
- Fraise_frame (WINDOW_FRAME (XWINDOW (window)));
+ Fraise_frame (frame);
}
+
return window;
}
else if (CONSP (car)
&& STRINGP (XCAR (car))
&& fast_string_match (XCAR (car), buffer_name) >= 0)
- return XCDR (tem);
+ return XCDR (car);
}
return Qnil;
}
return Qnil;
}
-DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 2,
- "bDisplay buffer: \nP",
+ /* Use B so the default is (other-buffer). */
+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\
\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.")
- (buffer, not_this_window)
- register Lisp_Object buffer, not_this_window;
+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' is non-nil,\n\
+ which means search visible and iconified frames.")
+ (buffer, not_this_window, frame)
+ register Lisp_Object buffer, not_this_window, frame;
{
- register Lisp_Object window, tem;
+ register Lisp_Object window, tem, swp;
+ struct frame *f;
+ swp = Qnil;
buffer = Fget_buffer (buffer);
CHECK_BUFFER (buffer, 0);
in the selected window. */
if (NILP (not_this_window))
{
- tem = Fsame_window_p (XBUFFER (buffer)->name);
- if (!NILP (tem))
+ 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 pop_up_frames,
look for a window showing BUFFER on any visible or iconified frame.
Otherwise search only the current frame. */
- if (pop_up_frames || last_nonminibuf_frame == 0)
+ if (! NILP (frame))
+ tem = frame;
+ else if (pop_up_frames || last_nonminibuf_frame == 0)
XSETFASTINT (tem, 0);
else
XSETFRAME (tem, last_nonminibuf_frame);
}
/* Certain buffer names get special handling. */
- if (!NILP (Vspecial_display_function))
+ if (!NILP (Vspecial_display_function) && NILP (swp))
{
tem = Fspecial_display_p (XBUFFER (buffer)->name);
if (EQ (tem, Qt))
return display_buffer_1 (window);
}
+ f = SELECTED_FRAME ();
if (pop_up_windows
- || FRAME_MINIBUF_ONLY_P (selected_frame)
+ || FRAME_MINIBUF_ONLY_P (f)
/* If the current frame is a special display frame,
don't try to reuse its windows. */
- || !NILP (XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->dedicated)
- )
+ || !NILP (XWINDOW (FRAME_ROOT_WINDOW (f))->dedicated))
{
Lisp_Object frames;
frames = Qnil;
- if (FRAME_MINIBUF_ONLY_P (selected_frame))
+ if (FRAME_MINIBUF_ONLY_P (f))
XSETFRAME (frames, last_nonminibuf_frame);
/* Don't try to create a window if would get an error */
if (split_height_threshold < window_min_height << 1)
/* If the frame we would try to split cannot be split,
try other frames. */
- if (FRAME_NO_SPLIT_P (NILP (frames) ? selected_frame
- : last_nonminibuf_frame))
+ if (FRAME_NO_SPLIT_P (NILP (frames) ? f : last_nonminibuf_frame))
{
/* Try visible frames first. */
window = Fget_largest_window (Qvisible);
&& window_height (window) >= window_min_height << 1)
window = Fsplit_window (window, Qnil, Qnil);
/* If Fget_lru_window returned nil, try other approaches. */
+
/* Try visible frames first. */
+ if (NILP (window))
+ window = Fget_buffer_window (buffer, Qvisible);
if (NILP (window))
window = Fget_largest_window (Qvisible);
/* If that didn't work, try iconified frames. */
+ if (NILP (window))
+ window = Fget_buffer_window (buffer, make_number (0));
if (NILP (window))
window = Fget_largest_window (make_number (0));
/* Try invisible frames. */
+ if (NILP (window))
+ window = Fget_buffer_window (buffer, Qt);
if (NILP (window))
window = Fget_largest_window (Qt);
/* As a last resort, make a new frame. */
{
int total = (XFASTINT (XWINDOW (other)->height)
+ XFASTINT (XWINDOW (window)->height));
- Lisp_Object old_selected_window;
- old_selected_window = selected_window;
-
- selected_window = upper;
- change_window_height ((total / 2
- - XFASTINT (XWINDOW (upper)->height)),
- 0);
- selected_window = old_selected_window;
+ enlarge_window (upper,
+ total / 2 - XFASTINT (XWINDOW (upper)->height),
+ 0);
}
}
}
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)->clip_changed = 1;
+ 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);
+ window = Fdisplay_buffer (buf, Qnil, Qnil);
- if (XFRAME (XWINDOW (window)->frame) != selected_frame)
+ 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);
- set_marker_restricted (w->start, make_number (1), buf);
- set_marker_restricted (w->pointm, make_number (1), buf);
+ set_marker_restricted_both (w->start, buf, 1, 1);
+ set_marker_restricted_both (w->pointm, buf, 1, 1);
- /* Run temp-buffer-show-hook, with the chosen window selected. */
+ /* Run temp-buffer-show-hook, with the chosen window selected
+ and it sbuffer current. */
if (!NILP (Vrun_hooks))
{
Lisp_Object tem;
if (!NILP (tem))
{
int count = specpdl_ptr - specpdl;
+ Lisp_Object prev_window;
+ prev_window = selected_window;
/* Select the window that was chosen, for running the hook. */
- record_unwind_protect (Fset_window_configuration,
- Fcurrent_window_configuration (Qnil));
-
- Fselect_window (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);
}
}
}
}
\f
-static
+static void
make_dummy_parent (window)
Lisp_Object window;
{
"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.")
+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;
{
{
if (!NILP (horflag))
/* Calculate the size of the left-hand window, by dividing
- the usable space in columns by two. */
- size_int = XFASTINT (o->width) >> 1;
+ the usable space in columns by two.
+ We round up, since the left-hand window may include
+ a dividing line, while the right-hand may not. */
+ size_int = (XFASTINT (o->width) + 1) >> 1;
else
size_int = XFASTINT (o->height) >> 1;
}
if (MINI_WINDOW_P (o))
error ("Attempt to split minibuffer window");
- else if (FRAME_NO_SPLIT_P (fo) && ! frame_override_unsplittable)
- error ("Attempt to split unsplittable frame");
+ else if (window_fixed_size_p (o, !NILP (horflag), 0))
+ error ("Attempt to split fixed-size window");
check_min_window_sizes ();
o->next = new;
p->parent = o->parent;
p->buffer = Qt;
+ p->window_end_valid = Qnil;
+ bzero (&p->last_cursor, sizeof p->last_cursor);
/* Apportion the available frame space among the two new windows */
XSETFASTINT (p->top, XFASTINT (o->top) + size_int);
}
+ /* Adjust glyph matrices. */
+ adjust_glyphs (fo);
Fset_window_buffer (new, o->buffer);
-
return new;
}
\f
register Lisp_Object arg, side;
{
CHECK_NUMBER (arg, 0);
- change_window_height (XINT (arg), !NILP (side));
+ enlarge_window (selected_window, XINT (arg), !NILP (side));
if (! NILP (Vwindow_configuration_change_hook))
call1 (Vrun_hooks, Qwindow_configuration_change_hook);
register Lisp_Object arg, side;
{
CHECK_NUMBER (arg, 0);
- change_window_height (-XINT (arg), !NILP (side));
+ enlarge_window (selected_window, -XINT (arg), !NILP (side));
if (! NILP (Vwindow_configuration_change_hook))
call1 (Vrun_hooks, Qwindow_configuration_change_hook);
return XFASTINT (p->width);
}
-#define MINSIZE(w) \
- (widthflag \
- ? window_min_width \
- : (MINI_WINDOW_P (XWINDOW (w)) ? 1 : window_min_height))
-
+
#define CURBEG(w) \
*(widthflag ? (int *) &(XWINDOW (w)->left) : (int *) &(XWINDOW (w)->top))
#define CURSIZE(w) \
*(widthflag ? (int *) &(XWINDOW (w)->width) : (int *) &(XWINDOW (w)->height))
-/* Unlike set_window_height, this function
- also changes the heights of the siblings so as to
- keep everything consistent. */
-change_window_height (delta, widthflag)
- register int delta;
- int widthflag;
-{
- register Lisp_Object parent;
- Lisp_Object window;
- register struct window *p;
- int *sizep;
- int (*sizefun) () = widthflag ? window_width : window_height;
- register int (*setsizefun) () = (widthflag
- ? set_window_width
- : set_window_height);
- int maximum;
- Lisp_Object next, prev;
+/* Enlarge selected_window by DELTA. WIDTHFLAG non-zero means
+ increase its width. Siblings of the selected window are resized to
+ fullfil the size request. If they become too small in the process,
+ they will be deleted. */
+static void
+enlarge_window (window, delta, widthflag)
+ Lisp_Object window;
+ int delta, widthflag;
+{
+ Lisp_Object parent, next, prev;
+ struct window *p;
+ int *sizep, 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 values of window_min_width and window_min_height for
+ validity. */
check_min_window_sizes ();
- window = selected_window;
+ /* Give up if this window cannot be resized. */
+ if (window_fixed_size_p (XWINDOW (window), widthflag, 1))
+ error ("Window is not resizable");
+
+ /* Find the parent of the selected window. */
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)
+
+ if (widthflag
+ ? !NILP (XWINDOW (parent)->hchild)
: !NILP (XWINDOW (parent)->vchild))
break;
+
window = parent;
}
register int maxdelta;
maxdelta = (!NILP (parent) ? (*sizefun) (parent) - *sizep
- : !NILP (p->next) ? (*sizefun) (p->next) - MINSIZE (p->next)
- : !NILP (p->prev) ? (*sizefun) (p->prev) - MINSIZE (p->prev)
+ : !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))
/* This is a frame with only one window, a minibuffer-only
or a minibufferless frame. */
: (delta = 0));
delta = maxdelta;
}
- if (*sizep + delta < MINSIZE (window))
+ if (*sizep + delta < window_min_size (XWINDOW (window), widthflag, 0, 0))
{
delete_window (window);
return;
/* Find the total we can get from other siblings. */
maximum = 0;
for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
- maximum += (*sizefun) (next) - MINSIZE (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) - MINSIZE (prev);
+ maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
+ widthflag, 0, 0);
/* If we can get it all from them, do so. */
- if (delta < maximum)
+ if (delta <= maximum)
{
Lisp_Object first_unaffected;
Lisp_Object first_affected;
+ int fixed_p;
next = p->next;
prev = p->prev;
/* Look at one sibling at a time,
moving away from this window in both directions alternately,
and take as much as we can get without deleting that sibling. */
- while (delta != 0)
+ while (delta != 0 && (!NILP (next) || !NILP (prev)))
{
- if (delta == 0)
- break;
if (! NILP (next))
{
- int this_one = (*sizefun) (next) - MINSIZE (next);
- if (this_one > delta)
- this_one = delta;
-
- (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
- (*setsizefun) (window, *sizep + this_one, 0);
+ 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, *sizep + this_one, 0);
- delta -= this_one;
+ delta -= this_one;
+ }
+
next = XWINDOW (next)->next;
}
+
if (delta == 0)
break;
+
if (! NILP (prev))
{
- int this_one = (*sizefun) (prev) - MINSIZE (prev);
- if (this_one > delta)
- this_one = delta;
-
- first_affected = prev;
-
- (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
- (*setsizefun) (window, *sizep + this_one, 0);
-
- delta -= this_one;
+ 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, *sizep + this_one, 0);
+
+ delta -= this_one;
+ }
+
prev = XWINDOW (prev)->prev;
}
}
+ xassert (delta == 0);
+
/* Now recalculate the edge positions of all the windows affected,
based on the new sizes. */
first_unaffected = next;
all the siblings end up with less than one line and are deleted. */
if (opht <= *sizep + delta)
delta1 = opht * opht * 2;
- /* Otherwise, make delta1 just right so that if we add delta1
- lines to this window and to the parent, and then shrink
- the parent back to its original size, the new proportional
- size of this window will increase by delta. */
else
- delta1 = (delta * opht * 100) / ((opht - *sizep - delta) * 100);
+ {
+ /* Otherwise, make delta1 just right so that if we add
+ delta1 lines to this window and to the parent, and then
+ shrink the parent back to its original size, the new
+ proportional size of this window will increase by delta.
+
+ The function size_window will compute the new height h'
+ of the window from delta1 as:
+
+ e = delta1/n
+ x = delta1 - delta1/n * n for the 1st resizable child
+ h' = h + e + x
+
+ where n is the number of children that can be resized.
+ We can ignore x by choosing a delta1 that is a multiple of
+ n. We want the height of this window to come out as
+
+ h' = h + delta
+
+ So, delta1 must be
+
+ h + e = h + delta
+ delta1/n = delta
+ delta1 = n * delta.
+
+ The number of children n rquals the number of resizable
+ children of this window + 1 because we know window itself
+ is resizable (otherwise we would have signalled an error. */
+
+ 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;
+ }
/* Add delta1 lines or columns to this window, and to the parent,
keeping things consistent while not affecting siblings. */
XSETFASTINT (p->last_modified, 0);
XSETFASTINT (p->last_overlay_modified, 0);
+
+ /* Adjust glyph matrices. */
+ adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
}
-#undef MINSIZE
+
#undef CURBEG
#undef CURSIZE
+
+\f
+/***********************************************************************
+ Resizing Mini-Windows
+ ***********************************************************************/
+
+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));
+
+/* Shrink windows rooted in window W to HEIGHT. Take the space needed
+ from lowest windows first. */
+
+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));
+
+ /* Set redisplay hints. */
+ 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;
+
+ /* Find the last child. We are taking space from lowest windows
+ first, so we iterate over children from the last child
+ backwards. */
+ for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
+ last_child = child;
+
+ /* Assign new heights. We leave only MIN_SAFE_WINDOW_HEIGHT. */
+ 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;
+ }
+
+ /* Compute new positions. */
+ last_top = 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);
+ }
+ }
+}
+
+
+/* Save, restore, or check positions and sizes in the window tree
+ rooted at W. ACTION says what to do.
+
+ If ACTION is CHECK_ORIG_SIZES, check if orig_top and orig_height
+ members are valid for all windows in the window tree. Value is
+ non-zero if they are valid.
+
+ If ACTION is SAVE_ORIG_SIZES, save members top and height in
+ orig_top and orig_height for all windows in the tree.
+
+ If ACTION is RESTORE_ORIG_SIZES, restore top and height from
+ values stored in orig_top and orig_height for all windows. */
+
+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;
+}
+
+
+/* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we can
+ without deleting other windows. */
+
+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 values of window_min_width and window_min_height for
+ validity. */
+ check_min_window_sizes ();
+
+ /* Compute how much we can enlarge the mini-window without deleting
+ other windows. */
+ 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 = XFASTINT (root->height) - min_height;
+ }
+
+ if (delta)
+ {
+ /* Save original window sizes and positions, if not already done. */
+ if (!save_restore_orig_size (root, CHECK_ORIG_SIZES))
+ save_restore_orig_size (root, SAVE_ORIG_SIZES);
+
+ /* Shrink other windows. */
+ shrink_window_lowest_first (root, XFASTINT (root->height) - delta);
+
+ /* Grow the mini-window. */
+ 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);
+ }
+}
+
+
+/* Shrink mini-window W. If there is recorded info about window sizes
+ before a call to grow_mini_window, restore recorded window sizes.
+ Otherwise, if the mini-window is higher than 1 line, resize it to 1
+ line. */
+
+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);
+ }
+}
+
+
\f
+/* Mark window cursors off for all windows in the window tree rooted
+ at W by setting their phys_cursor_on_p flag to zero. Called from
+ xterm.c, e.g. when a frame is cleared and thereby all cursors on
+ the frame are cleared. */
+
+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);
+ }
+}
+
+
/* Return number of lines of text (not counting mode line) in W. */
int
window_internal_height (w)
struct window *w;
{
- int ht = XFASTINT (w->height);
-
- if (MINI_WINDOW_P (w))
- return ht;
+ int ht = XFASTINT (w->height);
+
+ if (MINI_WINDOW_P (w))
+ return ht;
+
+ if (!NILP (w->parent) || !NILP (w->vchild) || !NILP (w->hchild)
+ || !NILP (w->next) || !NILP (w->prev)
+ || FRAME_WANTS_MODELINE_P (XFRAME (WINDOW_FRAME (w))))
+ return ht - 1;
+
+ return ht;
+}
+
+
+/* Return the number of columns in W.
+ Don't count columns occupied by scroll bars or the vertical bar
+ separating W from the sibling to its right. */
+
+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))
+ /* Scroll bars occupy a few columns. */
+ width -= FRAME_SCROLL_BAR_COLS (f);
+ else if (!WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
+ /* The column of `|' characters separating side-by-side windows
+ occupies one column only. */
+ width -= 1;
+
+ /* On window-systems, areas to the left and right of the window
+ are used to display bitmaps there. */
+ if (FRAME_WINDOW_P (f))
+ width -= FRAME_FLAGS_AREA_COLS (f);
+
+ return width;
+}
+
+\f
+/************************************************************************
+ Window Scrolling
+ ***********************************************************************/
+
+/* Scroll contents of window WINDOW up. If WHOLE is non-zero, scroll
+ one screen-full, which is defined as the height of the window minus
+ next_screen_context_lines. If WHOLE is zero, scroll up N lines
+ instead. Negative values of N mean scroll down. NOERROR non-zero
+ means don't signal an error if we try to move over BEGV or ZV,
+ respectively. */
+
+static void
+window_scroll (window, n, whole, noerror)
+ Lisp_Object window;
+ int n;
+ int whole;
+ int noerror;
+{
+ /* If we must, use the pixel-based version which is much slower than
+ the line-based one but can handle varying line heights. */
+ 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);
+}
+
+
+/* Implementation of window_scroll that works based on pixel line
+ heights. See the comment of window_scroll for parameter
+ descriptions. */
+
+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;
- if (!NILP (w->parent) || !NILP (w->vchild) || !NILP (w->hchild)
- || !NILP (w->next) || !NILP (w->prev)
- || FRAME_WANTS_MODELINE_P (XFRAME (WINDOW_FRAME (w))))
- return ht - 1;
+ SET_TEXT_POS_FROM_MARKER (start, w->start);
+
+ /* If PT is not visible in WINDOW, move back one half of
+ the screen. */
+ XSETFASTINT (tem, PT);
+ tem = Fpos_visible_in_window_p (tem, window);
+ if (NILP (tem))
+ {
+ /* Move backward half the height of the window. Performance note:
+ vmotion used here is about 10% faster, but would give wrong
+ results for variable height lines. */
+ init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
+ it.current_y = it.last_visible_y;
+ move_it_vertically (&it, -it.last_visible_y / 2);
+
+ /* The function move_iterator_vertically may move over more than
+ the specified y-distance. If it->w is small, e.g. a
+ mini-buffer window, we may end up in front of the window's
+ display area. This is the case when Start displaying at the
+ start of the line containing PT in this case. */
+ 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;
+ }
- return ht;
-}
+ start = it.current.pos;
+ }
+ /* If scroll_preserve_screen_position is non-zero, we try to set
+ point in the same window line as it is now, so get that line. */
+ if (!NILP (Vscroll_preserve_screen_position))
+ {
+ start_display (&it, w, start);
+ move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+ preserve_y = it.current_y;
+ }
+ else
+ preserve_y = -1;
-/* Return the number of columns in W.
- Don't count columns occupied by scroll bars or the vertical bar
- separating W from the sibling to its right. */
-int
-window_internal_width (w)
- struct window *w;
-{
- FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
- int width = XINT (w->width);
+ /* Move iterator it from start the specified distance forward or
+ backward. The result is the new window start. */
+ start_display (&it, w, start);
+ if (whole)
+ {
+ int screen_full = (it.last_visible_y
+ - next_screen_context_lines * CANON_Y_UNIT (it.f));
+ int direction = n < 0 ? -1 : 1;
+ move_it_vertically (&it, direction * screen_full);
+ }
+ else
+ move_it_by_lines (&it, n, 1);
- /* Scroll bars occupy a few columns. */
- if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
- return width - FRAME_SCROLL_BAR_COLS (f);
+ /* End if we end up at ZV or BEGV. */
+ if ((n > 0 && IT_CHARPOS (it) == ZV)
+ || (n < 0 && IT_CHARPOS (it) == CHARPOS (start)))
+ {
+ if (noerror)
+ return;
+ else if (IT_CHARPOS (it) == ZV)
+ Fsignal (Qend_of_buffer, Qnil);
+ else
+ Fsignal (Qbeginning_of_buffer, Qnil);
+ }
- /* The column of `|' characters separating side-by-side windows
- occupies one column only. */
- if (!WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
- return width - 1;
+ /* Set the window start, and set up the window for redisplay. */
+ 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);
+ /* Set force_start so that redisplay_window will run the
+ window-scroll-functions. */
+ w->force_start = Qt;
+
+ it.current_y = it.vpos = 0;
+
+ /* Preserve the screen position if we must. */
+ if (preserve_y >= 0)
+ {
+ move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
+ SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+ }
+ else
+ {
+ /* Move PT out of scroll margins. */
+ this_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);
- return width;
+ if (n > 0)
+ {
+ /* We moved the window start towards ZV, so PT may be now
+ in the scroll margin at the top. */
+ move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+ while (it.current_y < this_scroll_margin)
+ move_it_by_lines (&it, 1, 1);
+ SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+ }
+ else if (n < 0)
+ {
+ /* We moved the window start towards BEGV, so PT may be now
+ in the scroll margin at the bottom. */
+ move_it_to (&it, PT, -1,
+ it.last_visible_y - this_scroll_margin - 1, -1,
+ MOVE_TO_POS | MOVE_TO_Y);
+
+ /* Don't put point on a partially visible line at the end. */
+ if (it.current_y + it.max_ascent + it.max_descent
+ > it.last_visible_y)
+ move_it_by_lines (&it, -1, 0);
+
+ SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+ }
+ }
}
-/* Scroll contents of window WINDOW up N lines.
- If WHOLE is nonzero, it means scroll N screenfuls instead. */
+/* Implementation of window_scroll that works based on screen lines.
+ See the comment of window_scroll for parameter descriptions. */
static void
-window_scroll (window, n, whole, noerror)
+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;
- register int pos;
+ 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, nmoved;
+ Lisp_Object bolp;
int startpos;
struct position posit;
int original_vpos;
lose = n < 0 && PT == BEGV;
Fvertical_motion (make_number (n), window);
pos = PT;
+ pos_byte = PT_BYTE;
bolp = Fbolp ();
- SET_PT (opoint);
+ SET_PT_BOTH (opoint, opoint_byte);
if (lose)
{
if (XINT (w->height) < 4 * scroll_margin)
this_scroll_margin = XINT (w->height) / 4;
- set_marker_restricted (w->start, make_number (pos), w->buffer);
+ 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);
the window-scroll-functions. */
w->force_start = Qt;
- if (whole && scroll_preserve_screen_position)
+ if (whole && !NILP (Vscroll_preserve_screen_position))
{
- SET_PT (pos);
+ SET_PT_BOTH (pos, pos_byte);
Fvertical_motion (make_number (original_vpos), window);
}
/* If we scrolled forward, put point enough lines down
if (this_scroll_margin > 0)
{
- SET_PT (pos);
+ SET_PT_BOTH (pos, pos_byte);
Fvertical_motion (make_number (this_scroll_margin), window);
top_margin = PT;
}
top_margin = pos;
if (top_margin <= opoint)
- SET_PT (opoint);
- else if (scroll_preserve_screen_position)
+ SET_PT_BOTH (opoint, opoint_byte);
+ else if (!NILP (Vscroll_preserve_screen_position))
{
- SET_PT (pos);
+ SET_PT_BOTH (pos, pos_byte);
Fvertical_motion (make_number (original_vpos), window);
}
else
- SET_PT (pos);
+ SET_PT (top_margin);
}
else if (n < 0)
{
/* If we scrolled backward, put point near the end of the window
but not within the scroll margin. */
- SET_PT (pos);
+ 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;
bottom_margin = PT + 1;
if (bottom_margin > opoint)
- SET_PT (opoint);
+ SET_PT_BOTH (opoint, opoint_byte);
else
{
- if (scroll_preserve_screen_position)
+ if (!NILP (Vscroll_preserve_screen_position))
{
- SET_PT (pos);
+ SET_PT_BOTH (pos, pos_byte);
Fvertical_motion (make_number (original_vpos), window);
}
else
Fsignal (Qend_of_buffer, Qnil);
}
}
-\f
-/* This is the guts of Fscroll_up and Fscroll_down. */
+
+
+/* Scroll selected_window up or down. If N is nil, scroll a
+ screen-full which is defined as the height of the window minus
+ next_screen_context_lines. If N is the symbol `-', scroll.
+ DIRECTION may be 1 meaning to scroll down, or -1 meaning to scroll
+ up. This is the guts of Fscroll_up and Fscroll_down. */
static void
scroll_command (n, direction)
- register Lisp_Object n;
+ Lisp_Object n;
int direction;
{
register int defalt;
int count = specpdl_ptr - specpdl;
- /* If selected window's buffer isn't current, make it current for the moment.
- But don't screw up if window_scroll gets an error. */
+ xassert (abs (direction) == 1);
+
+ /* If selected window's buffer isn't current, make it current for
+ the moment. But don't screw up if window_scroll gets an error. */
if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
{
record_unwind_protect (save_excursion_restore, save_excursion_save ());
Fset_buffer (XWINDOW (selected_window)->buffer);
+
+ /* Make redisplay consider other windows than just selected_window. */
+ ++windows_or_buffers_changed;
}
defalt = (window_internal_height (XWINDOW (selected_window))
"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\
-When calling from a program, supply a number as argument or nil.")
+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;
{
}
DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
- "Scroll text of current window downward ARG lines; or near full screen if no ARG.\n\
+ "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\
-When calling from a program, supply a number as argument or nil.")
+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;
{
{
window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
if (NILP (window))
- window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt);
+ window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt, Qnil);
}
else
{
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\
-When calling from a program, supply a number as argument or nil.\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\
/* Don't screw up if window_scroll gets an error. */
record_unwind_protect (save_excursion_restore, save_excursion_save ());
+ ++windows_or_buffers_changed;
Fset_buffer (w->buffer);
SET_PT (marker_position (w->pointm));
window_scroll (window, XINT (arg), 0, 1);
}
- Fset_marker (w->pointm, make_number (PT), Qnil);
+ set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
unbind_to (count, Qnil);
return Qnil;
register struct window *w = XWINDOW (selected_window);
register int ht = window_internal_height (w);
struct position pos;
+ struct buffer *buf = XBUFFER (w->buffer);
+ struct buffer *obuf = current_buffer;
if (NILP (arg))
{
extern int frame_garbaged;
+ int i;
+ /* Invalidate pixel data calculated for all compositions. */
+ for (i = 0; i < n_compositions; i++)
+ composition_table[i]->font = NULL;
+
+ Fredraw_frame (w->frame);
SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
XSETFASTINT (arg, ht / 2);
}
if (XINT (arg) < 0)
XSETINT (arg, XINT (arg) + ht);
+ set_buffer_internal (buf);
pos = *vmotion (PT, - XINT (arg), w);
- Fset_marker (w->start, make_number (pos.bufpos), w->buffer);
- w->start_at_line_beg = ((pos.bufpos == BEGV
- || FETCH_BYTE (pos.bufpos - 1) == '\n')
+ set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
+ w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
+ || FETCH_BYTE (pos.bytepos - 1) == '\n')
? Qt : Qnil);
w->force_start = Qt;
+ set_buffer_internal (obuf);
return Qnil;
}
1, 1, "P",
"Position point relative to window.\n\
With no argument, position point at center of window.\n\
-An argument specifies frame line; zero means top of window,\n\
-negative means relative to bottom of window.")
+An argument specifies vertical position within the window;\n\
+zero means top of window, negative means relative to bottom of window.")
(arg)
register Lisp_Object arg;
{
if (start < BEGV || start > ZV)
{
Fvertical_motion (make_number (- (height / 2)), window);
- Fset_marker (w->start, make_number (PT), w->buffer);
+ set_marker_both (w->start, w->buffer, PT, PT_BYTE);
w->start_at_line_beg = Fbolp ();
w->force_start = Qt;
}
else
- SET_PT (start);
+ Fgoto_char (w->start);
return Fvertical_motion (arg, window);
}
+
+
\f
+/***********************************************************************
+ Window Configuration
+ ***********************************************************************/
+
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;
/* Record the values of window-min-width and window-min-height
so that window sizes remain consistent with them. */
Lisp_Object min_width, min_height;
- /* A vector, interpreted as a struct saved_window */
+ /* A vector, each of whose elements is a struct saved_window
+ for one window. */
Lisp_Object saved_windows;
};
-/* This is saved as a Lisp_Vector */
+/* This is saved as a Lisp_Vector */
struct saved_window
{
/* these first two must agree with struct Lisp_Vector in lisp.h */
((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
- "T if OBJECT is a window-configuration object.")
+ "Return t if OBJECT is a window-configuration object.")
(object)
Lisp_Object object;
{
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).")
- (configuration)
+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;
Lisp_Object new_current_buffer;
Lisp_Object frame;
FRAME_PTR f;
+ int old_point = -1;
while (!WINDOW_CONFIGURATIONP (configuration))
- {
- configuration = wrong_type_argument (intern ("window-configuration-p"),
- 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);
{
register struct window *w;
register struct saved_window *p;
- int k;
+ struct window *root_window;
+ struct window **leaf_windows;
+ int n_leaf_windows;
+ int k, i;
/* If the frame has been resized since this window configuration was
made, we change the frame to the size specified in the
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);
+
+ /* The mouse highlighting code could get screwed up
+ if it runs during this. */
+ BLOCK_INPUT;
if (XFASTINT (data->frame_height) != previous_frame_height
|| XFASTINT (data->frame_width) != previous_frame_width)
- change_frame_size (f, data->frame_height, data->frame_width, 0, 0);
+ 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, 0);
+ 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;
+ /* Problem: Freeing all matrices and later allocating them again
+ is a serious redisplay flickering problem. What we would
+ really like to do is to free only those matrices not reused
+ below. */
+ 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);
+
/* Temporarily avoid any problems with windows that are smaller
than they are supposed to be. */
window_min_height = 1;
{
w->buffer = p->buffer;
w->start_at_line_beg = p->start_at_line_beg;
- set_marker_restricted (w->start,
- Fmarker_position (p->start),
- w->buffer);
- set_marker_restricted (w->pointm,
- Fmarker_position (p->pointm),
- w->buffer);
+ set_marker_restricted (w->start, p->start, w->buffer);
+ set_marker_restricted (w->pointm, p->pointm, w->buffer);
Fset_marker (XBUFFER (w->buffer)->mark,
- Fmarker_position (p->mark), w->buffer);
+ p->mark, w->buffer);
/* As documented in Fcurrent_window_configuration, don't
save the location of point in the buffer which was current
set_marker_restricted (w->start, make_number (0),
w->buffer);
if (XMARKER (w->pointm)->buffer == 0)
- set_marker_restricted (w->pointm,
- (make_number
- (BUF_PT (XBUFFER (w->buffer)))),
- w->buffer);
+ 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;
Fselect_window (data->current_window);
+ XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
+ = selected_window;
if (NILP (data->focus_frame)
|| (FRAMEP (data->focus_frame)
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, 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, previous_frame_menu_bar_lines, 0);
+ 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
+
+ /* Now, free glyph matrices in windows that were not reused. */
+ for (i = 0; i < n_leaf_windows; ++i)
+ if (NILP (leaf_windows[i]->buffer))
+ {
+ /* Assert it's not reused as a combination. */
+ xassert (NILP (leaf_windows[i]->hchild)
+ && NILP (leaf_windows[i]->vchild));
+ free_window_matrices (leaf_windows[i]);
+ SET_FRAME_GARBAGED (f);
+ }
+
+ adjust_glyphs (f);
+
+ UNBLOCK_INPUT;
+
+ /* Fselect_window will have made f the selected frame, so we
+ reselect the proper frame here. Fhandle_switch_frame will change the
+ selected window too, but that doesn't make the call to
+ Fselect_window above totally superfluous; it still sets f's
+ selected window. */
+ if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
+ do_switch_frame (data->selected_frame, Qnil, 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 the buffer that is current now is the same
+ that was current before setting the window configuration,
+ don't alter its PT. */
+ if (old_point >= 0)
+ SET_PT (old_point);
}
/* Restore the minimum heights recorded in the configuration. */
window_min_height = XINT (data->min_height);
window_min_width = XINT (data->min_width);
- /* Fselect_window will have made f the selected frame, so we
- reselect the proper frame here. Fhandle_switch_frame will change the
- selected window too, but that doesn't make the call to
- Fselect_window above totally superfluous; it still sets f's
- selected window. */
- if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
- do_switch_frame (data->selected_frame, Qnil, 0);
-
- if (!NILP (new_current_buffer))
- Fset_buffer (new_current_buffer);
-
Vminibuf_scroll_window = data->minibuf_scroll_window;
- if (! NILP (Vwindow_configuration_change_hook)
- && ! NILP (Vrun_hooks))
- call1 (Vrun_hooks, Qwindow_configuration_change_hook);
-
- return (Qnil);
+ return (FRAME_LIVE_P (f) ? Qt : Qnil);
}
/* Mark all windows now on frame as deleted
return count;
}
+
+/* Fill vector FLAT with leaf windows under W, starting at index I.
+ Value is last index + 1. */
+
+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;
+}
+
+
+/* Return a pointer to the glyph W's physical cursor is on. Value is
+ null if W's current matrix is invalid, so that no meaningfull glyph
+ can be returned. */
+
+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;
if (EQ (window, selected_window))
{
p->pointm = Fmake_marker ();
- Fset_marker (p->pointm, BUF_PT (XBUFFER (w->buffer)),
- w->buffer);
+ 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);
FRAME_PTR f;
if (NILP (frame))
- f = selected_frame;
- else
- {
- CHECK_LIVE_FRAME (frame, 0);
- f = XFRAME (frame);
- }
+ frame = selected_frame;
+ CHECK_LIVE_FRAME (frame, 0);
+ f = XFRAME (frame);
n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
vec = allocate_vectorlike (VECSIZE (struct save_window_data));
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));
- XSETFRAME (data->selected_frame, selected_frame);
+ 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;
Restore which buffer appears in which window, where display starts,\n\
and the value of point and mark for each window.\n\
Also restore which buffer is current.\n\
-But do not preserve point in the current buffer.\n\
Does not restore the value of point in current buffer.")
(args)
Lisp_Object args;
val = Fprogn (args);
return unbind_to (count, val);
}
+
+\f
+/***********************************************************************
+ Marginal Areas
+ ***********************************************************************/
+
+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);
+
+ /* Check widths < 0 and translate a zero width to nil.
+ Margins that are too wide have to be checked elsewhere. */
+ 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);
+}
+
+
+\f
+/***********************************************************************
+ Smooth scrolling
+ ***********************************************************************/
+
+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 or omitted means use the selected window. VSCROLL is a\n\
+non-negative 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);
+
+ /* Adjust glyph matrix of the frame if the virtual display
+ area becomes larger than before. */
+ if (w->vscroll < 0 && w->vscroll < old_dy)
+ adjust_glyphs (f);
+
+ /* Prevent redisplay shortcuts. */
+ XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+ }
+
+ return Fwindow_vscroll (window);
+}
+
+\f
+/* Call FN for all leaf windows on frame F. FN is called with the
+ first argument being a pointer to the leaf window, and with
+ additional arguments A1..A4. */
+
+void
+foreach_window (f, fn, a1, a2, a3, a4)
+ struct frame *f;
+ void (* fn) ();
+ int a1, a2, a3, a4;
+{
+ foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, a1, a2, a3, a4);
+}
+
+
+/* Helper function for foreach_window. Call FN for all leaf windows
+ reachable from W. FN is called with the first argument being a
+ pointer to the leaf window, and with additional arguments A1..A4. */
+
+static void
+foreach_window_1 (w, fn, a1, a2, a3, a4)
+ struct window *w;
+ void (* fn) ();
+ int a1, a2, a3, a4;
+{
+ while (w)
+ {
+ if (!NILP (w->hchild))
+ foreach_window_1 (XWINDOW (w->hchild), fn, a1, a2, a3, a4);
+ else if (!NILP (w->vchild))
+ foreach_window_1 (XWINDOW (w->vchild), fn, a1, a2, a3, a4);
+ else
+ fn (w, a1, a2, a3, a4);
+
+ w = NILP (w->next) ? 0 : XWINDOW (w->next);
+ }
+}
+
+
+/* Freeze or unfreeze the window start of W if unless it is a
+ mini-window or the selected window. FREEZE_P non-zero means freeze
+ the window start. */
+
+static void
+freeze_window_start (w, freeze_p)
+ struct window *w;
+ int freeze_p;
+{
+ if (w == XWINDOW (selected_window)
+ || MINI_WINDOW_P (w)
+ || (MINI_WINDOW_P (XWINDOW (selected_window))
+ && w == XWINDOW (Vminibuf_scroll_window)))
+ freeze_p = 0;
+
+ w->frozen_window_start_p = freeze_p;
+}
+
+
+/* Freeze or unfreeze the window starts of all leaf windows on frame
+ F, except the selected window and a mini-window. FREEZE_P non-zero
+ means freeze the window start. */
+
+void
+freeze_window_starts (f, freeze_p)
+ struct frame *f;
+ int freeze_p;
+{
+ foreach_window (f, freeze_window_start, freeze_p);
+}
+
+\f
+/***********************************************************************
+ Initialization
+ ***********************************************************************/
+
+/* Return 1 if window configurations C1 and C2
+ describe the same state of affairs. This is used by Fequal. */
+
+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;
+
+ 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;
+ /* Don't compare the current_window field directly.
+ Instead see w1_is_current and w2_is_current, below. */
+ 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;
+ /* Don't compare the root_window field.
+ We don't require the two configurations
+ to use the same window object,
+ and the two root windows must be equivalent
+ if everything else compares equal. */
+ 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;
+
+ /* Verify that the two confis have the same number of windows. */
+ 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);
+
+ /* Verify that the current windows in the two
+ configurations correspond to each other. */
+ 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;
+
+ /* Verify that the corresponding windows do match. */
+ 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->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;
+}
\f
+void
init_window_once ()
{
- selected_frame = make_terminal_frame ();
- XSETFRAME (Vterminal_frame, selected_frame);
- minibuf_window = selected_frame->minibuffer_window;
- selected_window = selected_frame->selected_window;
- last_nonminibuf_frame = selected_frame;
+ 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
syms_of_window ()
{
+ Qleft_bitmap_area = intern ("left-bitmap-area");
+ staticpro (&Qleft_bitmap_area);
+ Qright_bitmap_area = intern ("right-bitmap-area");
+ staticpro (&Qright_bitmap_area);
+
+ 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);
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'.");
+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,
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'.");
+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,
"*Delete any window less than this wide.");
window_min_width = 10;
- DEFVAR_BOOL ("scroll-preserve-screen-position",
- &scroll_preserve_screen_position,
+ DEFVAR_LISP ("scroll-preserve-screen-position",
+ &Vscroll_preserve_screen_position,
"*Nonzero means scroll commands move point to keep its screen line unchanged.");
- scroll_preserve_screen_position = 0;
+ 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 frae is the one whose configuration has changed.");
+The selected frame is the one whose configuration has changed.");
Vwindow_configuration_change_hook = Qnil;
- DEFVAR_BOOL ("frame-override-unsplittable", &frame_override_unsplittable,
- "Non-nil means allow splitting an `unsplittable' frame.\n\
-\(That means, a frame whise `unsplittable' parameter is non-nil.)\n\
-Packages such as Ispell that work by splitting the selected frame\n\
-can bind this, so that they will work when used in an unsplittable frame.");
-
defsubr (&Sselected_window);
defsubr (&Sminibuffer_window);
defsubr (&Swindow_minibuffer_p);
defsubr (&Srecenter);
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);
}
+void
keys_of_window ()
{
initial_define_key (control_x_map, '1', "delete-other-windows");