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