/* 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;
+
#define min(a, b) ((a) < (b) ? (a) : (b))
+extern int scroll_margin;
+
extern Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
\f
DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
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, 0,
+ posint, height, - (1 << (BITS_PER_SHORT - 1)),
window_internal_width (w) - 1,
hscroll, 0, w);
"Remove WINDOW from the display. Default is selected window.")
(window)
register Lisp_Object window;
+{
+ delete_window (window);
+
+ if (! NILP (Vwindow_configuration_change_hook)
+ && ! NILP (Vrun_hooks))
+ call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+
+ return Qnil;
+}
+
+delete_window (window)
+ register Lisp_Object window;
{
register Lisp_Object tem, parent, sib;
register struct window *p;
if (NILP (p->buffer)
&& NILP (p->hchild)
&& NILP (p->vchild))
- return Qnil;
+ return;
parent = p->parent;
if (NILP (parent))
/* Mark this window as deleted. */
p->buffer = p->hchild = p->vchild = Qnil;
-
- return Qnil;
}
\f
Fset_marker (w->start, make_number (pos.bufpos), w->buffer);
w->start_at_line_beg = ((pos.bufpos == BEGV
- || FETCH_CHAR (pos.bufpos - 1) == '\n') ? Qt
+ || FETCH_BYTE (pos.bufpos - 1) == '\n') ? Qt
: Qnil);
/* We need to do this, so that the window-scroll-functions
get called. */
&& ! NILP (w->parent)
&& height < window_min_height)
{
- Fdelete_window (window);
+ delete_window (window);
return;
}
if (!nodelete && width < window_min_width && !NILP (w->parent))
{
- Fdelete_window (window);
+ delete_window (window);
return;
}
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);
XSETFASTINT (w->window_end_pos, 0);
w->window_end_valid = Qnil;
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);
return Qnil;
&& 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. */
other = lower = XWINDOW (window)->next, upper = window;
if (!NILP (other)
/* Check that OTHER and WINDOW are vertically arrayed. */
- && XWINDOW (other)->top != XWINDOW (window)->top
- && XWINDOW (other)->height > XWINDOW (window)->height)
+ && !EQ (XWINDOW (other)->top, XWINDOW (window)->top)
+ && (XFASTINT (XWINDOW (other)->height)
+ > XFASTINT (XWINDOW (window)->height)))
{
- int total = XWINDOW (other)->height + XWINDOW (window)->height;
+ 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 - XWINDOW (upper)->height, 0);
+ change_window_height ((total / 2
+ - XFASTINT (XWINDOW (upper)->height)),
+ 0);
selected_window = old_selected_window;
}
}
if (MINI_WINDOW_P (o))
error ("Attempt to split minibuffer window");
- else if (FRAME_NO_SPLIT_P (fo))
+ else if (FRAME_NO_SPLIT_P (fo) && ! frame_override_unsplittable)
error ("Attempt to split unsplittable frame");
check_min_window_sizes ();
p->parent = o->parent;
p->buffer = Qt;
- Fset_window_buffer (new, o->buffer);
-
/* Apportion the available frame space among the two new windows */
if (!NILP (horflag))
XSETFASTINT (p->top, XFASTINT (o->top) + size_int);
}
+ Fset_window_buffer (new, o->buffer);
+
return new;
}
\f
{
CHECK_NUMBER (arg, 0);
change_window_height (XINT (arg), !NILP (side));
+
+ if (! NILP (Vwindow_configuration_change_hook))
+ call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+
return Qnil;
}
{
CHECK_NUMBER (arg, 0);
change_window_height (-XINT (arg), !NILP (side));
+
+ if (! NILP (Vwindow_configuration_change_hook))
+ call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+
return Qnil;
}
register int (*setsizefun) () = (widthflag
? set_window_width
: set_window_height);
+ int maximum;
+ Lisp_Object next, prev;
check_min_window_sizes ();
if (*sizep + delta < MINSIZE (window))
{
- Fdelete_window (window);
+ delete_window (window);
return;
}
if (delta == 0)
return;
- if (!NILP (p->next)
- && (*sizefun) (p->next) - delta >= MINSIZE (p->next))
- {
- (*setsizefun) (p->next, (*sizefun) (p->next) - delta, 0);
- (*setsizefun) (window, *sizep + delta, 0);
- CURBEG (p->next) += delta;
- /* This does not change size of p->next,
- but it propagates the new top edge to its children */
- (*setsizefun) (p->next, (*sizefun) (p->next), 0);
- }
- else if (!NILP (p->prev)
- && (*sizefun) (p->prev) - delta >= MINSIZE (p->prev))
+ /* 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);
+ for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
+ maximum += (*sizefun) (prev) - MINSIZE (prev);
+
+ /* If we can get it all from them, do so. */
+ if (delta < maximum)
{
- (*setsizefun) (p->prev, (*sizefun) (p->prev) - delta, 0);
- CURBEG (window) -= delta;
- (*setsizefun) (window, *sizep + delta, 0);
+ Lisp_Object first_unaffected;
+ Lisp_Object first_affected;
+
+ next = p->next;
+ prev = p->prev;
+ first_affected = window;
+ /* 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)
+ {
+ 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);
+
+ 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;
+ prev = XWINDOW (prev)->prev;
+ }
+ }
+
+ /* Now recalculate the edge positions of all the windows affected,
+ based on the new sizes. */
+ first_unaffected = next;
+ prev = first_affected;
+ for (next = XWINDOW (prev)->next; ! EQ (next, first_unaffected);
+ prev = next, next = XWINDOW (next)->next)
+ {
+ CURBEG (next) = CURBEG (prev) + (*sizefun) (prev);
+ /* This does not change size of NEXT,
+ but it propagates the new top edge to its children */
+ (*setsizefun) (next, (*sizefun) (next), 0);
+ }
}
else
{
}
-/* Scroll contents of window WINDOW up N lines. */
+/* Scroll contents of window WINDOW up N lines.
+ If WHOLE is nonzero, it means scroll N screenfuls instead. */
-void
-window_scroll (window, n, noerror)
+static void
+window_scroll (window, n, whole, noerror)
Lisp_Object window;
int n;
+ int whole;
int noerror;
{
register struct window *w = XWINDOW (window);
register Lisp_Object tem;
int lose;
Lisp_Object bolp, nmoved;
+ int startpos;
+ struct position posit;
+ int original_vpos;
- /* Always set force_start so that redisplay_window will run
- the window-scroll-functions. */
- w->force_start = Qt;
+ startpos = marker_position (w->start);
+
+ posit = *compute_motion (startpos, 0, 0, 0,
+ PT, ht, 0,
+ window_internal_width (w), XINT (w->hscroll),
+ 0, w);
+ original_vpos = posit.vpos;
XSETFASTINT (tem, PT);
tem = Fpos_visible_in_window_p (tem, window);
if (NILP (tem))
{
Fvertical_motion (make_number (- (ht / 2)), window);
- XSETFASTINT (tem, PT);
- Fset_marker (w->start, tem, w->buffer);
+ startpos = PT;
}
- SET_PT (marker_position (w->start));
+ SET_PT (startpos);
lose = n < 0 && PT == BEGV;
Fvertical_motion (make_number (n), window);
pos = PT;
if (pos < ZV)
{
- extern int scroll_margin;
-
int this_scroll_margin = scroll_margin;
/* Don't use a scroll margin that is negative or too large. */
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;
- /* If we scrolled forward, put point enough lines down
- that it is outside the scroll margin. */
- if (n > 0 && this_scroll_margin > 0)
+ if (whole && scroll_preserve_screen_position)
{
SET_PT (pos);
- Fvertical_motion (make_number (this_scroll_margin), window);
- pos = PT;
+ Fvertical_motion (make_number (original_vpos), window);
}
-
- if (pos > opoint)
+ /* If we scrolled forward, put point enough lines down
+ that it is outside the scroll margin. */
+ else if (n > 0)
{
- SET_PT (pos);
+ int top_margin;
+
+ if (this_scroll_margin > 0)
+ {
+ SET_PT (pos);
+ Fvertical_motion (make_number (this_scroll_margin), window);
+ top_margin = PT;
+ }
+ else
+ top_margin = pos;
+
+ if (top_margin <= opoint)
+ SET_PT (opoint);
+ else if (scroll_preserve_screen_position)
+ {
+ SET_PT (pos);
+ Fvertical_motion (make_number (original_vpos), window);
+ }
+ else
+ SET_PT (pos);
}
- if (n < 0)
+ else if (n < 0)
{
+ int bottom_margin;
+
/* If we scrolled backward, put point near the end of the window
but not within the scroll margin. */
SET_PT (pos);
tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
- if (PT > opoint || XFASTINT (tem) < ht - this_scroll_margin)
+ if (XFASTINT (tem) == ht - this_scroll_margin)
+ bottom_margin = PT;
+ else
+ bottom_margin = PT + 1;
+
+ if (bottom_margin > opoint)
SET_PT (opoint);
else
- Fvertical_motion (make_number (-1), window);
+ {
+ if (scroll_preserve_screen_position)
+ {
+ SET_PT (pos);
+ Fvertical_motion (make_number (original_vpos), window);
+ }
+ else
+ Fvertical_motion (make_number (-1), window);
+ }
}
}
else
defalt = direction * (defalt < 1 ? 1 : defalt);
if (NILP (n))
- window_scroll (selected_window, defalt, 0);
+ window_scroll (selected_window, defalt, 1, 0);
else if (EQ (n, Qminus))
- window_scroll (selected_window, - defalt, 0);
+ window_scroll (selected_window, - defalt, 1, 0);
else
{
n = Fprefix_numeric_value (n);
- window_scroll (selected_window, XINT (n) * direction, 0);
+ window_scroll (selected_window, XINT (n) * direction, 0, 0);
}
unbind_to (count, Qnil);
SET_PT (marker_position (w->pointm));
if (NILP (arg))
- window_scroll (window, defalt, 1);
+ window_scroll (window, defalt, 1, 1);
else if (EQ (arg, Qminus))
- window_scroll (window, -defalt, 1);
+ window_scroll (window, -defalt, 1, 1);
else
{
if (CONSP (arg))
arg = Fcar (arg);
CHECK_NUMBER (arg, 0);
- window_scroll (window, XINT (arg), 1);
+ window_scroll (window, XINT (arg), 0, 1);
}
Fset_marker (w->pointm, make_number (PT), Qnil);
Fset_marker (w->start, make_number (pos.bufpos), w->buffer);
w->start_at_line_beg = ((pos.bufpos == BEGV
- || FETCH_CHAR (pos.bufpos - 1) == '\n')
+ || FETCH_BYTE (pos.bufpos - 1) == '\n')
? Qt : Qnil);
w->force_start = 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)
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);
}
syms_of_window ()
{
+ staticpro (&Qwindow_configuration_change_hook);
+ Qwindow_configuration_change_hook
+ = intern ("window-configuration-change-hook");
+
Qwindowp = intern ("windowp");
staticpro (&Qwindowp);
"*Delete any window less than this wide.");
window_min_width = 10;
+ DEFVAR_BOOL ("scroll-preserve-screen-position",
+ &scroll_preserve_screen_position,
+ "*Nonzero means scroll commands move point to keep its screen line unchanged.");
+ scroll_preserve_screen_position = 0;
+
+ 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.");
+ 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);