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