Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
+Lisp_Object Qscroll_up, Qscroll_down;
Lisp_Object Qwindow_size_fixed;
extern Lisp_Object Qleft_margin, Qright_margin;
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 size_window P_ ((Lisp_Object, int, int, int, int, int));
static int freeze_window_start P_ ((struct window *, void *));
static int window_fixed_size_p P_ ((struct window *, int, int));
static void enlarge_window P_ ((Lisp_Object, int, int));
int window_deletion_count;
+/* Used by the function window_scroll_pixel_based */
+
+static int window_scroll_pixel_based_preserve_y;
+
#if 0 /* This isn't used anywhere. */
/* Nonzero means we can split a frame even if it is "unsplittable". */
static int inhibit_frame_unsplittable;
|| WINDOW_RIGHTMOST_P (w))
{
if (!WINDOW_LEFTMOST_P (w) && abs (*x - x0) < grabbable_width)
- return ON_VERTICAL_BORDER;
+ {
+ /* Convert X and Y to window relative coordinates.
+ Vertical border is at the left edge of window. */
+ *x = max (0, *x - x0);
+ *y -= top_y;
+ return ON_VERTICAL_BORDER;
+ }
}
else
{
if (abs (*x - x1) < grabbable_width)
- return ON_VERTICAL_BORDER;
+ {
+ /* Convert X and Y to window relative coordinates.
+ Vertical border is at the right edge of window. */
+ *x = min (x1, *x) - x0;
+ *y -= top_y;
+ return ON_VERTICAL_BORDER;
+ }
}
if (*x < x0 || *x >= x1)
&& !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
&& !WINDOW_RIGHTMOST_P (w)
&& (abs (*x - right_x) < grabbable_width))
- return ON_VERTICAL_BORDER;
+ {
+ /* Convert X and Y to window relative coordinates.
+ Vertical border is at the right edge of window. */
+ *x = min (right_x, *x) - left_x;
+ *y -= top_y;
+ return ON_VERTICAL_BORDER;
+ }
}
else
{
{
/* On the border on the right side of the window? Assume that
this area begins at RIGHT_X minus a canonical char width. */
+ *x = min (right_x, *x) - left_x;
+ *y -= top_y;
return ON_VERTICAL_BORDER;
}
}
Lisp_Object frame, minibuf, window;
{
if (NILP (window))
- window = selected_window;
+ window = FRAMEP (frame) ? XFRAME (frame)->selected_window : selected_window;
+ CHECK_WINDOW (window);
if (NILP (frame))
frame = selected_frame;
`obj & 1' means consider only full-width windows.
`obj & 2' means consider also dedicated windows. */
if (((XINT (obj) & 1) && !WINDOW_FULL_WIDTH_P (w))
- || (!(XINT (obj) & 2) && EQ (w->dedicated, Qt))
+ || (!(XINT (obj) & 2) && !NILP (w->dedicated))
/* Minibuffer windows are always ignored. */
|| MINI_WINDOW_P (w))
break;
case GET_LARGEST_WINDOW:
{ /* nil `obj' means to ignore dedicated windows. */
/* Ignore dedicated windows and minibuffers. */
- if (MINI_WINDOW_P (w) || (NILP (obj) && EQ (w->dedicated, Qt)))
+ if (MINI_WINDOW_P (w) || (NILP (obj) && !NILP (w->dedicated)))
break;
if (NILP (best_window))
else
{
if (width_p)
- size = window_min_width;
+ size = max (window_min_width,
+ (MIN_SAFE_WINDOW_WIDTH
+ + WINDOW_FRINGE_COLS (w)
+ + WINDOW_SCROLL_BAR_COLS (w)));
else
{
if (MINI_WINDOW_P (w)
/* 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.
+ keep their proportionate size relative to WINDOW.
+
+ If FIRST_ONLY is 1, change only the first of WINDOW's children when
+ they are in series. If LAST_ONLY is 1, change only the last of
+ WINDOW's children when they are in series.
+
+ Propagate WINDOW's top or left edge position to children. Delete
+ windows that become too small unless NODELETE_P is non-zero.
If NODELETE_P is 2, that means we do delete windows that are
too small, even if they were too small before! */
static void
-size_window (window, size, width_p, nodelete_p)
+size_window (window, size, width_p, nodelete_p, first_only, last_only)
Lisp_Object window;
int size, width_p, nodelete_p;
+ int first_only, last_only;
{
struct window *w = XWINDOW (window);
struct window *c;
if (!NILP (*sideward))
{
+ /* We have a chain of parallel siblings whose size should all change. */
for (child = *sideward; !NILP (child); child = c->next)
{
c = XWINDOW (child);
c->left_col = w->left_col;
else
c->top_line = w->top_line;
- size_window (child, size, width_p, nodelete_p);
+ size_window (child, size, width_p, nodelete_p,
+ first_only, last_only);
+ }
+ }
+ else if (!NILP (*forward) && last_only)
+ {
+ /* Change the last in a series of siblings. */
+ Lisp_Object last_child;
+ int child_size;
+
+ for (child = *forward; !NILP (child); child = c->next)
+ {
+ c = XWINDOW (child);
+ last_child = child;
}
+
+ child_size = XINT (width_p ? c->total_cols : c->total_lines);
+ size_window (last_child,
+ size - old_size + child_size,
+ width_p, nodelete_p, first_only, last_only);
+ }
+ else if (!NILP (*forward) && first_only)
+ {
+ /* Change the first in a series of siblings. */
+ int child_size;
+
+ child = *forward;
+ c = XWINDOW (child);
+
+ if (width_p)
+ c->left_col = w->left_col;
+ else
+ c->top_line = w->top_line;
+
+ child_size = XINT (width_p ? c->total_cols : c->total_lines);
+ size_window (child,
+ size - old_size + child_size,
+ width_p, nodelete_p, first_only, last_only);
}
else if (!NILP (*forward))
{
int last_pos, first_pos, nchildren, total;
int *new_sizes = NULL;
- /* Determine the fixed-size portion of the this window, and the
+ /* Determine the fixed-size portion of this window, and the
number of child windows. */
fixed_size = nchildren = nfixed = total = 0;
for (child = *forward; !NILP (child); child = c->next, ++nchildren)
/* 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);
+ size_window (child, new_size, width_p, 1, first_only, last_only);
/* Remember the bottom/right edge position of this child; it
will be used to set the top/left edge of the next child. */
int child_size;
c = XWINDOW (child);
child_size = width_p ? XINT (c->total_cols) : XINT (c->total_lines);
- size_window (child, child_size, width_p, 2);
+ size_window (child, child_size, width_p, 2, first_only, last_only);
}
}
}
int height;
int nodelete;
{
- size_window (window, height, 0, nodelete);
+ size_window (window, height, 0, nodelete, 0, 0);
}
int width;
int nodelete;
{
- size_window (window, width, 1, nodelete);
+ size_window (window, width, 1, nodelete, 0, 0);
}
/* Change window heights in windows rooted in WINDOW by N lines. */
The variables `special-display-buffer-names',
`special-display-regexps', `same-window-buffer-names', and
`same-window-regexps' customize how certain buffer names are handled.
-The latter two take effect only if NOT-THIS-WINDOW is t.
+The latter two take effect only if NOT-THIS-WINDOW is nil.
If optional argument FRAME is `visible', search all visible frames.
If FRAME is 0, search all visible and iconified frames.
DEFUN ("force-window-update", Fforce_window_update, Sforce_window_update,
0, 1, 0,
- doc: /* Force redisplay of all windows.
+ doc: /* Force all windows to be updated on next redisplay.
If optional arg OBJECT is a window, force redisplay of that window only.
If OBJECT is a buffer or buffer name, force redisplay of all windows
displaying that buffer. */)
Interactively, all arguments are nil.
Returns the newly created window (which is the lower or rightmost one).
-The upper or leftmost window is the original one and remains selected.
+The upper or leftmost window is the original one, and remains selected
+if it was selected before.
+
See Info node `(elisp)Splitting Windows' for more details and examples.*/)
(window, size, horflag)
Lisp_Object window, size, horflag;
while (1)
{
+ Lisp_Object first_parallel = Qnil;
+
+ if (NILP (window))
+ {
+ /* This happens if WINDOW on the previous iteration was
+ at top level of the window tree. */
+ Fset_window_configuration (old_config);
+ error ("Specified window edge is fixed");
+ }
+
p = XWINDOW (window);
parent = p->parent;
- /* Make sure there is a following window. */
- if (NILP (parent)
- && (horiz_flag ? 1
- : NILP (XWINDOW (window)->next)))
+ /* See if this level has windows in parallel in the specified
+ direction. If so, set FIRST_PARALLEL to the first one. */
+ if (horiz_flag)
+ {
+ if (! NILP (parent) && !NILP (XWINDOW (parent)->vchild))
+ first_parallel = XWINDOW (parent)->vchild;
+ else if (NILP (parent) && !NILP (p->next))
+ {
+ /* Handle the vertical chain of main window and minibuffer
+ which has no parent. */
+ first_parallel = window;
+ while (! NILP (XWINDOW (first_parallel)->prev))
+ first_parallel = XWINDOW (first_parallel)->prev;
+ }
+ }
+ else
+ {
+ if (! NILP (parent) && !NILP (XWINDOW (parent)->hchild))
+ first_parallel = XWINDOW (parent)->hchild;
+ }
+
+ /* If this level's succession is in the desired dimension,
+ and this window is the last one, and there is no higher level,
+ its trailing edge is fixed. */
+ if (NILP (XWINDOW (window)->next) && NILP (first_parallel)
+ && NILP (parent))
{
Fset_window_configuration (old_config);
- error ("No other window following this one");
+ error ("Specified window edge is fixed");
}
/* Don't make this window too small. */
XINT (CURSIZE (window)) + delta);
/* If this window has following siblings in the desired dimension,
- make them smaller.
+ make them smaller, and exit the loop.
+
(If we reach the top of the tree and can never do this,
we will fail and report an error, above.) */
- if (horiz_flag
- ? !NILP (XWINDOW (parent)->hchild)
- : !NILP (XWINDOW (parent)->vchild))
+ if (NILP (first_parallel))
{
- if (!NILP (XWINDOW (window)->next))
+ if (!NILP (p->next))
{
/* This may happen for the minibuffer. In that case
the window_deletion_count check below does not work. */
XSETINT (CURBEG (p->next),
XINT (CURBEG (p->next)) + delta);
size_window (p->next, XINT (CURSIZE (p->next)) - delta,
- horiz_flag, 0);
+ horiz_flag, 0, 1, 0);
break;
}
}
else
/* Here we have a chain of parallel siblings, in the other dimension.
Change the size of the other siblings. */
- for (child = (horiz_flag
- ? XWINDOW (parent)->vchild
- : XWINDOW (parent)->hchild);
+ for (child = first_parallel;
! NILP (child);
child = XWINDOW (child)->next)
if (! EQ (child, window))
size_window (child, XINT (CURSIZE (child)) + delta,
- horiz_flag, 0);
+ horiz_flag, 0, 0, 1);
window = parent;
}
struct text_pos start;
Lisp_Object tem;
int this_scroll_margin;
- int preserve_y;
/* True if we fiddled the window vscroll field without really scrolling. */
int vscrolled = 0;
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;
+ /* We preserve the goal pixel coordinate across consecutive
+ calls to scroll-up or scroll-down. This avoids the
+ possibility of point becoming "stuck" on a tall line when
+ scrolling by one line. */
+ if (window_scroll_pixel_based_preserve_y < 0
+ || (!EQ (current_kboard->Vlast_command, Qscroll_up)
+ && !EQ (current_kboard->Vlast_command, Qscroll_down)))
+ {
+ start_display (&it, w, start);
+ move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+ window_scroll_pixel_based_preserve_y = it.current_y;
+ }
}
else
- preserve_y = -1;
+ window_scroll_pixel_based_preserve_y = -1;
/* Move iterator it from start the specified distance forward or
backward. The result is the new window start. */
{
if (it.current_y < it.last_visible_y
&& (it.current_y + it.max_ascent + it.max_descent
- >= it.last_visible_y))
+ > it.last_visible_y))
{
/* The last line was only partially visible, make it fully
visible. */
}
else if (noerror)
return;
+ else if (n < 0) /* could happen with empty buffers */
+ xsignal0 (Qbeginning_of_buffer);
else
- Fsignal (Qend_of_buffer, Qnil);
+ xsignal0 (Qend_of_buffer);
}
else
{
else if (noerror)
return;
else
- Fsignal (Qbeginning_of_buffer, Qnil);
+ xsignal0 (Qbeginning_of_buffer);
}
/* If control gets here, then we vscrolled. */
|| EQ (Vscroll_preserve_screen_position, Qt)))
/* We found PT at a legitimate height. Leave it alone. */
;
- else if (preserve_y >= 0)
+ else if (window_scroll_pixel_based_preserve_y >= 0)
{
/* If we have a header line, take account of it.
This is necessary because we set it.current_y to 0, above. */
- if (WINDOW_WANTS_HEADER_LINE_P (w))
- preserve_y -= CURRENT_HEADER_LINE_HEIGHT (w);
-
- move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
+ move_it_to (&it, -1, -1,
+ window_scroll_pixel_based_preserve_y
+ - (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0 ),
+ -1, MOVE_TO_Y);
SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
}
else
int charpos, bytepos;
int partial_p;
- /* Save our position, for the preserve_y case. */
+ /* Save our position, for the
+ window_scroll_pixel_based_preserve_y case. */
charpos = IT_CHARPOS (it);
bytepos = IT_BYTEPOS (it);
|| EQ (Vscroll_preserve_screen_position, Qt)))
/* We found PT before we found the display margin, so PT is ok. */
;
- else if (preserve_y >= 0)
+ else if (window_scroll_pixel_based_preserve_y >= 0)
{
SET_TEXT_POS_FROM_MARKER (start, w->start);
start_display (&it, w, start);
-#if 0 /* It's wrong to subtract this here
- because we called start_display again
- and did not alter it.current_y this time. */
-
- /* If we have a header line, take account of it. */
- if (WINDOW_WANTS_HEADER_LINE_P (w))
- preserve_y -= CURRENT_HEADER_LINE_HEIGHT (w);
-#endif
-
- move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
+ /* It would be wrong to subtract CURRENT_HEADER_LINE_HEIGHT
+ here because we called start_display again and did not
+ alter it.current_y this time. */
+ move_it_to (&it, -1, -1, window_scroll_pixel_based_preserve_y, -1,
+ MOVE_TO_Y);
SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
}
else
if (noerror)
return;
else
- Fsignal (Qbeginning_of_buffer, Qnil);
+ xsignal0 (Qbeginning_of_buffer);
}
if (pos < ZV)
if (noerror)
return;
else
- Fsignal (Qend_of_buffer, Qnil);
+ xsignal0 (Qend_of_buffer);
}
}
Lisp_Object left_margin_cols, right_margin_cols;
Lisp_Object left_fringe_width, right_fringe_width, fringes_outside_margins;
Lisp_Object scroll_bar_width, vertical_scroll_bar_type;
+ Lisp_Object dedicated;
};
#define SAVED_WINDOW_N(swv,n) \
(object)
Lisp_Object object;
{
- if (WINDOW_CONFIGURATIONP (object))
- return Qt;
- return Qnil;
+ return WINDOW_CONFIGURATIONP (object) ? Qt : Qnil;
}
DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
register struct save_window_data *data;
struct Lisp_Vector *saved_windows;
- if (! WINDOW_CONFIGURATIONP (config))
- wrong_type_argument (Qwindow_configuration_p, config);
+ CHECK_WINDOW_CONFIGURATION (config);
data = (struct save_window_data *) XVECTOR (config);
saved_windows = XVECTOR (data->saved_windows);
FRAME_PTR f;
int old_point = -1;
- while (!WINDOW_CONFIGURATIONP (configuration))
- wrong_type_argument (Qwindow_configuration_p, configuration);
+ CHECK_WINDOW_CONFIGURATION (configuration);
data = (struct save_window_data *) XVECTOR (configuration);
saved_windows = XVECTOR (data->saved_windows);
w->fringes_outside_margins = p->fringes_outside_margins;
w->scroll_bar_width = p->scroll_bar_width;
w->vertical_scroll_bar_type = p->vertical_scroll_bar_type;
+ w->dedicated = p->dedicated;
XSETFASTINT (w->last_modified, 0);
XSETFASTINT (w->last_overlay_modified, 0);
p->fringes_outside_margins = w->fringes_outside_margins;
p->scroll_bar_width = w->scroll_bar_width;
p->vertical_scroll_bar_type = w->vertical_scroll_bar_type;
+ p->dedicated = w->dedicated;
if (!NILP (w->buffer))
{
/* Save w's value of point in the window configuration.
CHECK_NATNUM (left_width);
if (!NILP (right_width))
CHECK_NATNUM (right_width);
-
- if (!EQ (w->left_fringe_width, left_width)
- || !EQ (w->right_fringe_width, right_width)
- || !EQ (w->fringes_outside_margins, outside_margins))
+
+ /* Do nothing on a tty. */
+ if (FRAME_WINDOW_P (WINDOW_XFRAME (w))
+ && (!EQ (w->left_fringe_width, left_width)
+ || !EQ (w->right_fringe_width, right_width)
+ || !EQ (w->fringes_outside_margins, outside_margins)))
{
w->left_fringe_width = left_width;
w->right_fringe_width = right_width;
Lisp_Object window;
{
struct window *w = decode_window (window);
+
return Fcons (make_number (WINDOW_LEFT_FRINGE_WIDTH (w)),
Fcons (make_number (WINDOW_RIGHT_FRINGE_WIDTH (w)),
- Fcons ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) ?
- Qt : Qnil), Qnil)));
+ Fcons ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+ ? Qt : Qnil), Qnil)));
}
int (* fn) P_ ((struct window *, void *));
void *user_data;
{
- foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data);
+ /* Fdelete_frame may set FRAME_ROOT_WINDOW (f) to Qnil. */
+ if (WINDOWP (FRAME_ROOT_WINDOW (f)))
+ foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data);
}
struct Lisp_Vector *sw1, *sw2;
int i;
- if (!WINDOW_CONFIGURATIONP (c1))
- wrong_type_argument (Qwindow_configuration_p, c1);
- if (!WINDOW_CONFIGURATIONP (c2))
- wrong_type_argument (Qwindow_configuration_p, c2);
+ CHECK_WINDOW_CONFIGURATION (c1);
+ CHECK_WINDOW_CONFIGURATION (c2);
d1 = (struct save_window_data *) XVECTOR (c1);
d2 = (struct save_window_data *) XVECTOR (c2);
void
syms_of_window ()
{
+ Qscroll_up = intern ("scroll-up");
+ staticpro (&Qscroll_up);
+
+ Qscroll_down = intern ("scroll-down");
+ staticpro (&Qscroll_down);
+
Qwindow_size_fixed = intern ("window-size-fixed");
staticpro (&Qwindow_size_fixed);
Fset (Qwindow_size_fixed, Qnil);
minibuf_selected_window = Qnil;
staticpro (&minibuf_selected_window);
+ window_scroll_pixel_based_preserve_y = -1;
+
DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
doc: /* Non-nil means call as function to display a help buffer.
The function is called with one argument, the buffer to be displayed.
next_screen_context_lines = 2;
DEFVAR_INT ("split-height-threshold", &split_height_threshold,
- doc: /* *A window must be at least this tall to be eligible for splitting by `display-buffer'.
+ doc: /* *A window must be at least this tall to be eligible for splitting
+by `display-buffer'. The value is in line units.
If there is only one window, it is split regardless of this value. */);
split_height_threshold = 500;
DEFVAR_INT ("window-min-height", &window_min_height,
- doc: /* *Delete any window less than this tall (including its mode line). */);
+ doc: /* *Delete any window less than this tall (including its mode line).
+The value is in line units. */);
window_min_height = 4;
DEFVAR_INT ("window-min-width", &window_min_width,
- doc: /* *Delete any window less than this wide. */);
+ doc: /* *Delete any window less than this wide (measured in characters). */);
window_min_width = 10;
DEFVAR_LISP ("scroll-preserve-screen-position",