Add 2012 to FSF copyright years for Emacs files (do not merge to trunk)
[bpt/emacs.git] / src / window.c
CommitLineData
7ab12479
JB
1/* Window creation, deletion and examination for GNU Emacs.
2 Does not include redisplay.
203eb0aa 3 Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1996, 1997, 1998, 2000,
49f70d46 4 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
8cabe764 5 Free Software Foundation, Inc.
7ab12479
JB
6
7This file is part of GNU Emacs.
8
9ec0b715 9GNU Emacs is free software: you can redistribute it and/or modify
7ab12479 10it under the terms of the GNU General Public License as published by
9ec0b715
GM
11the Free Software Foundation, either version 3 of the License, or
12(at your option) any later version.
7ab12479
JB
13
14GNU Emacs is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
9ec0b715 20along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
7ab12479 21
18160b98 22#include <config.h>
4d553a13 23#include <stdio.h>
d7306fe6 24#include <setjmp.h>
4d553a13 25
7ab12479
JB
26#include "lisp.h"
27#include "buffer.h"
3e4731a3 28#include "keyboard.h"
e35f6ff7 29#include "keymap.h"
44fa5b1e 30#include "frame.h"
7ab12479
JB
31#include "window.h"
32#include "commands.h"
33#include "indent.h"
34#include "termchar.h"
35#include "disptab.h"
dfcf069d 36#include "dispextern.h"
5500c422
GM
37#include "blockinput.h"
38#include "intervals.h"
de509a60 39#include "termhooks.h" /* For FRAME_TERMINAL. */
5500c422 40
6d55d620 41#ifdef HAVE_X_WINDOWS
dfcf069d 42#include "xterm.h"
5500c422 43#endif /* HAVE_X_WINDOWS */
8f23f280
AI
44#ifdef WINDOWSNT
45#include "w32term.h"
46#endif
1e3c8885
EZ
47#ifdef MSDOS
48#include "msdos.h"
49#endif
edfda783
AR
50#ifdef HAVE_NS
51#include "nsterm.h"
52#endif
5500c422 53
5500c422 54
3f8ab7bd 55Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
87478b52 56Lisp_Object Qdisplay_buffer;
c525d842 57Lisp_Object Qscroll_up, Qscroll_down;
90647b07 58Lisp_Object Qwindow_size_fixed;
87478b52 59
49b996e7 60extern Lisp_Object Qleft_margin, Qright_margin;
7ab12479 61
521b203e 62static int displayed_window_lines P_ ((struct window *));
5e14b1fc 63static struct window *decode_window P_ ((Lisp_Object));
5500c422
GM
64static int count_windows P_ ((struct window *));
65static int get_leaf_windows P_ ((struct window *, struct window **, int));
66static void window_scroll P_ ((Lisp_Object, int, int, int));
67static void window_scroll_pixel_based P_ ((Lisp_Object, int, int, int));
68static void window_scroll_line_based P_ ((Lisp_Object, int, int, int));
047aaeb9
MR
69static int window_min_size_1 P_ ((struct window *, int, int));
70static int window_min_size_2 P_ ((struct window *, int, int));
71static int window_min_size P_ ((struct window *, int, int, int, int *));
5fe0b054 72static void size_window P_ ((Lisp_Object, int, int, int, int, int));
f95464e4 73static int freeze_window_start P_ ((struct window *, void *));
f984d4fc 74static int window_fixed_size_p P_ ((struct window *, int, int));
56ebfae2 75static void enlarge_window P_ ((Lisp_Object, int, int));
67492200 76static Lisp_Object window_list P_ ((void));
f95464e4 77static int add_window_to_list P_ ((struct window *, void *));
118ea242
GM
78static int candidate_window_p P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
79 Lisp_Object));
67492200
GM
80static Lisp_Object next_window P_ ((Lisp_Object, Lisp_Object,
81 Lisp_Object, int));
82static void decode_next_window_args P_ ((Lisp_Object *, Lisp_Object *,
83 Lisp_Object *));
f95464e4
GM
84static int foreach_window_1 P_ ((struct window *,
85 int (* fn) (struct window *, void *),
86 void *));
cd2904bd 87static Lisp_Object window_list_1 P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
bd2a4b24 88static Lisp_Object select_window P_ ((Lisp_Object, Lisp_Object, int));
b7354ddf 89
7ab12479
JB
90/* This is the window in which the terminal's cursor should
91 be left when nothing is being done with it. This must
92 always be a leaf window, and its buffer is selected by
93 the top level editing loop at the end of each command.
94
95 This value is always the same as
44fa5b1e 96 FRAME_SELECTED_WINDOW (selected_frame). */
7ab12479
JB
97
98Lisp_Object selected_window;
99
67492200
GM
100/* A list of all windows for use by next_window and Fwindow_list.
101 Functions creating or deleting windows should invalidate this cache
102 by setting it to nil. */
103
104Lisp_Object Vwindow_list;
105
5500c422
GM
106/* The mini-buffer window of the selected frame.
107 Note that you cannot test for mini-bufferness of an arbitrary window
108 by comparing against this; but you can test for mini-bufferness of
7ab12479 109 the selected window. */
5500c422 110
7ab12479
JB
111Lisp_Object minibuf_window;
112
3f49fddc
KS
113/* Non-nil means it is the window whose mode line should be
114 shown as the selected window when the minibuffer is selected. */
115
3dbab091 116Lisp_Object minibuf_selected_window;
3f49fddc 117
7ab12479 118/* Non-nil means it is the window for C-M-v to scroll
5500c422
GM
119 when the mini-buffer is selected. */
120
7ab12479
JB
121Lisp_Object Vminibuf_scroll_window;
122
123/* Non-nil means this is the buffer whose window C-M-v should scroll. */
5500c422 124
7ab12479
JB
125Lisp_Object Vother_window_scroll_buffer;
126
7ab12479 127/* Non-nil means it's function to call to display temp buffers. */
5500c422 128
7ab12479
JB
129Lisp_Object Vtemp_buffer_show_function;
130
e56263e5
KS
131/* Non-zero means line and page scrolling on tall lines (with images)
132 does partial scrolling by modifying window-vscroll. */
133
134int auto_window_vscroll_p;
135
cc91894c
KS
136/* Non-zero means to use mode-line-inactive face in all windows but the
137 selected-window and the minibuffer-scroll-window when the
138 minibuffer is active. */
139int mode_line_in_non_selected_windows;
26124d5e 140
7ab12479 141/* If a window gets smaller than either of these, it is removed. */
5500c422 142
31ade731
SM
143EMACS_INT window_min_height;
144EMACS_INT window_min_width;
7ab12479 145
a58ec57d 146/* Hook run at end of temp_output_buffer_show. */
5500c422 147
a58ec57d
RS
148Lisp_Object Qtemp_buffer_show_hook;
149
7ab12479 150/* Number of lines of continuity in scrolling by screenfuls. */
5500c422 151
31ade731 152EMACS_INT next_screen_context_lines;
7ab12479
JB
153
154/* Incremented for each window created. */
5500c422 155
7ab12479
JB
156static int sequence_number;
157
5b03d3c0 158/* Nonzero after init_window_once has finished. */
5500c422 159
5b03d3c0
RS
160static int window_initialized;
161
543f5fb1 162/* Hook to run when window config changes. */
5500c422 163
eeca6f6f
SM
164static Lisp_Object Qwindow_configuration_change_hook;
165static Lisp_Object Vwindow_configuration_change_hook;
543f5fb1 166
d0c38d63 167/* Non-nil means scroll commands try to put point
9317a85d 168 at the same screen height as previously. */
9317a85d 169
5500c422
GM
170Lisp_Object Vscroll_preserve_screen_position;
171
a1562258
SM
172/* Non-nil means that text is inserted before window's markers. */
173
174Lisp_Object Vwindow_point_insertion_type;
175
0d384044
RS
176/* Incremented by 1 whenever a window is deleted. */
177
178int window_deletion_count;
179
66d43aea
LT
180/* Used by the function window_scroll_pixel_based */
181
c876b227 182static int window_scroll_pixel_based_preserve_x;
66fe93d1 183static int window_scroll_pixel_based_preserve_y;
66d43aea 184
c876b227
SM
185/* Same for window_scroll_line_based. */
186
187static int window_scroll_preserve_hpos;
188static int window_scroll_preserve_vpos;
189
31ade731 190extern EMACS_INT scroll_margin;
9317a85d 191
dba06815 192extern Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
666e158e
MB
193
194/* If non-nil, then the `recenter' command with a nil argument
195 the entire frame to be redrawn; the special value `tty' causes the
196 frame to be redrawn only if it is a tty frame. */
197
198static Lisp_Object Vrecenter_redisplay;
199extern Lisp_Object Qtty;
200
7ab12479
JB
201\f
202DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
23fe745a 203 doc: /* Return t if OBJECT is a window. */)
fdb82f93 204 (object)
413430c5 205 Lisp_Object object;
7ab12479 206{
413430c5 207 return WINDOWP (object) ? Qt : Qnil;
7ab12479
JB
208}
209
806b4d9b 210DEFUN ("window-live-p", Fwindow_live_p, Swindow_live_p, 1, 1, 0,
23fe745a 211 doc: /* Return t if OBJECT is a window which is currently visible. */)
413430c5
EN
212 (object)
213 Lisp_Object object;
605be8af 214{
9e571f49 215 return WINDOW_LIVE_P (object) ? Qt : Qnil;
605be8af
JB
216}
217
7ab12479
JB
218Lisp_Object
219make_window ()
220{
cffec418 221 Lisp_Object val;
7ab12479 222 register struct window *p;
cffec418 223
26605be9 224 p = allocate_window ();
2a1893f4
SM
225 ++sequence_number;
226 XSETFASTINT (p->sequence_number, sequence_number);
949cf20f
KS
227 XSETFASTINT (p->left_col, 0);
228 XSETFASTINT (p->top_line, 0);
229 XSETFASTINT (p->total_lines, 0);
230 XSETFASTINT (p->total_cols, 0);
d834a2e9 231 XSETFASTINT (p->hscroll, 0);
ea68264b 232 XSETFASTINT (p->min_hscroll, 0);
949cf20f 233 p->orig_top_line = p->orig_total_lines = Qnil;
7ab12479
JB
234 p->start = Fmake_marker ();
235 p->pointm = Fmake_marker ();
d834a2e9 236 XSETFASTINT (p->use_time, 0);
44fa5b1e 237 p->frame = Qnil;
7ab12479
JB
238 p->display_table = Qnil;
239 p->dedicated = Qnil;
cfbb2395 240 p->window_parameters = Qnil;
5500c422
GM
241 p->pseudo_window_p = 0;
242 bzero (&p->cursor, sizeof (p->cursor));
243 bzero (&p->last_cursor, sizeof (p->last_cursor));
244 bzero (&p->phys_cursor, sizeof (p->phys_cursor));
245 p->desired_matrix = p->current_matrix = 0;
7a146de2 246 p->nrows_scale_factor = p->ncols_scale_factor = 1;
5500c422 247 p->phys_cursor_type = -1;
4b26579e 248 p->phys_cursor_width = -1;
5500c422
GM
249 p->must_be_updated_p = 0;
250 XSETFASTINT (p->window_end_vpos, 0);
251 XSETFASTINT (p->window_end_pos, 0);
252 p->window_end_valid = Qnil;
253 p->vscroll = 0;
cffec418 254 XSETWINDOW (val, p);
5500c422 255 XSETFASTINT (p->last_point, 0);
7bbb5782 256 p->frozen_window_start_p = 0;
6b448755 257 p->last_cursor_off_p = p->cursor_off_p = 0;
949cf20f
KS
258 p->left_margin_cols = Qnil;
259 p->right_margin_cols = Qnil;
260 p->left_fringe_width = Qnil;
261 p->right_fringe_width = Qnil;
262 p->fringes_outside_margins = Qnil;
263 p->scroll_bar_width = Qnil;
264 p->vertical_scroll_bar_type = Qt;
047aaeb9 265 p->resize_proportionally = Qnil;
67492200
GM
266
267 Vwindow_list = Qnil;
7ab12479
JB
268 return val;
269}
270
271DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0,
fdb82f93
PJ
272 doc: /* Return the window that the cursor now appears in and commands apply to. */)
273 ()
7ab12479
JB
274{
275 return selected_window;
276}
277
83762ba4 278DEFUN ("minibuffer-window", Fminibuffer_window, Sminibuffer_window, 0, 1, 0,
fdb82f93
PJ
279 doc: /* Return the window used now for minibuffers.
280If the optional argument FRAME is specified, return the minibuffer window
281used by that frame. */)
282 (frame)
83762ba4 283 Lisp_Object frame;
7ab12479 284{
83762ba4 285 if (NILP (frame))
1ae1a37d 286 frame = selected_frame;
b7826503 287 CHECK_LIVE_FRAME (frame);
83762ba4 288 return FRAME_MINIBUF_WINDOW (XFRAME (frame));
7ab12479
JB
289}
290
605be8af 291DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1, 0,
23fe745a 292 doc: /* Return non-nil if WINDOW is a minibuffer window.
6b61353c 293WINDOW defaults to the selected window. */)
fdb82f93 294 (window)
7ab12479
JB
295 Lisp_Object window;
296{
297 struct window *w = decode_window (window);
53bb6b99 298 return MINI_WINDOW_P (w) ? Qt : Qnil;
81e4d465
MB
299}
300
301
7ab12479 302DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
fdb82f93 303 Spos_visible_in_window_p, 0, 3, 0,
a0a37a6f 304 doc: /* Return non-nil if position POS is currently on the frame in WINDOW.
fdb82f93
PJ
305Return nil if that position is scrolled vertically out of view.
306If a character is only partially visible, nil is returned, unless the
307optional argument PARTIALLY is non-nil.
a0a37a6f 308If POS is only out of view because of horizontal scrolling, return non-nil.
120b7781 309If POS is t, it specifies the position of the last visible glyph in WINDOW.
0cc1039f
KS
310POS defaults to point in WINDOW; WINDOW defaults to the selected window.
311
312If POS is visible, return t if PARTIALLY is nil; if PARTIALLY is non-nil,
5a857365
KS
313return value is a list of 2 or 6 elements (X Y [RTOP RBOT ROWH VPOS]),
314where X and Y are the pixel coordinates relative to the top left corner
315of the window. The remaining elements are omitted if the character after
316POS is fully visible; otherwise, RTOP and RBOT are the number of pixels
120b7781 317off-window at the top and bottom of the row, ROWH is the height of the
7bbc67d2 318display row, and VPOS is the row number (0-based) containing POS. */)
fdb82f93 319 (pos, window, partially)
5cdb3cf3 320 Lisp_Object pos, window, partially;
7ab12479
JB
321{
322 register struct window *w;
7ab12479
JB
323 register int posint;
324 register struct buffer *buf;
9a132b1f 325 struct text_pos top;
0cc1039f 326 Lisp_Object in_window = Qnil;
5a857365 327 int rtop, rbot, rowh, vpos, fully_p = 1;
0cc1039f 328 int x, y;
7ab12479 329
f28b75a9
MB
330 w = decode_window (window);
331 buf = XBUFFER (w->buffer);
332 SET_TEXT_POS_FROM_MARKER (top, w->start);
333
120b7781
KS
334 if (EQ (pos, Qt))
335 posint = -1;
336 else if (!NILP (pos))
7ab12479 337 {
b7826503 338 CHECK_NUMBER_COERCE_MARKER (pos);
7ab12479
JB
339 posint = XINT (pos);
340 }
f28b75a9
MB
341 else if (w == XWINDOW (selected_window))
342 posint = PT;
343 else
344 posint = XMARKER (w->pointm)->charpos;
7ab12479 345
0cc1039f
KS
346 /* If position is above window start or outside buffer boundaries,
347 or if window start is out of range, position is not visible. */
120b7781
KS
348 if ((EQ (pos, Qt)
349 || (posint >= CHARPOS (top) && posint <= BUF_ZV (buf)))
0cc1039f
KS
350 && CHARPOS (top) >= BUF_BEGV (buf)
351 && CHARPOS (top) <= BUF_ZV (buf)
5a857365 352 && pos_visible_p (w, posint, &x, &y, &rtop, &rbot, &rowh, &vpos)
e56263e5 353 && (fully_p = !rtop && !rbot, (!NILP (partially) || fully_p)))
0cc1039f
KS
354 in_window = Qt;
355
356 if (!NILP (in_window) && !NILP (partially))
5a857365
KS
357 {
358 Lisp_Object part = Qnil;
359 if (!fully_p)
360 part = list4 (make_number (rtop), make_number (rbot),
361 make_number (rowh), make_number (vpos));
362 in_window = Fcons (make_number (x),
363 Fcons (make_number (y), part));
364 }
365
9a132b1f 366 return in_window;
7ab12479 367}
53bb6b99 368
536833ab 369DEFUN ("window-line-height", Fwindow_line_height,
7bbc67d2 370 Swindow_line_height, 0, 2, 0,
536833ab
KS
371 doc: /* Return height in pixels of text line LINE in window WINDOW.
372If WINDOW is nil or omitted, use selected window.
373
7bbc67d2
KS
374Return height of current line if LINE is omitted or nil. Return height of
375header or mode line if LINE is `header-line' and `mode-line'.
376Otherwise, LINE is a text line number starting from 0. A negative number
377counts from the end of the window.
536833ab 378
7bbc67d2 379Value is a list (HEIGHT VPOS YPOS OFFBOT), where HEIGHT is the height
536833ab 380in pixels of the visible part of the line, VPOS and YPOS are the
68e67a4e 381vertical position in lines and pixels of the line, relative to the top
120b7781 382of the first text line, and OFFBOT is the number of off-window pixels at
68e67a4e
KS
383the bottom of the text line. If there are off-window pixels at the top
384of the (first) text line, YPOS is negative.
536833ab
KS
385
386Return nil if window display is not up-to-date. In that case, use
387`pos-visible-in-window-p' to obtain the information. */)
388 (line, window)
389 Lisp_Object line, window;
b3a10345
KS
390{
391 register struct window *w;
392 register struct buffer *b;
393 struct glyph_row *row, *end_row;
536833ab 394 int max_y, crop, i, n;
b3a10345
KS
395
396 w = decode_window (window);
397
398 if (noninteractive
b3a10345 399 || w->pseudo_window_p)
7bbc67d2 400 return Qnil;
b3a10345
KS
401
402 CHECK_BUFFER (w->buffer);
403 b = XBUFFER (w->buffer);
404
405 /* Fail if current matrix is not up-to-date. */
406 if (NILP (w->window_end_valid)
407 || current_buffer->clip_changed
408 || current_buffer->prevent_redisplay_optimizations_p
409 || XFASTINT (w->last_modified) < BUF_MODIFF (b)
410 || XFASTINT (w->last_overlay_modified) < BUF_OVERLAY_MODIFF (b))
411 return Qnil;
412
7bbc67d2
KS
413 if (NILP (line))
414 {
415 i = w->cursor.vpos;
416 if (i < 0 || i >= w->current_matrix->nrows
417 || (row = MATRIX_ROW (w->current_matrix, i), !row->enabled_p))
418 return Qnil;
419 max_y = window_text_bottom_y (w);
420 goto found_row;
421 }
422
536833ab 423 if (EQ (line, Qheader_line))
b3a10345 424 {
536833ab
KS
425 if (!WINDOW_WANTS_HEADER_LINE_P (w))
426 return Qnil;
427 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
b3a10345
KS
428 if (!row->enabled_p)
429 return Qnil;
536833ab
KS
430 return list4 (make_number (row->height),
431 make_number (0), make_number (0),
432 make_number (0));
b3a10345 433 }
536833ab
KS
434
435 if (EQ (line, Qmode_line))
b3a10345 436 {
536833ab
KS
437 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
438 if (!row->enabled_p)
439 return Qnil;
440 return list4 (make_number (row->height),
441 make_number (0), /* not accurate */
442 make_number (WINDOW_HEADER_LINE_HEIGHT (w)
443 + window_text_bottom_y (w)),
444 make_number (0));
445 }
b3a10345 446
536833ab 447 CHECK_NUMBER (line);
7bbc67d2 448 n = XINT (line);
536833ab
KS
449
450 row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
451 end_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
452 max_y = window_text_bottom_y (w);
7bbc67d2 453 i = 0;
536833ab
KS
454
455 while ((n < 0 || i < n)
456 && row <= end_row && row->enabled_p
457 && row->y + row->height < max_y)
458 row++, i++;
b3a10345 459
536833ab
KS
460 if (row > end_row || !row->enabled_p)
461 return Qnil;
462
7bbc67d2 463 if (++n < 0)
536833ab
KS
464 {
465 if (-n > i)
466 return Qnil;
7bbc67d2
KS
467 row += n;
468 i += n;
b3a10345
KS
469 }
470
7bbc67d2 471 found_row:
536833ab
KS
472 crop = max (0, (row->y + row->height) - max_y);
473 return list4 (make_number (row->height + min (0, row->y) - crop),
7bbc67d2 474 make_number (i),
536833ab
KS
475 make_number (row->y),
476 make_number (crop));
b3a10345
KS
477}
478
536833ab 479
7ab12479
JB
480\f
481static struct window *
482decode_window (window)
483 register Lisp_Object window;
484{
265a9e55 485 if (NILP (window))
7ab12479
JB
486 return XWINDOW (selected_window);
487
b7826503 488 CHECK_LIVE_WINDOW (window);
7ab12479
JB
489 return XWINDOW (window);
490}
491
6b61353c
KH
492static struct window *
493decode_any_window (window)
494 register Lisp_Object window;
495{
496 if (NILP (window))
497 return XWINDOW (selected_window);
498
499 CHECK_WINDOW (window);
500 return XWINDOW (window);
501}
502
7ab12479 503DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
c2755926
LT
504 doc: /* Return the buffer that WINDOW is displaying.
505WINDOW defaults to the selected window. */)
fdb82f93 506 (window)
7ab12479
JB
507 Lisp_Object window;
508{
509 return decode_window (window)->buffer;
510}
511
512DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0,
8fef9de1
MR
513 doc: /* Return the number of lines in WINDOW.
514WINDOW defaults to the selected window.
515
a77cfeaf
CS
516The return value includes WINDOW's mode line and header line, if any.
517
518Note: The function does not take into account the value of `line-spacing'
519when calculating the number of lines in WINDOW. */)
fdb82f93 520 (window)
7ab12479
JB
521 Lisp_Object window;
522{
6b61353c 523 return decode_any_window (window)->total_lines;
7ab12479
JB
524}
525
526DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
fdb82f93 527 doc: /* Return the number of display columns in WINDOW.
d653c8cc
MR
528WINDOW defaults to the selected window.
529
530Note: The return value is the number of columns available for text in
531WINDOW. If you want to find out how many columns WINDOW takes up, use
532(let ((edges (window-edges))) (- (nth 2 edges) (nth 0 edges))). */)
fdb82f93 533 (window)
7ab12479
JB
534 Lisp_Object window;
535{
6b61353c 536 return make_number (window_box_text_cols (decode_any_window (window)));
7ab12479
JB
537}
538
35ea56c9
MR
539DEFUN ("window-full-width-p", Fwindow_full_width_p, Swindow_full_width_p, 0, 1, 0,
540 doc: /* Return t if WINDOW is as wide as its frame.
541WINDOW defaults to the selected window. */)
542 (window)
543 Lisp_Object window;
544{
545 return WINDOW_FULL_WIDTH_P (decode_any_window (window)) ? Qt : Qnil;
546}
547
7ab12479 548DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
c85322d0
EZ
549 doc: /* Return the number of columns by which WINDOW is scrolled from left margin.
550WINDOW defaults to the selected window. */)
fdb82f93 551 (window)
7ab12479
JB
552 Lisp_Object window;
553{
554 return decode_window (window)->hscroll;
555}
556
557DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
fdb82f93 558 doc: /* Set number of columns WINDOW is scrolled from left margin to NCOL.
a0a37a6f 559Return NCOL. NCOL should be zero or positive.
ebadb1e4
EZ
560
561Note that if `automatic-hscrolling' is non-nil, you cannot scroll the
120b7781 562window so that the location of point moves off-window. */)
fdb82f93 563 (window, ncol)
ea68264b 564 Lisp_Object window, ncol;
7ab12479 565{
ea68264b
GM
566 struct window *w = decode_window (window);
567 int hscroll;
7ab12479 568
b7826503 569 CHECK_NUMBER (ncol);
ea68264b 570 hscroll = max (0, XINT (ncol));
177c0ea7 571
ea68264b
GM
572 /* Prevent redisplay shortcuts when changing the hscroll. */
573 if (XINT (w->hscroll) != hscroll)
b1599b4c 574 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
177c0ea7 575
c67fa410 576 w->hscroll = make_number (hscroll);
7ab12479
JB
577 return ncol;
578}
579
190eb263
RS
580DEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger,
581 Swindow_redisplay_end_trigger, 0, 1, 0,
fdb82f93 582 doc: /* Return WINDOW's redisplay end trigger value.
c85322d0 583WINDOW defaults to the selected window.
fdb82f93
PJ
584See `set-window-redisplay-end-trigger' for more information. */)
585 (window)
190eb263
RS
586 Lisp_Object window;
587{
588 return decode_window (window)->redisplay_end_trigger;
589}
590
591DEFUN ("set-window-redisplay-end-trigger", Fset_window_redisplay_end_trigger,
592 Sset_window_redisplay_end_trigger, 2, 2, 0,
fdb82f93
PJ
593 doc: /* Set WINDOW's redisplay end trigger value to VALUE.
594VALUE should be a buffer position (typically a marker) or nil.
595If it is a buffer position, then if redisplay in WINDOW reaches a position
596beyond VALUE, the functions in `redisplay-end-trigger-functions' are called
597with two arguments: WINDOW, and the end trigger value.
598Afterwards the end-trigger value is reset to nil. */)
599 (window, value)
190eb263
RS
600 register Lisp_Object window, value;
601{
602 register struct window *w;
603
604 w = decode_window (window);
605 w->redisplay_end_trigger = value;
606 return value;
607}
608
7ab12479 609DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0,
fdb82f93 610 doc: /* Return a list of the edge coordinates of WINDOW.
b35ac83e
CY
611The list has the form (LEFT TOP RIGHT BOTTOM).
612TOP and BOTTOM count by lines, and LEFT and RIGHT count by columns,
613all relative to 0, 0 at top left corner of frame.
614
615RIGHT is one more than the rightmost column occupied by WINDOW.
616BOTTOM is one more than the bottommost row occupied by WINDOW.
617The edges include the space used by WINDOW's scroll bar, display
618margins, fringes, header line, and/or mode line. For the edges of
619just the text area, use `window-inside-edges'. */)
fdb82f93 620 (window)
7ab12479
JB
621 Lisp_Object window;
622{
6b61353c 623 register struct window *w = decode_any_window (window);
7ab12479 624
949cf20f
KS
625 return Fcons (make_number (WINDOW_LEFT_EDGE_COL (w)),
626 Fcons (make_number (WINDOW_TOP_EDGE_LINE (w)),
627 Fcons (make_number (WINDOW_RIGHT_EDGE_COL (w)),
628 Fcons (make_number (WINDOW_BOTTOM_EDGE_LINE (w)),
629 Qnil))));
7ab12479
JB
630}
631
c99a9eb3
RS
632DEFUN ("window-pixel-edges", Fwindow_pixel_edges, Swindow_pixel_edges, 0, 1, 0,
633 doc: /* Return a list of the edge pixel coordinates of WINDOW.
b35ac83e
CY
634The list has the form (LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at
635the top left corner of the frame.
636
637RIGHT is one more than the rightmost x position occupied by WINDOW.
638BOTTOM is one more than the bottommost y position occupied by WINDOW.
639The pixel edges include the space used by WINDOW's scroll bar, display
640margins, fringes, header line, and/or mode line. For the pixel edges
641of just the text area, use `window-inside-pixel-edges'. */)
c99a9eb3
RS
642 (window)
643 Lisp_Object window;
644{
6b61353c 645 register struct window *w = decode_any_window (window);
c99a9eb3
RS
646
647 return Fcons (make_number (WINDOW_LEFT_EDGE_X (w)),
648 Fcons (make_number (WINDOW_TOP_EDGE_Y (w)),
649 Fcons (make_number (WINDOW_RIGHT_EDGE_X (w)),
650 Fcons (make_number (WINDOW_BOTTOM_EDGE_Y (w)),
651 Qnil))));
652}
653
654DEFUN ("window-inside-edges", Fwindow_inside_edges, Swindow_inside_edges, 0, 1, 0,
655 doc: /* Return a list of the edge coordinates of WINDOW.
b35ac83e
CY
656The list has the form (LEFT TOP RIGHT BOTTOM).
657TOP and BOTTOM count by lines, and LEFT and RIGHT count by columns,
658all relative to 0, 0 at top left corner of frame.
659
660RIGHT is one more than the rightmost column of WINDOW's text area.
661BOTTOM is one more than the bottommost row of WINDOW's text area.
662The inside edges do not include the space used by the WINDOW's scroll
663bar, display margins, fringes, header line, and/or mode line. */)
c99a9eb3
RS
664 (window)
665 Lisp_Object window;
666{
6b61353c 667 register struct window *w = decode_any_window (window);
c99a9eb3
RS
668
669 return list4 (make_number (WINDOW_BOX_LEFT_EDGE_COL (w)
670 + WINDOW_LEFT_MARGIN_COLS (w)
671 + WINDOW_LEFT_FRINGE_COLS (w)),
672 make_number (WINDOW_TOP_EDGE_LINE (w)
673 + WINDOW_HEADER_LINE_LINES (w)),
f3fbdb1f 674 make_number (WINDOW_BOX_RIGHT_EDGE_COL (w)
c99a9eb3
RS
675 - WINDOW_RIGHT_MARGIN_COLS (w)
676 - WINDOW_RIGHT_FRINGE_COLS (w)),
677 make_number (WINDOW_BOTTOM_EDGE_LINE (w)
678 - WINDOW_MODE_LINE_LINES (w)));
679}
680
681DEFUN ("window-inside-pixel-edges", Fwindow_inside_pixel_edges, Swindow_inside_pixel_edges, 0, 1, 0,
a0a37a6f 682 doc: /* Return a list of the edge pixel coordinates of WINDOW.
b35ac83e
CY
683The list has the form (LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at
684the top left corner of the frame.
685
686RIGHT is one more than the rightmost x position of WINDOW's text area.
687BOTTOM is one more than the bottommost y position of WINDOW's text area.
688The inside edges do not include the space used by WINDOW's scroll bar,
c99a9eb3
RS
689display margins, fringes, header line, and/or mode line. */)
690 (window)
691 Lisp_Object window;
692{
6b61353c 693 register struct window *w = decode_any_window (window);
c99a9eb3
RS
694
695 return list4 (make_number (WINDOW_BOX_LEFT_EDGE_X (w)
696 + WINDOW_LEFT_MARGIN_WIDTH (w)
697 + WINDOW_LEFT_FRINGE_WIDTH (w)),
698 make_number (WINDOW_TOP_EDGE_Y (w)
699 + WINDOW_HEADER_LINE_HEIGHT (w)),
f3fbdb1f 700 make_number (WINDOW_BOX_RIGHT_EDGE_X (w)
c99a9eb3
RS
701 - WINDOW_RIGHT_MARGIN_WIDTH (w)
702 - WINDOW_RIGHT_FRINGE_WIDTH (w)),
703 make_number (WINDOW_BOTTOM_EDGE_Y (w)
704 - WINDOW_MODE_LINE_HEIGHT (w)));
705}
706
fbad6f9a 707/* Test if the character at column *X, row *Y is within window W.
341f3858 708 If it is not, return ON_NOTHING;
d5783c40
JB
709 if it is in the window's text area,
710 set *x and *y to its location relative to the upper left corner
711 of the window, and
341f3858
KS
712 return ON_TEXT;
713 if it is on the window's modeline, return ON_MODE_LINE;
d5783c40 714 if it is on the border between the window and its right sibling,
341f3858 715 return ON_VERTICAL_BORDER.
6487f669
RS
716 if it is on a scroll bar,
717 return ON_SCROLL_BAR.
341f3858 718 if it is on the window's top line, return ON_HEADER_LINE;
81d189fd 719 if it is in left or right fringe of the window,
341f3858
KS
720 return ON_LEFT_FRINGE or ON_RIGHT_FRINGE, and convert *X and *Y
721 to window-relative coordinates;
49b996e7 722 if it is in the marginal area to the left/right of the window,
341f3858
KS
723 return ON_LEFT_MARGIN or ON_RIGHT_MARGIN, and convert *X and *Y
724 to window-relative coordinates.
5500c422
GM
725
726 X and Y are frame relative pixel coordinates. */
727
7442878f 728static enum window_part
d5783c40
JB
729coordinates_in_window (w, x, y)
730 register struct window *w;
731 register int *x, *y;
732{
b0228ace
GM
733 struct frame *f = XFRAME (WINDOW_FRAME (w));
734 int left_x, right_x, top_y, bottom_y;
7442878f 735 enum window_part part;
949cf20f
KS
736 int ux = FRAME_COLUMN_WIDTH (f);
737 int x0 = WINDOW_LEFT_EDGE_X (w);
738 int x1 = WINDOW_RIGHT_EDGE_X (w);
dad75588
GM
739 /* The width of the area where the vertical line can be dragged.
740 (Between mode lines for instance. */
741 int grabbable_width = ux;
949cf20f 742 int lmargin_width, rmargin_width, text_left, text_right;
b0228ace 743
466539bc
EZ
744 /* In what's below, we subtract 1 when computing right_x because we
745 want the rightmost pixel, which is given by left_pixel+width-1. */
5500c422
GM
746 if (w->pseudo_window_p)
747 {
748 left_x = 0;
949cf20f
KS
749 right_x = WINDOW_TOTAL_WIDTH (w) - 1;
750 top_y = WINDOW_TOP_EDGE_Y (w);
751 bottom_y = WINDOW_BOTTOM_EDGE_Y (w);
5500c422
GM
752 }
753 else
754 {
949cf20f
KS
755 left_x = WINDOW_BOX_LEFT_EDGE_X (w);
756 right_x = WINDOW_BOX_RIGHT_EDGE_X (w) - 1;
757 top_y = WINDOW_TOP_EDGE_Y (w);
758 bottom_y = WINDOW_BOTTOM_EDGE_Y (w);
5500c422 759 }
37962e60 760
949cf20f
KS
761 /* Outside any interesting row? */
762 if (*y < top_y || *y >= bottom_y)
763 return ON_NOTHING;
764
1cb794ba
GM
765 /* On the mode line or header line? If it's near the start of
766 the mode or header line of window that's has a horizontal
767 sibling, say it's on the vertical line. That's to be able
768 to resize windows horizontally in case we're using toolkit
769 scroll bars. */
b0228ace 770
1cb794ba 771 if (WINDOW_WANTS_MODELINE_P (w)
6b61353c 772 && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
1cb794ba 773 {
949cf20f
KS
774 part = ON_MODE_LINE;
775
776 header_vertical_border_check:
b0228ace
GM
777 /* We're somewhere on the mode line. We consider the place
778 between mode lines of horizontally adjacent mode lines
9d14503e 779 as the vertical border. If scroll bars on the left,
b0228ace 780 return the right window. */
949cf20f
KS
781 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
782 || WINDOW_RIGHTMOST_P (w))
b0228ace 783 {
1ea40aa2 784 if (!WINDOW_LEFTMOST_P (w) && eabs (*x - x0) < grabbable_width)
f8c62b70 785 {
3f489dc7
KS
786 /* Convert X and Y to window relative coordinates.
787 Vertical border is at the left edge of window. */
f8c62b70
NR
788 *x = max (0, *x - x0);
789 *y -= top_y;
790 return ON_VERTICAL_BORDER;
791 }
b0228ace 792 }
79fd290e 793 else
b0228ace 794 {
f6ef1e65
MR
795 /* Make sure we're not at the rightmost position of a
796 mode-/header-line and there's yet another window on
797 the right. (Bug#1372) */
798 if ((WINDOW_RIGHTMOST_P (w) || *x < x1)
799 && eabs (*x - x1) < grabbable_width)
f8c62b70 800 {
3f489dc7
KS
801 /* Convert X and Y to window relative coordinates.
802 Vertical border is at the right edge of window. */
f8c62b70
NR
803 *x = min (x1, *x) - x0;
804 *y -= top_y;
805 return ON_VERTICAL_BORDER;
806 }
b0228ace 807 }
949cf20f 808
cb639b8f
KS
809 if (*x < x0 || *x >= x1)
810 return ON_NOTHING;
811
a5303820
KS
812 /* Convert X and Y to window relative coordinates.
813 Mode line starts at left edge of window. */
814 *x -= x0;
815 *y -= top_y;
949cf20f 816 return part;
b0228ace 817 }
949cf20f
KS
818
819 if (WINDOW_WANTS_HEADER_LINE_P (w)
949cf20f 820 && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
1cb794ba 821 {
949cf20f
KS
822 part = ON_HEADER_LINE;
823 goto header_vertical_border_check;
1cb794ba 824 }
949cf20f 825
cb639b8f
KS
826 if (*x < x0 || *x >= x1)
827 return ON_NOTHING;
828
949cf20f
KS
829 /* Outside any interesting column? */
830 if (*x < left_x || *x > right_x)
4d1add72
KS
831 {
832 *y -= top_y;
833 return ON_SCROLL_BAR;
834 }
949cf20f
KS
835
836 lmargin_width = window_box_width (w, LEFT_MARGIN_AREA);
837 rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA);
79fd290e 838
949cf20f
KS
839 text_left = window_box_left (w, TEXT_AREA);
840 text_right = text_left + window_box_width (w, TEXT_AREA);
841
842 if (FRAME_WINDOW_P (f))
fbad6f9a 843 {
447e9da0 844 if (!w->pseudo_window_p
949cf20f 845 && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
447e9da0 846 && !WINDOW_RIGHTMOST_P (w)
1ea40aa2 847 && (eabs (*x - right_x) < grabbable_width))
f8c62b70 848 {
3f489dc7
KS
849 /* Convert X and Y to window relative coordinates.
850 Vertical border is at the right edge of window. */
f8c62b70
NR
851 *x = min (right_x, *x) - left_x;
852 *y -= top_y;
853 return ON_VERTICAL_BORDER;
854 }
fbad6f9a 855 }
447e9da0
GM
856 else
857 {
858 /* Need to say "*x > right_x" rather than >=, since on character
859 terminals, the vertical line's x coordinate is right_x. */
949cf20f
KS
860 if (!w->pseudo_window_p
861 && !WINDOW_RIGHTMOST_P (w)
862 && *x > right_x - ux)
b0228ace
GM
863 {
864 /* On the border on the right side of the window? Assume that
865 this area begins at RIGHT_X minus a canonical char width. */
f8c62b70
NR
866 *x = min (right_x, *x) - left_x;
867 *y -= top_y;
949cf20f 868 return ON_VERTICAL_BORDER;
b0228ace 869 }
447e9da0 870 }
b0228ace 871
949cf20f
KS
872 if (*x < text_left)
873 {
874 if (lmargin_width > 0
875 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
876 ? (*x >= left_x + WINDOW_LEFT_FRINGE_WIDTH (w))
877 : (*x < left_x + lmargin_width)))
a5303820 878 {
6b61353c 879 *x -= left_x;
a5303820
KS
880 if (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
881 *x -= WINDOW_LEFT_FRINGE_WIDTH (w);
882 *y -= top_y;
883 return ON_LEFT_MARGIN;
884 }
949cf20f
KS
885
886 /* Convert X and Y to window-relative pixel coordinates. */
887 *x -= left_x;
888 *y -= top_y;
889 return ON_LEFT_FRINGE;
890 }
891
892 if (*x >= text_right)
893 {
894 if (rmargin_width > 0
895 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
896 ? (*x < right_x - WINDOW_RIGHT_FRINGE_WIDTH (w))
897 : (*x >= right_x - rmargin_width)))
a5303820 898 {
66d41723
KS
899 *x -= right_x - rmargin_width;
900 if (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
901 *x += WINDOW_RIGHT_FRINGE_WIDTH (w);
a5303820
KS
902 *y -= top_y;
903 return ON_RIGHT_MARGIN;
904 }
949cf20f
KS
905
906 /* Convert X and Y to window-relative pixel coordinates. */
907 *x -= left_x + WINDOW_LEFT_FRINGE_WIDTH (w);
908 *y -= top_y;
909 return ON_RIGHT_FRINGE;
910 }
911
912 /* Everything special ruled out - must be on text area */
66d41723 913 *x -= text_left;
949cf20f
KS
914 *y -= top_y;
915 return ON_TEXT;
d5783c40
JB
916}
917
b0228ace 918
d5783c40 919DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
fdb82f93
PJ
920 Scoordinates_in_window_p, 2, 2, 0,
921 doc: /* Return non-nil if COORDINATES are in WINDOW.
922COORDINATES is a cons of the form (X . Y), X and Y being distances
923measured in characters from the upper-left corner of the frame.
23fe745a 924\(0 . 0) denotes the character in the upper left corner of the
fdb82f93
PJ
925frame.
926If COORDINATES are in the text portion of WINDOW,
927 the coordinates relative to the window are returned.
928If they are in the mode line of WINDOW, `mode-line' is returned.
929If they are in the top mode line of WINDOW, `header-line' is returned.
81d189fd
KS
930If they are in the left fringe of WINDOW, `left-fringe' is returned.
931If they are in the right fringe of WINDOW, `right-fringe' is returned.
fdb82f93 932If they are on the border between WINDOW and its right sibling,
49b996e7
GM
933 `vertical-line' is returned.
934If they are in the windows's left or right marginal areas, `left-margin'\n\
935 or `right-margin' is returned. */)
fdb82f93 936 (coordinates, window)
d5783c40
JB
937 register Lisp_Object coordinates, window;
938{
5500c422
GM
939 struct window *w;
940 struct frame *f;
d5783c40 941 int x, y;
5500c422 942 Lisp_Object lx, ly;
d5783c40 943
6b61353c 944 CHECK_WINDOW (window);
5500c422
GM
945 w = XWINDOW (window);
946 f = XFRAME (w->frame);
b7826503 947 CHECK_CONS (coordinates);
5500c422
GM
948 lx = Fcar (coordinates);
949 ly = Fcdr (coordinates);
b7826503
PJ
950 CHECK_NUMBER_OR_FLOAT (lx);
951 CHECK_NUMBER_OR_FLOAT (ly);
81159bb9
RS
952 x = FRAME_PIXEL_X_FROM_CANON_X (f, lx) + FRAME_INTERNAL_BORDER_WIDTH (f);
953 y = FRAME_PIXEL_Y_FROM_CANON_Y (f, ly) + FRAME_INTERNAL_BORDER_WIDTH (f);
5500c422
GM
954
955 switch (coordinates_in_window (w, &x, &y))
d5783c40 956 {
7442878f 957 case ON_NOTHING:
d5783c40
JB
958 return Qnil;
959
7442878f
GM
960 case ON_TEXT:
961 /* X and Y are now window relative pixel coordinates. Convert
962 them to canonical char units before returning them. */
949cf20f
KS
963 return Fcons (FRAME_CANON_X_FROM_PIXEL_X (f, x),
964 FRAME_CANON_Y_FROM_PIXEL_Y (f, y));
d5783c40 965
7442878f 966 case ON_MODE_LINE:
d5783c40 967 return Qmode_line;
37962e60 968
7442878f 969 case ON_VERTICAL_BORDER:
e5d77022 970 return Qvertical_line;
d5783c40 971
7442878f 972 case ON_HEADER_LINE:
045dee35 973 return Qheader_line;
5500c422 974
7442878f
GM
975 case ON_LEFT_FRINGE:
976 return Qleft_fringe;
177c0ea7 977
7442878f
GM
978 case ON_RIGHT_FRINGE:
979 return Qright_fringe;
fbad6f9a 980
49b996e7
GM
981 case ON_LEFT_MARGIN:
982 return Qleft_margin;
177c0ea7 983
49b996e7
GM
984 case ON_RIGHT_MARGIN:
985 return Qright_margin;
986
6487f669
RS
987 case ON_SCROLL_BAR:
988 /* Historically we are supposed to return nil in this case. */
989 return Qnil;
990
d5783c40
JB
991 default:
992 abort ();
993 }
994}
995
67492200
GM
996
997/* Callback for foreach_window, used in window_from_coordinates.
f95464e4
GM
998 Check if window W contains coordinates specified by USER_DATA which
999 is actually a pointer to a struct check_window_data CW.
1000
1001 Check if window W contains coordinates *CW->x and *CW->y. If it
1002 does, return W in *CW->window, as Lisp_Object, and return in
5372262f 1003 *CW->part the part of the window under coordinates *X,*Y. Return
f95464e4
GM
1004 zero from this function to stop iterating over windows. */
1005
1006struct check_window_data
1007{
1008 Lisp_Object *window;
341f3858
KS
1009 int *x, *y;
1010 enum window_part *part;
f95464e4 1011};
67492200
GM
1012
1013static int
f95464e4 1014check_window_containing (w, user_data)
67492200 1015 struct window *w;
f95464e4 1016 void *user_data;
67492200 1017{
f95464e4 1018 struct check_window_data *cw = (struct check_window_data *) user_data;
7442878f
GM
1019 enum window_part found;
1020 int continue_p = 1;
67492200 1021
f95464e4 1022 found = coordinates_in_window (w, cw->x, cw->y);
7442878f 1023 if (found != ON_NOTHING)
67492200 1024 {
341f3858 1025 *cw->part = found;
f95464e4 1026 XSETWINDOW (*cw->window, w);
7442878f 1027 continue_p = 0;
67492200 1028 }
177c0ea7 1029
7442878f 1030 return continue_p;
67492200
GM
1031}
1032
1033
5500c422 1034/* Find the window containing frame-relative pixel position X/Y and
949cf20f
KS
1035 return it as a Lisp_Object.
1036
1037 If X, Y is on one of the window's special `window_part' elements,
1038 set *PART to the id of that element, and return X and Y converted
1039 to window relative coordinates in WX and WY.
1040
341f3858 1041 If there is no window under X, Y return nil and leave *PART
67492200
GM
1042 unmodified. TOOL_BAR_P non-zero means detect tool-bar windows.
1043
1044 This function was previously implemented with a loop cycling over
1045 windows with Fnext_window, and starting with the frame's selected
1046 window. It turned out that this doesn't work with an
1047 implementation of next_window using Vwindow_list, because
1048 FRAME_SELECTED_WINDOW (F) is not always contained in the window
1049 tree of F when this function is called asynchronously from
1050 note_mouse_highlight. The original loop didn't terminate in this
1051 case. */
5500c422 1052
7ab12479 1053Lisp_Object
949cf20f 1054window_from_coordinates (f, x, y, part, wx, wy, tool_bar_p)
67492200 1055 struct frame *f;
7ab12479 1056 int x, y;
341f3858 1057 enum window_part *part;
949cf20f 1058 int *wx, *wy;
9ea173e8 1059 int tool_bar_p;
7ab12479 1060{
67492200 1061 Lisp_Object window;
f95464e4 1062 struct check_window_data cw;
341f3858
KS
1063 enum window_part dummy;
1064
1065 if (part == 0)
1066 part = &dummy;
5500c422 1067
67492200 1068 window = Qnil;
f95464e4
GM
1069 cw.window = &window, cw.x = &x, cw.y = &y; cw.part = part;
1070 foreach_window (f, check_window_containing, &cw);
177c0ea7 1071
67492200
GM
1072 /* If not found above, see if it's in the tool bar window, if a tool
1073 bar exists. */
1074 if (NILP (window)
1075 && tool_bar_p
1076 && WINDOWP (f->tool_bar_window)
949cf20f 1077 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0
7442878f
GM
1078 && (coordinates_in_window (XWINDOW (f->tool_bar_window), &x, &y)
1079 != ON_NOTHING))
5500c422 1080 {
341f3858 1081 *part = ON_TEXT;
67492200 1082 window = f->tool_bar_window;
5500c422 1083 }
37962e60 1084
949cf20f
KS
1085 if (wx) *wx = x;
1086 if (wy) *wy = y;
1087
67492200 1088 return window;
7ab12479
JB
1089}
1090
ab17c3f2 1091DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
fdb82f93
PJ
1092 doc: /* Return window containing coordinates X and Y on FRAME.
1093If omitted, FRAME defaults to the currently selected frame.
1094The top left corner of the frame is considered to be row 0,
1095column 0. */)
1096 (x, y, frame)
1097 Lisp_Object x, y, frame;
7ab12479 1098{
5500c422 1099 struct frame *f;
7ab12479 1100
44fa5b1e 1101 if (NILP (frame))
1ae1a37d 1102 frame = selected_frame;
b7826503 1103 CHECK_LIVE_FRAME (frame);
5500c422 1104 f = XFRAME (frame);
7ab12479 1105
5500c422 1106 /* Check that arguments are integers or floats. */
b7826503
PJ
1107 CHECK_NUMBER_OR_FLOAT (x);
1108 CHECK_NUMBER_OR_FLOAT (y);
5500c422 1109
177c0ea7 1110 return window_from_coordinates (f,
2c77cf3b
RS
1111 (FRAME_PIXEL_X_FROM_CANON_X (f, x)
1112 + FRAME_INTERNAL_BORDER_WIDTH (f)),
1113 (FRAME_PIXEL_Y_FROM_CANON_Y (f, y)
1114 + FRAME_INTERNAL_BORDER_WIDTH (f)),
949cf20f 1115 0, 0, 0, 0);
7ab12479
JB
1116}
1117
1118DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
fdb82f93 1119 doc: /* Return current value of point in WINDOW.
c85322d0
EZ
1120WINDOW defaults to the selected window.
1121
fdb82f93
PJ
1122For a nonselected window, this is the value point would have
1123if that window were selected.
1124
1125Note that, when WINDOW is the selected window and its buffer
1126is also currently selected, the value returned is the same as (point).
1127It would be more strictly correct to return the `top-level' value
1128of point, outside of any save-excursion forms.
1129But that is hard to define. */)
1130 (window)
7ab12479
JB
1131 Lisp_Object window;
1132{
1133 register struct window *w = decode_window (window);
1134
1135 if (w == XWINDOW (selected_window)
1136 && current_buffer == XBUFFER (w->buffer))
1137 return Fpoint ();
1138 return Fmarker_position (w->pointm);
1139}
1140
1141DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
fdb82f93 1142 doc: /* Return position at which display currently starts in WINDOW.
c85322d0 1143WINDOW defaults to the selected window.
fdb82f93
PJ
1144This is updated by redisplay or by calling `set-window-start'. */)
1145 (window)
7ab12479
JB
1146 Lisp_Object window;
1147{
1148 return Fmarker_position (decode_window (window)->start);
1149}
1150
8646118f
RS
1151/* This is text temporarily removed from the doc string below.
1152
fdb82f93
PJ
1153This function returns nil if the position is not currently known.
1154That happens when redisplay is preempted and doesn't finish.
1155If in that case you want to compute where the end of the window would
1156have been if redisplay had finished, do this:
1157 (save-excursion
1158 (goto-char (window-start window))
1159 (vertical-motion (1- (window-height window)) window)
8646118f
RS
1160 (point))") */
1161
478292ed 1162DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
fdb82f93 1163 doc: /* Return position at which display currently ends in WINDOW.
c85322d0 1164WINDOW defaults to the selected window.
fdb82f93
PJ
1165This is updated by redisplay, when it runs to completion.
1166Simply changing the buffer text or setting `window-start'
1167does not update this value.
a0a37a6f
LT
1168Return nil if there is no recorded value. \(This can happen if the
1169last redisplay of WINDOW was preempted, and did not finish.)
fdb82f93
PJ
1170If UPDATE is non-nil, compute the up-to-date position
1171if it isn't already recorded. */)
1172 (window, update)
478292ed 1173 Lisp_Object window, update;
7ab12479
JB
1174{
1175 Lisp_Object value;
1176 struct window *w = decode_window (window);
5a41ab94 1177 Lisp_Object buf;
31790df3 1178 struct buffer *b;
5a41ab94
RS
1179
1180 buf = w->buffer;
b7826503 1181 CHECK_BUFFER (buf);
b3a10345 1182 b = XBUFFER (buf);
5a41ab94 1183
8646118f 1184#if 0 /* This change broke some things. We should make it later. */
7250968e
RS
1185 /* If we don't know the end position, return nil.
1186 The user can compute it with vertical-motion if he wants to.
1187 It would be nicer to do it automatically,
1188 but that's so slow that it would probably bother people. */
1189 if (NILP (w->window_end_valid))
1190 return Qnil;
8646118f 1191#endif
7250968e 1192
478292ed
RS
1193 if (! NILP (update)
1194 && ! (! NILP (w->window_end_valid)
dfc265a3 1195 && XFASTINT (w->last_modified) >= BUF_MODIFF (b)
4c9564e8 1196 && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (b))
41791a20 1197 && !noninteractive)
478292ed 1198 {
cbc099e5
GM
1199 struct text_pos startp;
1200 struct it it;
b3a10345
KS
1201 struct buffer *old_buffer = NULL;
1202
1203 /* Cannot use Fvertical_motion because that function doesn't
1204 cope with variable-height lines. */
1205 if (b != current_buffer)
1206 {
1207 old_buffer = current_buffer;
1208 set_buffer_internal (b);
1209 }
2d6d9df0
GM
1210
1211 /* In case W->start is out of the range, use something
cb795ec4 1212 reasonable. This situation occurred when loading a file with
2d6d9df0
GM
1213 `-l' containing a call to `rmail' with subsequent other
1214 commands. At the end, W->start happened to be BEG, while
cbc099e5 1215 rmail had already narrowed the buffer. */
2d6d9df0 1216 if (XMARKER (w->start)->charpos < BEGV)
cbc099e5 1217 SET_TEXT_POS (startp, BEGV, BEGV_BYTE);
2d6d9df0 1218 else if (XMARKER (w->start)->charpos > ZV)
cbc099e5 1219 SET_TEXT_POS (startp, ZV, ZV_BYTE);
2d6d9df0 1220 else
cbc099e5
GM
1221 SET_TEXT_POS_FROM_MARKER (startp, w->start);
1222
cbc099e5
GM
1223 start_display (&it, w, startp);
1224 move_it_vertically (&it, window_box_height (w));
c3c45f65
GM
1225 if (it.current_y < it.last_visible_y)
1226 move_it_past_eol (&it);
cbc099e5 1227 value = make_number (IT_CHARPOS (it));
177c0ea7 1228
99593a9d
GM
1229 if (old_buffer)
1230 set_buffer_internal (old_buffer);
478292ed
RS
1231 }
1232 else
b3a10345 1233 XSETINT (value, BUF_Z (b) - XFASTINT (w->window_end_pos));
7ab12479
JB
1234
1235 return value;
1236}
1237
1238DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
a0a37a6f
LT
1239 doc: /* Make point value in WINDOW be at position POS in WINDOW's buffer.
1240Return POS. */)
fdb82f93 1241 (window, pos)
7ab12479
JB
1242 Lisp_Object window, pos;
1243{
1244 register struct window *w = decode_window (window);
1245
b7826503 1246 CHECK_NUMBER_COERCE_MARKER (pos);
e90c4fe6
RS
1247 if (w == XWINDOW (selected_window)
1248 && XBUFFER (w->buffer) == current_buffer)
7ab12479
JB
1249 Fgoto_char (pos);
1250 else
1251 set_marker_restricted (w->pointm, pos, w->buffer);
799417bd 1252
0685cb3c
GM
1253 /* We have to make sure that redisplay updates the window to show
1254 the new value of point. */
1255 if (!EQ (window, selected_window))
799417bd 1256 ++windows_or_buffers_changed;
177c0ea7 1257
7ab12479
JB
1258 return pos;
1259}
1260
1261DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
fdb82f93 1262 doc: /* Make display in WINDOW start at position POS in WINDOW's buffer.
d653c8cc
MR
1263WINDOW defaults to the selected window. Return POS.
1264Optional third arg NOFORCE non-nil inhibits next redisplay from
1265overriding motion of point in order to display at this exact start. */)
fdb82f93 1266 (window, pos, noforce)
7ab12479
JB
1267 Lisp_Object window, pos, noforce;
1268{
1269 register struct window *w = decode_window (window);
1270
b7826503 1271 CHECK_NUMBER_COERCE_MARKER (pos);
7ab12479
JB
1272 set_marker_restricted (w->start, pos, w->buffer);
1273 /* this is not right, but much easier than doing what is right. */
1274 w->start_at_line_beg = Qnil;
265a9e55 1275 if (NILP (noforce))
7ab12479
JB
1276 w->force_start = Qt;
1277 w->update_mode_line = Qt;
d834a2e9 1278 XSETFASTINT (w->last_modified, 0);
3cd21523 1279 XSETFASTINT (w->last_overlay_modified, 0);
62c07cc7
JB
1280 if (!EQ (window, selected_window))
1281 windows_or_buffers_changed++;
ce7fae7d 1282
7ab12479
JB
1283 return pos;
1284}
1285
d653c8cc 1286
7ab12479 1287DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
d653c8cc
MR
1288 0, 1, 0,
1289 doc: /* Return non-nil when WINDOW is dedicated to its buffer.
12bb3111 1290More precisely, return the value assigned by the last call of
7bfac547
MR
1291`set-window-dedicated-p' for WINDOW. Return nil if that function was
1292never called with WINDOW as its argument, or the value set by that
1293function was internally reset since its last call. WINDOW defaults to
1294the selected window.
1295
1296When a window is dedicated to its buffer, `display-buffer' will refrain
1297from displaying another buffer in it. `get-lru-window' and
1298`get-largest-window' treat dedicated windows specially.
1299`delete-windows-on', `replace-buffer-in-windows', `quit-window' and
1300`kill-buffer' can delete a dedicated window and the containing frame.
1301
1302Functions like `set-window-buffer' may change the buffer displayed by a
1303window, unless that window is "strongly" dedicated to its buffer, that
1304is the value returned by `window-dedicated-p' is t. */)
fdb82f93 1305 (window)
7ab12479
JB
1306 Lisp_Object window;
1307{
1308 return decode_window (window)->dedicated;
1309}
1310
d207b766
RS
1311DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p,
1312 Sset_window_dedicated_p, 2, 2, 0,
d653c8cc
MR
1313 doc: /* Mark WINDOW as dedicated according to FLAG.
1314WINDOW defaults to the selected window. FLAG non-nil means mark WINDOW
12bb3111 1315as dedicated to its buffer. FLAG nil means mark WINDOW as non-dedicated.
d653c8cc
MR
1316Return FLAG.
1317
7bfac547
MR
1318When a window is dedicated to its buffer, `display-buffer' will refrain
1319from displaying another buffer in it. `get-lru-window' and
1320`get-largest-window' treat dedicated windows specially.
1321`delete-windows-on', `replace-buffer-in-windows', `quit-window' and
1322`kill-buffer' can delete a dedicated window and the containing
1323frame.
1324
1325As a special case, if FLAG is t, mark WINDOW as "strongly" dedicated to
1326its buffer. Functions like `set-window-buffer' may change the buffer
1327displayed by a window, unless that window is strongly dedicated to its
1328buffer. If and when `set-window-buffer' displays another buffer in a
1329window, it also makes sure that the window is not marked as dedicated. */)
d653c8cc
MR
1330 (window, flag)
1331 Lisp_Object window, flag;
7ab12479
JB
1332{
1333 register struct window *w = decode_window (window);
1334
d653c8cc 1335 w->dedicated = flag;
7ab12479
JB
1336 return w->dedicated;
1337}
1338
d653c8cc 1339
cfbb2395
JB
1340DEFUN ("window-parameters", Fwindow_parameters, Swindow_parameters,
1341 0, 1, 0,
d653c8cc
MR
1342 doc: /* Return the parameters of WINDOW and their values.
1343WINDOW defaults to the selected window. The return value is a list of
1344elements of the form (PARAMETER . VALUE). */)
cfbb2395
JB
1345 (window)
1346 Lisp_Object window;
1347{
927abf37 1348 return Fcopy_alist (decode_window (window)->window_parameters);
cfbb2395
JB
1349}
1350
1351DEFUN ("window-parameter", Fwindow_parameter, Swindow_parameter,
1352 2, 2, 0,
d653c8cc
MR
1353 doc: /* Return WINDOW's value for PARAMETER.
1354WINDOW defaults to the selected window. */)
cfbb2395
JB
1355 (window, parameter)
1356 Lisp_Object window, parameter;
1357{
927abf37
JB
1358 Lisp_Object result;
1359
1360 result = Fassq (parameter, decode_window (window)->window_parameters);
1361 return CDR_SAFE (result);
cfbb2395
JB
1362}
1363
cfbb2395
JB
1364DEFUN ("set-window-parameter", Fset_window_parameter,
1365 Sset_window_parameter, 3, 3, 0,
d653c8cc
MR
1366 doc: /* Set WINDOW's value of PARAMETER to VALUE.
1367WINDOW defaults to the selected window. Return VALUE. */)
cfbb2395
JB
1368 (window, parameter, value)
1369 Lisp_Object window, parameter, value;
1370{
1371 register struct window *w = decode_window (window);
1372 Lisp_Object old_alist_elt;
1373
1374 old_alist_elt = Fassq (parameter, w->window_parameters);
12bb3111 1375 if (NILP (old_alist_elt))
cfbb2395
JB
1376 w->window_parameters = Fcons (Fcons (parameter, value), w->window_parameters);
1377 else
1378 Fsetcdr (old_alist_elt, value);
927abf37 1379 return value;
cfbb2395
JB
1380}
1381
1382
7ab12479
JB
1383DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
1384 0, 1, 0,
c85322d0
EZ
1385 doc: /* Return the display-table that WINDOW is using.
1386WINDOW defaults to the selected window. */)
fdb82f93 1387 (window)
7ab12479
JB
1388 Lisp_Object window;
1389{
1390 return decode_window (window)->display_table;
1391}
1392
5500c422
GM
1393/* Get the display table for use on window W. This is either W's
1394 display table or W's buffer's display table. Ignore the specified
1395 tables if they are not valid; if no valid table is specified,
1396 return 0. */
7ab12479 1397
319315f1 1398struct Lisp_Char_Table *
7ab12479
JB
1399window_display_table (w)
1400 struct window *w;
1401{
c756cdbe
GM
1402 struct Lisp_Char_Table *dp = NULL;
1403
1404 if (DISP_TABLE_P (w->display_table))
1405 dp = XCHAR_TABLE (w->display_table);
1406 else if (BUFFERP (w->buffer))
1407 {
1408 struct buffer *b = XBUFFER (w->buffer);
177c0ea7 1409
c756cdbe
GM
1410 if (DISP_TABLE_P (b->display_table))
1411 dp = XCHAR_TABLE (b->display_table);
1412 else if (DISP_TABLE_P (Vstandard_display_table))
1413 dp = XCHAR_TABLE (Vstandard_display_table);
1414 }
171d003c 1415
c756cdbe 1416 return dp;
7ab12479
JB
1417}
1418
3a2712f9 1419DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_display_table, 2, 2, 0,
fdb82f93
PJ
1420 doc: /* Set WINDOW's display-table to TABLE. */)
1421 (window, table)
7ab12479
JB
1422 register Lisp_Object window, table;
1423{
1424 register struct window *w;
7ab12479
JB
1425
1426 w = decode_window (window);
1427 w->display_table = table;
1428 return table;
1429}
1430\f
1431/* Record info on buffer window w is displaying
1432 when it is about to cease to display that buffer. */
dfcf069d 1433static void
7ab12479
JB
1434unshow_buffer (w)
1435 register struct window *w;
1436{
12cae7c0 1437 Lisp_Object buf;
b73ea88e 1438 struct buffer *b;
7ab12479 1439
12cae7c0 1440 buf = w->buffer;
b73ea88e
RS
1441 b = XBUFFER (buf);
1442 if (b != XMARKER (w->pointm)->buffer)
7ab12479
JB
1443 abort ();
1444
573f41ab 1445#if 0
7ab12479
JB
1446 if (w == XWINDOW (selected_window)
1447 || ! EQ (buf, XWINDOW (selected_window)->buffer))
1448 /* Do this except when the selected window's buffer
1449 is being removed from some other window. */
573f41ab
RS
1450#endif
1451 /* last_window_start records the start position that this buffer
1452 had in the last window to be disconnected from it.
1453 Now that this statement is unconditional,
1454 it is possible for the buffer to be displayed in the
1455 selected window, while last_window_start reflects another
1456 window which was recently showing the same buffer.
1457 Some people might say that might be a good thing. Let's see. */
b73ea88e 1458 b->last_window_start = marker_position (w->start);
7ab12479
JB
1459
1460 /* Point in the selected window's buffer
1461 is actually stored in that buffer, and the window's pointm isn't used.
1462 So don't clobber point in that buffer. */
719eaeb1
GM
1463 if (! EQ (buf, XWINDOW (selected_window)->buffer)
1464 /* This line helps to fix Horsley's testbug.el bug. */
8801a864
KR
1465 && !(WINDOWP (b->last_selected_window)
1466 && w != XWINDOW (b->last_selected_window)
719eaeb1 1467 && EQ (buf, XWINDOW (b->last_selected_window)->buffer)))
b73ea88e
RS
1468 temp_set_point_both (b,
1469 clip_to_bounds (BUF_BEGV (b),
1470 XMARKER (w->pointm)->charpos,
1471 BUF_ZV (b)),
1472 clip_to_bounds (BUF_BEGV_BYTE (b),
1473 marker_byte_position (w->pointm),
1474 BUF_ZV_BYTE (b)));
177c0ea7 1475
8801a864
KR
1476 if (WINDOWP (b->last_selected_window)
1477 && w == XWINDOW (b->last_selected_window))
719eaeb1 1478 b->last_selected_window = Qnil;
7ab12479
JB
1479}
1480
1481/* Put replacement into the window structure in place of old. */
dfcf069d 1482static void
7ab12479
JB
1483replace_window (old, replacement)
1484 Lisp_Object old, replacement;
1485{
1486 register Lisp_Object tem;
1487 register struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
1488
44fa5b1e
JB
1489 /* If OLD is its frame's root_window, then replacement is the new
1490 root_window for that frame. */
7ab12479 1491
7f4161e0 1492 if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
44fa5b1e 1493 FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
7ab12479 1494
949cf20f
KS
1495 p->left_col = o->left_col;
1496 p->top_line = o->top_line;
1497 p->total_cols = o->total_cols;
1498 p->total_lines = o->total_lines;
5500c422
GM
1499 p->desired_matrix = p->current_matrix = 0;
1500 p->vscroll = 0;
1501 bzero (&p->cursor, sizeof (p->cursor));
1502 bzero (&p->last_cursor, sizeof (p->last_cursor));
1503 bzero (&p->phys_cursor, sizeof (p->phys_cursor));
1504 p->phys_cursor_type = -1;
4b26579e 1505 p->phys_cursor_width = -1;
5500c422
GM
1506 p->must_be_updated_p = 0;
1507 p->pseudo_window_p = 0;
1508 XSETFASTINT (p->window_end_vpos, 0);
1509 XSETFASTINT (p->window_end_pos, 0);
1510 p->window_end_valid = Qnil;
7bbb5782 1511 p->frozen_window_start_p = 0;
949cf20f 1512 p->orig_top_line = p->orig_total_lines = Qnil;
7ab12479
JB
1513
1514 p->next = tem = o->next;
265a9e55 1515 if (!NILP (tem))
7ab12479
JB
1516 XWINDOW (tem)->prev = replacement;
1517
1518 p->prev = tem = o->prev;
265a9e55 1519 if (!NILP (tem))
7ab12479
JB
1520 XWINDOW (tem)->next = replacement;
1521
1522 p->parent = tem = o->parent;
265a9e55 1523 if (!NILP (tem))
7ab12479
JB
1524 {
1525 if (EQ (XWINDOW (tem)->vchild, old))
1526 XWINDOW (tem)->vchild = replacement;
1527 if (EQ (XWINDOW (tem)->hchild, old))
1528 XWINDOW (tem)->hchild = replacement;
1529 }
1530
1531/*** Here, if replacement is a vertical combination
1532and so is its new parent, we should make replacement's
1533children be children of that parent instead. ***/
1534}
1535
1536DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
8fef9de1
MR
1537 doc: /* Remove WINDOW from its frame.
1538WINDOW defaults to the selected window. Return nil.
1539Signal an error when WINDOW is the only window on its frame. */)
fdb82f93 1540 (window)
7ab12479 1541 register Lisp_Object window;
543f5fb1 1542{
eeca6f6f
SM
1543 struct frame *f;
1544 if (NILP (window))
1545 window = selected_window;
dbf64827
JB
1546 else
1547 CHECK_LIVE_WINDOW (window);
1548
eeca6f6f 1549 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
543f5fb1
RS
1550 delete_window (window);
1551
eeca6f6f 1552 run_window_configuration_change_hook (f);
543f5fb1
RS
1553
1554 return Qnil;
1555}
1556
5e14b1fc 1557void
543f5fb1
RS
1558delete_window (window)
1559 register Lisp_Object window;
7ab12479
JB
1560{
1561 register Lisp_Object tem, parent, sib;
1562 register struct window *p;
1563 register struct window *par;
951f9df5 1564 struct frame *f;
7ab12479 1565
605be8af
JB
1566 /* Because this function is called by other C code on non-leaf
1567 windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
1568 so we can't decode_window here. */
eeca6f6f 1569 CHECK_WINDOW (window);
7ab12479 1570 p = XWINDOW (window);
605be8af 1571
0d384044 1572 /* It's a no-op to delete an already-deleted window. */
605be8af
JB
1573 if (NILP (p->buffer)
1574 && NILP (p->hchild)
1575 && NILP (p->vchild))
296b535c 1576 return;
605be8af 1577
7ab12479 1578 parent = p->parent;
265a9e55 1579 if (NILP (parent))
7ab12479
JB
1580 error ("Attempt to delete minibuffer or sole ordinary window");
1581 par = XWINDOW (parent);
1582
1583 windows_or_buffers_changed++;
67492200 1584 Vwindow_list = Qnil;
951f9df5
GM
1585 f = XFRAME (WINDOW_FRAME (p));
1586 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
7ab12479 1587
605be8af
JB
1588 /* Are we trying to delete any frame's selected window? */
1589 {
192c3131 1590 Lisp_Object swindow, pwindow;
605be8af 1591
0def0403
RS
1592 /* See if the frame's selected window is either WINDOW
1593 or any subwindow of it, by finding all that window's parents
1594 and comparing each one with WINDOW. */
192c3131 1595 swindow = FRAME_SELECTED_WINDOW (f);
0def0403 1596
192c3131 1597 while (1)
0def0403 1598 {
192c3131
RS
1599 pwindow = swindow;
1600 while (!NILP (pwindow))
1601 {
1602 if (EQ (window, pwindow))
1603 break;
1604 pwindow = XWINDOW (pwindow)->parent;
1605 }
1606
1607 /* If the window being deleted is not a parent of SWINDOW,
1608 then SWINDOW is ok as the new selected window. */
1609 if (!EQ (window, pwindow))
0def0403 1610 break;
192c3131 1611 /* Otherwise, try another window for SWINDOW. */
3b8c0c70 1612 swindow = Fnext_window (swindow, Qlambda, Qnil);
192c3131
RS
1613
1614 /* If we get back to the frame's selected window,
1615 it means there was no acceptable alternative,
1616 so we cannot delete. */
1617 if (EQ (swindow, FRAME_SELECTED_WINDOW (f)))
1618 error ("Cannot delete window");
0def0403
RS
1619 }
1620
192c3131
RS
1621 /* If we need to change SWINDOW, do it. */
1622 if (! EQ (swindow, FRAME_SELECTED_WINDOW (f)))
605be8af 1623 {
605be8af
JB
1624 /* If we're about to delete the selected window on the
1625 selected frame, then we should use Fselect_window to select
1626 the new window. On the other hand, if we're about to
1627 delete the selected window on any other frame, we shouldn't do
1628 anything but set the frame's selected_window slot. */
192c3131 1629 if (EQ (FRAME_SELECTED_WINDOW (f), selected_window))
14d87dc9 1630 Fselect_window (swindow, Qnil);
605be8af 1631 else
192c3131 1632 FRAME_SELECTED_WINDOW (f) = swindow;
605be8af
JB
1633 }
1634 }
7ab12479 1635
0d384044
RS
1636 /* Now we know we can delete this one. */
1637 window_deletion_count++;
1638
7ab12479
JB
1639 tem = p->buffer;
1640 /* tem is null for dummy parent windows
1641 (which have inferiors but not any contents themselves) */
265a9e55 1642 if (!NILP (tem))
7ab12479
JB
1643 {
1644 unshow_buffer (p);
2d0834cc
SM
1645 unchain_marker (XMARKER (p->pointm));
1646 unchain_marker (XMARKER (p->start));
7ab12479
JB
1647 }
1648
05e71564
GM
1649 /* Free window glyph matrices. It is sure that they are allocated
1650 again when ADJUST_GLYPHS is called. Block input so that expose
1651 events and other events that access glyph matrices are not
1652 processed while we are changing them. */
1653 BLOCK_INPUT;
951f9df5 1654 free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (f)));
5500c422 1655
7ab12479 1656 tem = p->next;
265a9e55 1657 if (!NILP (tem))
7ab12479
JB
1658 XWINDOW (tem)->prev = p->prev;
1659
1660 tem = p->prev;
265a9e55 1661 if (!NILP (tem))
7ab12479
JB
1662 XWINDOW (tem)->next = p->next;
1663
1664 if (EQ (window, par->hchild))
1665 par->hchild = p->next;
1666 if (EQ (window, par->vchild))
1667 par->vchild = p->next;
1668
1669 /* Find one of our siblings to give our space to. */
1670 sib = p->prev;
265a9e55 1671 if (NILP (sib))
7ab12479
JB
1672 {
1673 /* If p gives its space to its next sibling, that sibling needs
1674 to have its top/left side pulled back to where p's is.
1675 set_window_{height,width} will re-position the sibling's
1676 children. */
1677 sib = p->next;
949cf20f
KS
1678 XWINDOW (sib)->top_line = p->top_line;
1679 XWINDOW (sib)->left_col = p->left_col;
7ab12479
JB
1680 }
1681
1682 /* Stretch that sibling. */
265a9e55 1683 if (!NILP (par->vchild))
7ab12479 1684 set_window_height (sib,
949cf20f 1685 XFASTINT (XWINDOW (sib)->total_lines) + XFASTINT (p->total_lines),
7ab12479 1686 1);
265a9e55 1687 if (!NILP (par->hchild))
7ab12479 1688 set_window_width (sib,
949cf20f 1689 XFASTINT (XWINDOW (sib)->total_cols) + XFASTINT (p->total_cols),
7ab12479
JB
1690 1);
1691
1692 /* If parent now has only one child,
1693 put the child into the parent's place. */
7ab12479 1694 tem = par->hchild;
265a9e55 1695 if (NILP (tem))
7ab12479 1696 tem = par->vchild;
5494d7bc 1697 if (NILP (XWINDOW (tem)->next)) {
7ab12479 1698 replace_window (parent, tem);
5494d7bc
JD
1699 par = XWINDOW (tem);
1700 }
605be8af
JB
1701
1702 /* Since we may be deleting combination windows, we must make sure that
1703 not only p but all its children have been marked as deleted. */
1704 if (! NILP (p->hchild))
1705 delete_all_subwindows (XWINDOW (p->hchild));
1706 else if (! NILP (p->vchild))
1707 delete_all_subwindows (XWINDOW (p->vchild));
1708
1709 /* Mark this window as deleted. */
1710 p->buffer = p->hchild = p->vchild = Qnil;
5500c422 1711
5494d7bc
JD
1712 if (! NILP (par->parent))
1713 par = XWINDOW (par->parent);
1714
1715 /* Check if we have a v/hchild with a v/hchild. In that case remove
1716 one of them. */
ae12ecd7 1717
5494d7bc
JD
1718 if (! NILP (par->vchild) && ! NILP (XWINDOW (par->vchild)->vchild))
1719 {
1720 p = XWINDOW (par->vchild);
1721 par->vchild = p->vchild;
1722 tem = p->vchild;
1723 }
1724 else if (! NILP (par->hchild) && ! NILP (XWINDOW (par->hchild)->hchild))
1725 {
1726 p = XWINDOW (par->hchild);
1727 par->hchild = p->hchild;
1728 tem = p->hchild;
1729 }
1730 else
1731 p = 0;
1732
1733 if (p)
1734 {
1735 while (! NILP (tem)) {
1736 XWINDOW (tem)->parent = p->parent;
1737 if (NILP (XWINDOW (tem)->next))
1738 break;
1739 tem = XWINDOW (tem)->next;
1740 }
1741 if (! NILP (tem)) {
1742 /* The next of the v/hchild we are removing is now the next of the
1743 last child for the v/hchild:
1744 Before v/hchild -> v/hchild -> next1 -> next2
1745 |
1746 -> next3
1747 After: v/hchild -> next1 -> next2 -> next3
1748 */
1749 XWINDOW (tem)->next = p->next;
1750 if (! NILP (p->next))
1751 XWINDOW (p->next)->prev = tem;
1752 }
1753 p->next = p->prev = p->vchild = p->hchild = p->buffer = Qnil;
1754 }
1755
1756
5500c422 1757 /* Adjust glyph matrices. */
951f9df5 1758 adjust_glyphs (f);
05e71564 1759 UNBLOCK_INPUT;
7ab12479 1760}
67492200
GM
1761
1762
7ab12479 1763\f
67492200
GM
1764/***********************************************************************
1765 Window List
1766 ***********************************************************************/
1767
f95464e4
GM
1768/* Add window W to *USER_DATA. USER_DATA is actually a Lisp_Object
1769 pointer. This is a callback function for foreach_window, used in
1770 function window_list. */
67492200
GM
1771
1772static int
f95464e4 1773add_window_to_list (w, user_data)
67492200 1774 struct window *w;
f95464e4 1775 void *user_data;
67492200 1776{
f95464e4 1777 Lisp_Object *list = (Lisp_Object *) user_data;
67492200
GM
1778 Lisp_Object window;
1779 XSETWINDOW (window, w);
212116d6 1780 *list = Fcons (window, *list);
67492200
GM
1781 return 1;
1782}
1783
1784
1785/* Return a list of all windows, for use by next_window. If
1786 Vwindow_list is a list, return that list. Otherwise, build a new
1787 list, cache it in Vwindow_list, and return that. */
1788
1789static Lisp_Object
1790window_list ()
1791{
1792 if (!CONSP (Vwindow_list))
1793 {
1794 Lisp_Object tail;
212116d6 1795
67492200
GM
1796 Vwindow_list = Qnil;
1797 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
212116d6
GM
1798 {
1799 Lisp_Object args[2];
1800
1801 /* We are visiting windows in canonical order, and add
1802 new windows at the front of args[1], which means we
1803 have to reverse this list at the end. */
1804 args[1] = Qnil;
1805 foreach_window (XFRAME (XCAR (tail)), add_window_to_list, &args[1]);
1806 args[0] = Vwindow_list;
1807 args[1] = Fnreverse (args[1]);
1808 Vwindow_list = Fnconc (2, args);
1809 }
67492200 1810 }
177c0ea7 1811
67492200
GM
1812 return Vwindow_list;
1813}
1814
1815
118ea242
GM
1816/* Value is non-zero if WINDOW satisfies the constraints given by
1817 OWINDOW, MINIBUF and ALL_FRAMES.
67492200 1818
118ea242
GM
1819 MINIBUF t means WINDOW may be minibuffer windows.
1820 `lambda' means WINDOW may not be a minibuffer window.
1821 a window means a specific minibuffer window
67492200 1822
118ea242
GM
1823 ALL_FRAMES t means search all frames,
1824 nil means search just current frame,
1825 `visible' means search just visible frames,
1826 0 means search visible and iconified frames,
1827 a window means search the frame that window belongs to,
1828 a frame means consider windows on that frame, only. */
67492200
GM
1829
1830static int
118ea242
GM
1831candidate_window_p (window, owindow, minibuf, all_frames)
1832 Lisp_Object window, owindow, minibuf, all_frames;
67492200
GM
1833{
1834 struct window *w = XWINDOW (window);
1835 struct frame *f = XFRAME (w->frame);
1836 int candidate_p = 1;
1837
1838 if (!BUFFERP (w->buffer))
1839 candidate_p = 0;
1840 else if (MINI_WINDOW_P (w)
1841 && (EQ (minibuf, Qlambda)
1842 || (WINDOWP (minibuf) && !EQ (minibuf, window))))
1843 {
1844 /* If MINIBUF is `lambda' don't consider any mini-windows.
1845 If it is a window, consider only that one. */
1846 candidate_p = 0;
1847 }
118ea242
GM
1848 else if (EQ (all_frames, Qt))
1849 candidate_p = 1;
67492200 1850 else if (NILP (all_frames))
118ea242
GM
1851 {
1852 xassert (WINDOWP (owindow));
1853 candidate_p = EQ (w->frame, XWINDOW (owindow)->frame);
1854 }
67492200
GM
1855 else if (EQ (all_frames, Qvisible))
1856 {
1857 FRAME_SAMPLE_VISIBILITY (f);
de509a60
SM
1858 candidate_p = FRAME_VISIBLE_P (f)
1859 && (FRAME_TERMINAL (XFRAME (w->frame))
1860 == FRAME_TERMINAL (XFRAME (selected_frame)));
1861
67492200
GM
1862 }
1863 else if (INTEGERP (all_frames) && XINT (all_frames) == 0)
1864 {
1865 FRAME_SAMPLE_VISIBILITY (f);
ca2d5566
SM
1866 candidate_p = (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f)
1867#ifdef HAVE_X_WINDOWS
1868 /* Yuck!! If we've just created the frame and the
1869 window-manager requested the user to place it
1870 manually, the window may still not be considered
1871 `visible'. I'd argue it should be at least
1872 something like `iconified', but don't know how to do
1873 that yet. --Stef */
1874 || (FRAME_X_P (f) && f->output_data.x->asked_for_visible
1875 && !f->output_data.x->has_been_visible)
1876#endif
de509a60
SM
1877 )
1878 && (FRAME_TERMINAL (XFRAME (w->frame))
1879 == FRAME_TERMINAL (XFRAME (selected_frame)));
67492200 1880 }
67492200
GM
1881 else if (WINDOWP (all_frames))
1882 candidate_p = (EQ (FRAME_MINIBUF_WINDOW (f), all_frames)
1883 || EQ (XWINDOW (all_frames)->frame, w->frame)
1884 || EQ (XWINDOW (all_frames)->frame, FRAME_FOCUS_FRAME (f)));
118ea242
GM
1885 else if (FRAMEP (all_frames))
1886 candidate_p = EQ (all_frames, w->frame);
67492200
GM
1887
1888 return candidate_p;
1889}
1890
1891
1892/* Decode arguments as allowed by Fnext_window, Fprevious_window, and
1893 Fwindow_list. See there for the meaning of WINDOW, MINIBUF, and
1894 ALL_FRAMES. */
1895
1896static void
1897decode_next_window_args (window, minibuf, all_frames)
1898 Lisp_Object *window, *minibuf, *all_frames;
1899{
1900 if (NILP (*window))
1901 *window = selected_window;
1902 else
b7826503 1903 CHECK_LIVE_WINDOW (*window);
177c0ea7 1904
67492200
GM
1905 /* MINIBUF nil may or may not include minibuffers. Decide if it
1906 does. */
1907 if (NILP (*minibuf))
1908 *minibuf = minibuf_level ? minibuf_window : Qlambda;
1909 else if (!EQ (*minibuf, Qt))
1910 *minibuf = Qlambda;
177c0ea7 1911
67492200
GM
1912 /* Now *MINIBUF can be t => count all minibuffer windows, `lambda'
1913 => count none of them, or a specific minibuffer window (the
1914 active one) to count. */
1915
1916 /* ALL_FRAMES nil doesn't specify which frames to include. */
1917 if (NILP (*all_frames))
1918 *all_frames = (!EQ (*minibuf, Qlambda)
1919 ? FRAME_MINIBUF_WINDOW (XFRAME (XWINDOW (*window)->frame))
1920 : Qnil);
1921 else if (EQ (*all_frames, Qvisible))
1922 ;
0f8fe9a2 1923 else if (EQ (*all_frames, make_number (0)))
67492200
GM
1924 ;
1925 else if (FRAMEP (*all_frames))
1926 ;
1927 else if (!EQ (*all_frames, Qt))
1928 *all_frames = Qnil;
177c0ea7 1929
67492200
GM
1930 /* Now *ALL_FRAMES is t meaning search all frames, nil meaning
1931 search just current frame, `visible' meaning search just visible
1932 frames, 0 meaning search visible and iconified frames, or a
1933 window, meaning search the frame that window belongs to, or a
1934 frame, meaning consider windows on that frame, only. */
1935}
1936
1937
ab6d1131 1938/* Return the next or previous window of WINDOW in cyclic ordering
67492200
GM
1939 of windows. NEXT_P non-zero means return the next window. See the
1940 documentation string of next-window for the meaning of MINIBUF and
1941 ALL_FRAMES. */
1942
1943static Lisp_Object
1944next_window (window, minibuf, all_frames, next_p)
1945 Lisp_Object window, minibuf, all_frames;
1946 int next_p;
1947{
1948 decode_next_window_args (&window, &minibuf, &all_frames);
177c0ea7 1949
67492200
GM
1950 /* If ALL_FRAMES is a frame, and WINDOW isn't on that frame, just
1951 return the first window on the frame. */
1952 if (FRAMEP (all_frames)
1953 && !EQ (all_frames, XWINDOW (window)->frame))
1954 return Fframe_first_window (all_frames);
177c0ea7 1955
212116d6 1956 if (next_p)
67492200
GM
1957 {
1958 Lisp_Object list;
177c0ea7 1959
67492200
GM
1960 /* Find WINDOW in the list of all windows. */
1961 list = Fmemq (window, window_list ());
1962
1963 /* Scan forward from WINDOW to the end of the window list. */
1964 if (CONSP (list))
1965 for (list = XCDR (list); CONSP (list); list = XCDR (list))
118ea242 1966 if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
67492200
GM
1967 break;
1968
1969 /* Scan from the start of the window list up to WINDOW. */
1970 if (!CONSP (list))
1971 for (list = Vwindow_list;
1972 CONSP (list) && !EQ (XCAR (list), window);
1973 list = XCDR (list))
118ea242 1974 if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
67492200
GM
1975 break;
1976
1977 if (CONSP (list))
1978 window = XCAR (list);
1979 }
1980 else
1981 {
1982 Lisp_Object candidate, list;
177c0ea7 1983
67492200
GM
1984 /* Scan through the list of windows for candidates. If there are
1985 candidate windows in front of WINDOW, the last one of these
1986 is the one we want. If there are candidates following WINDOW
1987 in the list, again the last one of these is the one we want. */
1988 candidate = Qnil;
1989 for (list = window_list (); CONSP (list); list = XCDR (list))
1990 {
1991 if (EQ (XCAR (list), window))
1992 {
1993 if (WINDOWP (candidate))
1994 break;
1995 }
118ea242
GM
1996 else if (candidate_window_p (XCAR (list), window, minibuf,
1997 all_frames))
67492200
GM
1998 candidate = XCAR (list);
1999 }
2000
2001 if (WINDOWP (candidate))
2002 window = candidate;
2003 }
2004
2005 return window;
2006}
7ab12479 2007
7ab12479 2008
26f6279d 2009DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
ab6d1131
MR
2010 doc: /* Return window following WINDOW in cyclic ordering of windows.
2011WINDOW defaults to the selected window. The optional arguments
2012MINIBUF and ALL-FRAMES specify the set of windows to consider.
fdb82f93 2013
ab6d1131
MR
2014MINIBUF t means consider the minibuffer window even if the
2015minibuffer is not active. MINIBUF nil or omitted means consider
2016the minibuffer window only if the minibuffer is active. Any
2017other value means do not consider the minibuffer window even if
2018the minibuffer is active.
fdb82f93
PJ
2019
2020Several frames may share a single minibuffer; if the minibuffer
ab6d1131
MR
2021is active, all windows on all frames that share that minibuffer
2022are considered too. Therefore, if you are using a separate
2023minibuffer frame and the minibuffer is active and MINIBUF says it
2024counts, `next-window' considers the windows in the frame from
2025which you entered the minibuffer, as well as the minibuffer
2026window.
2027
2028ALL-FRAMES nil or omitted means consider all windows on WINDOW's
2029 frame, plus the minibuffer window if specified by the MINIBUF
2030 argument, see above. If the minibuffer counts, consider all
2031 windows on all frames that share that minibuffer too.
2032ALL-FRAMES t means consider all windows on all existing frames.
2033ALL-FRAMES `visible' means consider all windows on all visible
2034 frames.
2035ALL-FRAMES 0 means consider all windows on all visible and
2036 iconified frames.
2037ALL-FRAMES a frame means consider all windows on that frame only.
2038Anything else means consider all windows on WINDOW's frame and no
2039 others.
fdb82f93
PJ
2040
2041If you use consistent values for MINIBUF and ALL-FRAMES, you can use
2042`next-window' to iterate through the entire cycle of acceptable
2043windows, eventually ending up back at the window you started with.
2044`previous-window' traverses the same cycle, in the reverse order. */)
2045 (window, minibuf, all_frames)
67492200 2046 Lisp_Object window, minibuf, all_frames;
7ab12479 2047{
67492200 2048 return next_window (window, minibuf, all_frames, 1);
7ab12479
JB
2049}
2050
67492200 2051
26f6279d 2052DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
ab6d1131
MR
2053 doc: /* Return window preceding WINDOW in cyclic ordering of windows.
2054WINDOW defaults to the selected window. The optional arguments
2055MINIBUF and ALL-FRAMES specify the set of windows to consider.
2056For the precise meaning of these arguments see `next-window'.
2057
2058If you use consistent values for MINIBUF and ALL-FRAMES, you can
2059use `previous-window' to iterate through the entire cycle of
2060acceptable windows, eventually ending up back at the window you
2061started with. `next-window' traverses the same cycle, in the
2062reverse order. */)
fdb82f93 2063 (window, minibuf, all_frames)
67492200 2064 Lisp_Object window, minibuf, all_frames;
7ab12479 2065{
67492200 2066 return next_window (window, minibuf, all_frames, 0);
7ab12479
JB
2067}
2068
67492200 2069
62c07cc7 2070DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
ab6d1131
MR
2071 doc: /* Select another window in cyclic ordering of windows.
2072COUNT specifies the number of windows to skip, starting with the
2073selected window, before making the selection. If COUNT is
2074positive, skip COUNT windows forwards. If COUNT is negative,
2075skip -COUNT windows backwards. COUNT zero means do not skip any
2076window, so select the selected window. In an interactive call,
2077COUNT is the numeric prefix argument. Return nil.
2078
2079This function uses `next-window' for finding the window to select.
2080The argument ALL-FRAMES has the same meaning as in `next-window',
2081but the MINIBUF argument of `next-window' is always effectively
2082nil. */)
2083 (count, all_frames)
2084 Lisp_Object count, all_frames;
7ab12479 2085{
67492200
GM
2086 Lisp_Object window;
2087 int i;
7ab12479 2088
ab6d1131 2089 CHECK_NUMBER (count);
67492200 2090 window = selected_window;
177c0ea7 2091
ab6d1131 2092 for (i = XINT (count); i > 0; --i)
67492200
GM
2093 window = Fnext_window (window, Qnil, all_frames);
2094 for (; i < 0; ++i)
2095 window = Fprevious_window (window, Qnil, all_frames);
50e88778 2096
14d87dc9 2097 Fselect_window (window, Qnil);
7ab12479
JB
2098 return Qnil;
2099}
67492200
GM
2100
2101
2102DEFUN ("window-list", Fwindow_list, Swindow_list, 0, 3, 0,
fdb82f93
PJ
2103 doc: /* Return a list of windows on FRAME, starting with WINDOW.
2104FRAME nil or omitted means use the selected frame.
2105WINDOW nil or omitted means use the selected window.
2106MINIBUF t means include the minibuffer window, even if it isn't active.
2107MINIBUF nil or omitted means include the minibuffer window only
2108if it's active.
2109MINIBUF neither nil nor t means never include the minibuffer window. */)
2110 (frame, minibuf, window)
cd2904bd
GM
2111 Lisp_Object frame, minibuf, window;
2112{
cd2904bd 2113 if (NILP (window))
acc6289a
SM
2114 window = FRAMEP (frame) ? XFRAME (frame)->selected_window : selected_window;
2115 CHECK_WINDOW (window);
cd2904bd
GM
2116 if (NILP (frame))
2117 frame = selected_frame;
2118
2119 if (!EQ (frame, XWINDOW (window)->frame))
2120 error ("Window is on a different frame");
2121
2122 return window_list_1 (window, minibuf, frame);
2123}
2124
2125
ab6d1131 2126/* Return a list of windows in cyclic ordering. Arguments are like
cd2904bd
GM
2127 for `next-window'. */
2128
2129static Lisp_Object
2130window_list_1 (window, minibuf, all_frames)
069f5950 2131 Lisp_Object window, minibuf, all_frames;
67492200 2132{
403de3b4 2133 Lisp_Object tail, list, rest;
67492200
GM
2134
2135 decode_next_window_args (&window, &minibuf, &all_frames);
2136 list = Qnil;
177c0ea7 2137
67492200 2138 for (tail = window_list (); CONSP (tail); tail = XCDR (tail))
118ea242 2139 if (candidate_window_p (XCAR (tail), window, minibuf, all_frames))
67492200 2140 list = Fcons (XCAR (tail), list);
177c0ea7 2141
403de3b4
RS
2142 /* Rotate the list to start with WINDOW. */
2143 list = Fnreverse (list);
2144 rest = Fmemq (window, list);
2145 if (!NILP (rest) && !EQ (rest, list))
2146 {
1725a7c9 2147 for (tail = list; !EQ (XCDR (tail), rest); tail = XCDR (tail))
403de3b4
RS
2148 ;
2149 XSETCDR (tail, Qnil);
2150 list = nconc2 (rest, list);
2151 }
2152 return list;
67492200
GM
2153}
2154
2155
7ab12479
JB
2156\f
2157/* Look at all windows, performing an operation specified by TYPE
2158 with argument OBJ.
75d8f668 2159 If FRAMES is Qt, look at all frames;
75d8f668 2160 Qnil, look at just the selected frame;
89bca612 2161 Qvisible, look at visible frames;
75d8f668 2162 a frame, just look at windows on that frame.
85fe3b5e 2163 If MINI is non-zero, perform the operation on minibuffer windows too. */
7ab12479
JB
2164
2165enum window_loop
2166{
2167 WINDOW_LOOP_UNUSED,
2168 GET_BUFFER_WINDOW, /* Arg is buffer */
2169 GET_LRU_WINDOW, /* Arg is t for full-width windows only */
2170 DELETE_OTHER_WINDOWS, /* Arg is window not to delete */
2171 DELETE_BUFFER_WINDOWS, /* Arg is buffer */
2172 GET_LARGEST_WINDOW,
3f8ab7bd 2173 UNSHOW_BUFFER, /* Arg is buffer */
6b61353c 2174 REDISPLAY_BUFFER_WINDOWS, /* Arg is buffer */
3f8ab7bd 2175 CHECK_ALL_WINDOWS
7ab12479
JB
2176};
2177
2178static Lisp_Object
44fa5b1e 2179window_loop (type, obj, mini, frames)
7ab12479 2180 enum window_loop type;
118ea242 2181 Lisp_Object obj, frames;
7ab12479
JB
2182 int mini;
2183{
118ea242
GM
2184 Lisp_Object window, windows, best_window, frame_arg;
2185 struct frame *f;
ffdc852d 2186 struct gcpro gcpro1;
177c0ea7 2187
44fa5b1e
JB
2188 /* If we're only looping through windows on a particular frame,
2189 frame points to that frame. If we're looping through windows
2190 on all frames, frame is 0. */
2191 if (FRAMEP (frames))
118ea242 2192 f = XFRAME (frames);
44fa5b1e 2193 else if (NILP (frames))
118ea242 2194 f = SELECTED_FRAME ();
7ab12479 2195 else
118ea242 2196 f = NULL;
177c0ea7 2197
118ea242 2198 if (f)
89bca612 2199 frame_arg = Qlambda;
0f8fe9a2 2200 else if (EQ (frames, make_number (0)))
f812f9c6 2201 frame_arg = frames;
89bca612
RS
2202 else if (EQ (frames, Qvisible))
2203 frame_arg = frames;
118ea242
GM
2204 else
2205 frame_arg = Qt;
7ab12479 2206
89bca612
RS
2207 /* frame_arg is Qlambda to stick to one frame,
2208 Qvisible to consider all visible frames,
2209 or Qt otherwise. */
2210
7ab12479 2211 /* Pick a window to start with. */
017b2bad 2212 if (WINDOWP (obj))
118ea242
GM
2213 window = obj;
2214 else if (f)
2215 window = FRAME_SELECTED_WINDOW (f);
7ab12479 2216 else
118ea242 2217 window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
4b206065 2218
cd2904bd 2219 windows = window_list_1 (window, mini ? Qt : Qnil, frame_arg);
118ea242 2220 GCPRO1 (windows);
7ab12479 2221 best_window = Qnil;
118ea242 2222
e67a1dea 2223 for (; CONSP (windows); windows = XCDR (windows))
7ab12479 2224 {
118ea242 2225 struct window *w;
177c0ea7 2226
118ea242
GM
2227 window = XCAR (windows);
2228 w = XWINDOW (window);
177c0ea7 2229
118ea242
GM
2230 /* Note that we do not pay attention here to whether the frame
2231 is visible, since Fwindow_list skips non-visible frames if
2232 that is desired, under the control of frame_arg. */
2233 if (!MINI_WINDOW_P (w)
65a04b96
RS
2234 /* For UNSHOW_BUFFER, we must always consider all windows. */
2235 || type == UNSHOW_BUFFER
7ab12479
JB
2236 || (mini && minibuf_level > 0))
2237 switch (type)
2238 {
2239 case GET_BUFFER_WINDOW:
118ea242 2240 if (EQ (w->buffer, obj)
5c204627
RS
2241 /* Don't find any minibuffer window
2242 except the one that is currently in use. */
118ea242
GM
2243 && (MINI_WINDOW_P (w)
2244 ? EQ (window, minibuf_window)
2245 : 1))
2246 {
5ddc1b75
GM
2247 if (NILP (best_window))
2248 best_window = window;
2249 else if (EQ (window, selected_window))
ca2d5566
SM
2250 /* Prefer to return selected-window. */
2251 RETURN_UNGCPRO (window);
2252 else if (EQ (Fwindow_frame (window), selected_frame))
2253 /* Prefer windows on the current frame. */
5ddc1b75 2254 best_window = window;
118ea242 2255 }
7ab12479
JB
2256 break;
2257
2258 case GET_LRU_WINDOW:
20b69789
SM
2259 /* `obj' is an integer encoding a bitvector.
2260 `obj & 1' means consider only full-width windows.
2261 `obj & 2' means consider also dedicated windows. */
2262 if (((XINT (obj) & 1) && !WINDOW_FULL_WIDTH_P (w))
3f489dc7 2263 || (!(XINT (obj) & 2) && !NILP (w->dedicated))
20b69789
SM
2264 /* Minibuffer windows are always ignored. */
2265 || MINI_WINDOW_P (w))
7ab12479 2266 break;
265a9e55 2267 if (NILP (best_window)
7ab12479 2268 || (XFASTINT (XWINDOW (best_window)->use_time)
118ea242
GM
2269 > XFASTINT (w->use_time)))
2270 best_window = window;
7ab12479
JB
2271 break;
2272
2273 case DELETE_OTHER_WINDOWS:
118ea242
GM
2274 if (!EQ (window, obj))
2275 Fdelete_window (window);
7ab12479
JB
2276 break;
2277
2278 case DELETE_BUFFER_WINDOWS:
118ea242 2279 if (EQ (w->buffer, obj))
7ab12479 2280 {
118ea242 2281 struct frame *f = XFRAME (WINDOW_FRAME (w));
3548e138
RS
2282
2283 /* If this window is dedicated, and in a frame of its own,
2284 kill the frame. */
118ea242
GM
2285 if (EQ (window, FRAME_ROOT_WINDOW (f))
2286 && !NILP (w->dedicated)
3548e138 2287 && other_visible_frames (f))
7ab12479 2288 {
3548e138
RS
2289 /* Skip the other windows on this frame.
2290 There might be one, the minibuffer! */
118ea242
GM
2291 while (CONSP (XCDR (windows))
2292 && EQ (XWINDOW (XCAR (windows))->frame,
2293 XWINDOW (XCAR (XCDR (windows)))->frame))
2294 windows = XCDR (windows);
177c0ea7 2295
3548e138 2296 /* Now we can safely delete the frame. */
56f2de10 2297 delete_frame (w->frame, Qnil);
118ea242
GM
2298 }
2299 else if (NILP (w->parent))
2300 {
2301 /* If we're deleting the buffer displayed in the
2302 only window on the frame, find a new buffer to
2303 display there. */
2304 Lisp_Object buffer;
2305 buffer = Fother_buffer (obj, Qnil, w->frame);
1c33c906
MR
2306 /* Reset dedicated state of window. */
2307 w->dedicated = Qnil;
949cf20f 2308 Fset_window_buffer (window, buffer, Qnil);
118ea242
GM
2309 if (EQ (window, selected_window))
2310 Fset_buffer (w->buffer);
7ab12479
JB
2311 }
2312 else
118ea242 2313 Fdelete_window (window);
7ab12479
JB
2314 }
2315 break;
2316
2317 case GET_LARGEST_WINDOW:
20b69789 2318 { /* nil `obj' means to ignore dedicated windows. */
118ea242 2319 /* Ignore dedicated windows and minibuffers. */
3f489dc7 2320 if (MINI_WINDOW_P (w) || (NILP (obj) && !NILP (w->dedicated)))
118ea242 2321 break;
177c0ea7 2322
c930dfab 2323 if (NILP (best_window))
118ea242 2324 best_window = window;
c930dfab
GM
2325 else
2326 {
2327 struct window *b = XWINDOW (best_window);
949cf20f
KS
2328 if (XFASTINT (w->total_lines) * XFASTINT (w->total_cols)
2329 > XFASTINT (b->total_lines) * XFASTINT (b->total_cols))
c930dfab
GM
2330 best_window = window;
2331 }
7ab12479
JB
2332 }
2333 break;
2334
2335 case UNSHOW_BUFFER:
118ea242 2336 if (EQ (w->buffer, obj))
7ab12479 2337 {
118ea242
GM
2338 Lisp_Object buffer;
2339 struct frame *f = XFRAME (w->frame);
177c0ea7 2340
7ab12479 2341 /* Find another buffer to show in this window. */
118ea242 2342 buffer = Fother_buffer (obj, Qnil, w->frame);
177c0ea7 2343
38ab08d1
RS
2344 /* If this window is dedicated, and in a frame of its own,
2345 kill the frame. */
118ea242
GM
2346 if (EQ (window, FRAME_ROOT_WINDOW (f))
2347 && !NILP (w->dedicated)
38ab08d1 2348 && other_visible_frames (f))
45945a7b
RS
2349 {
2350 /* Skip the other windows on this frame.
2351 There might be one, the minibuffer! */
118ea242
GM
2352 while (CONSP (XCDR (windows))
2353 && EQ (XWINDOW (XCAR (windows))->frame,
2354 XWINDOW (XCAR (XCDR (windows)))->frame))
2355 windows = XCDR (windows);
177c0ea7 2356
45945a7b 2357 /* Now we can safely delete the frame. */
56f2de10 2358 delete_frame (w->frame, Qnil);
45945a7b 2359 }
a5731348
SM
2360 else if (!NILP (w->dedicated) && !NILP (w->parent))
2361 {
2362 Lisp_Object window;
2363 XSETWINDOW (window, w);
2364 /* If this window is dedicated and not the only window
2365 in its frame, then kill it. */
2366 Fdelete_window (window);
2367 }
38ab08d1 2368 else
38ab08d1
RS
2369 {
2370 /* Otherwise show a different buffer in the window. */
118ea242 2371 w->dedicated = Qnil;
949cf20f 2372 Fset_window_buffer (window, buffer, Qnil);
118ea242
GM
2373 if (EQ (window, selected_window))
2374 Fset_buffer (w->buffer);
38ab08d1 2375 }
7ab12479
JB
2376 }
2377 break;
3f8ab7bd 2378
6b61353c
KH
2379 case REDISPLAY_BUFFER_WINDOWS:
2380 if (EQ (w->buffer, obj))
2381 {
2382 mark_window_display_accurate (window, 0);
2383 w->update_mode_line = Qt;
2384 XBUFFER (obj)->prevent_redisplay_optimizations_p = 1;
2385 ++update_mode_lines;
2386 best_window = window;
2387 }
2388 break;
2389
3f8ab7bd
RS
2390 /* Check for a window that has a killed buffer. */
2391 case CHECK_ALL_WINDOWS:
118ea242
GM
2392 if (! NILP (w->buffer)
2393 && NILP (XBUFFER (w->buffer)->name))
3f8ab7bd 2394 abort ();
118ea242 2395 break;
6bbd7a29
GM
2396
2397 case WINDOW_LOOP_UNUSED:
2398 break;
7ab12479 2399 }
7ab12479 2400 }
7ab12479 2401
118ea242 2402 UNGCPRO;
7ab12479 2403 return best_window;
37962e60 2404}
605be8af 2405
3f8ab7bd
RS
2406/* Used for debugging. Abort if any window has a dead buffer. */
2407
233a4a2c 2408void
3f8ab7bd
RS
2409check_all_windows ()
2410{
2411 window_loop (CHECK_ALL_WINDOWS, Qnil, 1, Qt);
2412}
2413
3cbb13c8 2414DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 2, 0,
fdb82f93 2415 doc: /* Return the window least recently selected or used for display.
a55ca73c
EZ
2416\(LRU means Least Recently Used.)
2417
6b61353c 2418Return a full-width window if possible.
c2755926 2419A minibuffer window is never a candidate.
3cbb13c8
SM
2420A dedicated window is never a candidate, unless DEDICATED is non-nil,
2421 so if all windows are dedicated, the value is nil.
fdb82f93
PJ
2422If optional argument FRAME is `visible', search all visible frames.
2423If FRAME is 0, search all visible and iconified frames.
2424If FRAME is t, search all frames.
2425If FRAME is nil, search only the selected frame.
2426If FRAME is a frame, search only that frame. */)
3cbb13c8
SM
2427 (frame, dedicated)
2428 Lisp_Object frame, dedicated;
7ab12479
JB
2429{
2430 register Lisp_Object w;
2431 /* First try for a window that is full-width */
20b69789
SM
2432 w = window_loop (GET_LRU_WINDOW,
2433 NILP (dedicated) ? make_number (1) : make_number (3),
2434 0, frame);
265a9e55 2435 if (!NILP (w) && !EQ (w, selected_window))
7ab12479
JB
2436 return w;
2437 /* If none of them, try the rest */
20b69789
SM
2438 return window_loop (GET_LRU_WINDOW,
2439 NILP (dedicated) ? make_number (0) : make_number (2),
2440 0, frame);
7ab12479
JB
2441}
2442
3cbb13c8 2443DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 2, 0,
fdb82f93 2444 doc: /* Return the largest window in area.
c2755926 2445A minibuffer window is never a candidate.
3cbb13c8
SM
2446A dedicated window is never a candidate unless DEDICATED is non-nil,
2447 so if all windows are dedicated, the value is nil.
fdb82f93
PJ
2448If optional argument FRAME is `visible', search all visible frames.
2449If FRAME is 0, search all visible and iconified frames.
2450If FRAME is t, search all frames.
2451If FRAME is nil, search only the selected frame.
2452If FRAME is a frame, search only that frame. */)
3cbb13c8
SM
2453 (frame, dedicated)
2454 Lisp_Object frame, dedicated;
7ab12479 2455{
20b69789 2456 return window_loop (GET_LARGEST_WINDOW, dedicated, 0,
44fa5b1e 2457 frame);
7ab12479
JB
2458}
2459
fec89261
MR
2460DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 0, 2, 0,
2461 doc: /* Return a window currently displaying BUFFER-OR-NAME, or nil if none.
2462BUFFER-OR-NAME may be a buffer or a buffer name and defaults to the
2463current buffer.
fdb82f93
PJ
2464If optional argument FRAME is `visible', search all visible frames.
2465If optional argument FRAME is 0, search all visible and iconified frames.
2466If FRAME is t, search all frames.
2467If FRAME is nil, search only the selected frame.
2468If FRAME is a frame, search only that frame. */)
fec89261
MR
2469 (buffer_or_name, frame)
2470 Lisp_Object buffer_or_name, frame;
7ab12479 2471{
fec89261
MR
2472 Lisp_Object buffer;
2473
2474 if (NILP (buffer_or_name))
2475 buffer = Fcurrent_buffer ();
2476 else
2477 buffer = Fget_buffer (buffer_or_name);
2478
017b2bad 2479 if (BUFFERP (buffer))
44fa5b1e 2480 return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame);
7ab12479
JB
2481 else
2482 return Qnil;
2483}
2484
2485DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
fdb82f93
PJ
2486 0, 1, "",
2487 doc: /* Make WINDOW (or the selected window) fill its frame.
2488Only the frame WINDOW is on is affected.
fec89261
MR
2489This function tries to reduce display jumps by keeping the text
2490previously visible in WINDOW in the same place on the frame. Doing this
2491depends on the value of (window-start WINDOW), so if calling this
2492function in a program gives strange scrolling, make sure the
2493window-start value is reasonable when this function is called. */)
fdb82f93 2494 (window)
7ab12479
JB
2495 Lisp_Object window;
2496{
2497 struct window *w;
00d3d838 2498 int startpos;
85fe3b5e 2499 int top, new_top;
7ab12479 2500
265a9e55 2501 if (NILP (window))
7ab12479
JB
2502 window = selected_window;
2503 else
b7826503 2504 CHECK_LIVE_WINDOW (window);
7ab12479 2505 w = XWINDOW (window);
a2b38b3c 2506
00d3d838 2507 startpos = marker_position (w->start);
949cf20f 2508 top = WINDOW_TOP_EDGE_LINE (w) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
7ab12479 2509
a2b38b3c
RS
2510 if (MINI_WINDOW_P (w) && top > 0)
2511 error ("Can't expand minibuffer to full frame");
2512
70728a80 2513 window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_FRAME (w));
7ab12479 2514
00d3d838
KH
2515 /* Try to minimize scrolling, by setting the window start to the point
2516 will cause the text at the old window start to be at the same place
2517 on the frame. But don't try to do this if the window start is
2518 outside the visible portion (as might happen when the display is
2519 not current, due to typeahead). */
949cf20f 2520 new_top = WINDOW_TOP_EDGE_LINE (w) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
85fe3b5e
GM
2521 if (new_top != top
2522 && startpos >= BUF_BEGV (XBUFFER (w->buffer))
00d3d838
KH
2523 && startpos <= BUF_ZV (XBUFFER (w->buffer)))
2524 {
2525 struct position pos;
2526 struct buffer *obuf = current_buffer;
2527
2528 Fset_buffer (w->buffer);
2529 /* This computation used to temporarily move point, but that can
2530 have unwanted side effects due to text properties. */
0383eb57 2531 pos = *vmotion (startpos, -top, w);
4d047f50 2532
b73ea88e 2533 set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
85fe3b5e 2534 w->window_end_valid = Qnil;
b73ea88e
RS
2535 w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
2536 || FETCH_BYTE (pos.bytepos - 1) == '\n') ? Qt
00d3d838 2537 : Qnil);
80622eec
RS
2538 /* We need to do this, so that the window-scroll-functions
2539 get called. */
4d047f50 2540 w->optional_new_start = Qt;
00d3d838
KH
2541
2542 set_buffer_internal (obuf);
2543 }
5500c422 2544
7ab12479
JB
2545 return Qnil;
2546}
2547
2548DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
fec89261
MR
2549 0, 2, "bDelete windows on (buffer): ",
2550 doc: /* Delete all windows showing BUFFER-OR-NAME.
2551BUFFER-OR-NAME may be a buffer or the name of an existing buffer and
2552defaults to the current buffer.
2553
fdb82f93
PJ
2554Optional second argument FRAME controls which frames are affected.
2555If optional argument FRAME is `visible', search all visible frames.
2556If FRAME is 0, search all visible and iconified frames.
2557If FRAME is nil, search all frames.
2558If FRAME is t, search only the selected frame.
d653c8cc 2559If FRAME is a frame, search only that frame.
fec89261
MR
2560When a window showing BUFFER-OR-NAME is dedicated and the only window of
2561its frame, that frame is deleted when there are other frames left. */)
2562 (buffer_or_name, frame)
2563 Lisp_Object buffer_or_name, frame;
7ab12479 2564{
fec89261
MR
2565 Lisp_Object buffer;
2566
26f6279d
JB
2567 /* FRAME uses t and nil to mean the opposite of what window_loop
2568 expects. */
c520265e
RS
2569 if (NILP (frame))
2570 frame = Qt;
2571 else if (EQ (frame, Qt))
2572 frame = Qnil;
26f6279d 2573
fec89261
MR
2574 if (NILP (buffer_or_name))
2575 buffer = Fcurrent_buffer ();
2576 else
7ab12479 2577 {
fec89261 2578 buffer = Fget_buffer (buffer_or_name);
b7826503 2579 CHECK_BUFFER (buffer);
7ab12479 2580 }
177c0ea7 2581
fec89261
MR
2582 window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
2583
7ab12479
JB
2584 return Qnil;
2585}
2586
2587DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
fdb82f93 2588 Sreplace_buffer_in_windows,
fec89261
MR
2589 0, 1, "bReplace buffer in windows: ",
2590 doc: /* Replace BUFFER-OR-NAME with some other buffer in all windows showing it.
2591BUFFER-OR-NAME may be a buffer or the name of an existing buffer and
2592defaults to the current buffer.
2593
2594When a window showing BUFFER-OR-NAME is dedicated that window is
2595deleted. If that window is the only window on its frame, that frame is
2596deleted too when there are other frames left. If there are no other
2597frames left, some other buffer is displayed in that window. */)
2598 (buffer_or_name)
2599 Lisp_Object buffer_or_name;
2600{
2601 Lisp_Object buffer;
2602
2603 if (NILP (buffer_or_name))
2604 buffer = Fcurrent_buffer ();
2605 else
7ab12479 2606 {
fec89261 2607 buffer = Fget_buffer (buffer_or_name);
b7826503 2608 CHECK_BUFFER (buffer);
7ab12479 2609 }
fec89261
MR
2610
2611 window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
2612
7ab12479
JB
2613 return Qnil;
2614}
ff58478b
RS
2615
2616/* Replace BUFFER with some other buffer in all windows
2617 of all frames, even those on other keyboards. */
2618
2619void
2620replace_buffer_in_all_windows (buffer)
2621 Lisp_Object buffer;
2622{
2623 Lisp_Object tail, frame;
2624
ff58478b
RS
2625 /* A single call to window_loop won't do the job
2626 because it only considers frames on the current keyboard.
2627 So loop manually over frames, and handle each one. */
2628 FOR_EACH_FRAME (tail, frame)
db7f721d 2629 window_loop (UNSHOW_BUFFER, buffer, 1, frame);
ff58478b 2630}
7ab12479
JB
2631\f
2632/* Set the height of WINDOW and all its inferiors. */
a481b3ea
JB
2633
2634/* The smallest acceptable dimensions for a window. Anything smaller
2635 might crash Emacs. */
5500c422 2636
a481b3ea 2637#define MIN_SAFE_WINDOW_WIDTH (2)
dc1ab1ee 2638#define MIN_SAFE_WINDOW_HEIGHT (1)
a481b3ea 2639
047aaeb9
MR
2640/* For wp non-zero the total number of columns of window w. Otherwise
2641 the total number of lines of w. */
a481b3ea 2642
047aaeb9
MR
2643#define WINDOW_TOTAL_SIZE(w, wp) \
2644 (wp ? WINDOW_TOTAL_COLS (w) : WINDOW_TOTAL_LINES (w))
a481b3ea
JB
2645
2646/* If *ROWS or *COLS are too small a size for FRAME, set them to the
2647 minimum allowable size. */
5500c422 2648
605be8af 2649void
a481b3ea 2650check_frame_size (frame, rows, cols)
605be8af
JB
2651 FRAME_PTR frame;
2652 int *rows, *cols;
a481b3ea 2653{
628df3bf 2654 /* For height, we have to see:
54b8bcb5
RS
2655 how many windows the frame has at minimum (one or two),
2656 and whether it has a menu bar or other special stuff at the top. */
2657 int min_height
2658 = ((FRAME_MINIBUF_ONLY_P (frame) || ! FRAME_HAS_MINIBUF_P (frame))
2659 ? MIN_SAFE_WINDOW_HEIGHT
2660 : 2 * MIN_SAFE_WINDOW_HEIGHT);
177c0ea7 2661
5500c422
GM
2662 if (FRAME_TOP_MARGIN (frame) > 0)
2663 min_height += FRAME_TOP_MARGIN (frame);
a481b3ea
JB
2664
2665 if (*rows < min_height)
2666 *rows = min_height;
2667 if (*cols < MIN_SAFE_WINDOW_WIDTH)
2668 *cols = MIN_SAFE_WINDOW_WIDTH;
2669}
2670
233a4a2c
GM
2671/* Value is non-zero if window W is fixed-size. WIDTH_P non-zero means
2672 check if W's width can be changed, otherwise check W's height.
2673 CHECK_SIBLINGS_P non-zero means check resizablity of WINDOW's
2674 siblings, too. If none of the siblings is resizable, WINDOW isn't
2675 either. */
c1636aa6 2676
233a4a2c
GM
2677static int
2678window_fixed_size_p (w, width_p, check_siblings_p)
2679 struct window *w;
2680 int width_p, check_siblings_p;
2681{
2682 int fixed_p;
2683 struct window *c;
177c0ea7 2684
233a4a2c
GM
2685 if (!NILP (w->hchild))
2686 {
2687 c = XWINDOW (w->hchild);
177c0ea7 2688
233a4a2c
GM
2689 if (width_p)
2690 {
047aaeb9 2691 /* A horizontal combination is fixed-width if all of if its
233a4a2c
GM
2692 children are. */
2693 while (c && window_fixed_size_p (c, width_p, 0))
2694 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2695 fixed_p = c == NULL;
2696 }
2697 else
2698 {
047aaeb9 2699 /* A horizontal combination is fixed-height if one of if its
233a4a2c
GM
2700 children is. */
2701 while (c && !window_fixed_size_p (c, width_p, 0))
2702 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2703 fixed_p = c != NULL;
2704 }
2705 }
2706 else if (!NILP (w->vchild))
2707 {
2708 c = XWINDOW (w->vchild);
177c0ea7 2709
233a4a2c
GM
2710 if (width_p)
2711 {
047aaeb9 2712 /* A vertical combination is fixed-width if one of if its
233a4a2c
GM
2713 children is. */
2714 while (c && !window_fixed_size_p (c, width_p, 0))
2715 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2716 fixed_p = c != NULL;
2717 }
2718 else
2719 {
047aaeb9 2720 /* A vertical combination is fixed-height if all of if its
233a4a2c
GM
2721 children are. */
2722 while (c && window_fixed_size_p (c, width_p, 0))
2723 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2724 fixed_p = c == NULL;
2725 }
2726 }
2727 else if (BUFFERP (w->buffer))
2728 {
3df0580e
AS
2729 struct buffer *old = current_buffer;
2730 Lisp_Object val;
177c0ea7 2731
3df0580e
AS
2732 current_buffer = XBUFFER (w->buffer);
2733 val = find_symbol_value (Qwindow_size_fixed);
2734 current_buffer = old;
a34dfd12 2735
3df0580e
AS
2736 fixed_p = 0;
2737 if (!EQ (val, Qunbound))
2738 {
2739 fixed_p = !NILP (val);
177c0ea7 2740
3df0580e
AS
2741 if (fixed_p
2742 && ((EQ (val, Qheight) && width_p)
2743 || (EQ (val, Qwidth) && !width_p)))
2744 fixed_p = 0;
233a4a2c
GM
2745 }
2746
2747 /* Can't tell if this one is resizable without looking at
2748 siblings. If all siblings are fixed-size this one is too. */
2749 if (!fixed_p && check_siblings_p && WINDOWP (w->parent))
2750 {
2751 Lisp_Object child;
177c0ea7 2752
9beb8baa 2753 for (child = w->prev; WINDOWP (child); child = XWINDOW (child)->prev)
233a4a2c
GM
2754 if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
2755 break;
2756
2757 if (NILP (child))
9beb8baa 2758 for (child = w->next; WINDOWP (child); child = XWINDOW (child)->next)
233a4a2c
GM
2759 if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
2760 break;
2761
2762 if (NILP (child))
2763 fixed_p = 1;
2764 }
2765 }
2766 else
2767 fixed_p = 1;
2768
2769 return fixed_p;
2770}
177c0ea7 2771
047aaeb9
MR
2772/* Return minimum size of leaf window W. WIDTH_P non-zero means return
2773 the minimum width of W, WIDTH_P zero means return the minimum height
2774 of W. SAFE_P non-zero means ignore window-min-height|width but just
2775 return values that won't crash Emacs and don't hide components like
2776 fringes, scrollbars, or modelines. If WIDTH_P is zero and W is the
2777 minibuffer window, always return 1. */
f1de8c77
MR
2778
2779static int
047aaeb9 2780window_min_size_2 (w, width_p, safe_p)
f1de8c77 2781 struct window *w;
047aaeb9 2782 int width_p, safe_p;
f1de8c77 2783{
047aaeb9
MR
2784 /* We should consider buffer-local values of window_min_height and
2785 window_min_width here. */
f1de8c77 2786 if (width_p)
047aaeb9
MR
2787 {
2788 int safe_size = (MIN_SAFE_WINDOW_WIDTH
12bb3111 2789 + WINDOW_FRINGE_COLS (w)
047aaeb9
MR
2790 + WINDOW_SCROLL_BAR_COLS (w));
2791
2792 return safe_p ? safe_size : max (window_min_width, safe_size);
2793 }
f1de8c77 2794 else if (MINI_WINDOW_P (w))
047aaeb9 2795 return 1;
f1de8c77 2796 else
047aaeb9
MR
2797 {
2798 int safe_size = (MIN_SAFE_WINDOW_HEIGHT
2799 + ((BUFFERP (w->buffer)
2800 && !NILP (XBUFFER (w->buffer)->mode_line_format))
2801 ? 1 : 0));
f1de8c77 2802
047aaeb9
MR
2803 return safe_p ? safe_size : max (window_min_height, safe_size);
2804 }
f1de8c77 2805}
233a4a2c 2806
047aaeb9
MR
2807/* Return minimum size of window W, not taking fixed-width windows into
2808 account. WIDTH_P non-zero means return the minimum width, otherwise
2809 return the minimum height. SAFE_P non-zero means ignore
2810 window-min-height|width but just return values that won't crash Emacs
2811 and don't hide components like fringes, scrollbars, or modelines. If
2812 W is a combination window, compute the minimum size from the minimum
2813 sizes of W's children. */
233a4a2c
GM
2814
2815static int
047aaeb9 2816window_min_size_1 (w, width_p, safe_p)
c1636aa6 2817 struct window *w;
047aaeb9 2818 int width_p, safe_p;
c1636aa6 2819{
233a4a2c 2820 struct window *c;
c1636aa6 2821 int size;
177c0ea7 2822
233a4a2c
GM
2823 if (!NILP (w->hchild))
2824 {
047aaeb9 2825 /* W is a horizontal combination. */
233a4a2c
GM
2826 c = XWINDOW (w->hchild);
2827 size = 0;
177c0ea7 2828
233a4a2c
GM
2829 if (width_p)
2830 {
047aaeb9
MR
2831 /* The minimum width of a horizontal combination is the sum of
2832 the minimum widths of its children. */
233a4a2c
GM
2833 while (c)
2834 {
047aaeb9 2835 size += window_min_size_1 (c, 1, safe_p);
233a4a2c
GM
2836 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2837 }
2838 }
2839 else
2840 {
047aaeb9
MR
2841 /* The minimum height of a horizontal combination is the
2842 maximum of the minimum heights of its children. */
233a4a2c
GM
2843 while (c)
2844 {
047aaeb9 2845 size = max (window_min_size_1 (c, 0, safe_p), size);
233a4a2c
GM
2846 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2847 }
2848 }
2849 }
2850 else if (!NILP (w->vchild))
2851 {
047aaeb9 2852 /* W is a vertical combination. */
233a4a2c
GM
2853 c = XWINDOW (w->vchild);
2854 size = 0;
177c0ea7 2855
233a4a2c
GM
2856 if (width_p)
2857 {
047aaeb9
MR
2858 /* The minimum width of a vertical combination is the maximum
2859 of the minimum widths of its children. */
233a4a2c
GM
2860 while (c)
2861 {
047aaeb9 2862 size = max (window_min_size_1 (c, 1, safe_p), size);
233a4a2c
GM
2863 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2864 }
2865 }
2866 else
2867 {
047aaeb9
MR
2868 /* The minimum height of a vertical combination is the sum of
2869 the minimum height of its children. */
233a4a2c
GM
2870 while (c)
2871 {
047aaeb9 2872 size += window_min_size_1 (c, 0, safe_p);
233a4a2c
GM
2873 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2874 }
2875 }
2876 }
c1636aa6 2877 else
047aaeb9
MR
2878 /* W is a leaf window. */
2879 size = window_min_size_2 (w, width_p, safe_p);
c1636aa6
GM
2880
2881 return size;
2882}
2883
233a4a2c 2884/* Return the minimum size of window W, taking fixed-size windows into
047aaeb9
MR
2885 account. WIDTH_P non-zero means return the minimum width, otherwise
2886 return the minimum height. SAFE_P non-zero means ignore
2887 window-min-height|width but just return values that won't crash Emacs
2888 and don't hide components like fringes, scrollbars, or modelines.
2889 IGNORE_FIXED_P non-zero means ignore if W is fixed-size. Set *FIXED
2890 to 1 if W is fixed-size unless FIXED is null. */
7ab12479 2891
233a4a2c 2892static int
047aaeb9 2893window_min_size (w, width_p, safe_p, ignore_fixed_p, fixed)
233a4a2c 2894 struct window *w;
047aaeb9 2895 int width_p, safe_p, ignore_fixed_p, *fixed;
233a4a2c
GM
2896{
2897 int size, fixed_p;
2898
f984d4fc
GM
2899 if (ignore_fixed_p)
2900 fixed_p = 0;
2901 else
2902 fixed_p = window_fixed_size_p (w, width_p, 1);
177c0ea7 2903
233a4a2c
GM
2904 if (fixed)
2905 *fixed = fixed_p;
177c0ea7 2906
233a4a2c 2907 if (fixed_p)
047aaeb9 2908 size = WINDOW_TOTAL_SIZE (w, width_p);
233a4a2c 2909 else
047aaeb9 2910 size = window_min_size_1 (w, width_p, safe_p);
177c0ea7 2911
233a4a2c
GM
2912 return size;
2913}
2914
2915
79fd290e 2916/* Adjust the margins of window W if text area is too small.
949cf20f
KS
2917 Return 1 if window width is ok after adjustment; 0 if window
2918 is still too narrow. */
2919
2920static int
2921adjust_window_margins (w)
2922 struct window *w;
2923{
2924 int box_cols = (WINDOW_TOTAL_COLS (w)
2925 - WINDOW_FRINGE_COLS (w)
2926 - WINDOW_SCROLL_BAR_COLS (w));
2927 int margin_cols = (WINDOW_LEFT_MARGIN_COLS (w)
2928 + WINDOW_RIGHT_MARGIN_COLS (w));
2929
2930 if (box_cols - margin_cols >= MIN_SAFE_WINDOW_WIDTH)
2931 return 1;
2932
2933 if (margin_cols < 0 || box_cols < MIN_SAFE_WINDOW_WIDTH)
2934 return 0;
2935
2936 /* Window's text area is too narrow, but reducing the window
2937 margins will fix that. */
2938 margin_cols = box_cols - MIN_SAFE_WINDOW_WIDTH;
2939 if (WINDOW_RIGHT_MARGIN_COLS (w) > 0)
2940 {
2941 if (WINDOW_LEFT_MARGIN_COLS (w) > 0)
2942 w->left_margin_cols = w->right_margin_cols
2943 = make_number (margin_cols/2);
2944 else
2945 w->right_margin_cols = make_number (margin_cols);
2946 }
2947 else
2948 w->left_margin_cols = make_number (margin_cols);
2949 return 1;
2950}
2951
047aaeb9
MR
2952/* Calculate new sizes for windows in the list FORWARD when their
2953 compound size goes from TOTAL to SIZE. TOTAL must be greater than
2954 SIZE. The number of windows in FORWARD is NCHILDREN, and the number
2955 that can shrink is SHRINKABLE. Fixed-size windows may be shrunk if
2956 and only if RESIZE_FIXED_P is non-zero. WIDTH_P non-zero means
2957 shrink columns, otherwise shrink lines.
6b61353c 2958
047aaeb9
MR
2959 SAFE_P zero means windows may be sized down to window-min-height
2960 lines (window-min-window columns for WIDTH_P non-zero). SAFE_P
2961 non-zero means windows may be sized down to their minimum safe sizes
2962 taking into account the space needed to display modelines, fringes,
2963 and scrollbars.
6b61353c 2964
047aaeb9
MR
2965 This function returns an allocated array of new sizes that the caller
2966 must free. A size -1 means the window is fixed and RESIZE_FIXED_P is
2967 zero. A size zero means the window shall be deleted. Array index 0
2968 refers to the first window in FORWARD, 1 to the second, and so on.
2969
2970 This function resizes windows proportionally to their size. It also
2971 tries to preserve smaller windows by resizing larger windows before
2972 resizing any window to zero. If resize_proportionally is non-nil for
2973 a specific window, it will attempt to strictly resize that window
2974 proportionally, even at the expense of deleting smaller windows. */
6b61353c 2975static int *
047aaeb9
MR
2976shrink_windows (total, size, nchildren, shrinkable, resize_fixed_p,
2977 forward, width_p, safe_p)
2978 int total, size, nchildren, shrinkable;
2979 int resize_fixed_p, width_p, safe_p;
6b61353c
KH
2980 Lisp_Object forward;
2981{
2982 int available_resize = 0;
047aaeb9 2983 int *new_sizes, *min_sizes;
6b61353c
KH
2984 struct window *c;
2985 Lisp_Object child;
2986 int smallest = total;
2987 int total_removed = 0;
2988 int total_shrink = total - size;
2989 int i;
2990
2991 new_sizes = xmalloc (sizeof (*new_sizes) * nchildren);
047aaeb9 2992 min_sizes = xmalloc (sizeof (*min_sizes) * nchildren);
6b61353c
KH
2993
2994 for (i = 0, child = forward; !NILP (child); child = c->next, ++i)
2995 {
2996 int child_size;
2997
2998 c = XWINDOW (child);
047aaeb9 2999 child_size = WINDOW_TOTAL_SIZE (c, width_p);
6b61353c 3000
047aaeb9 3001 if (!resize_fixed_p && window_fixed_size_p (c, width_p, 0))
6b61353c
KH
3002 new_sizes[i] = -1;
3003 else
3004 {
3005 new_sizes[i] = child_size;
047aaeb9
MR
3006 min_sizes[i] = window_min_size_1 (c, width_p, safe_p);
3007 if (child_size > min_sizes[i]
3008 && NILP (c->resize_proportionally))
3009 available_resize += child_size - min_sizes[i];
6b61353c
KH
3010 }
3011 }
3012 /* We might need to shrink some windows to zero. Find the smallest
3013 windows and set them to 0 until we can fulfil the new size. */
3014
3015 while (shrinkable > 1 && size + available_resize < total)
3016 {
3017 for (i = 0; i < nchildren; ++i)
3018 if (new_sizes[i] > 0 && smallest > new_sizes[i])
3019 smallest = new_sizes[i];
3020
3021 for (i = 0; i < nchildren; ++i)
3022 if (new_sizes[i] == smallest)
3023 {
3024 /* Resize this window down to zero. */
3025 new_sizes[i] = 0;
047aaeb9
MR
3026 if (smallest > min_sizes[i])
3027 available_resize -= smallest - min_sizes[i];
6b61353c
KH
3028 available_resize += smallest;
3029 --shrinkable;
3030 total_removed += smallest;
3031
ef614e04
JD
3032 /* We don't know what the smallest is now. */
3033 smallest = total;
3034
6b61353c
KH
3035 /* Out of for, just remove one window at the time and
3036 check again if we have enough space. */
3037 break;
3038 }
3039 }
3040
3041 /* Now, calculate the new sizes. Try to shrink each window
3042 proportional to its size. */
3043 for (i = 0; i < nchildren; ++i)
3044 {
047aaeb9 3045 if (new_sizes[i] > min_sizes[i])
6b61353c 3046 {
047aaeb9
MR
3047 int to_shrink = total_shrink * new_sizes[i] / total;
3048
3049 if (new_sizes[i] - to_shrink < min_sizes[i])
3050 to_shrink = new_sizes[i] - min_sizes[i];
6b61353c
KH
3051 new_sizes[i] -= to_shrink;
3052 total_removed += to_shrink;
3053 }
3054 }
3055
3056 /* Any reminder due to rounding, we just subtract from windows
3057 that are left and still can be shrunk. */
3058 while (total_shrink > total_removed)
3059 {
ef614e04
JD
3060 int nonzero_sizes = 0;
3061 int nonzero_idx = -1;
3062
3063 for (i = 0; i < nchildren; ++i)
3064 if (new_sizes[i] > 0)
3065 {
3066 ++nonzero_sizes;
3067 nonzero_idx = i;
3068 }
c49a0495 3069
6b61353c 3070 for (i = 0; i < nchildren; ++i)
047aaeb9 3071 if (new_sizes[i] > min_sizes[i])
6b61353c
KH
3072 {
3073 --new_sizes[i];
3074 ++total_removed;
3075
3076 /* Out of for, just shrink one window at the time and
3077 check again if we have enough space. */
3078 break;
3079 }
ef614e04 3080
ef614e04
JD
3081 /* Special case, only one window left. */
3082 if (nonzero_sizes == 1)
3083 break;
3084 }
3085
3086 /* Any surplus due to rounding, we add to windows that are left. */
3087 while (total_shrink < total_removed)
3088 {
3089 for (i = 0; i < nchildren; ++i)
3090 {
3091 if (new_sizes[i] != 0 && total_shrink < total_removed)
3092 {
3093 ++new_sizes[i];
3094 --total_removed;
3095 break;
3096 }
3097 }
6b61353c
KH
3098 }
3099
047aaeb9
MR
3100 xfree (min_sizes);
3101
6b61353c
KH
3102 return new_sizes;
3103}
949cf20f 3104
233a4a2c 3105/* Set WINDOW's height or width to SIZE. WIDTH_P non-zero means set
047aaeb9
MR
3106 WINDOW's width. Resize WINDOW's children, if any, so that they keep
3107 their proportionate size relative to WINDOW.
5fe0b054
RS
3108
3109 If FIRST_ONLY is 1, change only the first of WINDOW's children when
3110 they are in series. If LAST_ONLY is 1, change only the last of
3111 WINDOW's children when they are in series.
3112
3113 Propagate WINDOW's top or left edge position to children. Delete
047aaeb9
MR
3114 windows that become too small unless NODELETE_P is 1. When
3115 NODELETE_P equals 2 do not honor settings for window-min-height and
3116 window-min-width when resizing windows but use safe defaults instead.
3117 This should give better behavior when resizing frames. */
233a4a2c
GM
3118
3119static void
5fe0b054 3120size_window (window, size, width_p, nodelete_p, first_only, last_only)
7ab12479 3121 Lisp_Object window;
233a4a2c 3122 int size, width_p, nodelete_p;
5fe0b054 3123 int first_only, last_only;
7ab12479 3124{
233a4a2c
GM
3125 struct window *w = XWINDOW (window);
3126 struct window *c;
3127 Lisp_Object child, *forward, *sideward;
047aaeb9 3128 int old_size = WINDOW_TOTAL_SIZE (w, width_p);
7ab12479 3129
7ae2f10f 3130 size = max (0, size);
177c0ea7 3131
047aaeb9
MR
3132 /* Delete WINDOW if it's too small. */
3133 if (nodelete_p != 1 && !NILP (w->parent)
3134 && size < window_min_size_1 (w, width_p, nodelete_p == 2))
233a4a2c 3135 {
047aaeb9
MR
3136 delete_window (window);
3137 return;
7ab12479
JB
3138 }
3139
233a4a2c 3140 /* Set redisplay hints. */
7ae2f10f
GM
3141 w->last_modified = make_number (0);
3142 w->last_overlay_modified = make_number (0);
7ab12479 3143 windows_or_buffers_changed++;
7ae2f10f 3144 FRAME_WINDOW_SIZES_CHANGED (XFRAME (w->frame)) = 1;
29aeee73 3145
233a4a2c
GM
3146 if (width_p)
3147 {
3148 sideward = &w->vchild;
3149 forward = &w->hchild;
949cf20f
KS
3150 w->total_cols = make_number (size);
3151 adjust_window_margins (w);
233a4a2c
GM
3152 }
3153 else
3154 {
3155 sideward = &w->hchild;
3156 forward = &w->vchild;
949cf20f
KS
3157 w->total_lines = make_number (size);
3158 w->orig_total_lines = Qnil;
233a4a2c
GM
3159 }
3160
3161 if (!NILP (*sideward))
7ab12479 3162 {
5fe0b054 3163 /* We have a chain of parallel siblings whose size should all change. */
233a4a2c 3164 for (child = *sideward; !NILP (child); child = c->next)
7ab12479 3165 {
233a4a2c
GM
3166 c = XWINDOW (child);
3167 if (width_p)
949cf20f 3168 c->left_col = w->left_col;
233a4a2c 3169 else
949cf20f 3170 c->top_line = w->top_line;
5fe0b054
RS
3171 size_window (child, size, width_p, nodelete_p,
3172 first_only, last_only);
7ab12479
JB
3173 }
3174 }
5fe0b054
RS
3175 else if (!NILP (*forward) && last_only)
3176 {
3177 /* Change the last in a series of siblings. */
3178 Lisp_Object last_child;
3179 int child_size;
3180
3181 for (child = *forward; !NILP (child); child = c->next)
3182 {
3183 c = XWINDOW (child);
3184 last_child = child;
3185 }
3186
047aaeb9
MR
3187 child_size = WINDOW_TOTAL_SIZE (c, width_p);
3188 size_window (last_child, size - old_size + child_size,
5fe0b054
RS
3189 width_p, nodelete_p, first_only, last_only);
3190 }
3191 else if (!NILP (*forward) && first_only)
3192 {
3193 /* Change the first in a series of siblings. */
3194 int child_size;
3195
3196 child = *forward;
3197 c = XWINDOW (child);
3198
3199 if (width_p)
3200 c->left_col = w->left_col;
3201 else
3202 c->top_line = w->top_line;
3203
047aaeb9
MR
3204 child_size = WINDOW_TOTAL_SIZE (c, width_p);
3205 size_window (child, size - old_size + child_size,
5fe0b054
RS
3206 width_p, nodelete_p, first_only, last_only);
3207 }
233a4a2c 3208 else if (!NILP (*forward))
7ab12479 3209 {
233a4a2c
GM
3210 int fixed_size, each, extra, n;
3211 int resize_fixed_p, nfixed;
8b6d9dc9 3212 int last_pos, first_pos, nchildren, total;
6b61353c 3213 int *new_sizes = NULL;
233a4a2c 3214
5fe0b054 3215 /* Determine the fixed-size portion of this window, and the
233a4a2c 3216 number of child windows. */
8b6d9dc9 3217 fixed_size = nchildren = nfixed = total = 0;
233a4a2c 3218 for (child = *forward; !NILP (child); child = c->next, ++nchildren)
7ab12479 3219 {
8b6d9dc9 3220 int child_size;
177c0ea7 3221
7ab12479 3222 c = XWINDOW (child);
047aaeb9 3223 child_size = WINDOW_TOTAL_SIZE (c, width_p);
8b6d9dc9 3224 total += child_size;
177c0ea7 3225
233a4a2c
GM
3226 if (window_fixed_size_p (c, width_p, 0))
3227 {
8b6d9dc9 3228 fixed_size += child_size;
233a4a2c
GM
3229 ++nfixed;
3230 }
3231 }
7ab12479 3232
233a4a2c
GM
3233 /* If the new size is smaller than fixed_size, or if there
3234 aren't any resizable windows, allow resizing fixed-size
3235 windows. */
3236 resize_fixed_p = nfixed == nchildren || size < fixed_size;
3237
6b61353c 3238 /* Compute how many lines/columns to add/remove to each child. The
233a4a2c
GM
3239 value of extra takes care of rounding errors. */
3240 n = resize_fixed_p ? nchildren : nchildren - nfixed;
6b61353c 3241 if (size < total && n > 1)
047aaeb9
MR
3242 new_sizes = shrink_windows (total, size, nchildren, n,
3243 resize_fixed_p, *forward, width_p,
3244 nodelete_p == 2);
6b61353c
KH
3245 else
3246 {
3247 each = (size - total) / n;
3248 extra = (size - total) - n * each;
3249 }
233a4a2c
GM
3250
3251 /* Compute new children heights and edge positions. */
949cf20f 3252 first_pos = width_p ? XINT (w->left_col) : XINT (w->top_line);
233a4a2c 3253 last_pos = first_pos;
6b61353c 3254 for (n = 0, child = *forward; !NILP (child); child = c->next, ++n)
233a4a2c
GM
3255 {
3256 int new_size, old_size;
177c0ea7 3257
233a4a2c 3258 c = XWINDOW (child);
047aaeb9 3259 old_size = WINDOW_TOTAL_SIZE (c, width_p);
233a4a2c 3260 new_size = old_size;
7ab12479 3261
233a4a2c
GM
3262 /* The top or left edge position of this child equals the
3263 bottom or right edge of its predecessor. */
3264 if (width_p)
949cf20f 3265 c->left_col = make_number (last_pos);
233a4a2c 3266 else
949cf20f 3267 c->top_line = make_number (last_pos);
7ab12479 3268
233a4a2c
GM
3269 /* If this child can be resized, do it. */
3270 if (resize_fixed_p || !window_fixed_size_p (c, width_p, 0))
3271 {
6b61353c 3272 new_size = new_sizes ? new_sizes[n] : old_size + each + extra;
233a4a2c
GM
3273 extra = 0;
3274 }
177c0ea7 3275
047aaeb9 3276 /* Set new size. Note that size_window also propagates
233a4a2c
GM
3277 edge positions to children, so it's not a no-op if we
3278 didn't change the child's size. */
5fe0b054 3279 size_window (child, new_size, width_p, 1, first_only, last_only);
233a4a2c
GM
3280
3281 /* Remember the bottom/right edge position of this child; it
3282 will be used to set the top/left edge of the next child. */
6b61353c 3283 last_pos += new_size;
7ab12479 3284 }
233a4a2c 3285
70fdbb46 3286 xfree (new_sizes);
6b61353c 3287
233a4a2c
GM
3288 /* We should have covered the parent exactly with child windows. */
3289 xassert (size == last_pos - first_pos);
177c0ea7 3290
7ab12479 3291 /* Now delete any children that became too small. */
047aaeb9 3292 if (nodelete_p != 1)
233a4a2c 3293 for (child = *forward; !NILP (child); child = c->next)
7ab12479 3294 {
233a4a2c 3295 int child_size;
047aaeb9 3296
233a4a2c 3297 c = XWINDOW (child);
047aaeb9
MR
3298 child_size = WINDOW_TOTAL_SIZE (c, width_p);
3299 size_window (child, child_size, width_p, nodelete_p,
3300 first_only, last_only);
7ab12479
JB
3301 }
3302 }
3303}
3304
233a4a2c 3305/* Set WINDOW's height to HEIGHT, and recursively change the height of
047aaeb9
MR
3306 WINDOW's children. NODELETE zero means windows that have become
3307 smaller than window-min-height in the process may be deleted.
3308 NODELETE 1 means never delete windows that become too small in the
3309 process. (The caller should check later and do so if appropriate.)
3310 NODELETE 2 means delete only windows that have become too small to be
3311 displayed correctly. */
7ab12479 3312
5e14b1fc 3313void
233a4a2c 3314set_window_height (window, height, nodelete)
7ab12479 3315 Lisp_Object window;
233a4a2c 3316 int height;
7ab12479
JB
3317 int nodelete;
3318{
5fe0b054 3319 size_window (window, height, 0, nodelete, 0, 0);
233a4a2c 3320}
7ab12479 3321
233a4a2c 3322/* Set WINDOW's width to WIDTH, and recursively change the width of
047aaeb9
MR
3323 WINDOW's children. NODELETE zero means windows that have become
3324 smaller than window-min-width in the process may be deleted.
3325 NODELETE 1 means never delete windows that become too small in the
3326 process. (The caller should check later and do so if appropriate.)
3327 NODELETE 2 means delete only windows that have become too small to be
3328 displayed correctly. */
7ab12479 3329
233a4a2c
GM
3330void
3331set_window_width (window, width, nodelete)
3332 Lisp_Object window;
3333 int width;
3334 int nodelete;
3335{
5fe0b054 3336 size_window (window, width, 1, nodelete, 0, 0);
7ab12479 3337}
233a4a2c 3338
cdbc7fec
KS
3339/* Change window heights in windows rooted in WINDOW by N lines. */
3340
3341void
3342change_window_heights (window, n)
3343 Lisp_Object window;
3344 int n;
3345{
3346 struct window *w = XWINDOW (window);
3347
949cf20f
KS
3348 XSETFASTINT (w->top_line, XFASTINT (w->top_line) + n);
3349 XSETFASTINT (w->total_lines, XFASTINT (w->total_lines) - n);
cdbc7fec 3350
949cf20f
KS
3351 if (INTEGERP (w->orig_top_line))
3352 XSETFASTINT (w->orig_top_line, XFASTINT (w->orig_top_line) + n);
3353 if (INTEGERP (w->orig_total_lines))
3354 XSETFASTINT (w->orig_total_lines, XFASTINT (w->orig_total_lines) - n);
cdbc7fec
KS
3355
3356 /* Handle just the top child in a vertical split. */
3357 if (!NILP (w->vchild))
3358 change_window_heights (w->vchild, n);
3359
3360 /* Adjust all children in a horizontal split. */
3361 for (window = w->hchild; !NILP (window); window = w->next)
3362 {
3363 w = XWINDOW (window);
3364 change_window_heights (window, n);
3365 }
3366}
3367
7ab12479 3368\f
1d8d96fa 3369int window_select_count;
7ab12479 3370
56613f06
SM
3371EXFUN (Fset_window_fringes, 4);
3372EXFUN (Fset_window_scroll_bars, 4);
7ab12479 3373
6a44ffb3
SM
3374static void
3375run_funs (Lisp_Object funs)
3376{
3377 for (; CONSP (funs); funs = XCDR (funs))
3378 if (!EQ (XCAR (funs), Qt))
3379 call0 (XCAR (funs));
3380}
3381
3382static Lisp_Object select_window_norecord (Lisp_Object window);
c6932ecd 3383static Lisp_Object select_frame_norecord (Lisp_Object frame);
6a44ffb3 3384
ef264c42
SM
3385void
3386run_window_configuration_change_hook (struct frame *f)
3387{
fec89261 3388 int count = SPECPDL_INDEX ();
6a44ffb3
SM
3389 Lisp_Object frame, global_wcch
3390 = Fdefault_value (Qwindow_configuration_change_hook);
3391 XSETFRAME (frame, f);
3392
3393 if (NILP (Vrun_hooks))
3394 return;
3395
fec89261
MR
3396 if (SELECTED_FRAME () != f)
3397 {
c6932ecd
MR
3398 record_unwind_protect (select_frame_norecord, Fselected_frame ());
3399 Fselect_frame (frame, Qt);
fec89261 3400 }
6a44ffb3
SM
3401
3402 /* Use the right buffer. Matters when running the local hooks. */
3403 if (current_buffer != XBUFFER (Fwindow_buffer (Qnil)))
3404 {
3405 record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
3406 Fset_buffer (Fwindow_buffer (Qnil));
3407 }
3408
3409 /* Look for buffer-local values. */
3410 {
3411 Lisp_Object windows = Fwindow_list (frame, Qlambda, Qnil);
3412 for (; CONSP (windows); windows = XCDR (windows))
3413 {
3414 Lisp_Object window = XCAR (windows);
3415 Lisp_Object buffer = Fwindow_buffer (window);
3416 if (!NILP (Flocal_variable_p (Qwindow_configuration_change_hook,
3417 buffer)))
3418 {
3419 int count = SPECPDL_INDEX ();
3420 record_unwind_protect (select_window_norecord, Fselected_window ());
3421 select_window_norecord (window);
3422 run_funs (Fbuffer_local_value (Qwindow_configuration_change_hook,
3423 buffer));
fec89261
MR
3424 unbind_to (count, Qnil);
3425 }
6a44ffb3
SM
3426 }
3427 }
047aaeb9 3428
6a44ffb3
SM
3429 run_funs (global_wcch);
3430 unbind_to (count, Qnil);
ef264c42
SM
3431}
3432
5500c422
GM
3433/* Make WINDOW display BUFFER as its contents. RUN_HOOKS_P non-zero
3434 means it's allowed to run hooks. See make_frame for a case where
949cf20f
KS
3435 it's not allowed. KEEP_MARGINS_P non-zero means that the current
3436 margins, fringes, and scroll-bar settings of the window are not
3437 reset from the buffer's local settings. */
7ab12479 3438
5500c422 3439void
949cf20f 3440set_window_buffer (window, buffer, run_hooks_p, keep_margins_p)
5500c422 3441 Lisp_Object window, buffer;
949cf20f 3442 int run_hooks_p, keep_margins_p;
5500c422
GM
3443{
3444 struct window *w = XWINDOW (window);
3445 struct buffer *b = XBUFFER (buffer);
aed13378 3446 int count = SPECPDL_INDEX ();
c3b232e4 3447 int samebuf = EQ (buffer, w->buffer);
7ab12479
JB
3448
3449 w->buffer = buffer;
86e48436
RS
3450
3451 if (EQ (window, selected_window))
5500c422 3452 b->last_selected_window = window;
beb4e312 3453
c49a0495
KS
3454 /* Let redisplay errors through. */
3455 b->display_error_modiff = 0;
3456
beb4e312 3457 /* Update time stamps of buffer display. */
5500c422
GM
3458 if (INTEGERP (b->display_count))
3459 XSETINT (b->display_count, XINT (b->display_count) + 1);
3460 b->display_time = Fcurrent_time ();
86e48436 3461
d834a2e9 3462 XSETFASTINT (w->window_end_pos, 0);
5500c422
GM
3463 XSETFASTINT (w->window_end_vpos, 0);
3464 bzero (&w->last_cursor, sizeof w->last_cursor);
5a41ab94 3465 w->window_end_valid = Qnil;
c3b232e4 3466 if (!(keep_margins_p && samebuf))
23fe745a 3467 { /* If we're not actually changing the buffer, don't reset hscroll and
c3b232e4
SM
3468 vscroll. This case happens for example when called from
3469 change_frame_size_1, where we use a dummy call to
3470 Fset_window_buffer on the frame's selected window (and no other)
3471 just in order to run window-configuration-change-hook.
3472 Resetting hscroll and vscroll here is problematic for things like
3473 image-mode and doc-view-mode since it resets the image's position
3474 whenever we resize the frame. */
3475 w->hscroll = w->min_hscroll = make_number (0);
3476 w->vscroll = 0;
3477 set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
3478 set_marker_restricted (w->start,
3479 make_number (b->last_window_start),
3480 buffer);
3481 w->start_at_line_beg = Qnil;
3482 w->force_start = Qnil;
3483 XSETFASTINT (w->last_modified, 0);
3484 XSETFASTINT (w->last_overlay_modified, 0);
3485 }
3486 /* Maybe we could move this into the `if' but it's not obviously safe and
3487 I doubt it's worth the trouble. */
7ab12479 3488 windows_or_buffers_changed++;
5b03d3c0 3489
da39107c 3490 /* We must select BUFFER for running the window-scroll-functions. */
5b03d3c0
RS
3491 /* We can't check ! NILP (Vwindow_scroll_functions) here
3492 because that might itself be a local variable. */
da39107c 3493 if (window_initialized)
5b03d3c0 3494 {
da39107c 3495 record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
5b03d3c0
RS
3496 Fset_buffer (buffer);
3497 }
3498
a1562258
SM
3499 XMARKER (w->pointm)->insertion_type = !NILP (Vwindow_point_insertion_type);
3500
949cf20f
KS
3501 if (!keep_margins_p)
3502 {
3503 /* Set left and right marginal area width etc. from buffer. */
3504
79fd290e 3505 /* This may call adjust_window_margins three times, so
949cf20f 3506 temporarily disable window margins. */
6b61353c
KH
3507 Lisp_Object save_left = w->left_margin_cols;
3508 Lisp_Object save_right = w->right_margin_cols;
3509
949cf20f
KS
3510 w->left_margin_cols = w->right_margin_cols = Qnil;
3511
3512 Fset_window_fringes (window,
3513 b->left_fringe_width, b->right_fringe_width,
3514 b->fringes_outside_margins);
3515
3516 Fset_window_scroll_bars (window,
3517 b->scroll_bar_width,
3518 b->vertical_scroll_bar_type, Qnil);
3519
6b61353c
KH
3520 w->left_margin_cols = save_left;
3521 w->right_margin_cols = save_right;
3522
949cf20f
KS
3523 Fset_window_margins (window,
3524 b->left_margin_cols, b->right_margin_cols);
3525 }
7ab12479 3526
5500c422
GM
3527 if (run_hooks_p)
3528 {
3529 if (! NILP (Vwindow_scroll_functions))
3530 run_hook_with_args_2 (Qwindow_scroll_functions, window,
3531 Fmarker_position (w->start));
ef264c42 3532 run_window_configuration_change_hook (XFRAME (WINDOW_FRAME (w)));
5500c422 3533 }
543f5fb1 3534
5b03d3c0 3535 unbind_to (count, Qnil);
5500c422 3536}
5b03d3c0 3537
5500c422 3538
949cf20f 3539DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 3, 0,
d653c8cc
MR
3540 doc: /* Make WINDOW display BUFFER-OR-NAME as its contents.
3541WINDOW defaults to the selected window. BUFFER-OR-NAME must be a buffer
3542or the name of an existing buffer. Optional third argument KEEP-MARGINS
3543non-nil means that WINDOW's current display margins, fringe widths, and
3544scroll bar settings are preserved; the default is to reset these from
fec89261 3545the local settings for BUFFER-OR-NAME or the frame defaults. Return nil.
d653c8cc 3546
7bfac547
MR
3547This function throws an error when WINDOW is strongly dedicated to its
3548buffer (that is `window-dedicated-p' returns t for WINDOW) and does not
3549already display BUFFER-OR-NAME.
6cb4a892 3550
8fef9de1
MR
3551This function runs `window-scroll-functions' before running
3552`window-configuration-change-hook'. */)
d653c8cc
MR
3553 (window, buffer_or_name, keep_margins)
3554 register Lisp_Object window, buffer_or_name, keep_margins;
5500c422 3555{
d653c8cc 3556 register Lisp_Object tem, buffer;
5500c422 3557 register struct window *w = decode_window (window);
5500c422 3558
bed0c171 3559 XSETWINDOW (window, w);
d653c8cc 3560 buffer = Fget_buffer (buffer_or_name);
b7826503 3561 CHECK_BUFFER (buffer);
5500c422
GM
3562 if (NILP (XBUFFER (buffer)->name))
3563 error ("Attempt to display deleted buffer");
3564
3565 tem = w->buffer;
aac0c6e3
MR
3566 if (NILP (tem))
3567 error ("Window is deleted");
3568 else if (!EQ (tem, Qt))
d653c8cc 3569 /* w->buffer is t when the window is first being set up. */
5500c422 3570 {
f5385255
SM
3571 if (!EQ (tem, buffer))
3572 if (EQ (w->dedicated, Qt))
3573 error ("Window is dedicated to `%s'", SDATA (XBUFFER (tem)->name));
3574 else
3575 w->dedicated = Qnil;
5500c422
GM
3576
3577 unshow_buffer (w);
3578 }
3579
949cf20f 3580 set_window_buffer (window, buffer, 1, !NILP (keep_margins));
7ab12479
JB
3581 return Qnil;
3582}
3583
e6b84b30
MR
3584/* If select_window is called with inhibit_point_swap non-zero it will
3585 not store point of the old selected window's buffer back into that
3586 window's pointm slot. This is needed by Fset_window_configuration to
3587 avoid that the display routine is called with selected_window set to
3588 Qnil causing a subsequent crash. */
2d0834cc 3589
e6b84b30
MR
3590static Lisp_Object
3591select_window (window, norecord, inhibit_point_swap)
3592 Lisp_Object window, norecord;
3593 int inhibit_point_swap;
7ab12479
JB
3594{
3595 register struct window *w;
719eaeb1 3596 register struct window *ow;
1ae1a37d 3597 struct frame *sf;
7ab12479 3598
b7826503 3599 CHECK_LIVE_WINDOW (window);
7ab12479
JB
3600
3601 w = XWINDOW (window);
50e88778 3602 w->frozen_window_start_p = 0;
7ab12479 3603
4e822bdc
MR
3604 if (NILP (norecord))
3605 {
3606 ++window_select_count;
3607 XSETFASTINT (w->use_time, window_select_count);
3608 }
3609
bae1fa42 3610 if (EQ (window, selected_window) && !inhibit_point_swap)
7ab12479
JB
3611 return window;
3612
ca2d5566
SM
3613 sf = SELECTED_FRAME ();
3614 if (XFRAME (WINDOW_FRAME (w)) != sf)
3615 {
3616 XFRAME (WINDOW_FRAME (w))->selected_window = window;
3617 /* Use this rather than Fhandle_switch_frame
3618 so that FRAME_FOCUS_FRAME is moved appropriately as we
3619 move around in the state where a minibuffer in a separate
3620 frame is active. */
c6932ecd 3621 Fselect_frame (WINDOW_FRAME (w), norecord);
ca2d5566
SM
3622 /* Fselect_frame called us back so we've done all the work already. */
3623 eassert (EQ (window, selected_window));
3624 return window;
3625 }
3626 else
3627 sf->selected_window = window;
3628
a46c0153
RS
3629 /* Store the current buffer's actual point into the
3630 old selected window. It belongs to that window,
3631 and when the window is not selected, must be in the window. */
e6b84b30 3632 if (!inhibit_point_swap)
719eaeb1
GM
3633 {
3634 ow = XWINDOW (selected_window);
3635 if (! NILP (ow->buffer))
3636 set_marker_both (ow->pointm, ow->buffer,
3637 BUF_PT (XBUFFER (ow->buffer)),
3638 BUF_PT_BYTE (XBUFFER (ow->buffer)));
3639 }
7ab12479
JB
3640
3641 selected_window = window;
7ab12479 3642
14d87dc9 3643 if (NILP (norecord))
b7354ddf 3644 record_buffer (w->buffer);
7ab12479
JB
3645 Fset_buffer (w->buffer);
3646
86e48436
RS
3647 XBUFFER (w->buffer)->last_selected_window = window;
3648
7ab12479
JB
3649 /* Go to the point recorded in the window.
3650 This is important when the buffer is in more
3651 than one window. It also matters when
3652 redisplay_window has altered point after scrolling,
3653 because it makes the change only in the window. */
3654 {
3655 register int new_point = marker_position (w->pointm);
3656 if (new_point < BEGV)
3657 SET_PT (BEGV);
a9c95e08 3658 else if (new_point > ZV)
7ab12479
JB
3659 SET_PT (ZV);
3660 else
3661 SET_PT (new_point);
3662 }
3663
3664 windows_or_buffers_changed++;
3665 return window;
3666}
14d87dc9 3667
e6b84b30
MR
3668
3669/* Note that selected_window can be nil when this is called from
3670 Fset_window_configuration. */
3671
3672DEFUN ("select-window", Fselect_window, Sselect_window, 1, 2, 0,
3673 doc: /* Select WINDOW. Most editing will apply to WINDOW's buffer.
3674If WINDOW is not already selected, make WINDOW's buffer current
3675and make WINDOW the frame's selected window. Return WINDOW.
3676Optional second arg NORECORD non-nil means do not put this buffer
3677at the front of the list of recently selected ones and do not
3678make this window the most recently selected one.
3679
3680Note that the main editor command loop selects the buffer of the
3681selected window before each command. */)
3682 (window, norecord)
3683 register Lisp_Object window, norecord;
3684{
29feb0e9 3685 return select_window (window, norecord, 0);
e6b84b30
MR
3686}
3687
14d87dc9
SM
3688static Lisp_Object
3689select_window_norecord (window)
3690 Lisp_Object window;
3691{
ab6d1131
MR
3692 return WINDOW_LIVE_P (window)
3693 ? Fselect_window (window, Qt) : selected_window;
14d87dc9 3694}
c6932ecd
MR
3695
3696static Lisp_Object
3697select_frame_norecord (frame)
3698 Lisp_Object frame;
3699{
3700 return FRAME_LIVE_P (XFRAME (frame))
3701 ? Fselect_frame (frame, Qt) : selected_frame;
3702}
b7354ddf 3703\f
87478b52
SM
3704Lisp_Object
3705display_buffer (buffer, not_this_window_p, override_frame)
3706 Lisp_Object buffer, not_this_window_p, override_frame;
d07f802a 3707{
87478b52 3708 return call3 (Qdisplay_buffer, buffer, not_this_window_p, override_frame);
d07f802a
RS
3709}
3710
6b61353c
KH
3711DEFUN ("force-window-update", Fforce_window_update, Sforce_window_update,
3712 0, 1, 0,
5a1048a5 3713 doc: /* Force all windows to be updated on next redisplay.
6b61353c 3714If optional arg OBJECT is a window, force redisplay of that window only.
0cc1039f 3715If OBJECT is a buffer or buffer name, force redisplay of all windows
6b61353c
KH
3716displaying that buffer. */)
3717 (object)
3718 Lisp_Object object;
3719{
3720 if (NILP (object))
3721 {
3722 windows_or_buffers_changed++;
3723 update_mode_lines++;
3724 return Qt;
3725 }
3726
3727 if (WINDOWP (object))
3728 {
3729 struct window *w = XWINDOW (object);
3730 mark_window_display_accurate (object, 0);
3731 w->update_mode_line = Qt;
3732 if (BUFFERP (w->buffer))
3733 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
3734 ++update_mode_lines;
3735 return Qt;
3736 }
0cc1039f 3737
6b61353c
KH
3738 if (STRINGP (object))
3739 object = Fget_buffer (object);
3740 if (BUFFERP (object) && !NILP (XBUFFER (object)->name))
3741 {
3742 /* Walk all windows looking for buffer, and force update
3743 of each of those windows. */
3744
3745 object = window_loop (REDISPLAY_BUFFER_WINDOWS, object, 0, Qvisible);
3746 return NILP (object) ? Qnil : Qt;
3747 }
3748
3749 /* If nothing suitable was found, just return.
3750 We could signal an error, but this feature will typically be used
3751 asynchronously in timers or process sentinels, so we don't. */
3752 return Qnil;
3753}
3754
3755
7ab12479
JB
3756void
3757temp_output_buffer_show (buf)
3758 register Lisp_Object buf;
3759{
3760 register struct buffer *old = current_buffer;
3761 register Lisp_Object window;
3762 register struct window *w;
3763
bccd3dd1
RS
3764 XBUFFER (buf)->directory = current_buffer->directory;
3765
7ab12479 3766 Fset_buffer (buf);
c6367666 3767 BUF_SAVE_MODIFF (XBUFFER (buf)) = MODIFF;
7ab12479
JB
3768 BEGV = BEG;
3769 ZV = Z;
3770 SET_PT (BEG);
06be4f85 3771#if 0 /* rms: there should be no reason for this. */
b1599b4c 3772 XBUFFER (buf)->prevent_redisplay_optimizations_p = 1;
06be4f85 3773#endif
7ab12479
JB
3774 set_buffer_internal (old);
3775
e67a1dea 3776 if (!NILP (Vtemp_buffer_show_function))
7ab12479
JB
3777 call1 (Vtemp_buffer_show_function, buf);
3778 else
3779 {
87478b52 3780 window = display_buffer (buf, Qnil, Qnil);
7ab12479 3781
1ae1a37d 3782 if (!EQ (XWINDOW (window)->frame, selected_frame))
44fa5b1e 3783 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
7ab12479
JB
3784 Vminibuf_scroll_window = window;
3785 w = XWINDOW (window);
d834a2e9 3786 XSETFASTINT (w->hscroll, 0);
ea68264b 3787 XSETFASTINT (w->min_hscroll, 0);
2d0834cc
SM
3788 set_marker_restricted_both (w->start, buf, BEG, BEG);
3789 set_marker_restricted_both (w->pointm, buf, BEG, BEG);
a58ec57d 3790
beb4e312 3791 /* Run temp-buffer-show-hook, with the chosen window selected
a5731348 3792 and its buffer current. */
2d0834cc
SM
3793
3794 if (!NILP (Vrun_hooks)
3795 && !NILP (Fboundp (Qtemp_buffer_show_hook))
3796 && !NILP (Fsymbol_value (Qtemp_buffer_show_hook)))
2cccc823 3797 {
2d0834cc
SM
3798 int count = SPECPDL_INDEX ();
3799 Lisp_Object prev_window, prev_buffer;
3800 prev_window = selected_window;
3801 XSETBUFFER (prev_buffer, old);
0cc1039f 3802
2d0834cc
SM
3803 /* Select the window that was chosen, for running the hook.
3804 Note: Both Fselect_window and select_window_norecord may
3805 set-buffer to the buffer displayed in the window,
3806 so we need to save the current buffer. --stef */
3807 record_unwind_protect (Fset_buffer, prev_buffer);
3808 record_unwind_protect (select_window_norecord, prev_window);
3809 Fselect_window (window, Qt);
3810 Fset_buffer (w->buffer);
3811 call1 (Vrun_hooks, Qtemp_buffer_show_hook);
3812 unbind_to (count, Qnil);
2cccc823
RS
3813 }
3814 }
7ab12479
JB
3815}
3816\f
dfcf069d 3817static void
7ab12479
JB
3818make_dummy_parent (window)
3819 Lisp_Object window;
3820{
cffec418 3821 Lisp_Object new;
7ab12479 3822 register struct window *o, *p;
cffec418 3823 int i;
7ab12479 3824
cffec418 3825 o = XWINDOW (window);
26605be9 3826 p = allocate_window ();
cffec418 3827 for (i = 0; i < VECSIZE (struct window); ++i)
26605be9
GM
3828 ((struct Lisp_Vector *) p)->contents[i]
3829 = ((struct Lisp_Vector *)o)->contents[i];
cffec418 3830 XSETWINDOW (new, p);
7ab12479 3831
2a1893f4
SM
3832 ++sequence_number;
3833 XSETFASTINT (p->sequence_number, sequence_number);
7ab12479
JB
3834
3835 /* Put new into window structure in place of window */
3836 replace_window (window, new);
3837
3838 o->next = Qnil;
3839 o->prev = Qnil;
3840 o->vchild = Qnil;
3841 o->hchild = Qnil;
3842 o->parent = new;
3843
3844 p->start = Qnil;
3845 p->pointm = Qnil;
3846 p->buffer = Qnil;
3847}
3848
3849DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
fdb82f93
PJ
3850 doc: /* Split WINDOW, putting SIZE lines in the first of the pair.
3851WINDOW defaults to selected one and SIZE to half its size.
87527026
MR
3852If optional third arg HORIZONTAL is non-nil, split side by side and put
3853SIZE columns in the first of the pair. In that case, SIZE includes that
3854window's scroll bar, or the divider column to its right.
c2755926 3855Interactively, all arguments are nil.
c2755926 3856Returns the newly created window (which is the lower or rightmost one).
19ca94ce
RS
3857The upper or leftmost window is the original one, and remains selected
3858if it was selected before.
3859
87527026
MR
3860See Info node `(elisp)Splitting Windows' for more details and examples. */)
3861 (window, size, horizontal)
3862 Lisp_Object window, size, horizontal;
7ab12479
JB
3863{
3864 register Lisp_Object new;
3865 register struct window *o, *p;
c0807608 3866 FRAME_PTR fo;
77ae0fe3 3867 register int size_int;
7ab12479 3868
265a9e55 3869 if (NILP (window))
7ab12479
JB
3870 window = selected_window;
3871 else
b7826503 3872 CHECK_LIVE_WINDOW (window);
7ab12479
JB
3873
3874 o = XWINDOW (window);
c0807608 3875 fo = XFRAME (WINDOW_FRAME (o));
7ab12479 3876
77ae0fe3 3877 if (NILP (size))
7ab12479 3878 {
87527026 3879 if (!NILP (horizontal))
c0807608 3880 /* Calculate the size of the left-hand window, by dividing
25b33244
KH
3881 the usable space in columns by two.
3882 We round up, since the left-hand window may include
3883 a dividing line, while the right-hand may not. */
949cf20f 3884 size_int = (XFASTINT (o->total_cols) + 1) >> 1;
7ab12479 3885 else
949cf20f 3886 size_int = XFASTINT (o->total_lines) >> 1;
7ab12479
JB
3887 }
3888 else
3889 {
b7826503 3890 CHECK_NUMBER (size);
77ae0fe3 3891 size_int = XINT (size);
7ab12479
JB
3892 }
3893
3894 if (MINI_WINDOW_P (o))
3895 error ("Attempt to split minibuffer window");
87527026 3896 else if (window_fixed_size_p (o, !NILP (horizontal), 0))
233a4a2c 3897 error ("Attempt to split fixed-size window");
7ab12479 3898
87527026 3899 if (NILP (horizontal))
7ab12479 3900 {
047aaeb9
MR
3901 int window_safe_height = window_min_size_2 (o, 0, 0);
3902
f1de8c77 3903 if (size_int < window_safe_height)
77ae0fe3 3904 error ("Window height %d too small (after splitting)", size_int);
f1de8c77 3905 if (size_int + window_safe_height > XFASTINT (o->total_lines))
37962e60 3906 error ("Window height %d too small (after splitting)",
949cf20f 3907 XFASTINT (o->total_lines) - size_int);
265a9e55
JB
3908 if (NILP (o->parent)
3909 || NILP (XWINDOW (o->parent)->vchild))
7ab12479
JB
3910 {
3911 make_dummy_parent (window);
3912 new = o->parent;
3913 XWINDOW (new)->vchild = window;
3914 }
3915 }
3916 else
3917 {
047aaeb9
MR
3918 int window_safe_width = window_min_size_2 (o, 1, 0);
3919
f1de8c77 3920 if (size_int < window_safe_width)
77ae0fe3 3921 error ("Window width %d too small (after splitting)", size_int);
f1de8c77 3922 if (size_int + window_safe_width > XFASTINT (o->total_cols))
37962e60 3923 error ("Window width %d too small (after splitting)",
949cf20f 3924 XFASTINT (o->total_cols) - size_int);
265a9e55
JB
3925 if (NILP (o->parent)
3926 || NILP (XWINDOW (o->parent)->hchild))
7ab12479
JB
3927 {
3928 make_dummy_parent (window);
3929 new = o->parent;
3930 XWINDOW (new)->hchild = window;
3931 }
3932 }
3933
3934 /* Now we know that window's parent is a vertical combination
3935 if we are dividing vertically, or a horizontal combination
3936 if we are making side-by-side windows */
3937
3938 windows_or_buffers_changed++;
c0807608 3939 FRAME_WINDOW_SIZES_CHANGED (fo) = 1;
7ab12479
JB
3940 new = make_window ();
3941 p = XWINDOW (new);
3942
44fa5b1e 3943 p->frame = o->frame;
7ab12479 3944 p->next = o->next;
265a9e55 3945 if (!NILP (p->next))
7ab12479
JB
3946 XWINDOW (p->next)->prev = new;
3947 p->prev = window;
3948 o->next = new;
3949 p->parent = o->parent;
3950 p->buffer = Qt;
5500c422
GM
3951 p->window_end_valid = Qnil;
3952 bzero (&p->last_cursor, sizeof p->last_cursor);
7ab12479 3953
949cf20f
KS
3954 /* Duplicate special geometry settings. */
3955
3956 p->left_margin_cols = o->left_margin_cols;
3957 p->right_margin_cols = o->right_margin_cols;
3958 p->left_fringe_width = o->left_fringe_width;
3959 p->right_fringe_width = o->right_fringe_width;
3960 p->fringes_outside_margins = o->fringes_outside_margins;
3961 p->scroll_bar_width = o->scroll_bar_width;
3962 p->vertical_scroll_bar_type = o->vertical_scroll_bar_type;
3963
44fa5b1e 3964 /* Apportion the available frame space among the two new windows */
7ab12479 3965
87527026 3966 if (!NILP (horizontal))
7ab12479 3967 {
949cf20f
KS
3968 p->total_lines = o->total_lines;
3969 p->top_line = o->top_line;
3970 XSETFASTINT (p->total_cols, XFASTINT (o->total_cols) - size_int);
3971 XSETFASTINT (o->total_cols, size_int);
3972 XSETFASTINT (p->left_col, XFASTINT (o->left_col) + size_int);
3973 adjust_window_margins (p);
3974 adjust_window_margins (o);
7ab12479
JB
3975 }
3976 else
3977 {
949cf20f
KS
3978 p->left_col = o->left_col;
3979 p->total_cols = o->total_cols;
3980 XSETFASTINT (p->total_lines, XFASTINT (o->total_lines) - size_int);
3981 XSETFASTINT (o->total_lines, size_int);
3982 XSETFASTINT (p->top_line, XFASTINT (o->top_line) + size_int);
7ab12479
JB
3983 }
3984
5500c422
GM
3985 /* Adjust glyph matrices. */
3986 adjust_glyphs (fo);
949cf20f
KS
3987
3988 Fset_window_buffer (new, o->buffer, Qt);
7ab12479
JB
3989 return new;
3990}
3991\f
56ebfae2 3992DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
aac0c6e3
MR
3993 doc: /* Make selected window SIZE lines taller.
3994Interactively, if no argument is given, make the selected window one
3995line taller. If optional argument HORIZONTAL is non-nil, make selected
3996window wider by SIZE columns. If SIZE is negative, shrink the window by
3997-SIZE lines or columns. Return nil.
3998
3999This function can delete windows if they get too small. The size of
4000fixed size windows is not altered by this function. */)
4001 (size, horizontal)
4002 Lisp_Object size, horizontal;
7ab12479 4003{
aac0c6e3
MR
4004 CHECK_NUMBER (size);
4005 enlarge_window (selected_window, XINT (size), !NILP (horizontal));
543f5fb1 4006
eeca6f6f 4007 run_window_configuration_change_hook (SELECTED_FRAME ());
543f5fb1 4008
7ab12479
JB
4009 return Qnil;
4010}
4011
56ebfae2 4012DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
aac0c6e3
MR
4013 doc: /* Make selected window SIZE lines smaller.
4014Interactively, if no argument is given, make the selected window one
4015line smaller. If optional argument HORIZONTAL is non-nil, make the
4016window narrower by SIZE columns. If SIZE is negative, enlarge selected
4017window by -SIZE lines or columns. Return nil.
4018
4019This function can delete windows if they get too small. The size of
4020fixed size windows is not altered by this function. */)
4021 (size, horizontal)
4022 Lisp_Object size, horizontal;
4023{
4024 CHECK_NUMBER (size);
4025 enlarge_window (selected_window, -XINT (size), !NILP (horizontal));
543f5fb1 4026
eeca6f6f 4027 run_window_configuration_change_hook (SELECTED_FRAME ());
543f5fb1 4028
7ab12479
JB
4029 return Qnil;
4030}
4031
4032int
4033window_height (window)
4034 Lisp_Object window;
4035{
4036 register struct window *p = XWINDOW (window);
949cf20f 4037 return WINDOW_TOTAL_LINES (p);
7ab12479
JB
4038}
4039
4040int
4041window_width (window)
4042 Lisp_Object window;
4043{
4044 register struct window *p = XWINDOW (window);
949cf20f 4045 return WINDOW_TOTAL_COLS (p);
7ab12479
JB
4046}
4047
177c0ea7 4048
7ab12479 4049#define CURBEG(w) \
5afc696a 4050 *(horiz_flag ? &(XWINDOW (w)->left_col) : &(XWINDOW (w)->top_line))
7ab12479
JB
4051
4052#define CURSIZE(w) \
5afc696a 4053 *(horiz_flag ? &(XWINDOW (w)->total_cols) : &(XWINDOW (w)->total_lines))
7ab12479 4054
233a4a2c 4055
047aaeb9
MR
4056/* Enlarge WINDOW by DELTA. HORIZ_FLAG nonzero means enlarge it
4057 horizontally; zero means do it vertically.
f95284d2 4058
5afc696a 4059 Siblings of the selected window are resized to fulfill the size
047aaeb9 4060 request. If they become too small in the process, they may be
56ebfae2 4061 deleted. */
7ab12479 4062
f984d4fc 4063static void
56ebfae2 4064enlarge_window (window, delta, horiz_flag)
86c8e823 4065 Lisp_Object window;
56ebfae2 4066 int delta, horiz_flag;
7ab12479 4067{
86c8e823 4068 Lisp_Object parent, next, prev;
233a4a2c 4069 struct window *p;
3578db3c
KR
4070 Lisp_Object *sizep;
4071 int maximum;
5e14b1fc 4072 int (*sizefun) P_ ((Lisp_Object))
5afc696a 4073 = horiz_flag ? window_width : window_height;
233a4a2c 4074 void (*setsizefun) P_ ((Lisp_Object, int, int))
5afc696a 4075 = (horiz_flag ? set_window_width : set_window_height);
7ab12479 4076
233a4a2c 4077 /* Give up if this window cannot be resized. */
5afc696a 4078 if (window_fixed_size_p (XWINDOW (window), horiz_flag, 1))
233a4a2c
GM
4079 error ("Window is not resizable");
4080
4081 /* Find the parent of the selected window. */
7ab12479
JB
4082 while (1)
4083 {
4084 p = XWINDOW (window);
4085 parent = p->parent;
177c0ea7 4086
265a9e55 4087 if (NILP (parent))
7ab12479 4088 {
5afc696a 4089 if (horiz_flag)
7ab12479
JB
4090 error ("No other window to side of this one");
4091 break;
4092 }
177c0ea7 4093
5afc696a 4094 if (horiz_flag
233a4a2c 4095 ? !NILP (XWINDOW (parent)->hchild)
265a9e55 4096 : !NILP (XWINDOW (parent)->vchild))
7ab12479 4097 break;
177c0ea7 4098
7ab12479
JB
4099 window = parent;
4100 }
4101
05c2896a 4102 sizep = &CURSIZE (window);
7ab12479 4103
7ab12479
JB
4104 {
4105 register int maxdelta;
7ab12479 4106
f95284d2
RS
4107 /* Compute the maximum size increment this window can have. */
4108
56ebfae2
RS
4109 maxdelta = (!NILP (parent) ? (*sizefun) (parent) - XINT (*sizep)
4110 /* This is a main window followed by a minibuffer. */
4111 : !NILP (p->next) ? ((*sizefun) (p->next)
4112 - window_min_size (XWINDOW (p->next),
047aaeb9 4113 horiz_flag, 0, 0, 0))
56ebfae2
RS
4114 /* This is a minibuffer following a main window. */
4115 : !NILP (p->prev) ? ((*sizefun) (p->prev)
4116 - window_min_size (XWINDOW (p->prev),
047aaeb9 4117 horiz_flag, 0, 0, 0))
56ebfae2
RS
4118 /* This is a frame with only one window, a minibuffer-only
4119 or a minibufferless frame. */
4120 : (delta = 0));
7ab12479
JB
4121
4122 if (delta > maxdelta)
4123 /* This case traps trying to make the minibuffer
44fa5b1e
JB
4124 the full frame, or make the only window aside from the
4125 minibuffer the full frame. */
7ab12479 4126 delta = maxdelta;
6b54027b 4127 }
d5783c40 4128
047aaeb9
MR
4129 if (XINT (*sizep) + delta < window_min_size (XWINDOW (window),
4130 horiz_flag, 0, 0, 0))
6b54027b 4131 {
543f5fb1 4132 delete_window (window);
d5783c40 4133 return;
6b54027b
RS
4134 }
4135
4136 if (delta == 0)
4137 return;
7ab12479 4138
f95284d2 4139 /* Find the total we can get from other siblings without deleting them. */
db98a733 4140 maximum = 0;
9beb8baa 4141 for (next = p->next; WINDOWP (next); next = XWINDOW (next)->next)
c1636aa6 4142 maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
047aaeb9 4143 horiz_flag, 0, 0, 0);
9beb8baa 4144 for (prev = p->prev; WINDOWP (prev); prev = XWINDOW (prev)->prev)
56ebfae2 4145 maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
047aaeb9 4146 horiz_flag, 0, 0, 0);
db98a733 4147
f95284d2 4148 /* If we can get it all from them without deleting them, do so. */
c6b530ed 4149 if (delta <= maximum)
7ab12479 4150 {
db98a733
RS
4151 Lisp_Object first_unaffected;
4152 Lisp_Object first_affected;
233a4a2c 4153 int fixed_p;
db98a733
RS
4154
4155 next = p->next;
4156 prev = p->prev;
4157 first_affected = window;
4158 /* Look at one sibling at a time,
4159 moving away from this window in both directions alternately,
4160 and take as much as we can get without deleting that sibling. */
f95284d2 4161 while (delta != 0
56ebfae2 4162 && (!NILP (next) || !NILP (prev)))
db98a733 4163 {
db98a733
RS
4164 if (! NILP (next))
4165 {
c1636aa6 4166 int this_one = ((*sizefun) (next)
047aaeb9
MR
4167 - window_min_size (XWINDOW (next), horiz_flag,
4168 0, 0, &fixed_p));
233a4a2c
GM
4169 if (!fixed_p)
4170 {
4171 if (this_one > delta)
4172 this_one = delta;
177c0ea7 4173
233a4a2c 4174 (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
3578db3c 4175 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
db98a733 4176
233a4a2c
GM
4177 delta -= this_one;
4178 }
177c0ea7 4179
db98a733
RS
4180 next = XWINDOW (next)->next;
4181 }
177c0ea7 4182
db98a733
RS
4183 if (delta == 0)
4184 break;
177c0ea7 4185
56ebfae2 4186 if (! NILP (prev))
db98a733 4187 {
c1636aa6 4188 int this_one = ((*sizefun) (prev)
047aaeb9
MR
4189 - window_min_size (XWINDOW (prev), horiz_flag,
4190 0, 0, &fixed_p));
233a4a2c
GM
4191 if (!fixed_p)
4192 {
4193 if (this_one > delta)
4194 this_one = delta;
177c0ea7 4195
233a4a2c 4196 first_affected = prev;
177c0ea7 4197
233a4a2c 4198 (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
3578db3c 4199 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
233a4a2c
GM
4200
4201 delta -= this_one;
4202 }
177c0ea7 4203
db98a733
RS
4204 prev = XWINDOW (prev)->prev;
4205 }
4206 }
4207
233a4a2c
GM
4208 xassert (delta == 0);
4209
db98a733
RS
4210 /* Now recalculate the edge positions of all the windows affected,
4211 based on the new sizes. */
4212 first_unaffected = next;
4213 prev = first_affected;
4214 for (next = XWINDOW (prev)->next; ! EQ (next, first_unaffected);
4215 prev = next, next = XWINDOW (next)->next)
4216 {
3578db3c 4217 XSETINT (CURBEG (next), XINT (CURBEG (prev)) + (*sizefun) (prev));
db98a733
RS
4218 /* This does not change size of NEXT,
4219 but it propagates the new top edge to its children */
4220 (*setsizefun) (next, (*sizefun) (next), 0);
4221 }
7ab12479
JB
4222 }
4223 else
4224 {
4225 register int delta1;
4226 register int opht = (*sizefun) (parent);
4227
3578db3c 4228 if (opht <= XINT (*sizep) + delta)
daf516d3
RS
4229 {
4230 /* If trying to grow this window to or beyond size of the parent,
4231 just delete all the sibling windows. */
dc1ab1ee 4232 Lisp_Object start, tem, next;
daf516d3 4233
dc1ab1ee
RS
4234 start = XWINDOW (parent)->vchild;
4235 if (NILP (start))
4236 start = XWINDOW (parent)->hchild;
daf516d3 4237
dc1ab1ee
RS
4238 /* Delete any siblings that come after WINDOW. */
4239 tem = XWINDOW (window)->next;
daf516d3
RS
4240 while (! NILP (tem))
4241 {
4242 next = XWINDOW (tem)->next;
dc1ab1ee
RS
4243 delete_window (tem);
4244 tem = next;
4245 }
4246
4247 /* Delete any siblings that come after WINDOW.
4248 Note that if START is not WINDOW, then WINDOW still
047aaeb9 4249 has siblings, so WINDOW has not yet replaced its parent. */
dc1ab1ee
RS
4250 tem = start;
4251 while (! EQ (tem, window))
4252 {
4253 next = XWINDOW (tem)->next;
4254 delete_window (tem);
daf516d3
RS
4255 tem = next;
4256 }
4257 }
7ab12479 4258 else
233a4a2c
GM
4259 {
4260 /* Otherwise, make delta1 just right so that if we add
4261 delta1 lines to this window and to the parent, and then
4262 shrink the parent back to its original size, the new
4263 proportional size of this window will increase by delta.
4264
4265 The function size_window will compute the new height h'
4266 of the window from delta1 as:
177c0ea7 4267
233a4a2c
GM
4268 e = delta1/n
4269 x = delta1 - delta1/n * n for the 1st resizable child
4270 h' = h + e + x
4271
4272 where n is the number of children that can be resized.
4273 We can ignore x by choosing a delta1 that is a multiple of
4274 n. We want the height of this window to come out as
177c0ea7 4275
233a4a2c
GM
4276 h' = h + delta
4277
4278 So, delta1 must be
177c0ea7 4279
233a4a2c
GM
4280 h + e = h + delta
4281 delta1/n = delta
4282 delta1 = n * delta.
4283
a5731348 4284 The number of children n equals the number of resizable
233a4a2c 4285 children of this window + 1 because we know window itself
04bf5b65 4286 is resizable (otherwise we would have signaled an error).
047aaeb9
MR
4287
4288 This reasoning is not correct when other windows become too
4289 small and shrink_windows refuses to delete them. Below we
4290 use resize_proportionally to work around this problem. */
233a4a2c
GM
4291
4292 struct window *w = XWINDOW (window);
4293 Lisp_Object s;
4294 int n = 1;
4295
9beb8baa 4296 for (s = w->next; WINDOWP (s); s = XWINDOW (s)->next)
5afc696a 4297 if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
233a4a2c 4298 ++n;
9beb8baa 4299 for (s = w->prev; WINDOWP (s); s = XWINDOW (s)->prev)
5afc696a 4300 if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
233a4a2c
GM
4301 ++n;
4302
4303 delta1 = n * delta;
7ab12479 4304
daf516d3
RS
4305 /* Add delta1 lines or columns to this window, and to the parent,
4306 keeping things consistent while not affecting siblings. */
4307 XSETINT (CURSIZE (parent), opht + delta1);
4308 (*setsizefun) (window, XINT (*sizep) + delta1, 0);
4309
4310 /* Squeeze out delta1 lines or columns from our parent,
047aaeb9
MR
4311 shrinking this window and siblings proportionately. This
4312 brings parent back to correct size. Delta1 was calculated
4313 so this makes this window the desired size, taking it all
4314 out of the siblings.
4315
4316 Temporarily set resize_proportionally to Qt to assure that,
4317 if necessary, shrink_windows deletes smaller windows rather
4318 than shrink this window. */
4319 w->resize_proportionally = Qt;
daf516d3 4320 (*setsizefun) (parent, opht, 0);
047aaeb9 4321 w->resize_proportionally = Qnil;
daf516d3 4322 }
7ab12479
JB
4323 }
4324
d834a2e9 4325 XSETFASTINT (p->last_modified, 0);
3cd21523 4326 XSETFASTINT (p->last_overlay_modified, 0);
5500c422
GM
4327
4328 /* Adjust glyph matrices. */
4329 adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
7ab12479 4330}
c1636aa6 4331
0d384044
RS
4332
4333/* Adjust the size of WINDOW by DELTA, moving only its trailing edge.
4334 HORIZ_FLAG nonzero means adjust the width, moving the right edge.
4335 zero means adjust the height, moving the bottom edge.
4336
4337 Following siblings of the selected window are resized to fulfill
4338 the size request. If they become too small in the process, they
4339 are not deleted; instead, we signal an error. */
4340
4341static void
4342adjust_window_trailing_edge (window, delta, horiz_flag)
4343 Lisp_Object window;
4344 int delta, horiz_flag;
4345{
4346 Lisp_Object parent, child;
4347 struct window *p;
4348 Lisp_Object old_config = Fcurrent_window_configuration (Qnil);
4349 int delcount = window_deletion_count;
4350
0d384044
RS
4351 CHECK_WINDOW (window);
4352
4353 /* Give up if this window cannot be resized. */
4354 if (window_fixed_size_p (XWINDOW (window), horiz_flag, 1))
4355 error ("Window is not resizable");
4356
4357 while (1)
4358 {
bd99e242
RS
4359 Lisp_Object first_parallel = Qnil;
4360
c32de52a 4361 if (NILP (window))
0d384044 4362 {
5fe0b054
RS
4363 /* This happens if WINDOW on the previous iteration was
4364 at top level of the window tree. */
0d384044 4365 Fset_window_configuration (old_config);
c32de52a 4366 error ("Specified window edge is fixed");
0d384044
RS
4367 }
4368
c32de52a
RS
4369 p = XWINDOW (window);
4370 parent = p->parent;
4371
bd99e242
RS
4372 /* See if this level has windows in parallel in the specified
4373 direction. If so, set FIRST_PARALLEL to the first one. */
4374 if (horiz_flag)
4375 {
4376 if (! NILP (parent) && !NILP (XWINDOW (parent)->vchild))
4377 first_parallel = XWINDOW (parent)->vchild;
5fe0b054
RS
4378 else if (NILP (parent) && !NILP (p->next))
4379 {
4380 /* Handle the vertical chain of main window and minibuffer
4381 which has no parent. */
4382 first_parallel = window;
4383 while (! NILP (XWINDOW (first_parallel)->prev))
4384 first_parallel = XWINDOW (first_parallel)->prev;
4385 }
bd99e242
RS
4386 }
4387 else
4388 {
4389 if (! NILP (parent) && !NILP (XWINDOW (parent)->hchild))
4390 first_parallel = XWINDOW (parent)->hchild;
4391 }
4392
c32de52a 4393 /* If this level's succession is in the desired dimension,
5fe0b054
RS
4394 and this window is the last one, and there is no higher level,
4395 its trailing edge is fixed. */
4396 if (NILP (XWINDOW (window)->next) && NILP (first_parallel)
4397 && NILP (parent))
c32de52a
RS
4398 {
4399 Fset_window_configuration (old_config);
4400 error ("Specified window edge is fixed");
4401 }
4402
0d384044
RS
4403 /* Don't make this window too small. */
4404 if (XINT (CURSIZE (window)) + delta
047aaeb9 4405 < window_min_size_2 (XWINDOW (window), horiz_flag, 0))
0d384044
RS
4406 {
4407 Fset_window_configuration (old_config);
4408 error ("Cannot adjust window size as specified");
4409 }
4410
4411 /* Clear out some redisplay caches. */
4412 XSETFASTINT (p->last_modified, 0);
4413 XSETFASTINT (p->last_overlay_modified, 0);
4414
4415 /* Adjust this window's edge. */
4416 XSETINT (CURSIZE (window),
4417 XINT (CURSIZE (window)) + delta);
4418
4419 /* If this window has following siblings in the desired dimension,
bd99e242
RS
4420 make them smaller, and exit the loop.
4421
0d384044
RS
4422 (If we reach the top of the tree and can never do this,
4423 we will fail and report an error, above.) */
bd99e242 4424 if (NILP (first_parallel))
0d384044 4425 {
c32de52a 4426 if (!NILP (p->next))
0d384044 4427 {
e99c7521
JD
4428 /* This may happen for the minibuffer. In that case
4429 the window_deletion_count check below does not work. */
a53d44a8 4430 if (XINT (CURSIZE (p->next)) - delta <= 0)
e99c7521
JD
4431 {
4432 Fset_window_configuration (old_config);
4433 error ("Cannot adjust window size as specified");
4434 }
4435
0d384044
RS
4436 XSETINT (CURBEG (p->next),
4437 XINT (CURBEG (p->next)) + delta);
4438 size_window (p->next, XINT (CURSIZE (p->next)) - delta,
5fe0b054 4439 horiz_flag, 0, 1, 0);
0d384044
RS
4440 break;
4441 }
4442 }
4443 else
4444 /* Here we have a chain of parallel siblings, in the other dimension.
4445 Change the size of the other siblings. */
bd99e242 4446 for (child = first_parallel;
0d384044
RS
4447 ! NILP (child);
4448 child = XWINDOW (child)->next)
4449 if (! EQ (child, window))
4450 size_window (child, XINT (CURSIZE (child)) + delta,
5fe0b054 4451 horiz_flag, 0, 0, 1);
0d384044
RS
4452
4453 window = parent;
4454 }
4455
4456 /* If we made a window so small it got deleted,
4457 we failed. Report failure. */
4458 if (delcount != window_deletion_count)
4459 {
4460 Fset_window_configuration (old_config);
4461 error ("Cannot adjust window size as specified");
4462 }
4463
4464 /* Adjust glyph matrices. */
4465 adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
4466}
4467
7ab12479
JB
4468#undef CURBEG
4469#undef CURSIZE
4470
0d384044
RS
4471DEFUN ("adjust-window-trailing-edge", Fadjust_window_trailing_edge,
4472 Sadjust_window_trailing_edge, 3, 3, 0,
4473 doc: /* Adjust the bottom or right edge of WINDOW by DELTA.
56ebfae2 4474If HORIZONTAL is non-nil, that means adjust the width, moving the right edge.
0d384044
RS
4475Otherwise, adjust the height, moving the bottom edge.
4476
4477Following siblings of the selected window are resized to fulfill
4478the size request. If they become too small in the process, they
4479are not deleted; instead, we signal an error. */)
4480 (window, delta, horizontal)
4481 Lisp_Object window, delta, horizontal;
4482{
4483 CHECK_NUMBER (delta);
eeca6f6f
SM
4484 if (NILP (window))
4485 window = selected_window;
0d384044
RS
4486 adjust_window_trailing_edge (window, XINT (delta), !NILP (horizontal));
4487
eeca6f6f
SM
4488 run_window_configuration_change_hook
4489 (XFRAME (WINDOW_FRAME (XWINDOW (window))));
0d384044
RS
4490
4491 return Qnil;
4492}
4493
5500c422 4494
f984d4fc
GM
4495\f
4496/***********************************************************************
4497 Resizing Mini-Windows
4498 ***********************************************************************/
4499
4500static void shrink_window_lowest_first P_ ((struct window *, int));
f984d4fc 4501
43b4a21f
GM
4502enum save_restore_action
4503{
4504 CHECK_ORIG_SIZES,
4505 SAVE_ORIG_SIZES,
4506 RESTORE_ORIG_SIZES
4507};
4508
177c0ea7 4509static int save_restore_orig_size P_ ((struct window *,
43b4a21f 4510 enum save_restore_action));
f984d4fc
GM
4511
4512/* Shrink windows rooted in window W to HEIGHT. Take the space needed
4513 from lowest windows first. */
4514
4515static void
4516shrink_window_lowest_first (w, height)
4517 struct window *w;
4518 int height;
4519{
4520 struct window *c;
4521 Lisp_Object child;
4522 int old_height;
4523
4524 xassert (!MINI_WINDOW_P (w));
4525
4526 /* Set redisplay hints. */
4527 XSETFASTINT (w->last_modified, 0);
4528 XSETFASTINT (w->last_overlay_modified, 0);
4529 windows_or_buffers_changed++;
4530 FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
4531
949cf20f
KS
4532 old_height = XFASTINT (w->total_lines);
4533 XSETFASTINT (w->total_lines, height);
f984d4fc
GM
4534
4535 if (!NILP (w->hchild))
4536 {
4537 for (child = w->hchild; !NILP (child); child = c->next)
4538 {
4539 c = XWINDOW (child);
949cf20f 4540 c->top_line = w->top_line;
f984d4fc
GM
4541 shrink_window_lowest_first (c, height);
4542 }
4543 }
4544 else if (!NILP (w->vchild))
4545 {
4546 Lisp_Object last_child;
4547 int delta = old_height - height;
4548 int last_top;
6bbd7a29
GM
4549
4550 last_child = Qnil;
177c0ea7 4551
f984d4fc
GM
4552 /* Find the last child. We are taking space from lowest windows
4553 first, so we iterate over children from the last child
4554 backwards. */
9beb8baa 4555 for (child = w->vchild; WINDOWP (child); child = XWINDOW (child)->next)
f984d4fc
GM
4556 last_child = child;
4557
047aaeb9 4558 /* Size children down to their safe heights. */
f984d4fc
GM
4559 for (child = last_child; delta && !NILP (child); child = c->prev)
4560 {
4561 int this_one;
177c0ea7 4562
f984d4fc 4563 c = XWINDOW (child);
047aaeb9 4564 this_one = XFASTINT (c->total_lines) - window_min_size_1 (c, 0, 1);
f984d4fc
GM
4565
4566 if (this_one > delta)
4567 this_one = delta;
4568
949cf20f 4569 shrink_window_lowest_first (c, XFASTINT (c->total_lines) - this_one);
f984d4fc
GM
4570 delta -= this_one;
4571 }
4572
4573 /* Compute new positions. */
949cf20f 4574 last_top = XINT (w->top_line);
f984d4fc
GM
4575 for (child = w->vchild; !NILP (child); child = c->next)
4576 {
4577 c = XWINDOW (child);
949cf20f
KS
4578 c->top_line = make_number (last_top);
4579 shrink_window_lowest_first (c, XFASTINT (c->total_lines));
4580 last_top += XFASTINT (c->total_lines);
f984d4fc
GM
4581 }
4582 }
4583}
4584
4585
43b4a21f
GM
4586/* Save, restore, or check positions and sizes in the window tree
4587 rooted at W. ACTION says what to do.
f984d4fc 4588
949cf20f
KS
4589 If ACTION is CHECK_ORIG_SIZES, check if orig_top_line and
4590 orig_total_lines members are valid for all windows in the window
4591 tree. Value is non-zero if they are valid.
177c0ea7 4592
43b4a21f 4593 If ACTION is SAVE_ORIG_SIZES, save members top and height in
949cf20f 4594 orig_top_line and orig_total_lines for all windows in the tree.
43b4a21f 4595
949cf20f
KS
4596 If ACTION is RESTORE_ORIG_SIZES, restore top and height from values
4597 stored in orig_top_line and orig_total_lines for all windows. */
43b4a21f
GM
4598
4599static int
4600save_restore_orig_size (w, action)
f984d4fc 4601 struct window *w;
43b4a21f 4602 enum save_restore_action action;
f984d4fc 4603{
43b4a21f
GM
4604 int success_p = 1;
4605
f984d4fc
GM
4606 while (w)
4607 {
4608 if (!NILP (w->hchild))
43b4a21f
GM
4609 {
4610 if (!save_restore_orig_size (XWINDOW (w->hchild), action))
4611 success_p = 0;
4612 }
f984d4fc 4613 else if (!NILP (w->vchild))
43b4a21f
GM
4614 {
4615 if (!save_restore_orig_size (XWINDOW (w->vchild), action))
4616 success_p = 0;
4617 }
177c0ea7 4618
43b4a21f 4619 switch (action)
f984d4fc 4620 {
43b4a21f 4621 case CHECK_ORIG_SIZES:
949cf20f 4622 if (!INTEGERP (w->orig_top_line) || !INTEGERP (w->orig_total_lines))
43b4a21f
GM
4623 return 0;
4624 break;
4625
4626 case SAVE_ORIG_SIZES:
949cf20f
KS
4627 w->orig_top_line = w->top_line;
4628 w->orig_total_lines = w->total_lines;
43b4a21f
GM
4629 XSETFASTINT (w->last_modified, 0);
4630 XSETFASTINT (w->last_overlay_modified, 0);
4631 break;
4632
4633 case RESTORE_ORIG_SIZES:
949cf20f
KS
4634 xassert (INTEGERP (w->orig_top_line) && INTEGERP (w->orig_total_lines));
4635 w->top_line = w->orig_top_line;
4636 w->total_lines = w->orig_total_lines;
4637 w->orig_total_lines = w->orig_top_line = Qnil;
43b4a21f
GM
4638 XSETFASTINT (w->last_modified, 0);
4639 XSETFASTINT (w->last_overlay_modified, 0);
4640 break;
4641
4642 default:
4643 abort ();
f984d4fc 4644 }
43b4a21f 4645
f984d4fc
GM
4646 w = NILP (w->next) ? NULL : XWINDOW (w->next);
4647 }
43b4a21f
GM
4648
4649 return success_p;
f984d4fc
GM
4650}
4651
4652
4653/* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we can
4654 without deleting other windows. */
4655
4656void
4657grow_mini_window (w, delta)
4658 struct window *w;
4659 int delta;
4660{
4661 struct frame *f = XFRAME (w->frame);
4662 struct window *root;
177c0ea7 4663
f984d4fc 4664 xassert (MINI_WINDOW_P (w));
522d013a
JB
4665 /* Commenting out the following assertion goes against the stated interface
4666 of the function, but it currently does not seem to do anything useful.
4667 See discussion of this issue in the thread for bug#4534.
4668 xassert (delta >= 0); */
177c0ea7 4669
f984d4fc
GM
4670 /* Compute how much we can enlarge the mini-window without deleting
4671 other windows. */
4672 root = XWINDOW (FRAME_ROOT_WINDOW (f));
522d013a 4673 if (delta > 0)
f984d4fc 4674 {
047aaeb9 4675 int min_height = window_min_size (root, 0, 0, 0, 0);
949cf20f 4676 if (XFASTINT (root->total_lines) - delta < min_height)
8b8bd9c6 4677 /* Note that the root window may already be smaller than
eafa3196 4678 min_height. */
949cf20f 4679 delta = max (0, XFASTINT (root->total_lines) - min_height);
f984d4fc 4680 }
177c0ea7 4681
f984d4fc
GM
4682 if (delta)
4683 {
4684 /* Save original window sizes and positions, if not already done. */
43b4a21f
GM
4685 if (!save_restore_orig_size (root, CHECK_ORIG_SIZES))
4686 save_restore_orig_size (root, SAVE_ORIG_SIZES);
f984d4fc
GM
4687
4688 /* Shrink other windows. */
949cf20f 4689 shrink_window_lowest_first (root, XFASTINT (root->total_lines) - delta);
f984d4fc
GM
4690
4691 /* Grow the mini-window. */
949cf20f
KS
4692 w->top_line = make_number (XFASTINT (root->top_line) + XFASTINT (root->total_lines));
4693 w->total_lines = make_number (XFASTINT (w->total_lines) + delta);
f984d4fc
GM
4694 XSETFASTINT (w->last_modified, 0);
4695 XSETFASTINT (w->last_overlay_modified, 0);
177c0ea7 4696
f984d4fc
GM
4697 adjust_glyphs (f);
4698 }
4699}
4700
4701
86c8e823
GM
4702/* Shrink mini-window W. If there is recorded info about window sizes
4703 before a call to grow_mini_window, restore recorded window sizes.
4704 Otherwise, if the mini-window is higher than 1 line, resize it to 1
4705 line. */
f984d4fc
GM
4706
4707void
4708shrink_mini_window (w)
4709 struct window *w;
4710{
4711 struct frame *f = XFRAME (w->frame);
4712 struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
4713
43b4a21f 4714 if (save_restore_orig_size (root, CHECK_ORIG_SIZES))
f984d4fc 4715 {
43b4a21f 4716 save_restore_orig_size (root, RESTORE_ORIG_SIZES);
f984d4fc
GM
4717 adjust_glyphs (f);
4718 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
4719 windows_or_buffers_changed = 1;
4720 }
949cf20f 4721 else if (XFASTINT (w->total_lines) > 1)
86c8e823 4722 {
0130fe1a
GM
4723 /* Distribute the additional lines of the mini-window
4724 among the other windows. */
86c8e823
GM
4725 Lisp_Object window;
4726 XSETWINDOW (window, w);
56ebfae2 4727 enlarge_window (window, 1 - XFASTINT (w->total_lines), 0);
86c8e823 4728 }
f984d4fc
GM
4729}
4730
4731
4732\f
5500c422
GM
4733/* Mark window cursors off for all windows in the window tree rooted
4734 at W by setting their phys_cursor_on_p flag to zero. Called from
4735 xterm.c, e.g. when a frame is cleared and thereby all cursors on
4736 the frame are cleared. */
4737
4738void
4739mark_window_cursors_off (w)
4740 struct window *w;
4741{
4742 while (w)
4743 {
4744 if (!NILP (w->hchild))
4745 mark_window_cursors_off (XWINDOW (w->hchild));
4746 else if (!NILP (w->vchild))
4747 mark_window_cursors_off (XWINDOW (w->vchild));
4748 else
4749 w->phys_cursor_on_p = 0;
4750
4751 w = NILP (w->next) ? 0 : XWINDOW (w->next);
4752 }
4753}
4754
4755
e9c195b1 4756/* Return number of lines of text (not counting mode lines) in W. */
7ab12479
JB
4757
4758int
4759window_internal_height (w)
4760 struct window *w;
4761{
949cf20f 4762 int ht = XFASTINT (w->total_lines);
7ab12479 4763
e9c195b1
GM
4764 if (!MINI_WINDOW_P (w))
4765 {
4766 if (!NILP (w->parent)
4767 || !NILP (w->vchild)
4768 || !NILP (w->hchild)
4769 || !NILP (w->next)
4770 || !NILP (w->prev)
4771 || WINDOW_WANTS_MODELINE_P (w))
4772 --ht;
7ab12479 4773
e9c195b1
GM
4774 if (WINDOW_WANTS_HEADER_LINE_P (w))
4775 --ht;
4776 }
7ab12479
JB
4777
4778 return ht;
4779}
4780
535e0b8e
JB
4781
4782/* Return the number of columns in W.
a3c87d4e 4783 Don't count columns occupied by scroll bars or the vertical bar
535e0b8e 4784 separating W from the sibling to its right. */
5500c422 4785
535e0b8e 4786int
949cf20f 4787window_box_text_cols (w)
535e0b8e
JB
4788 struct window *w;
4789{
5500c422 4790 struct frame *f = XFRAME (WINDOW_FRAME (w));
949cf20f 4791 int width = XINT (w->total_cols);
535e0b8e 4792
949cf20f 4793 if (WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
5500c422 4794 /* Scroll bars occupy a few columns. */
949cf20f
KS
4795 width -= WINDOW_CONFIG_SCROLL_BAR_COLS (w);
4796 else if (!FRAME_WINDOW_P (f)
4797 && !WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
5500c422
GM
4798 /* The column of `|' characters separating side-by-side windows
4799 occupies one column only. */
4800 width -= 1;
4801
5500c422 4802 if (FRAME_WINDOW_P (f))
949cf20f
KS
4803 /* On window-systems, fringes and display margins cannot be
4804 used for normal text. */
4805 width -= (WINDOW_FRINGE_COLS (w)
4806 + WINDOW_LEFT_MARGIN_COLS (w)
4807 + WINDOW_RIGHT_MARGIN_COLS (w));
111e5992
RS
4808
4809 return width;
535e0b8e
JB
4810}
4811
5500c422
GM
4812\f
4813/************************************************************************
4814 Window Scrolling
4815 ***********************************************************************/
535e0b8e 4816
5500c422 4817/* Scroll contents of window WINDOW up. If WHOLE is non-zero, scroll
d4e7cf01 4818 N screen-fulls, which is defined as the height of the window minus
5500c422
GM
4819 next_screen_context_lines. If WHOLE is zero, scroll up N lines
4820 instead. Negative values of N mean scroll down. NOERROR non-zero
4821 means don't signal an error if we try to move over BEGV or ZV,
4822 respectively. */
7ab12479 4823
101d1605
RS
4824static void
4825window_scroll (window, n, whole, noerror)
7ab12479
JB
4826 Lisp_Object window;
4827 int n;
101d1605 4828 int whole;
f8026fd8 4829 int noerror;
5500c422 4830{
cba59f77
RS
4831 immediate_quit = 1;
4832
5500c422
GM
4833 /* If we must, use the pixel-based version which is much slower than
4834 the line-based one but can handle varying line heights. */
4835 if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
4836 window_scroll_pixel_based (window, n, whole, noerror);
4837 else
4838 window_scroll_line_based (window, n, whole, noerror);
cba59f77
RS
4839
4840 immediate_quit = 0;
5500c422
GM
4841}
4842
4843
4844/* Implementation of window_scroll that works based on pixel line
4845 heights. See the comment of window_scroll for parameter
4846 descriptions. */
4847
4848static void
4849window_scroll_pixel_based (window, n, whole, noerror)
4850 Lisp_Object window;
4851 int n;
4852 int whole;
4853 int noerror;
4854{
4855 struct it it;
4856 struct window *w = XWINDOW (window);
4857 struct text_pos start;
5500c422 4858 int this_scroll_margin;
9d14503e 4859 /* True if we fiddled the window vscroll field without really scrolling. */
5cdb3cf3 4860 int vscrolled = 0;
5a857365 4861 int x, y, rtop, rbot, rowh, vpos;
5500c422
GM
4862
4863 SET_TEXT_POS_FROM_MARKER (start, w->start);
177c0ea7 4864
5500c422 4865 /* If PT is not visible in WINDOW, move back one half of
288d4e06
GM
4866 the screen. Allow PT to be partially visible, otherwise
4867 something like (scroll-down 1) with PT in the line before
4868 the partially visible one would recenter. */
5a857365
KS
4869
4870 if (!pos_visible_p (w, PT, &x, &y, &rtop, &rbot, &rowh, &vpos))
5500c422
GM
4871 {
4872 /* Move backward half the height of the window. Performance note:
4873 vmotion used here is about 10% faster, but would give wrong
4874 results for variable height lines. */
4875 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
4876 it.current_y = it.last_visible_y;
f204989e 4877 move_it_vertically_backward (&it, window_box_height (w) / 2);
177c0ea7 4878
5500c422
GM
4879 /* The function move_iterator_vertically may move over more than
4880 the specified y-distance. If it->w is small, e.g. a
4881 mini-buffer window, we may end up in front of the window's
4882 display area. This is the case when Start displaying at the
4883 start of the line containing PT in this case. */
4884 if (it.current_y <= 0)
4885 {
4886 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
f204989e 4887 move_it_vertically_backward (&it, 0);
5500c422
GM
4888 it.current_y = 0;
4889 }
4890
4891 start = it.current.pos;
4892 }
e56263e5
KS
4893 else if (auto_window_vscroll_p)
4894 {
5a857365 4895 if (rtop || rbot) /* partially visible */
e56263e5
KS
4896 {
4897 int px;
4898 int dy = WINDOW_FRAME_LINE_HEIGHT (w);
4899 if (whole)
e856c216
KS
4900 dy = max ((window_box_height (w)
4901 - next_screen_context_lines * dy),
4902 dy);
e56263e5
KS
4903 dy *= n;
4904
5a857365 4905 if (n < 0)
e56263e5 4906 {
5a857365
KS
4907 /* Only vscroll backwards if already vscrolled forwards. */
4908 if (w->vscroll < 0 && rtop > 0)
4909 {
4910 px = max (0, -w->vscroll - min (rtop, -dy));
4911 Fset_window_vscroll (window, make_number (px), Qt);
4912 return;
4913 }
e56263e5 4914 }
5a857365 4915 if (n > 0)
e56263e5 4916 {
5a857365
KS
4917 /* Do vscroll if already vscrolled or only display line. */
4918 if (rbot > 0 && (w->vscroll < 0 || vpos == 0))
4919 {
4920 px = max (0, -w->vscroll + min (rbot, dy));
4921 Fset_window_vscroll (window, make_number (px), Qt);
4922 return;
4923 }
4924
4925 /* Maybe modify window start instead of scrolling. */
4926 if (rbot > 0 || w->vscroll < 0)
4927 {
4928 int spos;
4929
4930 Fset_window_vscroll (window, make_number (0), Qt);
4931 /* If there are other text lines above the current row,
4932 move window start to current row. Else to next row. */
4933 if (rbot > 0)
4934 spos = XINT (Fline_beginning_position (Qnil));
4935 else
4936 spos = min (XINT (Fline_end_position (Qnil)) + 1, ZV);
4937 set_marker_restricted (w->start, make_number (spos),
4938 w->buffer);
4939 w->start_at_line_beg = Qt;
4940 w->update_mode_line = Qt;
4941 XSETFASTINT (w->last_modified, 0);
4942 XSETFASTINT (w->last_overlay_modified, 0);
4943 /* Set force_start so that redisplay_window will run the
4944 window-scroll-functions. */
4945 w->force_start = Qt;
4946 return;
4947 }
e56263e5
KS
4948 }
4949 }
5a857365 4950 /* Cancel previous vscroll. */
e56263e5
KS
4951 Fset_window_vscroll (window, make_number (0), Qt);
4952 }
5500c422 4953
d0c38d63 4954 /* If scroll_preserve_screen_position is non-nil, we try to set
5500c422
GM
4955 point in the same window line as it is now, so get that line. */
4956 if (!NILP (Vscroll_preserve_screen_position))
4957 {
c525d842
CY
4958 /* We preserve the goal pixel coordinate across consecutive
4959 calls to scroll-up or scroll-down. This avoids the
4960 possibility of point becoming "stuck" on a tall line when
4961 scrolling by one line. */
66fe93d1 4962 if (window_scroll_pixel_based_preserve_y < 0
7d619454
SM
4963 || (!EQ (current_kboard->Vlast_command, Qscroll_up)
4964 && !EQ (current_kboard->Vlast_command, Qscroll_down)))
c525d842
CY
4965 {
4966 start_display (&it, w, start);
4967 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
66fe93d1 4968 window_scroll_pixel_based_preserve_y = it.current_y;
c876b227 4969 window_scroll_pixel_based_preserve_x = it.current_x;
c525d842 4970 }
5500c422
GM
4971 }
4972 else
c876b227
SM
4973 window_scroll_pixel_based_preserve_y
4974 = window_scroll_pixel_based_preserve_x = -1;
5500c422
GM
4975
4976 /* Move iterator it from start the specified distance forward or
4977 backward. The result is the new window start. */
4978 start_display (&it, w, start);
4979 if (whole)
4980 {
e856c216
KS
4981 int start_pos = IT_CHARPOS (it);
4982 int dy = WINDOW_FRAME_LINE_HEIGHT (w);
4983 dy = max ((window_box_height (w)
4984 - next_screen_context_lines * dy),
4985 dy) * n;
d72340d4
GM
4986
4987 /* Note that move_it_vertically always moves the iterator to the
4988 start of a line. So, if the last line doesn't have a newline,
4989 we would end up at the start of the line ending at ZV. */
4990 if (dy <= 0)
e856c216
KS
4991 {
4992 move_it_vertically_backward (&it, -dy);
5a857365 4993 /* Ensure we actually do move, e.g. in case we are currently
e856c216
KS
4994 looking at an image that is taller that the window height. */
4995 while (start_pos == IT_CHARPOS (it)
4996 && start_pos > BEGV)
4997 move_it_by_lines (&it, -1, 1);
4998 }
d72340d4 4999 else if (dy > 0)
bed83ee4 5000 {
bed83ee4
KS
5001 move_it_to (&it, ZV, -1, it.current_y + dy, -1,
5002 MOVE_TO_POS | MOVE_TO_Y);
5a857365 5003 /* Ensure we actually do move, e.g. in case we are currently
bed83ee4
KS
5004 looking at an image that is taller that the window height. */
5005 while (start_pos == IT_CHARPOS (it)
5006 && start_pos < ZV)
5007 move_it_by_lines (&it, 1, 1);
5008 }
5500c422
GM
5009 }
5010 else
5011 move_it_by_lines (&it, n, 1);
5012
96ae58c8
RS
5013 /* We failed if we find ZV is already on the screen (scrolling up,
5014 means there's nothing past the end), or if we can't start any
5015 earlier (scrolling down, means there's nothing past the top). */
5500c422 5016 if ((n > 0 && IT_CHARPOS (it) == ZV)
96ae58c8 5017 || (n < 0 && IT_CHARPOS (it) == CHARPOS (start)))
5500c422 5018 {
5cdb3cf3
MB
5019 if (IT_CHARPOS (it) == ZV)
5020 {
07ce8b53
RS
5021 if (it.current_y < it.last_visible_y
5022 && (it.current_y + it.max_ascent + it.max_descent
3f489dc7 5023 > it.last_visible_y))
a74eca50
GM
5024 {
5025 /* The last line was only partially visible, make it fully
5026 visible. */
5027 w->vscroll = (it.last_visible_y
5028 - it.current_y + it.max_ascent + it.max_descent);
5029 adjust_glyphs (it.f);
5030 }
5cdb3cf3
MB
5031 else if (noerror)
5032 return;
cf402f3f 5033 else if (n < 0) /* could happen with empty buffers */
ba96a5cf 5034 xsignal0 (Qbeginning_of_buffer);
5cdb3cf3 5035 else
ba96a5cf 5036 xsignal0 (Qend_of_buffer);
5cdb3cf3 5037 }
5500c422 5038 else
5cdb3cf3
MB
5039 {
5040 if (w->vscroll != 0)
5041 /* The first line was only partially visible, make it fully
5042 visible. */
5043 w->vscroll = 0;
5044 else if (noerror)
5045 return;
5046 else
ba96a5cf 5047 xsignal0 (Qbeginning_of_buffer);
5cdb3cf3
MB
5048 }
5049
5050 /* If control gets here, then we vscrolled. */
5051
5052 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
5053
5054 /* Don't try to change the window start below. */
5055 vscrolled = 1;
5500c422
GM
5056 }
5057
5cdb3cf3
MB
5058 if (! vscrolled)
5059 {
dad67609
RS
5060 int pos = IT_CHARPOS (it);
5061 int bytepos;
e68def1e
AS
5062
5063 /* If in the middle of a multi-glyph character move forward to
5064 the next character. */
5065 if (in_display_vector_p (&it))
5066 {
5067 ++pos;
5068 move_it_to (&it, pos, -1, -1, -1, MOVE_TO_POS);
5069 }
5070
5cdb3cf3 5071 /* Set the window start, and set up the window for redisplay. */
dad67609 5072 set_marker_restricted (w->start, make_number (pos),
5cdb3cf3 5073 w->buffer);
dad67609
RS
5074 bytepos = XMARKER (w->start)->bytepos;
5075 w->start_at_line_beg = ((pos == BEGV || FETCH_BYTE (bytepos - 1) == '\n')
5076 ? Qt : Qnil);
5cdb3cf3
MB
5077 w->update_mode_line = Qt;
5078 XSETFASTINT (w->last_modified, 0);
5079 XSETFASTINT (w->last_overlay_modified, 0);
5080 /* Set force_start so that redisplay_window will run the
5081 window-scroll-functions. */
5082 w->force_start = Qt;
5083 }
177c0ea7 5084
dc297565
RS
5085 /* The rest of this function uses current_y in a nonstandard way,
5086 not including the height of the header line if any. */
5500c422 5087 it.current_y = it.vpos = 0;
177c0ea7 5088
940f53e5
RS
5089 /* Move PT out of scroll margins.
5090 This code wants current_y to be zero at the window start position
5091 even if there is a header line. */
5092 this_scroll_margin = max (0, scroll_margin);
5093 this_scroll_margin = min (this_scroll_margin, XFASTINT (w->total_lines) / 4);
5094 this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
5095
5096 if (n > 0)
5500c422 5097 {
940f53e5
RS
5098 /* We moved the window start towards ZV, so PT may be now
5099 in the scroll margin at the top. */
5100 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
bdf4ec93
RS
5101 if (IT_CHARPOS (it) == PT && it.current_y >= this_scroll_margin
5102 && (NILP (Vscroll_preserve_screen_position)
5103 || EQ (Vscroll_preserve_screen_position, Qt)))
940f53e5
RS
5104 /* We found PT at a legitimate height. Leave it alone. */
5105 ;
66fe93d1 5106 else if (window_scroll_pixel_based_preserve_y >= 0)
940f53e5 5107 {
fa3c3426
RS
5108 /* If we have a header line, take account of it.
5109 This is necessary because we set it.current_y to 0, above. */
c876b227
SM
5110 move_it_to (&it, -1,
5111 window_scroll_pixel_based_preserve_x,
66fe93d1
LT
5112 window_scroll_pixel_based_preserve_y
5113 - (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0 ),
c876b227 5114 -1, MOVE_TO_Y | MOVE_TO_X);
940f53e5
RS
5115 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5116 }
5117 else
5500c422 5118 {
5500c422 5119 while (it.current_y < this_scroll_margin)
e9b2c961
RS
5120 {
5121 int prev = it.current_y;
5122 move_it_by_lines (&it, 1, 1);
5123 if (prev == it.current_y)
5124 break;
5125 }
5500c422
GM
5126 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5127 }
940f53e5
RS
5128 }
5129 else if (n < 0)
5130 {
5131 int charpos, bytepos;
aed328bf 5132 int partial_p;
940f53e5 5133
66fe93d1
LT
5134 /* Save our position, for the
5135 window_scroll_pixel_based_preserve_y case. */
940f53e5
RS
5136 charpos = IT_CHARPOS (it);
5137 bytepos = IT_BYTEPOS (it);
5cdb3cf3 5138
940f53e5
RS
5139 /* We moved the window start towards BEGV, so PT may be now
5140 in the scroll margin at the bottom. */
5141 move_it_to (&it, PT, -1,
7ad53239
RS
5142 (it.last_visible_y - CURRENT_HEADER_LINE_HEIGHT (w)
5143 - this_scroll_margin - 1),
5144 -1,
940f53e5
RS
5145 MOVE_TO_POS | MOVE_TO_Y);
5146
aed328bf
KS
5147 /* Save our position, in case it's correct. */
5148 charpos = IT_CHARPOS (it);
5149 bytepos = IT_BYTEPOS (it);
5150
5151 /* See if point is on a partially visible line at the end. */
5152 if (it.what == IT_EOB)
5153 partial_p = it.current_y + it.ascent + it.descent > it.last_visible_y;
5154 else
5155 {
5156 move_it_by_lines (&it, 1, 1);
5157 partial_p = it.current_y > it.last_visible_y;
5158 }
5159
bdf4ec93
RS
5160 if (charpos == PT && !partial_p
5161 && (NILP (Vscroll_preserve_screen_position)
5162 || EQ (Vscroll_preserve_screen_position, Qt)))
940f53e5
RS
5163 /* We found PT before we found the display margin, so PT is ok. */
5164 ;
66fe93d1 5165 else if (window_scroll_pixel_based_preserve_y >= 0)
940f53e5
RS
5166 {
5167 SET_TEXT_POS_FROM_MARKER (start, w->start);
5168 start_display (&it, w, start);
c525d842
CY
5169 /* It would be wrong to subtract CURRENT_HEADER_LINE_HEIGHT
5170 here because we called start_display again and did not
5171 alter it.current_y this time. */
c876b227
SM
5172 move_it_to (&it, -1, window_scroll_pixel_based_preserve_x,
5173 window_scroll_pixel_based_preserve_y, -1,
5174 MOVE_TO_Y | MOVE_TO_X);
940f53e5
RS
5175 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5176 }
5177 else
5178 {
aed328bf 5179 if (partial_p)
5cdb3cf3
MB
5180 /* The last line was only partially visible, so back up two
5181 lines to make sure we're on a fully visible line. */
5182 {
5183 move_it_by_lines (&it, -2, 0);
5184 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5185 }
5186 else
5187 /* No, the position we saved is OK, so use it. */
5188 SET_PT_BOTH (charpos, bytepos);
5500c422
GM
5189 }
5190 }
5191}
5192
5193
5194/* Implementation of window_scroll that works based on screen lines.
5195 See the comment of window_scroll for parameter descriptions. */
5196
5197static void
5198window_scroll_line_based (window, n, whole, noerror)
5199 Lisp_Object window;
5200 int n;
5201 int whole;
5202 int noerror;
7ab12479
JB
5203{
5204 register struct window *w = XWINDOW (window);
5500c422 5205 register int opoint = PT, opoint_byte = PT_BYTE;
b73ea88e 5206 register int pos, pos_byte;
7ab12479
JB
5207 register int ht = window_internal_height (w);
5208 register Lisp_Object tem;
5209 int lose;
5500c422 5210 Lisp_Object bolp;
345d45b2 5211 int startpos;
c876b227 5212 Lisp_Object original_pos = Qnil;
101d1605 5213
d4e7cf01
GM
5214 /* If scrolling screen-fulls, compute the number of lines to
5215 scroll from the window's height. */
5216 if (whole)
5217 n *= max (1, ht - next_screen_context_lines);
5218
101d1605
RS
5219 startpos = marker_position (w->start);
5220
c876b227
SM
5221 if (!NILP (Vscroll_preserve_screen_position))
5222 {
5223 if (window_scroll_preserve_vpos <= 0
5224 || (!EQ (current_kboard->Vlast_command, Qscroll_up)
5225 && !EQ (current_kboard->Vlast_command, Qscroll_down)))
5226 {
5227 struct position posit
5228 = *compute_motion (startpos, 0, 0, 0,
5229 PT, ht, 0,
5230 -1, XINT (w->hscroll),
5231 0, w);
5232 window_scroll_preserve_vpos = posit.vpos;
5233 window_scroll_preserve_hpos = posit.hpos + XINT (w->hscroll);
5234 }
5235
5236 original_pos = Fcons (make_number (window_scroll_preserve_hpos),
5237 make_number (window_scroll_preserve_vpos));
5238 }
0a1f771a 5239
d834a2e9 5240 XSETFASTINT (tem, PT);
6ffdb539 5241 tem = Fpos_visible_in_window_p (tem, window, Qnil);
7ab12479 5242
265a9e55 5243 if (NILP (tem))
7ab12479 5244 {
cd2be1dd 5245 Fvertical_motion (make_number (- (ht / 2)), window);
345d45b2 5246 startpos = PT;
7ab12479
JB
5247 }
5248
345d45b2 5249 SET_PT (startpos);
5ce7b543 5250 lose = n < 0 && PT == BEGV;
540b6aa0 5251 Fvertical_motion (make_number (n), window);
5ce7b543 5252 pos = PT;
b73ea88e 5253 pos_byte = PT_BYTE;
7ab12479 5254 bolp = Fbolp ();
b73ea88e 5255 SET_PT_BOTH (opoint, opoint_byte);
7ab12479
JB
5256
5257 if (lose)
f8026fd8
JB
5258 {
5259 if (noerror)
5260 return;
5261 else
ba96a5cf 5262 xsignal0 (Qbeginning_of_buffer);
f8026fd8 5263 }
7ab12479
JB
5264
5265 if (pos < ZV)
7ab12479 5266 {
0c7da84e
RS
5267 int this_scroll_margin = scroll_margin;
5268
5269 /* Don't use a scroll margin that is negative or too large. */
5270 if (this_scroll_margin < 0)
5271 this_scroll_margin = 0;
5272
949cf20f
KS
5273 if (XINT (w->total_lines) < 4 * scroll_margin)
5274 this_scroll_margin = XINT (w->total_lines) / 4;
0c7da84e 5275
b73ea88e 5276 set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
7ab12479
JB
5277 w->start_at_line_beg = bolp;
5278 w->update_mode_line = Qt;
d834a2e9 5279 XSETFASTINT (w->last_modified, 0);
3cd21523 5280 XSETFASTINT (w->last_overlay_modified, 0);
345d45b2
RS
5281 /* Set force_start so that redisplay_window will run
5282 the window-scroll-functions. */
5283 w->force_start = Qt;
0c7da84e 5284
bdf4ec93
RS
5285 if (!NILP (Vscroll_preserve_screen_position)
5286 && (whole || !EQ (Vscroll_preserve_screen_position, Qt)))
0c7da84e 5287 {
b73ea88e 5288 SET_PT_BOTH (pos, pos_byte);
c876b227 5289 Fvertical_motion (original_pos, window);
0c7da84e 5290 }
101d1605
RS
5291 /* If we scrolled forward, put point enough lines down
5292 that it is outside the scroll margin. */
5293 else if (n > 0)
0c7da84e 5294 {
101d1605
RS
5295 int top_margin;
5296
5297 if (this_scroll_margin > 0)
5298 {
b73ea88e 5299 SET_PT_BOTH (pos, pos_byte);
101d1605
RS
5300 Fvertical_motion (make_number (this_scroll_margin), window);
5301 top_margin = PT;
5302 }
5303 else
5304 top_margin = pos;
5305
5306 if (top_margin <= opoint)
b73ea88e 5307 SET_PT_BOTH (opoint, opoint_byte);
5500c422 5308 else if (!NILP (Vscroll_preserve_screen_position))
101d1605 5309 {
b73ea88e 5310 SET_PT_BOTH (pos, pos_byte);
c876b227 5311 Fvertical_motion (original_pos, window);
101d1605 5312 }
9317a85d 5313 else
335406fc 5314 SET_PT (top_margin);
0c7da84e 5315 }
101d1605 5316 else if (n < 0)
7ab12479 5317 {
101d1605
RS
5318 int bottom_margin;
5319
0c7da84e
RS
5320 /* If we scrolled backward, put point near the end of the window
5321 but not within the scroll margin. */
b73ea88e 5322 SET_PT_BOTH (pos, pos_byte);
0c7da84e 5323 tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
101d1605
RS
5324 if (XFASTINT (tem) == ht - this_scroll_margin)
5325 bottom_margin = PT;
5326 else
5327 bottom_margin = PT + 1;
5328
5329 if (bottom_margin > opoint)
b73ea88e 5330 SET_PT_BOTH (opoint, opoint_byte);
7ab12479 5331 else
101d1605 5332 {
5500c422 5333 if (!NILP (Vscroll_preserve_screen_position))
9317a85d 5334 {
b73ea88e 5335 SET_PT_BOTH (pos, pos_byte);
c876b227 5336 Fvertical_motion (original_pos, window);
9317a85d
RS
5337 }
5338 else
5339 Fvertical_motion (make_number (-1), window);
101d1605 5340 }
7ab12479
JB
5341 }
5342 }
5343 else
f8026fd8
JB
5344 {
5345 if (noerror)
5346 return;
5347 else
ba96a5cf 5348 xsignal0 (Qend_of_buffer);
f8026fd8 5349 }
7ab12479 5350}
5500c422
GM
5351
5352
5353/* Scroll selected_window up or down. If N is nil, scroll a
5354 screen-full which is defined as the height of the window minus
5355 next_screen_context_lines. If N is the symbol `-', scroll.
5356 DIRECTION may be 1 meaning to scroll down, or -1 meaning to scroll
5357 up. This is the guts of Fscroll_up and Fscroll_down. */
7ab12479
JB
5358
5359static void
5360scroll_command (n, direction)
5500c422 5361 Lisp_Object n;
7ab12479
JB
5362 int direction;
5363{
331379bf 5364 int count = SPECPDL_INDEX ();
7ab12479 5365
1ea40aa2 5366 xassert (eabs (direction) == 1);
5500c422
GM
5367
5368 /* If selected window's buffer isn't current, make it current for
5369 the moment. But don't screw up if window_scroll gets an error. */
7ab12479 5370 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
95605e15
JB
5371 {
5372 record_unwind_protect (save_excursion_restore, save_excursion_save ());
5373 Fset_buffer (XWINDOW (selected_window)->buffer);
5500c422
GM
5374
5375 /* Make redisplay consider other windows than just selected_window. */
5376 ++windows_or_buffers_changed;
95605e15 5377 }
7ab12479 5378
265a9e55 5379 if (NILP (n))
d4e7cf01 5380 window_scroll (selected_window, direction, 1, 0);
7ab12479 5381 else if (EQ (n, Qminus))
d4e7cf01 5382 window_scroll (selected_window, -direction, 1, 0);
7ab12479
JB
5383 else
5384 {
5385 n = Fprefix_numeric_value (n);
101d1605 5386 window_scroll (selected_window, XINT (n) * direction, 0, 0);
7ab12479 5387 }
95605e15
JB
5388
5389 unbind_to (count, Qnil);
7ab12479
JB
5390}
5391
e0965597 5392DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "^P",
12bb3111 5393 doc: /* Scroll text of selected window upward ARG lines.
a0a37a6f 5394If ARG is omitted or nil, scroll upward by a near full screen.
fdb82f93
PJ
5395A near full screen is `next-screen-context-lines' less than a full screen.
5396Negative ARG means scroll downward.
5397If ARG is the atom `-', scroll downward by nearly full screen.
5398When calling from a program, supply as argument a number, nil, or `-'. */)
5399 (arg)
413430c5 5400 Lisp_Object arg;
7ab12479 5401{
413430c5 5402 scroll_command (arg, 1);
7ab12479
JB
5403 return Qnil;
5404}
5405
e0965597 5406DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "^P",
12bb3111 5407 doc: /* Scroll text of selected window down ARG lines.
a0a37a6f 5408If ARG is omitted or nil, scroll down by a near full screen.
fdb82f93
PJ
5409A near full screen is `next-screen-context-lines' less than a full screen.
5410Negative ARG means scroll upward.
5411If ARG is the atom `-', scroll upward by nearly full screen.
5412When calling from a program, supply as argument a number, nil, or `-'. */)
5413 (arg)
413430c5 5414 Lisp_Object arg;
7ab12479 5415{
413430c5 5416 scroll_command (arg, -1);
7ab12479
JB
5417 return Qnil;
5418}
ccd0664b
RS
5419\f
5420DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0,
fdb82f93 5421 doc: /* Return the other window for \"other window scroll\" commands.
fdb82f93 5422If `other-window-scroll-buffer' is non-nil, a window
a0a37a6f
LT
5423showing that buffer is used.
5424If in the minibuffer, `minibuffer-scroll-window' if non-nil
5425specifies the window. This takes precedence over
5426`other-window-scroll-buffer'. */)
fdb82f93 5427 ()
7ab12479 5428{
ccd0664b 5429 Lisp_Object window;
7ab12479
JB
5430
5431 if (MINI_WINDOW_P (XWINDOW (selected_window))
265a9e55 5432 && !NILP (Vminibuf_scroll_window))
7ab12479
JB
5433 window = Vminibuf_scroll_window;
5434 /* If buffer is specified, scroll that buffer. */
265a9e55 5435 else if (!NILP (Vother_window_scroll_buffer))
7ab12479
JB
5436 {
5437 window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
265a9e55 5438 if (NILP (window))
87478b52 5439 window = display_buffer (Vother_window_scroll_buffer, Qt, Qnil);
7ab12479
JB
5440 }
5441 else
dbc4e1c1
JB
5442 {
5443 /* Nothing specified; look for a neighboring window on the same
5444 frame. */
5445 window = Fnext_window (selected_window, Qnil, Qnil);
5446
5447 if (EQ (window, selected_window))
5448 /* That didn't get us anywhere; look for a window on another
5449 visible frame. */
5450 do
5451 window = Fnext_window (window, Qnil, Qt);
5452 while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
5453 && ! EQ (window, selected_window));
5454 }
5455
b7826503 5456 CHECK_LIVE_WINDOW (window);
7ab12479
JB
5457
5458 if (EQ (window, selected_window))
5459 error ("There is no other window");
5460
ccd0664b
RS
5461 return window;
5462}
5463
5464DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
fdb82f93
PJ
5465 doc: /* Scroll next window upward ARG lines; or near full screen if no ARG.
5466A near full screen is `next-screen-context-lines' less than a full screen.
5467The next window is the one below the current one; or the one at the top
5468if the current one is at the bottom. Negative ARG means scroll downward.
5469If ARG is the atom `-', scroll downward by nearly full screen.
5470When calling from a program, supply as argument a number, nil, or `-'.
5471
fdb82f93 5472If `other-window-scroll-buffer' is non-nil, scroll the window
a0a37a6f
LT
5473showing that buffer, popping the buffer up if necessary.
5474If in the minibuffer, `minibuffer-scroll-window' if non-nil
5475specifies the window to scroll. This takes precedence over
5476`other-window-scroll-buffer'. */)
fdb82f93 5477 (arg)
d4e7cf01 5478 Lisp_Object arg;
ccd0664b 5479{
d4e7cf01
GM
5480 Lisp_Object window;
5481 struct window *w;
331379bf 5482 int count = SPECPDL_INDEX ();
ccd0664b
RS
5483
5484 window = Fother_window_for_scrolling ();
7ab12479 5485 w = XWINDOW (window);
7ab12479
JB
5486
5487 /* Don't screw up if window_scroll gets an error. */
5488 record_unwind_protect (save_excursion_restore, save_excursion_save ());
5500c422 5489 ++windows_or_buffers_changed;
7ab12479
JB
5490
5491 Fset_buffer (w->buffer);
5492 SET_PT (marker_position (w->pointm));
5493
413430c5 5494 if (NILP (arg))
d4e7cf01 5495 window_scroll (window, 1, 1, 1);
413430c5 5496 else if (EQ (arg, Qminus))
d4e7cf01 5497 window_scroll (window, -1, 1, 1);
7ab12479
JB
5498 else
5499 {
413430c5
EN
5500 if (CONSP (arg))
5501 arg = Fcar (arg);
b7826503 5502 CHECK_NUMBER (arg);
101d1605 5503 window_scroll (window, XINT (arg), 0, 1);
7ab12479
JB
5504 }
5505
b73ea88e 5506 set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
f4e7b2c2 5507 unbind_to (count, Qnil);
7ab12479
JB
5508
5509 return Qnil;
5510}
5511\f
e0965597 5512DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 2, "^P\np",
fdb82f93 5513 doc: /* Scroll selected window display ARG columns left.
2fe41216
EZ
5514Default for ARG is window width minus 2.
5515Value is the total amount of leftward horizontal scrolling in
5516effect after the change.
23fe745a 5517If SET-MINIMUM is non-nil, the new scroll amount becomes the
dc297565 5518lower bound for automatic scrolling, i.e. automatic scrolling
2fe41216 5519will not scroll a window to a column less than the value returned
dc297565
RS
5520by this function. This happens in an interactive call. */)
5521 (arg, set_minimum)
5522 register Lisp_Object arg, set_minimum;
7ab12479 5523{
c67fa410
GM
5524 Lisp_Object result;
5525 int hscroll;
5526 struct window *w = XWINDOW (selected_window);
177c0ea7 5527
265a9e55 5528 if (NILP (arg))
949cf20f 5529 XSETFASTINT (arg, window_box_text_cols (w) - 2);
7ab12479
JB
5530 else
5531 arg = Fprefix_numeric_value (arg);
5532
c67fa410
GM
5533 hscroll = XINT (w->hscroll) + XINT (arg);
5534 result = Fset_window_hscroll (selected_window, make_number (hscroll));
5535
dc297565 5536 if (!NILP (set_minimum))
c67fa410
GM
5537 w->min_hscroll = w->hscroll;
5538
5539 return result;
7ab12479
JB
5540}
5541
e0965597 5542DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 2, "^P\np",
fdb82f93 5543 doc: /* Scroll selected window display ARG columns right.
2fe41216
EZ
5544Default for ARG is window width minus 2.
5545Value is the total amount of leftward horizontal scrolling in
5546effect after the change.
23fe745a 5547If SET-MINIMUM is non-nil, the new scroll amount becomes the
dc297565 5548lower bound for automatic scrolling, i.e. automatic scrolling
2fe41216 5549will not scroll a window to a column less than the value returned
dc297565
RS
5550by this function. This happens in an interactive call. */)
5551 (arg, set_minimum)
a93563fd 5552 register Lisp_Object arg, set_minimum;
7ab12479 5553{
c67fa410
GM
5554 Lisp_Object result;
5555 int hscroll;
5556 struct window *w = XWINDOW (selected_window);
177c0ea7 5557
265a9e55 5558 if (NILP (arg))
949cf20f 5559 XSETFASTINT (arg, window_box_text_cols (w) - 2);
7ab12479
JB
5560 else
5561 arg = Fprefix_numeric_value (arg);
5562
c67fa410
GM
5563 hscroll = XINT (w->hscroll) - XINT (arg);
5564 result = Fset_window_hscroll (selected_window, make_number (hscroll));
177c0ea7 5565
dc297565 5566 if (!NILP (set_minimum))
c67fa410
GM
5567 w->min_hscroll = w->hscroll;
5568
5569 return result;
7ab12479
JB
5570}
5571
fa832261
KS
5572DEFUN ("minibuffer-selected-window", Fminibuffer_selected_window, Sminibuffer_selected_window, 0, 0, 0,
5573 doc: /* Return the window which was selected when entering the minibuffer.
12bb3111 5574Returns nil, if selected window is not a minibuffer window. */)
fa832261
KS
5575 ()
5576{
5577 if (minibuf_level > 0
5578 && MINI_WINDOW_P (XWINDOW (selected_window))
fa832261
KS
5579 && WINDOW_LIVE_P (minibuf_selected_window))
5580 return minibuf_selected_window;
5581
5582 return Qnil;
5583}
5584
12c8b416
GM
5585/* Value is the number of lines actually displayed in window W,
5586 as opposed to its height. */
5587
5588static int
5589displayed_window_lines (w)
5590 struct window *w;
5591{
5592 struct it it;
5593 struct text_pos start;
5594 int height = window_box_height (w);
5595 struct buffer *old_buffer;
5596 int bottom_y;
5597
5598 if (XBUFFER (w->buffer) != current_buffer)
5599 {
5600 old_buffer = current_buffer;
5601 set_buffer_internal (XBUFFER (w->buffer));
5602 }
5603 else
5604 old_buffer = NULL;
5605
521b203e
GM
5606 /* In case W->start is out of the accessible range, do something
5607 reasonable. This happens in Info mode when Info-scroll-down
5608 calls (recenter -1) while W->start is 1. */
5609 if (XMARKER (w->start)->charpos < BEGV)
5610 SET_TEXT_POS (start, BEGV, BEGV_BYTE);
5611 else if (XMARKER (w->start)->charpos > ZV)
5612 SET_TEXT_POS (start, ZV, ZV_BYTE);
5613 else
5614 SET_TEXT_POS_FROM_MARKER (start, w->start);
5615
12c8b416
GM
5616 start_display (&it, w, start);
5617 move_it_vertically (&it, height);
c8bc6f65 5618 bottom_y = line_bottom_y (&it);
12c8b416 5619
1de65f51
RS
5620 /* rms: On a non-window display,
5621 the value of it.vpos at the bottom of the screen
5622 seems to be 1 larger than window_box_height (w).
5623 This kludge fixes a bug whereby (move-to-window-line -1)
5624 when ZV is on the last screen line
5625 moves to the previous screen line instead of the last one. */
5626 if (! FRAME_WINDOW_P (XFRAME (w->frame)))
5627 height++;
5628
12c8b416
GM
5629 /* Add in empty lines at the bottom of the window. */
5630 if (bottom_y < height)
5631 {
949cf20f 5632 int uy = FRAME_LINE_HEIGHT (it.f);
c8bc6f65 5633 it.vpos += (height - bottom_y + uy - 1) / uy;
12c8b416
GM
5634 }
5635
c8bc6f65
GM
5636 if (old_buffer)
5637 set_buffer_internal (old_buffer);
5638
12c8b416
GM
5639 return it.vpos;
5640}
5641
5642
7ab12479 5643DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
666e158e 5644 doc: /* Center point in selected window and maybe redisplay frame.
fdb82f93 5645With prefix argument ARG, recenter putting point on screen line ARG
12bb3111 5646relative to the selected window. If ARG is negative, it counts up from the
fdb82f93
PJ
5647bottom of the window. (ARG should be less than the height of the window.)
5648
666e158e
MB
5649If ARG is omitted or nil, then recenter with point on the middle line of
5650the selected window; if the variable `recenter-redisplay' is non-nil,
5651also erase the entire frame and redraw it (when `auto-resize-tool-bars'
5652is set to `grow-only', this resets the tool-bar's height to the minimum
5653height needed); if `recenter-redisplay' has the special value `tty',
5654then only tty frame are redrawn.
7d1d98ee 5655
fdb82f93
PJ
5656Just C-u as prefix means put point in the center of the window
5657and redisplay normally--don't erase and redraw the frame. */)
5658 (arg)
413430c5 5659 register Lisp_Object arg;
7ab12479 5660{
6df47b59 5661 struct window *w = XWINDOW (selected_window);
478292ed
RS
5662 struct buffer *buf = XBUFFER (w->buffer);
5663 struct buffer *obuf = current_buffer;
6df47b59
GM
5664 int center_p = 0;
5665 int charpos, bytepos;
f6b43440
RS
5666 int iarg;
5667 int this_scroll_margin;
7ab12479 5668
0fa5d25b
RS
5669 /* If redisplay is suppressed due to an error, try again. */
5670 obuf->display_error_modiff = 0;
5671
413430c5 5672 if (NILP (arg))
7ab12479 5673 {
666e158e
MB
5674 if (!NILP (Vrecenter_redisplay)
5675 && (!EQ (Vrecenter_redisplay, Qtty)
5676 || !NILP (Ftty_type (selected_frame))))
5677 {
5678 int i;
f02d6d5c 5679
666e158e
MB
5680 /* Invalidate pixel data calculated for all compositions. */
5681 for (i = 0; i < n_compositions; i++)
5682 composition_table[i]->font = NULL;
7ab12479 5683
666e158e
MB
5684 WINDOW_XFRAME (w)->minimize_tool_bar_window_p = 1;
5685
5686 Fredraw_frame (WINDOW_FRAME (w));
5687 SET_FRAME_GARBAGED (WINDOW_XFRAME (w));
5688 }
7d1d98ee 5689
6df47b59 5690 center_p = 1;
7ab12479 5691 }
413430c5 5692 else if (CONSP (arg)) /* Just C-u. */
6df47b59 5693 center_p = 1;
7ab12479
JB
5694 else
5695 {
413430c5 5696 arg = Fprefix_numeric_value (arg);
b7826503 5697 CHECK_NUMBER (arg);
ae12ecd7 5698 iarg = XINT (arg);
7ab12479
JB
5699 }
5700
478292ed 5701 set_buffer_internal (buf);
7ab12479 5702
f6b43440
RS
5703 /* Do this after making BUF current
5704 in case scroll_margin is buffer-local. */
5705 this_scroll_margin = max (0, scroll_margin);
5706 this_scroll_margin = min (this_scroll_margin,
5707 XFASTINT (w->total_lines) / 4);
5708
521b203e 5709 /* Handle centering on a graphical frame specially. Such frames can
6df47b59
GM
5710 have variable-height lines and centering point on the basis of
5711 line counts would lead to strange effects. */
521b203e 5712 if (FRAME_WINDOW_P (XFRAME (w->frame)))
6df47b59 5713 {
6df47b59
GM
5714 if (center_p)
5715 {
521b203e
GM
5716 struct it it;
5717 struct text_pos pt;
177c0ea7 5718
521b203e
GM
5719 SET_TEXT_POS (pt, PT, PT_BYTE);
5720 start_display (&it, w, pt);
f204989e 5721 move_it_vertically_backward (&it, window_box_height (w) / 2);
521b203e
GM
5722 charpos = IT_CHARPOS (it);
5723 bytepos = IT_BYTEPOS (it);
6df47b59 5724 }
f6b43440 5725 else if (iarg < 0)
6df47b59 5726 {
521b203e
GM
5727 struct it it;
5728 struct text_pos pt;
f6b43440 5729 int nlines = -iarg;
f204989e
KS
5730 int extra_line_spacing;
5731 int h = window_box_height (w);
177c0ea7 5732
f6b43440
RS
5733 iarg = - max (-iarg, this_scroll_margin);
5734
521b203e
GM
5735 SET_TEXT_POS (pt, PT, PT_BYTE);
5736 start_display (&it, w, pt);
f204989e
KS
5737
5738 /* Be sure we have the exact height of the full line containing PT. */
5739 move_it_by_lines (&it, 0, 1);
521b203e 5740
d466fa4d 5741 /* The amount of pixels we have to move back is the window
521b203e
GM
5742 height minus what's displayed in the line containing PT,
5743 and the lines below. */
f204989e
KS
5744 it.current_y = 0;
5745 it.vpos = 0;
d466fa4d
GM
5746 move_it_by_lines (&it, nlines, 1);
5747
f204989e
KS
5748 if (it.vpos == nlines)
5749 h -= it.current_y;
5750 else
5751 {
5752 /* Last line has no newline */
5753 h -= line_bottom_y (&it);
5754 it.vpos++;
5755 }
5756
5757 /* Don't reserve space for extra line spacing of last line. */
5758 extra_line_spacing = it.max_extra_line_spacing;
d466fa4d
GM
5759
5760 /* If we can't move down NLINES lines because we hit
5761 the end of the buffer, count in some empty lines. */
5762 if (it.vpos < nlines)
f204989e
KS
5763 {
5764 nlines -= it.vpos;
5765 extra_line_spacing = it.extra_line_spacing;
5766 h -= nlines * (FRAME_LINE_HEIGHT (it.f) + extra_line_spacing);
5767 }
5768 if (h <= 0)
5769 return Qnil;
201c831a 5770
f204989e 5771 /* Now find the new top line (starting position) of the window. */
521b203e 5772 start_display (&it, w, pt);
f204989e
KS
5773 it.current_y = 0;
5774 move_it_vertically_backward (&it, h);
5775
5776 /* If extra line spacing is present, we may move too far
5777 back. This causes the last line to be only partially
5778 visible (which triggers redisplay to recenter that line
5779 in the middle), so move forward.
5780 But ignore extra line spacing on last line, as it is not
5781 considered to be part of the visible height of the line.
5782 */
5783 h += extra_line_spacing;
5784 while (-it.current_y > h)
5785 move_it_by_lines (&it, 1, 1);
5786
521b203e
GM
5787 charpos = IT_CHARPOS (it);
5788 bytepos = IT_BYTEPOS (it);
6df47b59 5789 }
521b203e
GM
5790 else
5791 {
5792 struct position pos;
f6b43440 5793
f6b43440
RS
5794 iarg = max (iarg, this_scroll_margin);
5795
5796 pos = *vmotion (PT, -iarg, w);
521b203e
GM
5797 charpos = pos.bufpos;
5798 bytepos = pos.bytepos;
5799 }
5800 }
5801 else
5802 {
5803 struct position pos;
5804 int ht = window_internal_height (w);
5805
5806 if (center_p)
a4429c5b 5807 iarg = ht / 2;
f567c488
KS
5808 else if (iarg < 0)
5809 iarg += ht;
f6b43440
RS
5810
5811 /* Don't let it get into the margin at either top or bottom. */
5812 iarg = max (iarg, this_scroll_margin);
5813 iarg = min (iarg, ht - this_scroll_margin - 1);
177c0ea7 5814
f6b43440 5815 pos = *vmotion (PT, - iarg, w);
6df47b59
GM
5816 charpos = pos.bufpos;
5817 bytepos = pos.bytepos;
5818 }
5819
5820 /* Set the new window start. */
5821 set_marker_both (w->start, w->buffer, charpos, bytepos);
2f3cad6c 5822 w->window_end_valid = Qnil;
177c0ea7 5823
95605b1b
RS
5824 w->optional_new_start = Qt;
5825
6df47b59
GM
5826 if (bytepos == BEGV_BYTE || FETCH_BYTE (bytepos - 1) == '\n')
5827 w->start_at_line_beg = Qt;
5828 else
5829 w->start_at_line_beg = Qnil;
177c0ea7 5830
478292ed 5831 set_buffer_internal (obuf);
7ab12479
JB
5832 return Qnil;
5833}
b7617575
GM
5834
5835
81fe0836 5836DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height,
fdb82f93
PJ
5837 0, 1, 0,
5838 doc: /* Return the height in lines of the text display area of WINDOW.
c85322d0 5839WINDOW defaults to the selected window.
8fef9de1 5840
f039b2d2
CY
5841The return value does not include the mode line, any header line, nor
5842any partial-height lines in the text display area. */)
fdb82f93 5843 (window)
81fe0836
MB
5844 Lisp_Object window;
5845{
5846 struct window *w = decode_window (window);
5847 int pixel_height = window_box_height (w);
949cf20f 5848 int line_height = pixel_height / FRAME_LINE_HEIGHT (XFRAME (w->frame));
81fe0836
MB
5849 return make_number (line_height);
5850}
5851
5852
7ab12479
JB
5853\f
5854DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
fdb82f93
PJ
5855 1, 1, "P",
5856 doc: /* Position point relative to window.
5857With no argument, position point at center of window.
5858An argument specifies vertical position within the window;
5859zero means top of window, negative means relative to bottom of window. */)
5860 (arg)
b7617575 5861 Lisp_Object arg;
7ab12479 5862{
b7617575
GM
5863 struct window *w = XWINDOW (selected_window);
5864 int lines, start;
540b6aa0 5865 Lisp_Object window;
f6b43440
RS
5866#if 0
5867 int this_scroll_margin;
5868#endif
7ab12479 5869
794b75c7
SM
5870 if (!(BUFFERP (w->buffer)
5871 && XBUFFER (w->buffer) == current_buffer))
5872 /* This test is needed to make sure PT/PT_BYTE make sense in w->buffer
5873 when passed below to set_marker_both. */
5874 error ("move-to-window-line called from unrelated buffer");
6dc1d2d3 5875
b7617575 5876 window = selected_window;
7ab12479
JB
5877 start = marker_position (w->start);
5878 if (start < BEGV || start > ZV)
5879 {
b7617575 5880 int height = window_internal_height (w);
cd2be1dd 5881 Fvertical_motion (make_number (- (height / 2)), window);
b73ea88e 5882 set_marker_both (w->start, w->buffer, PT, PT_BYTE);
7ab12479
JB
5883 w->start_at_line_beg = Fbolp ();
5884 w->force_start = Qt;
5885 }
5886 else
b73ea88e 5887 Fgoto_char (w->start);
7ab12479 5888
b7617575 5889 lines = displayed_window_lines (w);
f6b43440
RS
5890
5891#if 0
5892 this_scroll_margin = max (0, scroll_margin);
5893 this_scroll_margin = min (this_scroll_margin, lines / 4);
5894#endif
5895
b7617575
GM
5896 if (NILP (arg))
5897 XSETFASTINT (arg, lines / 2);
5898 else
5899 {
f6b43440
RS
5900 int iarg = XINT (Fprefix_numeric_value (arg));
5901
5902 if (iarg < 0)
5903 iarg = iarg + lines;
5904
5905#if 0 /* This code would prevent move-to-window-line from moving point
5906 to a place inside the scroll margins (which would cause the
5907 next redisplay to scroll). I wrote this code, but then concluded
5908 it is probably better not to install it. However, it is here
5909 inside #if 0 so as not to lose it. -- rms. */
5910
5911 /* Don't let it get into the margin at either top or bottom. */
5912 iarg = max (iarg, this_scroll_margin);
5913 iarg = min (iarg, lines - this_scroll_margin - 1);
5914#endif
5915
5916 arg = make_number (iarg);
b7617575
GM
5917 }
5918
c8bc6f65 5919 /* Skip past a partially visible first line. */
163784df 5920 if (w->vscroll)
163784df
MB
5921 XSETINT (arg, XINT (arg) + 1);
5922
540b6aa0 5923 return Fvertical_motion (arg, window);
7ab12479 5924}
5500c422
GM
5925
5926
7ab12479 5927\f
5500c422
GM
5928/***********************************************************************
5929 Window Configuration
5930 ***********************************************************************/
5931
7ab12479
JB
5932struct save_window_data
5933 {
14fe7b53 5934 struct vectorlike_header header;
bdc727bf 5935 Lisp_Object selected_frame;
7ab12479
JB
5936 Lisp_Object current_window;
5937 Lisp_Object current_buffer;
5938 Lisp_Object minibuf_scroll_window;
3f49fddc 5939 Lisp_Object minibuf_selected_window;
7ab12479 5940 Lisp_Object root_window;
bdc727bf 5941 Lisp_Object focus_frame;
cbff28e8
RS
5942 /* A vector, each of whose elements is a struct saved_window
5943 for one window. */
7ab12479 5944 Lisp_Object saved_windows;
b05b4e27
SM
5945
5946 /* All fields above are traced by the GC.
5947 From `fame-cols' down, the fields are ignored by the GC. */
5948
5949 int frame_cols, frame_lines, frame_menu_bar_lines;
5950 int frame_tool_bar_lines;
7ab12479 5951 };
ff06df24 5952
cbff28e8 5953/* This is saved as a Lisp_Vector */
7ab12479 5954struct saved_window
ea68264b 5955{
14fe7b53 5956 struct vectorlike_header header;
ea68264b
GM
5957 Lisp_Object window;
5958 Lisp_Object buffer, start, pointm, mark;
949cf20f
KS
5959 Lisp_Object left_col, top_line, total_cols, total_lines;
5960 Lisp_Object hscroll, min_hscroll;
ea68264b
GM
5961 Lisp_Object parent, prev;
5962 Lisp_Object start_at_line_beg;
5963 Lisp_Object display_table;
949cf20f
KS
5964 Lisp_Object orig_top_line, orig_total_lines;
5965 Lisp_Object left_margin_cols, right_margin_cols;
5966 Lisp_Object left_fringe_width, right_fringe_width, fringes_outside_margins;
5967 Lisp_Object scroll_bar_width, vertical_scroll_bar_type;
047aaeb9 5968 Lisp_Object dedicated, resize_proportionally;
ea68264b
GM
5969};
5970
7ab12479
JB
5971#define SAVED_WINDOW_N(swv,n) \
5972 ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
5973
5974DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
fdb82f93
PJ
5975 doc: /* Return t if OBJECT is a window-configuration object. */)
5976 (object)
413430c5 5977 Lisp_Object object;
7ab12479 5978{
6ad0381c 5979 return WINDOW_CONFIGURATIONP (object) ? Qt : Qnil;
7ab12479
JB
5980}
5981
3f8ab7bd 5982DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
fdb82f93
PJ
5983 doc: /* Return the frame that CONFIG, a window-configuration object, is about. */)
5984 (config)
3f8ab7bd
RS
5985 Lisp_Object config;
5986{
5987 register struct save_window_data *data;
5988 struct Lisp_Vector *saved_windows;
5989
663fbbba 5990 CHECK_WINDOW_CONFIGURATION (config);
3f8ab7bd
RS
5991
5992 data = (struct save_window_data *) XVECTOR (config);
5993 saved_windows = XVECTOR (data->saved_windows);
5994 return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
5995}
5996
d5b2799e 5997DEFUN ("set-window-configuration", Fset_window_configuration,
fdb82f93
PJ
5998 Sset_window_configuration, 1, 1, 0,
5999 doc: /* Set the configuration of windows and buffers as specified by CONFIGURATION.
6000CONFIGURATION must be a value previously returned
6001by `current-window-configuration' (which see).
6002If CONFIGURATION was made from a frame that is now deleted,
6003only frame-independent values can be restored. In this case,
6004the return value is nil. Otherwise the value is t. */)
6005 (configuration)
2f83aebe 6006 Lisp_Object configuration;
7ab12479 6007{
7ab12479
JB
6008 register struct save_window_data *data;
6009 struct Lisp_Vector *saved_windows;
7ab12479 6010 Lisp_Object new_current_buffer;
fd482be5 6011 Lisp_Object frame;
44fa5b1e 6012 FRAME_PTR f;
72695e47 6013 int old_point = -1;
7ab12479 6014
663fbbba 6015 CHECK_WINDOW_CONFIGURATION (configuration);
7ab12479 6016
2f83aebe 6017 data = (struct save_window_data *) XVECTOR (configuration);
7ab12479
JB
6018 saved_windows = XVECTOR (data->saved_windows);
6019
7ab12479 6020 new_current_buffer = data->current_buffer;
265a9e55 6021 if (NILP (XBUFFER (new_current_buffer)->name))
7ab12479 6022 new_current_buffer = Qnil;
72695e47 6023 else
73cadfc1
DK
6024 {
6025 if (XBUFFER (new_current_buffer) == current_buffer)
e67a1dea
SM
6026 /* The code further down "preserves point" by saving here PT in
6027 old_point and then setting it later back into PT. When the
6028 current-selected-window and the final-selected-window both show
6029 the current buffer, this suffers from the problem that the
6030 current PT is the window-point of the current-selected-window,
6031 while the final PT is the point of the final-selected-window, so
6032 this copy from one PT to the other would end up moving the
6033 window-point of the final-selected-window to the window-point of
6034 the current-selected-window. So we have to be careful which
6035 point of the current-buffer we copy into old_point. */
6036 if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer)
6037 && WINDOWP (selected_window)
6038 && EQ (XWINDOW (selected_window)->buffer, new_current_buffer)
6039 && !EQ (selected_window, data->current_window))
6040 old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos;
6041 else
6042 old_point = PT;
73cadfc1 6043 else
203eb0aa
SM
6044 /* BUF_PT (XBUFFER (new_current_buffer)) gives us the position of
6045 point in new_current_buffer as of the last time this buffer was
6046 used. This can be non-deterministic since it can be changed by
6047 things like jit-lock by mere temporary selection of some random
6048 window that happens to show this buffer.
6049 So if possible we want this arbitrary choice of "which point" to
6050 be the one from the to-be-selected-window so as to prevent this
6051 window's cursor from being copied from another window. */
6052 if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer)
6053 /* If current_window = selected_window, its point is in BUF_PT. */
6054 && !EQ (selected_window, data->current_window))
6055 old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos;
6056 else
6057 old_point = BUF_PT (XBUFFER (new_current_buffer));
73cadfc1 6058 }
7ab12479 6059
fd482be5
JB
6060 frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
6061 f = XFRAME (frame);
177c0ea7 6062
fd482be5
JB
6063 /* If f is a dead frame, don't bother rebuilding its window tree.
6064 However, there is other stuff we should still try to do below. */
6065 if (FRAME_LIVE_P (f))
7ab12479 6066 {
fd482be5
JB
6067 register struct window *w;
6068 register struct saved_window *p;
5500c422
GM
6069 struct window *root_window;
6070 struct window **leaf_windows;
6071 int n_leaf_windows;
c4280705 6072 int k, i, n;
fd482be5
JB
6073
6074 /* If the frame has been resized since this window configuration was
6075 made, we change the frame to the size specified in the
6076 configuration, restore the configuration, and then resize it
6077 back. We keep track of the prevailing height in these variables. */
949cf20f
KS
6078 int previous_frame_lines = FRAME_LINES (f);
6079 int previous_frame_cols = FRAME_COLS (f);
8f6ea2e9 6080 int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
9ea173e8 6081 int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
fd482be5 6082
d2b35234
RS
6083 /* The mouse highlighting code could get screwed up
6084 if it runs during this. */
6085 BLOCK_INPUT;
6086
b05b4e27
SM
6087 if (data->frame_lines != previous_frame_lines
6088 || data->frame_cols != previous_frame_cols)
6089 change_frame_size (f, data->frame_lines,
6090 data->frame_cols, 0, 0, 0);
e3678b64 6091#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
b05b4e27 6092 if (data->frame_menu_bar_lines
8f6ea2e9 6093 != previous_frame_menu_bar_lines)
b05b4e27
SM
6094 x_set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines),
6095 make_number (0));
4314246f 6096#ifdef HAVE_WINDOW_SYSTEM
b05b4e27 6097 if (data->frame_tool_bar_lines
9ea173e8 6098 != previous_frame_tool_bar_lines)
b05b4e27
SM
6099 x_set_tool_bar_lines (f, make_number (data->frame_tool_bar_lines),
6100 make_number (0));
4314246f 6101#endif
217f2871 6102#endif
fd482be5 6103
a46c0153
RS
6104 /* "Swap out" point from the selected window's buffer
6105 into the window itself. (Normally the pointm of the selected
6106 window holds garbage.) We do this now, before
719eaeb1
GM
6107 restoring the window contents, and prevent it from
6108 being done later on when we select a new window. */
596ae0cf
RS
6109 if (! NILP (XWINDOW (selected_window)->buffer))
6110 {
6111 w = XWINDOW (selected_window);
6112 set_marker_both (w->pointm,
6113 w->buffer,
6114 BUF_PT (XBUFFER (w->buffer)),
6115 BUF_PT_BYTE (XBUFFER (w->buffer)));
6116 }
6117
fd482be5 6118 windows_or_buffers_changed++;
29aeee73 6119 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
fd482be5 6120
5500c422 6121 /* Problem: Freeing all matrices and later allocating them again
177c0ea7 6122 is a serious redisplay flickering problem. What we would
5500c422 6123 really like to do is to free only those matrices not reused
9d14503e 6124 below. */
5500c422
GM
6125 root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
6126 leaf_windows
6127 = (struct window **) alloca (count_windows (root_window)
6128 * sizeof (struct window *));
6129 n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
6130
fd482be5
JB
6131 /* Kludge Alert!
6132 Mark all windows now on frame as "deleted".
6133 Restoring the new configuration "undeletes" any that are in it.
37962e60 6134
fd482be5
JB
6135 Save their current buffers in their height fields, since we may
6136 need it later, if a buffer saved in the configuration is now
6137 dead. */
6138 delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
6139
14fe7b53 6140 for (k = 0; k < saved_windows->header.size; k++)
fd482be5
JB
6141 {
6142 p = SAVED_WINDOW_N (saved_windows, k);
6143 w = XWINDOW (p->window);
6144 w->next = Qnil;
7ab12479 6145
fd482be5
JB
6146 if (!NILP (p->parent))
6147 w->parent = SAVED_WINDOW_N (saved_windows,
6148 XFASTINT (p->parent))->window;
6149 else
6150 w->parent = Qnil;
7ab12479 6151
fd482be5 6152 if (!NILP (p->prev))
7ab12479 6153 {
fd482be5
JB
6154 w->prev = SAVED_WINDOW_N (saved_windows,
6155 XFASTINT (p->prev))->window;
6156 XWINDOW (w->prev)->next = p->window;
6157 }
6158 else
6159 {
6160 w->prev = Qnil;
6161 if (!NILP (w->parent))
6162 {
949cf20f 6163 if (EQ (p->total_cols, XWINDOW (w->parent)->total_cols))
fd482be5
JB
6164 {
6165 XWINDOW (w->parent)->vchild = p->window;
6166 XWINDOW (w->parent)->hchild = Qnil;
6167 }
6168 else
6169 {
6170 XWINDOW (w->parent)->hchild = p->window;
6171 XWINDOW (w->parent)->vchild = Qnil;
6172 }
6173 }
6174 }
6175
6176 /* If we squirreled away the buffer in the window's height,
6177 restore it now. */
949cf20f
KS
6178 if (BUFFERP (w->total_lines))
6179 w->buffer = w->total_lines;
6180 w->left_col = p->left_col;
6181 w->top_line = p->top_line;
6182 w->total_cols = p->total_cols;
6183 w->total_lines = p->total_lines;
fd482be5 6184 w->hscroll = p->hscroll;
ea68264b 6185 w->min_hscroll = p->min_hscroll;
fd482be5 6186 w->display_table = p->display_table;
949cf20f
KS
6187 w->orig_top_line = p->orig_top_line;
6188 w->orig_total_lines = p->orig_total_lines;
6189 w->left_margin_cols = p->left_margin_cols;
6190 w->right_margin_cols = p->right_margin_cols;
6191 w->left_fringe_width = p->left_fringe_width;
6192 w->right_fringe_width = p->right_fringe_width;
6193 w->fringes_outside_margins = p->fringes_outside_margins;
6194 w->scroll_bar_width = p->scroll_bar_width;
6195 w->vertical_scroll_bar_type = p->vertical_scroll_bar_type;
6ad0381c 6196 w->dedicated = p->dedicated;
047aaeb9 6197 w->resize_proportionally = p->resize_proportionally;
d834a2e9 6198 XSETFASTINT (w->last_modified, 0);
3cd21523 6199 XSETFASTINT (w->last_overlay_modified, 0);
fd482be5
JB
6200
6201 /* Reinstall the saved buffer and pointers into it. */
6202 if (NILP (p->buffer))
6203 w->buffer = p->buffer;
6204 else
6205 {
6206 if (!NILP (XBUFFER (p->buffer)->name))
6207 /* If saved buffer is alive, install it. */
6208 {
6209 w->buffer = p->buffer;
6210 w->start_at_line_beg = p->start_at_line_beg;
b73ea88e
RS
6211 set_marker_restricted (w->start, p->start, w->buffer);
6212 set_marker_restricted (w->pointm, p->pointm, w->buffer);
fd482be5 6213 Fset_marker (XBUFFER (w->buffer)->mark,
b73ea88e 6214 p->mark, w->buffer);
fd482be5
JB
6215
6216 /* As documented in Fcurrent_window_configuration, don't
243a5ce6
RS
6217 restore the location of point in the buffer which was
6218 current when the window configuration was recorded. */
6b54027b
RS
6219 if (!EQ (p->buffer, new_current_buffer)
6220 && XBUFFER (p->buffer) == current_buffer)
fd482be5
JB
6221 Fgoto_char (w->pointm);
6222 }
52a68e98
RS
6223 else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
6224 /* Else unless window has a live buffer, get one. */
7ab12479 6225 {
fd482be5
JB
6226 w->buffer = Fcdr (Fcar (Vbuffer_alist));
6227 /* This will set the markers to beginning of visible
6228 range. */
6229 set_marker_restricted (w->start, make_number (0), w->buffer);
6230 set_marker_restricted (w->pointm, make_number (0),w->buffer);
6231 w->start_at_line_beg = Qt;
7ab12479
JB
6232 }
6233 else
fd482be5 6234 /* Keeping window's old buffer; make sure the markers
52a68e98 6235 are real. */
7ab12479 6236 {
fd482be5
JB
6237 /* Set window markers at start of visible range. */
6238 if (XMARKER (w->start)->buffer == 0)
6239 set_marker_restricted (w->start, make_number (0),
6240 w->buffer);
6241 if (XMARKER (w->pointm)->buffer == 0)
b73ea88e
RS
6242 set_marker_restricted_both (w->pointm, w->buffer,
6243 BUF_PT (XBUFFER (w->buffer)),
6244 BUF_PT_BYTE (XBUFFER (w->buffer)));
fd482be5 6245 w->start_at_line_beg = Qt;
7ab12479
JB
6246 }
6247 }
6248 }
9ace597f 6249
fd482be5 6250 FRAME_ROOT_WINDOW (f) = data->root_window;
a46c0153
RS
6251
6252 /* Arrange *not* to restore point in the buffer that was
6253 current when the window configuration was saved. */
243a5ce6
RS
6254 if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer))
6255 set_marker_restricted (XWINDOW (data->current_window)->pointm,
18787f5e 6256 make_number (old_point),
243a5ce6 6257 XWINDOW (data->current_window)->buffer);
177c0ea7 6258
6dc1d2d3
MR
6259 /* In the following call to `select-window, prevent "swapping
6260 out point" in the old selected window using the buffer that
6261 has been restored into it. We already swapped out that point
6262 from that window's old buffer. */
e6b84b30 6263 select_window (data->current_window, Qnil, 1);
396a830c
RS
6264 XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
6265 = selected_window;
7ab12479 6266
db269683 6267 if (NILP (data->focus_frame)
017b2bad 6268 || (FRAMEP (data->focus_frame)
db269683
JB
6269 && FRAME_LIVE_P (XFRAME (data->focus_frame))))
6270 Fredirect_frame_focus (frame, data->focus_frame);
7ab12479 6271
fd482be5 6272 /* Set the screen height to the value it had before this function. */
949cf20f
KS
6273 if (previous_frame_lines != FRAME_LINES (f)
6274 || previous_frame_cols != FRAME_COLS (f))
6275 change_frame_size (f, previous_frame_lines, previous_frame_cols,
2b653806 6276 0, 0, 0);
e3678b64 6277#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
8f6ea2e9 6278 if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
f8ad443a
AS
6279 x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
6280 make_number (0));
4314246f 6281#ifdef HAVE_WINDOW_SYSTEM
9ea173e8
GM
6282 if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
6283 x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
6284 make_number (0));
4314246f 6285#endif
217f2871 6286#endif
d2b35234 6287
5500c422 6288 /* Now, free glyph matrices in windows that were not reused. */
c4280705
GM
6289 for (i = n = 0; i < n_leaf_windows; ++i)
6290 {
6291 if (NILP (leaf_windows[i]->buffer))
6292 {
6293 /* Assert it's not reused as a combination. */
177c0ea7 6294 xassert (NILP (leaf_windows[i]->hchild)
c4280705
GM
6295 && NILP (leaf_windows[i]->vchild));
6296 free_window_matrices (leaf_windows[i]);
c4280705
GM
6297 }
6298 else if (EQ (leaf_windows[i]->buffer, new_current_buffer))
6299 ++n;
6300 }
177c0ea7 6301
5500c422
GM
6302 adjust_glyphs (f);
6303
d2b35234 6304 UNBLOCK_INPUT;
756b6edc 6305
478292ed
RS
6306 /* Fselect_window will have made f the selected frame, so we
6307 reselect the proper frame here. Fhandle_switch_frame will change the
6308 selected window too, but that doesn't make the call to
6309 Fselect_window above totally superfluous; it still sets f's
6310 selected window. */
6311 if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
c6932ecd 6312 do_switch_frame (data->selected_frame, 0, 0, Qnil);
478292ed 6313
eeca6f6f 6314 run_window_configuration_change_hook (f);
478292ed 6315 }
bdc727bf
JB
6316
6317 if (!NILP (new_current_buffer))
243a5ce6 6318 Fset_buffer (new_current_buffer);
bdc727bf 6319
478292ed 6320 Vminibuf_scroll_window = data->minibuf_scroll_window;
3dbab091 6321 minibuf_selected_window = data->minibuf_selected_window;
543f5fb1 6322
3f8ab7bd 6323 return (FRAME_LIVE_P (f) ? Qt : Qnil);
7ab12479
JB
6324}
6325
44fa5b1e 6326/* Mark all windows now on frame as deleted
7ab12479
JB
6327 by setting their buffers to nil. */
6328
fd482be5 6329void
7ab12479
JB
6330delete_all_subwindows (w)
6331 register struct window *w;
6332{
265a9e55 6333 if (!NILP (w->next))
7ab12479 6334 delete_all_subwindows (XWINDOW (w->next));
265a9e55 6335 if (!NILP (w->vchild))
7ab12479 6336 delete_all_subwindows (XWINDOW (w->vchild));
265a9e55 6337 if (!NILP (w->hchild))
7ab12479 6338 delete_all_subwindows (XWINDOW (w->hchild));
605be8af 6339
949cf20f 6340 w->total_lines = w->buffer; /* See Fset_window_configuration for excuse. */
605be8af 6341
86e48436
RS
6342 if (!NILP (w->buffer))
6343 unshow_buffer (w);
6344
605be8af
JB
6345 /* We set all three of these fields to nil, to make sure that we can
6346 distinguish this dead window from any live window. Live leaf
6347 windows will have buffer set, and combination windows will have
6348 vchild or hchild set. */
6349 w->buffer = Qnil;
6350 w->vchild = Qnil;
6351 w->hchild = Qnil;
acf70840
GM
6352
6353 Vwindow_list = Qnil;
7ab12479
JB
6354}
6355\f
6356static int
6357count_windows (window)
6358 register struct window *window;
6359{
6360 register int count = 1;
265a9e55 6361 if (!NILP (window->next))
7ab12479 6362 count += count_windows (XWINDOW (window->next));
265a9e55 6363 if (!NILP (window->vchild))
7ab12479 6364 count += count_windows (XWINDOW (window->vchild));
265a9e55 6365 if (!NILP (window->hchild))
7ab12479
JB
6366 count += count_windows (XWINDOW (window->hchild));
6367 return count;
6368}
6369
5500c422 6370
177c0ea7 6371/* Fill vector FLAT with leaf windows under W, starting at index I.
5500c422
GM
6372 Value is last index + 1. */
6373
6374static int
6375get_leaf_windows (w, flat, i)
6376 struct window *w;
6377 struct window **flat;
6378 int i;
6379{
6380 while (w)
6381 {
6382 if (!NILP (w->hchild))
6383 i = get_leaf_windows (XWINDOW (w->hchild), flat, i);
6384 else if (!NILP (w->vchild))
6385 i = get_leaf_windows (XWINDOW (w->vchild), flat, i);
177c0ea7 6386 else
5500c422
GM
6387 flat[i++] = w;
6388
6389 w = NILP (w->next) ? 0 : XWINDOW (w->next);
6390 }
6391
6392 return i;
6393}
6394
6395
6396/* Return a pointer to the glyph W's physical cursor is on. Value is
6397 null if W's current matrix is invalid, so that no meaningfull glyph
6398 can be returned. */
6399
6400struct glyph *
6401get_phys_cursor_glyph (w)
6402 struct window *w;
6403{
6404 struct glyph_row *row;
6405 struct glyph *glyph;
6406
6407 if (w->phys_cursor.vpos >= 0
6408 && w->phys_cursor.vpos < w->current_matrix->nrows
6409 && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
6410 row->enabled_p)
6411 && row->used[TEXT_AREA] > w->phys_cursor.hpos)
6412 glyph = row->glyphs[TEXT_AREA] + w->phys_cursor.hpos;
6413 else
6414 glyph = NULL;
6415
6416 return glyph;
6417}
6418
6419
7ab12479
JB
6420static int
6421save_window_save (window, vector, i)
6422 Lisp_Object window;
6423 struct Lisp_Vector *vector;
6424 int i;
6425{
6426 register struct saved_window *p;
6427 register struct window *w;
6428 register Lisp_Object tem;
6429
265a9e55 6430 for (;!NILP (window); window = w->next)
7ab12479
JB
6431 {
6432 p = SAVED_WINDOW_N (vector, i);
6433 w = XWINDOW (window);
6434
2a1893f4 6435 XSETFASTINT (w->temslot, i); i++;
7ab12479
JB
6436 p->window = window;
6437 p->buffer = w->buffer;
949cf20f
KS
6438 p->left_col = w->left_col;
6439 p->top_line = w->top_line;
6440 p->total_cols = w->total_cols;
6441 p->total_lines = w->total_lines;
7ab12479 6442 p->hscroll = w->hscroll;
ea68264b 6443 p->min_hscroll = w->min_hscroll;
7ab12479 6444 p->display_table = w->display_table;
949cf20f
KS
6445 p->orig_top_line = w->orig_top_line;
6446 p->orig_total_lines = w->orig_total_lines;
6447 p->left_margin_cols = w->left_margin_cols;
6448 p->right_margin_cols = w->right_margin_cols;
6449 p->left_fringe_width = w->left_fringe_width;
6450 p->right_fringe_width = w->right_fringe_width;
6451 p->fringes_outside_margins = w->fringes_outside_margins;
6452 p->scroll_bar_width = w->scroll_bar_width;
6453 p->vertical_scroll_bar_type = w->vertical_scroll_bar_type;
6ad0381c 6454 p->dedicated = w->dedicated;
047aaeb9 6455 p->resize_proportionally = w->resize_proportionally;
265a9e55 6456 if (!NILP (w->buffer))
7ab12479
JB
6457 {
6458 /* Save w's value of point in the window configuration.
6459 If w is the selected window, then get the value of point
6460 from the buffer; pointm is garbage in the selected window. */
6461 if (EQ (window, selected_window))
6462 {
6463 p->pointm = Fmake_marker ();
b73ea88e
RS
6464 set_marker_both (p->pointm, w->buffer,
6465 BUF_PT (XBUFFER (w->buffer)),
6466 BUF_PT_BYTE (XBUFFER (w->buffer)));
7ab12479
JB
6467 }
6468 else
eeb82665 6469 p->pointm = Fcopy_marker (w->pointm, Qnil);
7ab12479 6470
eeb82665 6471 p->start = Fcopy_marker (w->start, Qnil);
7ab12479
JB
6472 p->start_at_line_beg = w->start_at_line_beg;
6473
6474 tem = XBUFFER (w->buffer)->mark;
eeb82665 6475 p->mark = Fcopy_marker (tem, Qnil);
7ab12479
JB
6476 }
6477 else
6478 {
6479 p->pointm = Qnil;
6480 p->start = Qnil;
6481 p->mark = Qnil;
6482 p->start_at_line_beg = Qnil;
6483 }
6484
265a9e55 6485 if (NILP (w->parent))
7ab12479
JB
6486 p->parent = Qnil;
6487 else
6488 p->parent = XWINDOW (w->parent)->temslot;
6489
265a9e55 6490 if (NILP (w->prev))
7ab12479
JB
6491 p->prev = Qnil;
6492 else
6493 p->prev = XWINDOW (w->prev)->temslot;
6494
265a9e55 6495 if (!NILP (w->vchild))
7ab12479 6496 i = save_window_save (w->vchild, vector, i);
265a9e55 6497 if (!NILP (w->hchild))
7ab12479
JB
6498 i = save_window_save (w->hchild, vector, i);
6499 }
6500
6501 return i;
6502}
6503
a0d76c27 6504DEFUN ("current-window-configuration", Fcurrent_window_configuration,
fdb82f93
PJ
6505 Scurrent_window_configuration, 0, 1, 0,
6506 doc: /* Return an object representing the current window configuration of FRAME.
6507If FRAME is nil or omitted, use the selected frame.
6508This describes the number of windows, their sizes and current buffers,
6509and for each displayed buffer, where display starts, and the positions of
6510point and mark. An exception is made for point in the current buffer:
6511its value is -not- saved.
6512This also records the currently selected frame, and FRAME's focus
6513redirection (see `redirect-frame-focus'). */)
6514 (frame)
44fa5b1e 6515 Lisp_Object frame;
7ab12479
JB
6516{
6517 register Lisp_Object tem;
6518 register int n_windows;
6519 register struct save_window_data *data;
6520 register int i;
44fa5b1e 6521 FRAME_PTR f;
43bad991 6522
44fa5b1e 6523 if (NILP (frame))
1ae1a37d 6524 frame = selected_frame;
b7826503 6525 CHECK_LIVE_FRAME (frame);
1ae1a37d 6526 f = XFRAME (frame);
7ab12479 6527
44fa5b1e 6528 n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
b05b4e27
SM
6529 data = ALLOCATE_PSEUDOVECTOR (struct save_window_data, frame_cols,
6530 PVEC_WINDOW_CONFIGURATION);
6531
6532 data->frame_cols = FRAME_COLS (f);
6533 data->frame_lines = FRAME_LINES (f);
6534 data->frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
6535 data->frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
1ae1a37d 6536 data->selected_frame = selected_frame;
44fa5b1e 6537 data->current_window = FRAME_SELECTED_WINDOW (f);
74112613 6538 XSETBUFFER (data->current_buffer, current_buffer);
3f49fddc 6539 data->minibuf_scroll_window = minibuf_level > 0 ? Vminibuf_scroll_window : Qnil;
3dbab091 6540 data->minibuf_selected_window = minibuf_level > 0 ? minibuf_selected_window : Qnil;
44fa5b1e 6541 data->root_window = FRAME_ROOT_WINDOW (f);
bdc727bf 6542 data->focus_frame = FRAME_FOCUS_FRAME (f);
7ab12479
JB
6543 tem = Fmake_vector (make_number (n_windows), Qnil);
6544 data->saved_windows = tem;
6545 for (i = 0; i < n_windows; i++)
6546 XVECTOR (tem)->contents[i]
8a450f0a 6547 = Fmake_vector (make_number (VECSIZE (struct saved_window)), Qnil);
a1d58e5b 6548 save_window_save (FRAME_ROOT_WINDOW (f), XVECTOR (tem), 0);
74112613 6549 XSETWINDOW_CONFIGURATION (tem, data);
7ab12479
JB
6550 return (tem);
6551}
6552
6553DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
fdb82f93 6554 0, UNEVALLED, 0,
a0a37a6f
LT
6555 doc: /* Execute BODY, preserving window sizes and contents.
6556Return the value of the last form in BODY.
fdb82f93
PJ
6557Restore which buffer appears in which window, where display starts,
6558and the value of point and mark for each window.
6559Also restore the choice of selected window.
6560Also restore which buffer is current.
6924dda6 6561Does not restore the value of point in current buffer.
7254a30c 6562usage: (save-window-excursion BODY...) */)
fdb82f93 6563 (args)
7ab12479
JB
6564 Lisp_Object args;
6565{
6566 register Lisp_Object val;
aed13378 6567 register int count = SPECPDL_INDEX ();
7ab12479
JB
6568
6569 record_unwind_protect (Fset_window_configuration,
43bad991 6570 Fcurrent_window_configuration (Qnil));
7ab12479
JB
6571 val = Fprogn (args);
6572 return unbind_to (count, val);
6573}
5500c422 6574
94e16dd5
KS
6575
6576\f
6577/***********************************************************************
6578 Window Split Tree
6579 ***********************************************************************/
6580
6581static Lisp_Object
c16e1cc3 6582window_tree (w)
94e16dd5
KS
6583 struct window *w;
6584{
6585 Lisp_Object tail = Qnil;
6586 Lisp_Object result = Qnil;
6587
6588 while (w)
6589 {
6590 Lisp_Object wn;
6591
6592 XSETWINDOW (wn, w);
6593 if (!NILP (w->hchild))
6594 wn = Fcons (Qnil, Fcons (Fwindow_edges (wn),
c16e1cc3 6595 window_tree (XWINDOW (w->hchild))));
94e16dd5
KS
6596 else if (!NILP (w->vchild))
6597 wn = Fcons (Qt, Fcons (Fwindow_edges (wn),
c16e1cc3 6598 window_tree (XWINDOW (w->vchild))));
94e16dd5
KS
6599
6600 if (NILP (result))
6601 {
6602 result = tail = Fcons (wn, Qnil);
6603 }
6604 else
6605 {
6606 XSETCDR (tail, Fcons (wn, Qnil));
6607 tail = XCDR (tail);
6608 }
6609
6610 w = NILP (w->next) ? 0 : XWINDOW (w->next);
6611 }
6612
6613 return result;
6614}
6615
6616
6617
c16e1cc3 6618DEFUN ("window-tree", Fwindow_tree, Swindow_tree,
94e16dd5 6619 0, 1, 0,
c16e1cc3 6620 doc: /* Return the window tree for frame FRAME.
94e16dd5
KS
6621
6622The return value is a list of the form (ROOT MINI), where ROOT
c16e1cc3 6623represents the window tree of the frame's root window, and MINI
94e16dd5
KS
6624is the frame's minibuffer window.
6625
6626If the root window is not split, ROOT is the root window itself.
6627Otherwise, ROOT is a list (DIR EDGES W1 W2 ...) where DIR is nil for a
008171a4 6628horizontal split, and t for a vertical split, EDGES gives the combined
94e16dd5
KS
6629size and position of the subwindows in the split, and the rest of the
6630elements are the subwindows in the split. Each of the subwindows may
6631again be a window or a list representing a window split, and so on.
6632EDGES is a list \(LEFT TOP RIGHT BOTTOM) as returned by `window-edges'.
6633
6634If FRAME is nil or omitted, return information on the currently
6635selected frame. */)
6636 (frame)
6637 Lisp_Object frame;
6638{
94e16dd5
KS
6639 FRAME_PTR f;
6640
6641 if (NILP (frame))
6642 frame = selected_frame;
6643
6644 CHECK_FRAME (frame);
6645 f = XFRAME (frame);
6646
6647 if (!FRAME_LIVE_P (f))
6648 return Qnil;
6649
c16e1cc3 6650 return window_tree (XWINDOW (FRAME_ROOT_WINDOW (f)));
94e16dd5
KS
6651}
6652
5500c422
GM
6653\f
6654/***********************************************************************
6655 Marginal Areas
6656 ***********************************************************************/
6657
6658DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
a7bdfc08 6659 2, 3, 0,
fdb82f93 6660 doc: /* Set width of marginal areas of window WINDOW.
6b61353c
KH
6661If WINDOW is nil, set margins of the currently selected window.
6662Second arg LEFT-WIDTH specifies the number of character cells to
6663reserve for the left marginal area. Optional third arg RIGHT-WIDTH
6664does the same for the right marginal area. A nil width parameter
6665means no margin. */)
c10ce82e
JB
6666 (window, left_width, right_width)
6667 Lisp_Object window, left_width, right_width;
5500c422
GM
6668{
6669 struct window *w = decode_window (window);
5500c422 6670
6b61353c
KH
6671 /* Translate negative or zero widths to nil.
6672 Margins that are too wide have to be checked elsewhere. */
949cf20f 6673
c10ce82e 6674 if (!NILP (left_width))
6b61353c 6675 {
c10ce82e
JB
6676 CHECK_NUMBER (left_width);
6677 if (XINT (left_width) <= 0)
6678 left_width = Qnil;
6b61353c 6679 }
5500c422 6680
c10ce82e 6681 if (!NILP (right_width))
6b61353c 6682 {
c10ce82e
JB
6683 CHECK_NUMBER (right_width);
6684 if (XINT (right_width) <= 0)
6685 right_width = Qnil;
6b61353c 6686 }
5500c422 6687
c10ce82e
JB
6688 if (!EQ (w->left_margin_cols, left_width)
6689 || !EQ (w->right_margin_cols, right_width))
949cf20f 6690 {
c10ce82e
JB
6691 w->left_margin_cols = left_width;
6692 w->right_margin_cols = right_width;
949cf20f
KS
6693
6694 adjust_window_margins (w);
6695
6696 ++windows_or_buffers_changed;
6697 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6698 }
5500c422 6699
5500c422
GM
6700 return Qnil;
6701}
6702
6703
6704DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
6705 0, 1, 0,
fdb82f93
PJ
6706 doc: /* Get width of marginal areas of window WINDOW.
6707If WINDOW is omitted or nil, use the currently selected window.
6708Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).
6709If a marginal area does not exist, its width will be returned
6710as nil. */)
6711 (window)
5500c422
GM
6712 Lisp_Object window;
6713{
6714 struct window *w = decode_window (window);
949cf20f
KS
6715 return Fcons (w->left_margin_cols, w->right_margin_cols);
6716}
6717
6718
6719\f
6720/***********************************************************************
6721 Fringes
6722 ***********************************************************************/
6723
6724DEFUN ("set-window-fringes", Fset_window_fringes, Sset_window_fringes,
6725 2, 4, 0,
6b61353c
KH
6726 doc: /* Set the fringe widths of window WINDOW.
6727If WINDOW is nil, set the fringe widths of the currently selected
6728window.
6729Second arg LEFT-WIDTH specifies the number of pixels to reserve for
6730the left fringe. Optional third arg RIGHT-WIDTH specifies the right
6731fringe width. If a fringe width arg is nil, that means to use the
6732frame's default fringe width. Default fringe widths can be set with
6733the command `set-fringe-style'.
6734If optional fourth arg OUTSIDE-MARGINS is non-nil, draw the fringes
6735outside of the display margins. By default, fringes are drawn between
6736display marginal areas and the text area. */)
c10ce82e
JB
6737 (window, left_width, right_width, outside_margins)
6738 Lisp_Object window, left_width, right_width, outside_margins;
949cf20f
KS
6739{
6740 struct window *w = decode_window (window);
6741
c10ce82e
JB
6742 if (!NILP (left_width))
6743 CHECK_NATNUM (left_width);
6744 if (!NILP (right_width))
6745 CHECK_NATNUM (right_width);
5a857365 6746
017e297e 6747 /* Do nothing on a tty. */
d46c6df5
NR
6748 if (FRAME_WINDOW_P (WINDOW_XFRAME (w))
6749 && (!EQ (w->left_fringe_width, left_width)
6750 || !EQ (w->right_fringe_width, right_width)
6751 || !EQ (w->fringes_outside_margins, outside_margins)))
949cf20f 6752 {
c10ce82e
JB
6753 w->left_fringe_width = left_width;
6754 w->right_fringe_width = right_width;
949cf20f
KS
6755 w->fringes_outside_margins = outside_margins;
6756
6757 adjust_window_margins (w);
6758
6759 clear_glyph_matrix (w->current_matrix);
6760 w->window_end_valid = Qnil;
6761
6762 ++windows_or_buffers_changed;
6763 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6764 }
6765
6766 return Qnil;
6767}
6768
6769
6770DEFUN ("window-fringes", Fwindow_fringes, Swindow_fringes,
6771 0, 1, 0,
6772 doc: /* Get width of fringes of window WINDOW.
6773If WINDOW is omitted or nil, use the currently selected window.
6b61353c 6774Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS). */)
949cf20f
KS
6775 (window)
6776 Lisp_Object window;
6777{
6778 struct window *w = decode_window (window);
d46c6df5 6779
949cf20f
KS
6780 return Fcons (make_number (WINDOW_LEFT_FRINGE_WIDTH (w)),
6781 Fcons (make_number (WINDOW_RIGHT_FRINGE_WIDTH (w)),
d46c6df5
NR
6782 Fcons ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
6783 ? Qt : Qnil), Qnil)));
949cf20f
KS
6784}
6785
6786
6787\f
6788/***********************************************************************
6789 Scroll bars
6790 ***********************************************************************/
6791
6792DEFUN ("set-window-scroll-bars", Fset_window_scroll_bars, Sset_window_scroll_bars,
6793 2, 4, 0,
6794 doc: /* Set width and type of scroll bars of window WINDOW.
6795If window is nil, set scroll bars of the currently selected window.
6796Second parameter WIDTH specifies the pixel width for the scroll bar;
6797this is automatically adjusted to a multiple of the frame column width.
6798Third parameter VERTICAL-TYPE specifies the type of the vertical scroll
6799bar: left, right, or nil.
6b61353c 6800If WIDTH is nil, use the frame's scroll-bar width.
a53d44a8
JB
6801If VERTICAL-TYPE is t, use the frame's scroll-bar type.
6802Fourth parameter HORIZONTAL-TYPE is currently unused. */)
79fd290e
JB
6803 (window, width, vertical_type, horizontal_type)
6804 Lisp_Object window, width, vertical_type, horizontal_type;
949cf20f
KS
6805{
6806 struct window *w = decode_window (window);
6807
6808 if (!NILP (width))
0f8fe9a2
SM
6809 {
6810 CHECK_NATNUM (width);
949cf20f 6811
0f8fe9a2
SM
6812 if (XINT (width) == 0)
6813 vertical_type = Qnil;
6814 }
949cf20f 6815
413a79ad 6816 if (!(NILP (vertical_type)
0cc1039f 6817 || EQ (vertical_type, Qleft)
6b61353c
KH
6818 || EQ (vertical_type, Qright)
6819 || EQ (vertical_type, Qt)))
6820 error ("Invalid type of vertical scroll bar");
6821
949cf20f
KS
6822 if (!EQ (w->scroll_bar_width, width)
6823 || !EQ (w->vertical_scroll_bar_type, vertical_type))
6824 {
6825 w->scroll_bar_width = width;
6826 w->vertical_scroll_bar_type = vertical_type;
6827
6828 adjust_window_margins (w);
6829
6830 clear_glyph_matrix (w->current_matrix);
6831 w->window_end_valid = Qnil;
6832
6833 ++windows_or_buffers_changed;
6834 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6835 }
6836
6837 return Qnil;
6838}
6839
6840
6841DEFUN ("window-scroll-bars", Fwindow_scroll_bars, Swindow_scroll_bars,
6842 0, 1, 0,
6843 doc: /* Get width and type of scroll bars of window WINDOW.
6844If WINDOW is omitted or nil, use the currently selected window.
6b61353c
KH
6845Value is a list of the form (WIDTH COLS VERTICAL-TYPE HORIZONTAL-TYPE).
6846If WIDTH is nil or TYPE is t, the window is using the frame's corresponding
6847value. */)
949cf20f
KS
6848 (window)
6849 Lisp_Object window;
6850{
6851 struct window *w = decode_window (window);
6852 return Fcons (make_number ((WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
6853 ? WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
6854 : WINDOW_SCROLL_BAR_AREA_WIDTH (w))),
6855 Fcons (make_number (WINDOW_SCROLL_BAR_COLS (w)),
6856 Fcons (w->vertical_scroll_bar_type,
6857 Fcons (Qnil, Qnil))));
5500c422
GM
6858}
6859
6860
7ab12479 6861\f
5500c422
GM
6862/***********************************************************************
6863 Smooth scrolling
6864 ***********************************************************************/
6865
0cc1039f 6866DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 2, 0,
fdb82f93
PJ
6867 doc: /* Return the amount by which WINDOW is scrolled vertically.
6868Use the selected window if WINDOW is nil or omitted.
0cc1039f 6869Normally, value is a multiple of the canonical character height of WINDOW;
8cd0d661 6870optional second arg PIXELS-P means value is measured in pixels. */)
0cc1039f
KS
6871 (window, pixels_p)
6872 Lisp_Object window, pixels_p;
5500c422 6873{
47004952 6874 Lisp_Object result;
5500c422
GM
6875 struct frame *f;
6876 struct window *w;
177c0ea7 6877
5500c422
GM
6878 if (NILP (window))
6879 window = selected_window;
47004952 6880 else
b7826503 6881 CHECK_WINDOW (window);
5500c422
GM
6882 w = XWINDOW (window);
6883 f = XFRAME (w->frame);
177c0ea7 6884
5500c422 6885 if (FRAME_WINDOW_P (f))
0cc1039f
KS
6886 result = (NILP (pixels_p)
6887 ? FRAME_CANON_Y_FROM_PIXEL_Y (f, -w->vscroll)
6888 : make_number (-w->vscroll));
5500c422 6889 else
47004952
GM
6890 result = make_number (0);
6891 return result;
5500c422
GM
6892}
6893
6894
6895DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
0cc1039f 6896 2, 3, 0,
fdb82f93 6897 doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL.
0cc1039f
KS
6898WINDOW nil means use the selected window. Normally, VSCROLL is a
6899non-negative multiple of the canonical character height of WINDOW;
8cd0d661 6900optional third arg PIXELS-P non-nil means that VSCROLL is in pixels.
a0a37a6f
LT
6901If PIXELS-P is nil, VSCROLL may have to be rounded so that it
6902corresponds to an integral number of pixels. The return value is the
6903result of this rounding.
6904If PIXELS-P is non-nil, the return value is VSCROLL. */)
0cc1039f
KS
6905 (window, vscroll, pixels_p)
6906 Lisp_Object window, vscroll, pixels_p;
5500c422
GM
6907{
6908 struct window *w;
6909 struct frame *f;
177c0ea7 6910
5500c422
GM
6911 if (NILP (window))
6912 window = selected_window;
47004952 6913 else
b7826503
PJ
6914 CHECK_WINDOW (window);
6915 CHECK_NUMBER_OR_FLOAT (vscroll);
177c0ea7 6916
5500c422
GM
6917 w = XWINDOW (window);
6918 f = XFRAME (w->frame);
6919
6920 if (FRAME_WINDOW_P (f))
6921 {
6922 int old_dy = w->vscroll;
177c0ea7 6923
0cc1039f
KS
6924 w->vscroll = - (NILP (pixels_p)
6925 ? FRAME_LINE_HEIGHT (f) * XFLOATINT (vscroll)
6926 : XFLOATINT (vscroll));
47004952 6927 w->vscroll = min (w->vscroll, 0);
5500c422 6928
e56263e5
KS
6929 if (w->vscroll != old_dy)
6930 {
6931 /* Adjust glyph matrix of the frame if the virtual display
6932 area becomes larger than before. */
6933 if (w->vscroll < 0 && w->vscroll < old_dy)
6934 adjust_glyphs (f);
177c0ea7 6935
e56263e5
KS
6936 /* Prevent redisplay shortcuts. */
6937 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
6938 }
5500c422 6939 }
177c0ea7 6940
0cc1039f 6941 return Fwindow_vscroll (window, pixels_p);
5500c422 6942}
177c0ea7 6943
7bbb5782
GM
6944\f
6945/* Call FN for all leaf windows on frame F. FN is called with the
6946 first argument being a pointer to the leaf window, and with
f95464e4 6947 additional argument USER_DATA. Stops when FN returns 0. */
7bbb5782
GM
6948
6949void
f95464e4 6950foreach_window (f, fn, user_data)
7bbb5782 6951 struct frame *f;
f95464e4
GM
6952 int (* fn) P_ ((struct window *, void *));
6953 void *user_data;
7bbb5782 6954{
56f2de10 6955 /* delete_frame may set FRAME_ROOT_WINDOW (f) to Qnil. */
76fb556f
YM
6956 if (WINDOWP (FRAME_ROOT_WINDOW (f)))
6957 foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data);
7bbb5782
GM
6958}
6959
6960
6961/* Helper function for foreach_window. Call FN for all leaf windows
6962 reachable from W. FN is called with the first argument being a
f95464e4 6963 pointer to the leaf window, and with additional argument USER_DATA.
67492200 6964 Stop when FN returns 0. Value is 0 if stopped by FN. */
7bbb5782 6965
67492200 6966static int
f95464e4 6967foreach_window_1 (w, fn, user_data)
7bbb5782 6968 struct window *w;
f95464e4
GM
6969 int (* fn) P_ ((struct window *, void *));
6970 void *user_data;
7bbb5782 6971{
67492200 6972 int cont;
177c0ea7 6973
67492200 6974 for (cont = 1; w && cont;)
7bbb5782
GM
6975 {
6976 if (!NILP (w->hchild))
f95464e4 6977 cont = foreach_window_1 (XWINDOW (w->hchild), fn, user_data);
7bbb5782 6978 else if (!NILP (w->vchild))
f95464e4 6979 cont = foreach_window_1 (XWINDOW (w->vchild), fn, user_data);
177c0ea7 6980 else
0f532a9a 6981 cont = fn (w, user_data);
177c0ea7 6982
7bbb5782
GM
6983 w = NILP (w->next) ? 0 : XWINDOW (w->next);
6984 }
67492200
GM
6985
6986 return cont;
7bbb5782
GM
6987}
6988
6989
6d194a45 6990/* Freeze or unfreeze the window start of W unless it is a
f95464e4 6991 mini-window or the selected window. FREEZE_P non-null means freeze
7bbb5782
GM
6992 the window start. */
6993
67492200 6994static int
7bbb5782
GM
6995freeze_window_start (w, freeze_p)
6996 struct window *w;
f95464e4 6997 void *freeze_p;
7bbb5782 6998{
08c1d235
SM
6999 if (MINI_WINDOW_P (w)
7000 || (WINDOWP (selected_window) /* Can be nil in corner cases. */
7001 && (w == XWINDOW (selected_window)
7002 || (MINI_WINDOW_P (XWINDOW (selected_window))
7003 && ! NILP (Vminibuf_scroll_window)
7004 && w == XWINDOW (Vminibuf_scroll_window)))))
f95464e4 7005 freeze_p = NULL;
177c0ea7 7006
f95464e4 7007 w->frozen_window_start_p = freeze_p != NULL;
67492200 7008 return 1;
7bbb5782
GM
7009}
7010
7011
7012/* Freeze or unfreeze the window starts of all leaf windows on frame
7013 F, except the selected window and a mini-window. FREEZE_P non-zero
7014 means freeze the window start. */
7015
7016void
7017freeze_window_starts (f, freeze_p)
7018 struct frame *f;
7019 int freeze_p;
7020{
cbccabec 7021 foreach_window (f, freeze_window_start, (void *) (freeze_p ? f : 0));
7bbb5782 7022}
5500c422
GM
7023
7024\f
7025/***********************************************************************
7026 Initialization
7027 ***********************************************************************/
7028
cbff28e8 7029/* Return 1 if window configurations C1 and C2
9d14503e 7030 describe the same state of affairs. This is used by Fequal. */
cbff28e8
RS
7031
7032int
2f8274be 7033compare_window_configurations (c1, c2, ignore_positions)
cbff28e8 7034 Lisp_Object c1, c2;
2f8274be 7035 int ignore_positions;
cbff28e8
RS
7036{
7037 register struct save_window_data *d1, *d2;
7038 struct Lisp_Vector *sw1, *sw2;
7039 int i;
7040
663fbbba
KS
7041 CHECK_WINDOW_CONFIGURATION (c1);
7042 CHECK_WINDOW_CONFIGURATION (c2);
177c0ea7 7043
cbff28e8
RS
7044 d1 = (struct save_window_data *) XVECTOR (c1);
7045 d2 = (struct save_window_data *) XVECTOR (c2);
7046 sw1 = XVECTOR (d1->saved_windows);
7047 sw2 = XVECTOR (d2->saved_windows);
7048
b05b4e27 7049 if (d1->frame_cols != d2->frame_cols)
cbff28e8 7050 return 0;
b05b4e27 7051 if (d1->frame_lines != d2->frame_lines)
cbff28e8 7052 return 0;
b05b4e27 7053 if (d1->frame_menu_bar_lines != d2->frame_menu_bar_lines)
cbff28e8
RS
7054 return 0;
7055 if (! EQ (d1->selected_frame, d2->selected_frame))
7056 return 0;
7057 /* Don't compare the current_window field directly.
7058 Instead see w1_is_current and w2_is_current, below. */
7059 if (! EQ (d1->current_buffer, d2->current_buffer))
7060 return 0;
2f8274be 7061 if (! ignore_positions)
3f49fddc
KS
7062 {
7063 if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
7064 return 0;
7065 if (! EQ (d1->minibuf_selected_window, d2->minibuf_selected_window))
7066 return 0;
7067 }
cbff28e8
RS
7068 /* Don't compare the root_window field.
7069 We don't require the two configurations
7070 to use the same window object,
7071 and the two root windows must be equivalent
7072 if everything else compares equal. */
7073 if (! EQ (d1->focus_frame, d2->focus_frame))
7074 return 0;
cbff28e8
RS
7075
7076 /* Verify that the two confis have the same number of windows. */
14fe7b53 7077 if (sw1->header.size != sw2->header.size)
cbff28e8
RS
7078 return 0;
7079
14fe7b53 7080 for (i = 0; i < sw1->header.size; i++)
cbff28e8
RS
7081 {
7082 struct saved_window *p1, *p2;
7083 int w1_is_current, w2_is_current;
7084
7085 p1 = SAVED_WINDOW_N (sw1, i);
7086 p2 = SAVED_WINDOW_N (sw2, i);
7087
7088 /* Verify that the current windows in the two
7089 configurations correspond to each other. */
7090 w1_is_current = EQ (d1->current_window, p1->window);
7091 w2_is_current = EQ (d2->current_window, p2->window);
7092
7093 if (w1_is_current != w2_is_current)
7094 return 0;
7095
7096 /* Verify that the corresponding windows do match. */
7097 if (! EQ (p1->buffer, p2->buffer))
7098 return 0;
949cf20f 7099 if (! EQ (p1->left_col, p2->left_col))
cbff28e8 7100 return 0;
949cf20f 7101 if (! EQ (p1->top_line, p2->top_line))
cbff28e8 7102 return 0;
949cf20f 7103 if (! EQ (p1->total_cols, p2->total_cols))
cbff28e8 7104 return 0;
949cf20f 7105 if (! EQ (p1->total_lines, p2->total_lines))
cbff28e8 7106 return 0;
cbff28e8
RS
7107 if (! EQ (p1->display_table, p2->display_table))
7108 return 0;
7109 if (! EQ (p1->parent, p2->parent))
7110 return 0;
7111 if (! EQ (p1->prev, p2->prev))
7112 return 0;
2f8274be
RS
7113 if (! ignore_positions)
7114 {
7115 if (! EQ (p1->hscroll, p2->hscroll))
7116 return 0;
ea68264b
GM
7117 if (!EQ (p1->min_hscroll, p2->min_hscroll))
7118 return 0;
2f8274be
RS
7119 if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
7120 return 0;
7121 if (NILP (Fequal (p1->start, p2->start)))
7122 return 0;
7123 if (NILP (Fequal (p1->pointm, p2->pointm)))
7124 return 0;
7125 if (NILP (Fequal (p1->mark, p2->mark)))
7126 return 0;
7127 }
949cf20f
KS
7128 if (! EQ (p1->left_margin_cols, p2->left_margin_cols))
7129 return 0;
7130 if (! EQ (p1->right_margin_cols, p2->right_margin_cols))
7131 return 0;
7132 if (! EQ (p1->left_fringe_width, p2->left_fringe_width))
7133 return 0;
7134 if (! EQ (p1->right_fringe_width, p2->right_fringe_width))
7135 return 0;
7136 if (! EQ (p1->fringes_outside_margins, p2->fringes_outside_margins))
7137 return 0;
7138 if (! EQ (p1->scroll_bar_width, p2->scroll_bar_width))
7139 return 0;
7140 if (! EQ (p1->vertical_scroll_bar_type, p2->vertical_scroll_bar_type))
7141 return 0;
cbff28e8
RS
7142 }
7143
7144 return 1;
7145}
2f8274be
RS
7146
7147DEFUN ("compare-window-configurations", Fcompare_window_configurations,
7148 Scompare_window_configurations, 2, 2, 0,
fdb82f93
PJ
7149 doc: /* Compare two window configurations as regards the structure of windows.
7150This function ignores details such as the values of point and mark
7151and scrolling positions. */)
7152 (x, y)
2f8274be
RS
7153 Lisp_Object x, y;
7154{
7155 if (compare_window_configurations (x, y, 1))
7156 return Qt;
7157 return Qnil;
7158}
cbff28e8 7159\f
dfcf069d 7160void
7ab12479
JB
7161init_window_once ()
7162{
3224dac1 7163 struct frame *f = make_initial_frame ();
1ae1a37d
GM
7164 XSETFRAME (selected_frame, f);
7165 Vterminal_frame = selected_frame;
7166 minibuf_window = f->minibuffer_window;
7167 selected_window = f->selected_window;
7168 last_nonminibuf_frame = f;
5b03d3c0
RS
7169
7170 window_initialized = 1;
7ab12479
JB
7171}
7172
67492200
GM
7173void
7174init_window ()
7175{
7176 Vwindow_list = Qnil;
7177}
7178
dfcf069d 7179void
7ab12479
JB
7180syms_of_window ()
7181{
d67b4f80 7182 Qscroll_up = intern_c_string ("scroll-up");
c525d842
CY
7183 staticpro (&Qscroll_up);
7184
d67b4f80 7185 Qscroll_down = intern_c_string ("scroll-down");
c525d842
CY
7186 staticpro (&Qscroll_down);
7187
d67b4f80 7188 Qwindow_size_fixed = intern_c_string ("window-size-fixed");
8a37516b 7189 staticpro (&Qwindow_size_fixed);
c0e7ccd3 7190 Fset (Qwindow_size_fixed, Qnil);
177c0ea7 7191
543f5fb1
RS
7192 staticpro (&Qwindow_configuration_change_hook);
7193 Qwindow_configuration_change_hook
d67b4f80 7194 = intern_c_string ("window-configuration-change-hook");
543f5fb1 7195
d67b4f80 7196 Qwindowp = intern_c_string ("windowp");
7ab12479
JB
7197 staticpro (&Qwindowp);
7198
d67b4f80 7199 Qwindow_configuration_p = intern_c_string ("window-configuration-p");
3f8ab7bd
RS
7200 staticpro (&Qwindow_configuration_p);
7201
d67b4f80 7202 Qwindow_live_p = intern_c_string ("window-live-p");
806b4d9b 7203 staticpro (&Qwindow_live_p);
605be8af 7204
d67b4f80 7205 Qdisplay_buffer = intern_c_string ("display-buffer");
87478b52
SM
7206 staticpro (&Qdisplay_buffer);
7207
d67b4f80 7208 Qtemp_buffer_show_hook = intern_c_string ("temp-buffer-show-hook");
a58ec57d
RS
7209 staticpro (&Qtemp_buffer_show_hook);
7210
67492200 7211 staticpro (&Vwindow_list);
8bfb170b
KS
7212
7213 minibuf_selected_window = Qnil;
3dbab091 7214 staticpro (&minibuf_selected_window);
67492200 7215
c876b227 7216 window_scroll_pixel_based_preserve_x = -1;
66fe93d1 7217 window_scroll_pixel_based_preserve_y = -1;
c876b227
SM
7218 window_scroll_preserve_hpos = -1;
7219 window_scroll_preserve_vpos = -1;
66d43aea 7220
7ab12479 7221 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
fdb82f93
PJ
7222 doc: /* Non-nil means call as function to display a help buffer.
7223The function is called with one argument, the buffer to be displayed.
7224Used by `with-output-to-temp-buffer'.
7225If this function is used, then it must do the entire job of showing
7226the buffer; `temp-buffer-show-hook' is not run unless this function runs it. */);
7ab12479
JB
7227 Vtemp_buffer_show_function = Qnil;
7228
7ab12479 7229 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
fdb82f93 7230 doc: /* Non-nil means it is the window that C-M-v in minibuffer should scroll. */);
7ab12479
JB
7231 Vminibuf_scroll_window = Qnil;
7232
cc91894c 7233 DEFVAR_BOOL ("mode-line-in-non-selected-windows", &mode_line_in_non_selected_windows,
26124d5e 7234 doc: /* Non-nil means to use `mode-line-inactive' face in non-selected windows.
cc91894c
KS
7235If the minibuffer is active, the `minibuffer-scroll-window' mode line
7236is displayed in the `mode-line' face. */);
7237 mode_line_in_non_selected_windows = 1;
26124d5e 7238
7ab12479 7239 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
fdb82f93 7240 doc: /* If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window. */);
7ab12479
JB
7241 Vother_window_scroll_buffer = Qnil;
7242
e56263e5
KS
7243 DEFVAR_BOOL ("auto-window-vscroll", &auto_window_vscroll_p,
7244 doc: /* *Non-nil means to automatically adjust `window-vscroll' to view tall lines. */);
7245 auto_window_vscroll_p = 1;
7246
7ab12479 7247 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
fdb82f93 7248 doc: /* *Number of lines of continuity when scrolling by screenfuls. */);
7ab12479
JB
7249 next_screen_context_lines = 2;
7250
7ab12479 7251 DEFVAR_INT ("window-min-height", &window_min_height,
047aaeb9
MR
7252 doc: /* Allow deleting windows less than this tall.
7253The value is measured in line units. If a window wants a modeline it
7254is counted as one line.
7255
7256Emacs honors settings of this variable when enlarging or shrinking
7257windows vertically. A value less than 1 is invalid. */);
7ab12479
JB
7258 window_min_height = 4;
7259
7260 DEFVAR_INT ("window-min-width", &window_min_width,
047aaeb9
MR
7261 doc: /* Allow deleting windows less than this wide.
7262The value is measured in characters and includes any fringes or
7263the scrollbar.
7264
7265Emacs honors settings of this variable when enlarging or shrinking
7266windows horizontally. A value less than 2 is invalid. */);
7ab12479
JB
7267 window_min_width = 10;
7268
5500c422
GM
7269 DEFVAR_LISP ("scroll-preserve-screen-position",
7270 &Vscroll_preserve_screen_position,
c876b227 7271 doc: /* *Controls if scroll commands move point to keep its screen position unchanged.
bdf4ec93
RS
7272A value of nil means point does not keep its screen position except
7273at the scroll margin or window boundary respectively.
7274A value of t means point keeps its screen position if the scroll
7275command moved it vertically out of the window, e.g. when scrolling
7276by full screens.
7277Any other value means point always keeps its screen position. */);
5500c422 7278 Vscroll_preserve_screen_position = Qnil;
9317a85d 7279
a1562258
SM
7280 DEFVAR_LISP ("window-point-insertion-type", &Vwindow_point_insertion_type,
7281 doc: /* Type of marker to use for `window-point'. */);
7282 Vwindow_point_insertion_type = Qnil;
7283
543f5fb1
RS
7284 DEFVAR_LISP ("window-configuration-change-hook",
7285 &Vwindow_configuration_change_hook,
fdb82f93 7286 doc: /* Functions to call when window configuration changes.
6a44ffb3
SM
7287The buffer-local part is run once per window, with the relevant window
7288selected; while the global part is run only once for the modified frame,
7289with the relevant frame selected. */);
543f5fb1
RS
7290 Vwindow_configuration_change_hook = Qnil;
7291
666e158e
MB
7292 DEFVAR_LISP ("recenter-redisplay", &Vrecenter_redisplay,
7293 doc: /* If non-nil, then the `recenter' command with a nil argument
7294the entire frame to be redrawn; the special value `tty' causes the
7295frame to be redrawn only if it is a tty frame. */);
7296 Vrecenter_redisplay = Qtty;
7297
7298
7ab12479
JB
7299 defsubr (&Sselected_window);
7300 defsubr (&Sminibuffer_window);
7301 defsubr (&Swindow_minibuffer_p);
7302 defsubr (&Swindowp);
806b4d9b 7303 defsubr (&Swindow_live_p);
7ab12479 7304 defsubr (&Spos_visible_in_window_p);
536833ab 7305 defsubr (&Swindow_line_height);
7ab12479
JB
7306 defsubr (&Swindow_buffer);
7307 defsubr (&Swindow_height);
7308 defsubr (&Swindow_width);
35ea56c9 7309 defsubr (&Swindow_full_width_p);
7ab12479
JB
7310 defsubr (&Swindow_hscroll);
7311 defsubr (&Sset_window_hscroll);
190eb263
RS
7312 defsubr (&Swindow_redisplay_end_trigger);
7313 defsubr (&Sset_window_redisplay_end_trigger);
7ab12479 7314 defsubr (&Swindow_edges);
c99a9eb3
RS
7315 defsubr (&Swindow_pixel_edges);
7316 defsubr (&Swindow_inside_edges);
7317 defsubr (&Swindow_inside_pixel_edges);
d5783c40
JB
7318 defsubr (&Scoordinates_in_window_p);
7319 defsubr (&Swindow_at);
7ab12479
JB
7320 defsubr (&Swindow_point);
7321 defsubr (&Swindow_start);
7322 defsubr (&Swindow_end);
7323 defsubr (&Sset_window_point);
7324 defsubr (&Sset_window_start);
7325 defsubr (&Swindow_dedicated_p);
d207b766 7326 defsubr (&Sset_window_dedicated_p);
7ab12479
JB
7327 defsubr (&Swindow_display_table);
7328 defsubr (&Sset_window_display_table);
7329 defsubr (&Snext_window);
7330 defsubr (&Sprevious_window);
7331 defsubr (&Sother_window);
7332 defsubr (&Sget_lru_window);
7333 defsubr (&Sget_largest_window);
7334 defsubr (&Sget_buffer_window);
7335 defsubr (&Sdelete_other_windows);
7336 defsubr (&Sdelete_windows_on);
7337 defsubr (&Sreplace_buffer_in_windows);
7338 defsubr (&Sdelete_window);
7339 defsubr (&Sset_window_buffer);
7340 defsubr (&Sselect_window);
6b61353c 7341 defsubr (&Sforce_window_update);
7ab12479
JB
7342 defsubr (&Ssplit_window);
7343 defsubr (&Senlarge_window);
7344 defsubr (&Sshrink_window);
0d384044 7345 defsubr (&Sadjust_window_trailing_edge);
7ab12479
JB
7346 defsubr (&Sscroll_up);
7347 defsubr (&Sscroll_down);
7348 defsubr (&Sscroll_left);
7349 defsubr (&Sscroll_right);
ccd0664b 7350 defsubr (&Sother_window_for_scrolling);
7ab12479 7351 defsubr (&Sscroll_other_window);
fa832261 7352 defsubr (&Sminibuffer_selected_window);
7ab12479 7353 defsubr (&Srecenter);
81fe0836 7354 defsubr (&Swindow_text_height);
7ab12479
JB
7355 defsubr (&Smove_to_window_line);
7356 defsubr (&Swindow_configuration_p);
3f8ab7bd 7357 defsubr (&Swindow_configuration_frame);
7ab12479
JB
7358 defsubr (&Sset_window_configuration);
7359 defsubr (&Scurrent_window_configuration);
7360 defsubr (&Ssave_window_excursion);
c16e1cc3 7361 defsubr (&Swindow_tree);
5500c422
GM
7362 defsubr (&Sset_window_margins);
7363 defsubr (&Swindow_margins);
949cf20f
KS
7364 defsubr (&Sset_window_fringes);
7365 defsubr (&Swindow_fringes);
7366 defsubr (&Sset_window_scroll_bars);
7367 defsubr (&Swindow_scroll_bars);
5500c422
GM
7368 defsubr (&Swindow_vscroll);
7369 defsubr (&Sset_window_vscroll);
2f8274be 7370 defsubr (&Scompare_window_configurations);
67492200 7371 defsubr (&Swindow_list);
cfbb2395
JB
7372 defsubr (&Swindow_parameters);
7373 defsubr (&Swindow_parameter);
7374 defsubr (&Sset_window_parameter);
7375
7ab12479
JB
7376}
7377
dfcf069d 7378void
7ab12479
JB
7379keys_of_window ()
7380{
7381 initial_define_key (control_x_map, '1', "delete-other-windows");
7382 initial_define_key (control_x_map, '2', "split-window");
7383 initial_define_key (control_x_map, '0', "delete-window");
7384 initial_define_key (control_x_map, 'o', "other-window");
7385 initial_define_key (control_x_map, '^', "enlarge-window");
7386 initial_define_key (control_x_map, '<', "scroll-left");
7387 initial_define_key (control_x_map, '>', "scroll-right");
7388
7389 initial_define_key (global_map, Ctl ('V'), "scroll-up");
7390 initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
7391 initial_define_key (meta_map, 'v', "scroll-down");
7392
7393 initial_define_key (global_map, Ctl('L'), "recenter");
7394 initial_define_key (meta_map, 'r', "move-to-window-line");
7395}
6b61353c
KH
7396
7397/* arch-tag: 90a9c576-0590-48f1-a5f1-6c96a0452d9f
2c2cd782 7398 (do not change this comment) */