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