Declare Lisp_Object Q* variables to be 'static' if not exproted.
[bpt/emacs.git] / src / window.c
CommitLineData
7ab12479
JB
1/* Window creation, deletion and examination for GNU Emacs.
2 Does not include redisplay.
73b0cd50 3 Copyright (C) 1985-1987, 1993-1998, 2000-2011
8cabe764 4 Free Software Foundation, Inc.
7ab12479
JB
5
6This file is part of GNU Emacs.
7
9ec0b715 8GNU Emacs is free software: you can redistribute it and/or modify
7ab12479 9it under the terms of the GNU General Public License as published by
9ec0b715
GM
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
7ab12479
JB
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
9ec0b715 19along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
7ab12479 20
18160b98 21#include <config.h>
4d553a13 22#include <stdio.h>
d7306fe6 23#include <setjmp.h>
4d553a13 24
7ab12479
JB
25#include "lisp.h"
26#include "buffer.h"
3e4731a3 27#include "keyboard.h"
e35f6ff7 28#include "keymap.h"
44fa5b1e 29#include "frame.h"
7ab12479
JB
30#include "window.h"
31#include "commands.h"
32#include "indent.h"
33#include "termchar.h"
34#include "disptab.h"
dfcf069d 35#include "dispextern.h"
5500c422
GM
36#include "blockinput.h"
37#include "intervals.h"
de509a60 38#include "termhooks.h" /* For FRAME_TERMINAL. */
5500c422 39
6d55d620 40#ifdef HAVE_X_WINDOWS
dfcf069d 41#include "xterm.h"
5500c422 42#endif /* HAVE_X_WINDOWS */
8f23f280
AI
43#ifdef WINDOWSNT
44#include "w32term.h"
45#endif
1e3c8885
EZ
46#ifdef MSDOS
47#include "msdos.h"
48#endif
edfda783
AR
49#ifdef HAVE_NS
50#include "nsterm.h"
51#endif
5500c422 52
955cbe7b
PE
53Lisp_Object Qwindowp, Qwindow_live_p;
54static Lisp_Object Qwindow_configuration_p;
55static Lisp_Object Qdisplay_buffer;
56static Lisp_Object Qscroll_up, Qscroll_down, Qscroll_command;
57static Lisp_Object Qwindow_size_fixed;
87478b52 58
f57e2426
J
59static int displayed_window_lines (struct window *);
60static struct window *decode_window (Lisp_Object);
61static int count_windows (struct window *);
62static int get_leaf_windows (struct window *, struct window **, int);
63static void window_scroll (Lisp_Object, int, int, int);
64static void window_scroll_pixel_based (Lisp_Object, int, int, int);
65static void window_scroll_line_based (Lisp_Object, int, int, int);
66static int window_min_size_1 (struct window *, int, int);
67static int window_min_size_2 (struct window *, int, int);
68static int window_min_size (struct window *, int, int, int, int *);
69static void size_window (Lisp_Object, int, int, int, int, int);
70static int freeze_window_start (struct window *, void *);
71static int window_fixed_size_p (struct window *, int, int);
72static void enlarge_window (Lisp_Object, int, int);
73static Lisp_Object window_list (void);
74static int add_window_to_list (struct window *, void *);
75static int candidate_window_p (Lisp_Object, Lisp_Object, Lisp_Object,
76 Lisp_Object);
77static Lisp_Object next_window (Lisp_Object, Lisp_Object,
78 Lisp_Object, int);
79static void decode_next_window_args (Lisp_Object *, Lisp_Object *,
80 Lisp_Object *);
2f7c71a1 81static void foreach_window (struct frame *,
f95464e4 82 int (* fn) (struct window *, void *),
2f7c71a1 83 void *);
f57e2426
J
84static int foreach_window_1 (struct window *,
85 int (* fn) (struct window *, void *),
86 void *);
87static Lisp_Object window_list_1 (Lisp_Object, Lisp_Object, Lisp_Object);
7c82f3e2 88static Lisp_Object select_window (Lisp_Object, Lisp_Object, int);
b7354ddf 89
7ab12479
JB
90/* This is the window in which the terminal's cursor should
91 be left when nothing is being done with it. This must
92 always be a leaf window, and its buffer is selected by
93 the top level editing loop at the end of each command.
94
95 This value is always the same as
44fa5b1e 96 FRAME_SELECTED_WINDOW (selected_frame). */
7ab12479
JB
97
98Lisp_Object selected_window;
99
67492200
GM
100/* A list of all windows for use by next_window and Fwindow_list.
101 Functions creating or deleting windows should invalidate this cache
102 by setting it to nil. */
103
104Lisp_Object Vwindow_list;
105
5500c422
GM
106/* The mini-buffer window of the selected frame.
107 Note that you cannot test for mini-bufferness of an arbitrary window
108 by comparing against this; but you can test for mini-bufferness of
7ab12479 109 the selected window. */
5500c422 110
7ab12479
JB
111Lisp_Object minibuf_window;
112
3f49fddc
KS
113/* Non-nil means it is the window whose mode line should be
114 shown as the selected window when the minibuffer is selected. */
115
3dbab091 116Lisp_Object minibuf_selected_window;
3f49fddc 117
a58ec57d 118/* Hook run at end of temp_output_buffer_show. */
5500c422 119
955cbe7b 120static Lisp_Object Qtemp_buffer_show_hook;
a58ec57d 121
7ab12479 122/* Incremented for each window created. */
5500c422 123
7ab12479
JB
124static int sequence_number;
125
5b03d3c0 126/* Nonzero after init_window_once has finished. */
5500c422 127
5b03d3c0
RS
128static int window_initialized;
129
543f5fb1 130/* Hook to run when window config changes. */
5500c422 131
eeca6f6f 132static Lisp_Object Qwindow_configuration_change_hook;
0d384044
RS
133/* Incremented by 1 whenever a window is deleted. */
134
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
16a97296 220DEFUE ("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
16a97296
PE
239DEFUE ("window-minibuffer-p", Fwindow_minibuffer_p,
240 Swindow_minibuffer_p, 0, 1, 0,
23fe745a 241 doc: /* Return non-nil if WINDOW is a minibuffer window.
6b61353c 242WINDOW defaults to the selected window. */)
5842a27b 243 (Lisp_Object window)
7ab12479
JB
244{
245 struct window *w = decode_window (window);
53bb6b99 246 return MINI_WINDOW_P (w) ? Qt : Qnil;
81e4d465
MB
247}
248
249
16a97296 250DEFUE ("pos-visible-in-window-p", Fpos_visible_in_window_p,
fdb82f93 251 Spos_visible_in_window_p, 0, 3, 0,
a0a37a6f 252 doc: /* Return non-nil if position POS is currently on the frame in WINDOW.
fdb82f93
PJ
253Return nil if that position is scrolled vertically out of view.
254If a character is only partially visible, nil is returned, unless the
255optional argument PARTIALLY is non-nil.
a0a37a6f 256If POS is only out of view because of horizontal scrolling, return non-nil.
120b7781 257If POS is t, it specifies the position of the last visible glyph in WINDOW.
0cc1039f
KS
258POS defaults to point in WINDOW; WINDOW defaults to the selected window.
259
260If POS is visible, return t if PARTIALLY is nil; if PARTIALLY is non-nil,
5a857365
KS
261return value is a list of 2 or 6 elements (X Y [RTOP RBOT ROWH VPOS]),
262where X and Y are the pixel coordinates relative to the top left corner
263of the window. The remaining elements are omitted if the character after
264POS is fully visible; otherwise, RTOP and RBOT are the number of pixels
120b7781 265off-window at the top and bottom of the row, ROWH is the height of the
7bbc67d2 266display row, and VPOS is the row number (0-based) containing POS. */)
5842a27b 267 (Lisp_Object pos, Lisp_Object window, Lisp_Object partially)
7ab12479
JB
268{
269 register struct window *w;
2452438f 270 register EMACS_INT posint;
7ab12479 271 register struct buffer *buf;
9a132b1f 272 struct text_pos top;
0cc1039f 273 Lisp_Object in_window = Qnil;
5a857365 274 int rtop, rbot, rowh, vpos, fully_p = 1;
0cc1039f 275 int x, y;
7ab12479 276
f28b75a9
MB
277 w = decode_window (window);
278 buf = XBUFFER (w->buffer);
279 SET_TEXT_POS_FROM_MARKER (top, w->start);
280
120b7781
KS
281 if (EQ (pos, Qt))
282 posint = -1;
283 else if (!NILP (pos))
7ab12479 284 {
b7826503 285 CHECK_NUMBER_COERCE_MARKER (pos);
7ab12479
JB
286 posint = XINT (pos);
287 }
f28b75a9
MB
288 else if (w == XWINDOW (selected_window))
289 posint = PT;
290 else
291 posint = XMARKER (w->pointm)->charpos;
7ab12479 292
0cc1039f
KS
293 /* If position is above window start or outside buffer boundaries,
294 or if window start is out of range, position is not visible. */
120b7781
KS
295 if ((EQ (pos, Qt)
296 || (posint >= CHARPOS (top) && posint <= BUF_ZV (buf)))
0cc1039f
KS
297 && CHARPOS (top) >= BUF_BEGV (buf)
298 && CHARPOS (top) <= BUF_ZV (buf)
5a857365 299 && pos_visible_p (w, posint, &x, &y, &rtop, &rbot, &rowh, &vpos)
e56263e5 300 && (fully_p = !rtop && !rbot, (!NILP (partially) || fully_p)))
0cc1039f
KS
301 in_window = Qt;
302
303 if (!NILP (in_window) && !NILP (partially))
5a857365
KS
304 {
305 Lisp_Object part = Qnil;
306 if (!fully_p)
307 part = list4 (make_number (rtop), make_number (rbot),
308 make_number (rowh), make_number (vpos));
309 in_window = Fcons (make_number (x),
310 Fcons (make_number (y), part));
311 }
312
9a132b1f 313 return in_window;
7ab12479 314}
53bb6b99 315
536833ab 316DEFUN ("window-line-height", Fwindow_line_height,
7bbc67d2 317 Swindow_line_height, 0, 2, 0,
536833ab
KS
318 doc: /* Return height in pixels of text line LINE in window WINDOW.
319If WINDOW is nil or omitted, use selected window.
320
7bbc67d2
KS
321Return height of current line if LINE is omitted or nil. Return height of
322header or mode line if LINE is `header-line' and `mode-line'.
323Otherwise, LINE is a text line number starting from 0. A negative number
324counts from the end of the window.
536833ab 325
7bbc67d2 326Value is a list (HEIGHT VPOS YPOS OFFBOT), where HEIGHT is the height
536833ab 327in pixels of the visible part of the line, VPOS and YPOS are the
68e67a4e 328vertical position in lines and pixels of the line, relative to the top
120b7781 329of the first text line, and OFFBOT is the number of off-window pixels at
68e67a4e
KS
330the bottom of the text line. If there are off-window pixels at the top
331of the (first) text line, YPOS is negative.
536833ab
KS
332
333Return nil if window display is not up-to-date. In that case, use
334`pos-visible-in-window-p' to obtain the information. */)
5842a27b 335 (Lisp_Object line, Lisp_Object window)
b3a10345
KS
336{
337 register struct window *w;
338 register struct buffer *b;
339 struct glyph_row *row, *end_row;
536833ab 340 int max_y, crop, i, n;
b3a10345
KS
341
342 w = decode_window (window);
343
344 if (noninteractive
b3a10345 345 || w->pseudo_window_p)
7bbc67d2 346 return Qnil;
b3a10345
KS
347
348 CHECK_BUFFER (w->buffer);
349 b = XBUFFER (w->buffer);
350
351 /* Fail if current matrix is not up-to-date. */
352 if (NILP (w->window_end_valid)
353 || current_buffer->clip_changed
354 || current_buffer->prevent_redisplay_optimizations_p
355 || XFASTINT (w->last_modified) < BUF_MODIFF (b)
356 || XFASTINT (w->last_overlay_modified) < BUF_OVERLAY_MODIFF (b))
357 return Qnil;
358
7bbc67d2
KS
359 if (NILP (line))
360 {
361 i = w->cursor.vpos;
362 if (i < 0 || i >= w->current_matrix->nrows
363 || (row = MATRIX_ROW (w->current_matrix, i), !row->enabled_p))
364 return Qnil;
365 max_y = window_text_bottom_y (w);
366 goto found_row;
367 }
368
536833ab 369 if (EQ (line, Qheader_line))
b3a10345 370 {
536833ab
KS
371 if (!WINDOW_WANTS_HEADER_LINE_P (w))
372 return Qnil;
373 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
b3a10345
KS
374 if (!row->enabled_p)
375 return Qnil;
536833ab
KS
376 return list4 (make_number (row->height),
377 make_number (0), make_number (0),
378 make_number (0));
b3a10345 379 }
536833ab
KS
380
381 if (EQ (line, Qmode_line))
b3a10345 382 {
536833ab
KS
383 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
384 if (!row->enabled_p)
385 return Qnil;
386 return list4 (make_number (row->height),
387 make_number (0), /* not accurate */
388 make_number (WINDOW_HEADER_LINE_HEIGHT (w)
389 + window_text_bottom_y (w)),
390 make_number (0));
391 }
b3a10345 392
536833ab 393 CHECK_NUMBER (line);
7bbc67d2 394 n = XINT (line);
536833ab
KS
395
396 row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
397 end_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
398 max_y = window_text_bottom_y (w);
7bbc67d2 399 i = 0;
536833ab
KS
400
401 while ((n < 0 || i < n)
402 && row <= end_row && row->enabled_p
403 && row->y + row->height < max_y)
404 row++, i++;
b3a10345 405
536833ab
KS
406 if (row > end_row || !row->enabled_p)
407 return Qnil;
408
7bbc67d2 409 if (++n < 0)
536833ab
KS
410 {
411 if (-n > i)
412 return Qnil;
7bbc67d2
KS
413 row += n;
414 i += n;
b3a10345
KS
415 }
416
7bbc67d2 417 found_row:
536833ab
KS
418 crop = max (0, (row->y + row->height) - max_y);
419 return list4 (make_number (row->height + min (0, row->y) - crop),
7bbc67d2 420 make_number (i),
536833ab
KS
421 make_number (row->y),
422 make_number (crop));
b3a10345
KS
423}
424
536833ab 425
7ab12479
JB
426\f
427static struct window *
971de7fb 428decode_window (register Lisp_Object window)
7ab12479 429{
265a9e55 430 if (NILP (window))
7ab12479
JB
431 return XWINDOW (selected_window);
432
b7826503 433 CHECK_LIVE_WINDOW (window);
7ab12479
JB
434 return XWINDOW (window);
435}
436
6b61353c 437static struct window *
971de7fb 438decode_any_window (register Lisp_Object window)
6b61353c
KH
439{
440 if (NILP (window))
441 return XWINDOW (selected_window);
442
443 CHECK_WINDOW (window);
444 return XWINDOW (window);
445}
446
16a97296 447DEFUE ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
c2755926
LT
448 doc: /* Return the buffer that WINDOW is displaying.
449WINDOW defaults to the selected window. */)
5842a27b 450 (Lisp_Object window)
7ab12479
JB
451{
452 return decode_window (window)->buffer;
453}
454
455DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0,
8fef9de1
MR
456 doc: /* Return the number of lines in WINDOW.
457WINDOW defaults to the selected window.
458
a77cfeaf
CS
459The return value includes WINDOW's mode line and header line, if any.
460
461Note: The function does not take into account the value of `line-spacing'
462when calculating the number of lines in WINDOW. */)
5842a27b 463 (Lisp_Object window)
7ab12479 464{
6b61353c 465 return decode_any_window (window)->total_lines;
7ab12479
JB
466}
467
468DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
fdb82f93 469 doc: /* Return the number of display columns in WINDOW.
d653c8cc
MR
470WINDOW defaults to the selected window.
471
472Note: The return value is the number of columns available for text in
473WINDOW. If you want to find out how many columns WINDOW takes up, use
474(let ((edges (window-edges))) (- (nth 2 edges) (nth 0 edges))). */)
5842a27b 475 (Lisp_Object window)
7ab12479 476{
6b61353c 477 return make_number (window_box_text_cols (decode_any_window (window)));
7ab12479
JB
478}
479
35ea56c9
MR
480DEFUN ("window-full-width-p", Fwindow_full_width_p, Swindow_full_width_p, 0, 1, 0,
481 doc: /* Return t if WINDOW is as wide as its frame.
482WINDOW defaults to the selected window. */)
5842a27b 483 (Lisp_Object window)
35ea56c9
MR
484{
485 return WINDOW_FULL_WIDTH_P (decode_any_window (window)) ? Qt : Qnil;
486}
487
7ab12479 488DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
c85322d0
EZ
489 doc: /* Return the number of columns by which WINDOW is scrolled from left margin.
490WINDOW defaults to the selected window. */)
5842a27b 491 (Lisp_Object window)
7ab12479
JB
492{
493 return decode_window (window)->hscroll;
494}
495
496DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
fdb82f93 497 doc: /* Set number of columns WINDOW is scrolled from left margin to NCOL.
a0a37a6f 498Return NCOL. NCOL should be zero or positive.
ebadb1e4
EZ
499
500Note that if `automatic-hscrolling' is non-nil, you cannot scroll the
120b7781 501window so that the location of point moves off-window. */)
5842a27b 502 (Lisp_Object window, Lisp_Object ncol)
7ab12479 503{
ea68264b
GM
504 struct window *w = decode_window (window);
505 int hscroll;
7ab12479 506
b7826503 507 CHECK_NUMBER (ncol);
ea68264b 508 hscroll = max (0, XINT (ncol));
177c0ea7 509
ea68264b
GM
510 /* Prevent redisplay shortcuts when changing the hscroll. */
511 if (XINT (w->hscroll) != hscroll)
b1599b4c 512 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
177c0ea7 513
c67fa410 514 w->hscroll = make_number (hscroll);
7ab12479
JB
515 return ncol;
516}
517
190eb263
RS
518DEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger,
519 Swindow_redisplay_end_trigger, 0, 1, 0,
fdb82f93 520 doc: /* Return WINDOW's redisplay end trigger value.
c85322d0 521WINDOW defaults to the selected window.
fdb82f93 522See `set-window-redisplay-end-trigger' for more information. */)
5842a27b 523 (Lisp_Object window)
190eb263
RS
524{
525 return decode_window (window)->redisplay_end_trigger;
526}
527
528DEFUN ("set-window-redisplay-end-trigger", Fset_window_redisplay_end_trigger,
529 Sset_window_redisplay_end_trigger, 2, 2, 0,
fdb82f93
PJ
530 doc: /* Set WINDOW's redisplay end trigger value to VALUE.
531VALUE should be a buffer position (typically a marker) or nil.
532If it is a buffer position, then if redisplay in WINDOW reaches a position
533beyond VALUE, the functions in `redisplay-end-trigger-functions' are called
534with two arguments: WINDOW, and the end trigger value.
535Afterwards the end-trigger value is reset to nil. */)
5842a27b 536 (register Lisp_Object window, Lisp_Object value)
190eb263
RS
537{
538 register struct window *w;
539
540 w = decode_window (window);
541 w->redisplay_end_trigger = value;
542 return value;
543}
544
7ab12479 545DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0,
fdb82f93 546 doc: /* Return a list of the edge coordinates of WINDOW.
b35ac83e
CY
547The list has the form (LEFT TOP RIGHT BOTTOM).
548TOP and BOTTOM count by lines, and LEFT and RIGHT count by columns,
549all relative to 0, 0 at top left corner of frame.
550
551RIGHT is one more than the rightmost column occupied by WINDOW.
552BOTTOM is one more than the bottommost row occupied by WINDOW.
553The edges include the space used by WINDOW's scroll bar, display
554margins, fringes, header line, and/or mode line. For the edges of
555just the text area, use `window-inside-edges'. */)
5842a27b 556 (Lisp_Object window)
7ab12479 557{
6b61353c 558 register struct window *w = decode_any_window (window);
7ab12479 559
949cf20f
KS
560 return Fcons (make_number (WINDOW_LEFT_EDGE_COL (w)),
561 Fcons (make_number (WINDOW_TOP_EDGE_LINE (w)),
562 Fcons (make_number (WINDOW_RIGHT_EDGE_COL (w)),
563 Fcons (make_number (WINDOW_BOTTOM_EDGE_LINE (w)),
564 Qnil))));
7ab12479
JB
565}
566
c99a9eb3
RS
567DEFUN ("window-pixel-edges", Fwindow_pixel_edges, Swindow_pixel_edges, 0, 1, 0,
568 doc: /* Return a list of the edge pixel coordinates of WINDOW.
b35ac83e
CY
569The list has the form (LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at
570the top left corner of the frame.
571
572RIGHT is one more than the rightmost x position occupied by WINDOW.
573BOTTOM is one more than the bottommost y position occupied by WINDOW.
574The pixel edges include the space used by WINDOW's scroll bar, display
575margins, fringes, header line, and/or mode line. For the pixel edges
576of just the text area, use `window-inside-pixel-edges'. */)
5842a27b 577 (Lisp_Object window)
c99a9eb3 578{
6b61353c 579 register struct window *w = decode_any_window (window);
c99a9eb3
RS
580
581 return Fcons (make_number (WINDOW_LEFT_EDGE_X (w)),
582 Fcons (make_number (WINDOW_TOP_EDGE_Y (w)),
583 Fcons (make_number (WINDOW_RIGHT_EDGE_X (w)),
584 Fcons (make_number (WINDOW_BOTTOM_EDGE_Y (w)),
585 Qnil))));
586}
587
9d5405ec
J
588static void
589calc_absolute_offset(struct window *w, int *add_x, int *add_y)
590{
591 struct frame *f = XFRAME (w->frame);
592 *add_y = f->top_pos;
593#ifdef FRAME_MENUBAR_HEIGHT
594 *add_y += FRAME_MENUBAR_HEIGHT (f);
595#endif
bfeabdc3
JD
596#ifdef FRAME_TOOLBAR_TOP_HEIGHT
597 *add_y += FRAME_TOOLBAR_TOP_HEIGHT (f);
598#elif FRAME_TOOLBAR_HEIGHT
9d5405ec
J
599 *add_y += FRAME_TOOLBAR_HEIGHT (f);
600#endif
601#ifdef FRAME_NS_TITLEBAR_HEIGHT
602 *add_y += FRAME_NS_TITLEBAR_HEIGHT (f);
603#endif
604 *add_x = f->left_pos;
bfeabdc3
JD
605#ifdef FRAME_TOOLBAR_LEFT_WIDTH
606 *add_x += FRAME_TOOLBAR_LEFT_WIDTH (f);
607#endif
9d5405ec
J
608}
609
610DEFUN ("window-absolute-pixel-edges", Fwindow_absolute_pixel_edges,
611 Swindow_absolute_pixel_edges, 0, 1, 0,
612 doc: /* Return a list of the edge pixel coordinates of WINDOW.
613The list has the form (LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at
614the top left corner of the display.
615
616RIGHT is one more than the rightmost x position occupied by WINDOW.
617BOTTOM is one more than the bottommost y position occupied by WINDOW.
618The pixel edges include the space used by WINDOW's scroll bar, display
619margins, fringes, header line, and/or mode line. For the pixel edges
c49d071a 620of just the text area, use `window-inside-absolute-pixel-edges'. */)
5842a27b 621 (Lisp_Object window)
9d5405ec
J
622{
623 register struct window *w = decode_any_window (window);
624 int add_x, add_y;
ed3751c8 625 calc_absolute_offset (w, &add_x, &add_y);
9d5405ec
J
626
627 return Fcons (make_number (WINDOW_LEFT_EDGE_X (w) + add_x),
628 Fcons (make_number (WINDOW_TOP_EDGE_Y (w) + add_y),
629 Fcons (make_number (WINDOW_RIGHT_EDGE_X (w) + add_x),
630 Fcons (make_number (WINDOW_BOTTOM_EDGE_Y (w) + add_y),
631 Qnil))));
632}
633
c99a9eb3
RS
634DEFUN ("window-inside-edges", Fwindow_inside_edges, Swindow_inside_edges, 0, 1, 0,
635 doc: /* Return a list of the edge coordinates of WINDOW.
b35ac83e
CY
636The list has the form (LEFT TOP RIGHT BOTTOM).
637TOP and BOTTOM count by lines, and LEFT and RIGHT count by columns,
638all relative to 0, 0 at top left corner of frame.
639
640RIGHT is one more than the rightmost column of WINDOW's text area.
641BOTTOM is one more than the bottommost row of WINDOW's text area.
642The inside edges do not include the space used by the WINDOW's scroll
643bar, display margins, fringes, header line, and/or mode line. */)
5842a27b 644 (Lisp_Object window)
c99a9eb3 645{
6b61353c 646 register struct window *w = decode_any_window (window);
c99a9eb3
RS
647
648 return list4 (make_number (WINDOW_BOX_LEFT_EDGE_COL (w)
649 + WINDOW_LEFT_MARGIN_COLS (w)
650 + WINDOW_LEFT_FRINGE_COLS (w)),
651 make_number (WINDOW_TOP_EDGE_LINE (w)
652 + WINDOW_HEADER_LINE_LINES (w)),
f3fbdb1f 653 make_number (WINDOW_BOX_RIGHT_EDGE_COL (w)
c99a9eb3
RS
654 - WINDOW_RIGHT_MARGIN_COLS (w)
655 - WINDOW_RIGHT_FRINGE_COLS (w)),
656 make_number (WINDOW_BOTTOM_EDGE_LINE (w)
657 - WINDOW_MODE_LINE_LINES (w)));
658}
659
660DEFUN ("window-inside-pixel-edges", Fwindow_inside_pixel_edges, Swindow_inside_pixel_edges, 0, 1, 0,
a0a37a6f 661 doc: /* Return a list of the edge pixel coordinates of WINDOW.
b35ac83e
CY
662The list has the form (LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at
663the top left corner of the frame.
664
665RIGHT is one more than the rightmost x position of WINDOW's text area.
666BOTTOM is one more than the bottommost y position of WINDOW's text area.
667The inside edges do not include the space used by WINDOW's scroll bar,
c99a9eb3 668display margins, fringes, header line, and/or mode line. */)
5842a27b 669 (Lisp_Object window)
c99a9eb3 670{
6b61353c 671 register struct window *w = decode_any_window (window);
c99a9eb3
RS
672
673 return list4 (make_number (WINDOW_BOX_LEFT_EDGE_X (w)
674 + WINDOW_LEFT_MARGIN_WIDTH (w)
675 + WINDOW_LEFT_FRINGE_WIDTH (w)),
676 make_number (WINDOW_TOP_EDGE_Y (w)
677 + WINDOW_HEADER_LINE_HEIGHT (w)),
f3fbdb1f 678 make_number (WINDOW_BOX_RIGHT_EDGE_X (w)
c99a9eb3
RS
679 - WINDOW_RIGHT_MARGIN_WIDTH (w)
680 - WINDOW_RIGHT_FRINGE_WIDTH (w)),
681 make_number (WINDOW_BOTTOM_EDGE_Y (w)
682 - WINDOW_MODE_LINE_HEIGHT (w)));
683}
684
9d5405ec
J
685DEFUN ("window-inside-absolute-pixel-edges",
686 Fwindow_inside_absolute_pixel_edges,
687 Swindow_inside_absolute_pixel_edges, 0, 1, 0,
688 doc: /* Return a list of the edge pixel coordinates of WINDOW.
689The list has the form (LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at
690the top left corner of the display.
691
692RIGHT is one more than the rightmost x position of WINDOW's text area.
693BOTTOM is one more than the bottommost y position of WINDOW's text area.
694The inside edges do not include the space used by WINDOW's scroll bar,
695display margins, fringes, header line, and/or mode line. */)
5842a27b 696 (Lisp_Object window)
9d5405ec
J
697{
698 register struct window *w = decode_any_window (window);
699 int add_x, add_y;
ed3751c8 700 calc_absolute_offset (w, &add_x, &add_y);
9d5405ec
J
701
702 return list4 (make_number (WINDOW_BOX_LEFT_EDGE_X (w)
703 + WINDOW_LEFT_MARGIN_WIDTH (w)
704 + WINDOW_LEFT_FRINGE_WIDTH (w) + add_x),
705 make_number (WINDOW_TOP_EDGE_Y (w)
706 + WINDOW_HEADER_LINE_HEIGHT (w) + add_y),
707 make_number (WINDOW_BOX_RIGHT_EDGE_X (w)
708 - WINDOW_RIGHT_MARGIN_WIDTH (w)
709 - WINDOW_RIGHT_FRINGE_WIDTH (w) + add_x),
710 make_number (WINDOW_BOTTOM_EDGE_Y (w)
711 - WINDOW_MODE_LINE_HEIGHT (w) + add_y));
712}
713
9173a8fb 714/* Test if the character at column X, row Y is within window W.
341f3858 715 If it is not, return ON_NOTHING;
9173a8fb 716 if it is in the window's text area, return ON_TEXT;
341f3858 717 if it is on the window's modeline, return ON_MODE_LINE;
d5783c40 718 if it is on the border between the window and its right sibling,
341f3858 719 return ON_VERTICAL_BORDER.
9173a8fb 720 if it is on a scroll bar, return ON_SCROLL_BAR.
341f3858 721 if it is on the window's top line, return ON_HEADER_LINE;
81d189fd 722 if it is in left or right fringe of the window,
9173a8fb 723 return ON_LEFT_FRINGE or ON_RIGHT_FRINGE;
49b996e7 724 if it is in the marginal area to the left/right of the window,
9173a8fb 725 return ON_LEFT_MARGIN or ON_RIGHT_MARGIN.
5500c422
GM
726
727 X and Y are frame relative pixel coordinates. */
728
7442878f 729static enum window_part
9173a8fb 730coordinates_in_window (register struct window *w, int x, int y)
d5783c40 731{
b0228ace 732 struct frame *f = XFRAME (WINDOW_FRAME (w));
9173a8fb 733 int left_x, right_x;
7442878f 734 enum window_part part;
949cf20f
KS
735 int ux = FRAME_COLUMN_WIDTH (f);
736 int x0 = WINDOW_LEFT_EDGE_X (w);
737 int x1 = WINDOW_RIGHT_EDGE_X (w);
dad75588
GM
738 /* The width of the area where the vertical line can be dragged.
739 (Between mode lines for instance. */
740 int grabbable_width = ux;
949cf20f 741 int lmargin_width, rmargin_width, text_left, text_right;
9173a8fb
CY
742 int top_y = WINDOW_TOP_EDGE_Y (w);
743 int bottom_y = WINDOW_BOTTOM_EDGE_Y (w);
744
745 /* Outside any interesting row? */
746 if (y < top_y || y >= bottom_y)
747 return ON_NOTHING;
b0228ace 748
466539bc
EZ
749 /* In what's below, we subtract 1 when computing right_x because we
750 want the rightmost pixel, which is given by left_pixel+width-1. */
5500c422
GM
751 if (w->pseudo_window_p)
752 {
753 left_x = 0;
949cf20f 754 right_x = WINDOW_TOTAL_WIDTH (w) - 1;
5500c422
GM
755 }
756 else
757 {
949cf20f
KS
758 left_x = WINDOW_BOX_LEFT_EDGE_X (w);
759 right_x = WINDOW_BOX_RIGHT_EDGE_X (w) - 1;
5500c422 760 }
37962e60 761
1cb794ba
GM
762 /* On the mode line or header line? If it's near the start of
763 the mode or header line of window that's has a horizontal
764 sibling, say it's on the vertical line. That's to be able
765 to resize windows horizontally in case we're using toolkit
766 scroll bars. */
b0228ace 767
1cb794ba 768 if (WINDOW_WANTS_MODELINE_P (w)
9173a8fb 769 && y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
1cb794ba 770 {
949cf20f
KS
771 part = ON_MODE_LINE;
772
773 header_vertical_border_check:
b0228ace
GM
774 /* We're somewhere on the mode line. We consider the place
775 between mode lines of horizontally adjacent mode lines
9d14503e 776 as the vertical border. If scroll bars on the left,
b0228ace 777 return the right window. */
9173a8fb
CY
778 if ((WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
779 || WINDOW_RIGHTMOST_P (w))
780 && !WINDOW_LEFTMOST_P (w)
781 && eabs (x - x0) < grabbable_width)
782 return ON_VERTICAL_BORDER;
783
784 /* Make sure we're not at the rightmost position of a
785 mode-/header-line and there's yet another window on the
786 right. (Bug#1372) */
787 else if ((WINDOW_RIGHTMOST_P (w) || x < x1)
788 && eabs (x - x1) < grabbable_width)
789 return ON_VERTICAL_BORDER;
790
791 if (x < x0 || x >= x1)
cb639b8f
KS
792 return ON_NOTHING;
793
949cf20f 794 return part;
b0228ace 795 }
949cf20f
KS
796
797 if (WINDOW_WANTS_HEADER_LINE_P (w)
9173a8fb 798 && y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
1cb794ba 799 {
949cf20f
KS
800 part = ON_HEADER_LINE;
801 goto header_vertical_border_check;
1cb794ba 802 }
949cf20f 803
9173a8fb 804 if (x < x0 || x >= x1) return ON_NOTHING;
cb639b8f 805
949cf20f 806 /* Outside any interesting column? */
9173a8fb
CY
807 if (x < left_x || x > right_x)
808 return ON_SCROLL_BAR;
949cf20f
KS
809
810 lmargin_width = window_box_width (w, LEFT_MARGIN_AREA);
811 rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA);
79fd290e 812
949cf20f
KS
813 text_left = window_box_left (w, TEXT_AREA);
814 text_right = text_left + window_box_width (w, TEXT_AREA);
815
816 if (FRAME_WINDOW_P (f))
fbad6f9a 817 {
447e9da0 818 if (!w->pseudo_window_p
949cf20f 819 && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
447e9da0 820 && !WINDOW_RIGHTMOST_P (w)
9173a8fb
CY
821 && (eabs (x - right_x) < grabbable_width))
822 return ON_VERTICAL_BORDER;
fbad6f9a 823 }
9173a8fb
CY
824 /* Need to say "x > right_x" rather than >=, since on character
825 terminals, the vertical line's x coordinate is right_x. */
826 else if (!w->pseudo_window_p
827 && !WINDOW_RIGHTMOST_P (w)
828 && x > right_x - ux)
829 return ON_VERTICAL_BORDER;
830
831 if (x < text_left)
949cf20f
KS
832 {
833 if (lmargin_width > 0
834 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
9173a8fb
CY
835 ? (x >= left_x + WINDOW_LEFT_FRINGE_WIDTH (w))
836 : (x < left_x + lmargin_width)))
837 return ON_LEFT_MARGIN;
838
949cf20f
KS
839 return ON_LEFT_FRINGE;
840 }
841
9173a8fb 842 if (x >= text_right)
949cf20f
KS
843 {
844 if (rmargin_width > 0
845 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
9173a8fb
CY
846 ? (x < right_x - WINDOW_RIGHT_FRINGE_WIDTH (w))
847 : (x >= right_x - rmargin_width)))
848 return ON_RIGHT_MARGIN;
849
949cf20f
KS
850 return ON_RIGHT_FRINGE;
851 }
852
853 /* Everything special ruled out - must be on text area */
949cf20f 854 return ON_TEXT;
d5783c40
JB
855}
856
9173a8fb
CY
857/* Take X is the frame-relative pixel x-coordinate, and return the
858 x-coordinate relative to part PART of window W. */
859int
860window_relative_x_coord (struct window *w, enum window_part part, int x)
861{
862 int left_x = (w->pseudo_window_p) ? 0 : WINDOW_BOX_LEFT_EDGE_X (w);
863
864 switch (part)
865 {
866 case ON_TEXT:
867 return x - window_box_left (w, TEXT_AREA);
868
869 case ON_LEFT_FRINGE:
870 return x - left_x;
871
872 case ON_RIGHT_FRINGE:
873 return x - left_x - WINDOW_LEFT_FRINGE_WIDTH (w);
874
875 case ON_LEFT_MARGIN:
876 return (x - left_x
877 - ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
878 ? WINDOW_LEFT_FRINGE_WIDTH (w) : 0));
879
880 case ON_RIGHT_MARGIN:
881 return (x + 1
882 - ((w->pseudo_window_p)
883 ? WINDOW_TOTAL_WIDTH (w)
884 : WINDOW_BOX_RIGHT_EDGE_X (w))
885 + window_box_width (w, RIGHT_MARGIN_AREA)
886 + ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
887 ? WINDOW_RIGHT_FRINGE_WIDTH (w) : 0));
888 }
889
890 /* ON_SCROLL_BAR, ON_NOTHING, and ON_VERTICAL_BORDER: */
891 return 0;
892}
893
b0228ace 894
d5783c40 895DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
fdb82f93
PJ
896 Scoordinates_in_window_p, 2, 2, 0,
897 doc: /* Return non-nil if COORDINATES are in WINDOW.
898COORDINATES is a cons of the form (X . Y), X and Y being distances
899measured in characters from the upper-left corner of the frame.
23fe745a 900\(0 . 0) denotes the character in the upper left corner of the
fdb82f93
PJ
901frame.
902If COORDINATES are in the text portion of WINDOW,
903 the coordinates relative to the window are returned.
904If they are in the mode line of WINDOW, `mode-line' is returned.
905If they are in the top mode line of WINDOW, `header-line' is returned.
81d189fd
KS
906If they are in the left fringe of WINDOW, `left-fringe' is returned.
907If they are in the right fringe of WINDOW, `right-fringe' is returned.
fdb82f93 908If they are on the border between WINDOW and its right sibling,
49b996e7
GM
909 `vertical-line' is returned.
910If they are in the windows's left or right marginal areas, `left-margin'\n\
911 or `right-margin' is returned. */)
5842a27b 912 (register Lisp_Object coordinates, Lisp_Object window)
d5783c40 913{
5500c422
GM
914 struct window *w;
915 struct frame *f;
d5783c40 916 int x, y;
5500c422 917 Lisp_Object lx, ly;
d5783c40 918
6b61353c 919 CHECK_WINDOW (window);
5500c422
GM
920 w = XWINDOW (window);
921 f = XFRAME (w->frame);
b7826503 922 CHECK_CONS (coordinates);
5500c422
GM
923 lx = Fcar (coordinates);
924 ly = Fcdr (coordinates);
b7826503
PJ
925 CHECK_NUMBER_OR_FLOAT (lx);
926 CHECK_NUMBER_OR_FLOAT (ly);
81159bb9
RS
927 x = FRAME_PIXEL_X_FROM_CANON_X (f, lx) + FRAME_INTERNAL_BORDER_WIDTH (f);
928 y = FRAME_PIXEL_Y_FROM_CANON_Y (f, ly) + FRAME_INTERNAL_BORDER_WIDTH (f);
5500c422 929
9173a8fb 930 switch (coordinates_in_window (w, x, y))
d5783c40 931 {
7442878f 932 case ON_NOTHING:
d5783c40
JB
933 return Qnil;
934
7442878f 935 case ON_TEXT:
9173a8fb
CY
936 /* Convert X and Y to window relative pixel coordinates, and
937 return the canonical char units. */
938 x -= window_box_left (w, TEXT_AREA);
939 y -= WINDOW_TOP_EDGE_Y (w);
949cf20f
KS
940 return Fcons (FRAME_CANON_X_FROM_PIXEL_X (f, x),
941 FRAME_CANON_Y_FROM_PIXEL_Y (f, y));
d5783c40 942
7442878f 943 case ON_MODE_LINE:
d5783c40 944 return Qmode_line;
37962e60 945
7442878f 946 case ON_VERTICAL_BORDER:
e5d77022 947 return Qvertical_line;
d5783c40 948
7442878f 949 case ON_HEADER_LINE:
045dee35 950 return Qheader_line;
5500c422 951
7442878f
GM
952 case ON_LEFT_FRINGE:
953 return Qleft_fringe;
177c0ea7 954
7442878f
GM
955 case ON_RIGHT_FRINGE:
956 return Qright_fringe;
fbad6f9a 957
49b996e7
GM
958 case ON_LEFT_MARGIN:
959 return Qleft_margin;
177c0ea7 960
49b996e7
GM
961 case ON_RIGHT_MARGIN:
962 return Qright_margin;
963
6487f669
RS
964 case ON_SCROLL_BAR:
965 /* Historically we are supposed to return nil in this case. */
966 return Qnil;
967
d5783c40
JB
968 default:
969 abort ();
970 }
971}
972
67492200
GM
973
974/* Callback for foreach_window, used in window_from_coordinates.
f95464e4
GM
975 Check if window W contains coordinates specified by USER_DATA which
976 is actually a pointer to a struct check_window_data CW.
977
978 Check if window W contains coordinates *CW->x and *CW->y. If it
979 does, return W in *CW->window, as Lisp_Object, and return in
5372262f 980 *CW->part the part of the window under coordinates *X,*Y. Return
f95464e4
GM
981 zero from this function to stop iterating over windows. */
982
983struct check_window_data
984{
985 Lisp_Object *window;
9173a8fb 986 int x, y;
341f3858 987 enum window_part *part;
f95464e4 988};
67492200
GM
989
990static int
971de7fb 991check_window_containing (struct window *w, void *user_data)
67492200 992{
f95464e4 993 struct check_window_data *cw = (struct check_window_data *) user_data;
7442878f
GM
994 enum window_part found;
995 int continue_p = 1;
67492200 996
f95464e4 997 found = coordinates_in_window (w, cw->x, cw->y);
7442878f 998 if (found != ON_NOTHING)
67492200 999 {
341f3858 1000 *cw->part = found;
f95464e4 1001 XSETWINDOW (*cw->window, w);
7442878f 1002 continue_p = 0;
67492200 1003 }
177c0ea7 1004
7442878f 1005 return continue_p;
67492200
GM
1006}
1007
1008
5500c422 1009/* Find the window containing frame-relative pixel position X/Y and
949cf20f
KS
1010 return it as a Lisp_Object.
1011
1012 If X, Y is on one of the window's special `window_part' elements,
9173a8fb 1013 set *PART to the id of that element.
949cf20f 1014
341f3858 1015 If there is no window under X, Y return nil and leave *PART
67492200
GM
1016 unmodified. TOOL_BAR_P non-zero means detect tool-bar windows.
1017
1018 This function was previously implemented with a loop cycling over
1019 windows with Fnext_window, and starting with the frame's selected
1020 window. It turned out that this doesn't work with an
1021 implementation of next_window using Vwindow_list, because
1022 FRAME_SELECTED_WINDOW (F) is not always contained in the window
1023 tree of F when this function is called asynchronously from
1024 note_mouse_highlight. The original loop didn't terminate in this
1025 case. */
5500c422 1026
7ab12479 1027Lisp_Object
9173a8fb
CY
1028window_from_coordinates (struct frame *f, int x, int y,
1029 enum window_part *part, int tool_bar_p)
7ab12479 1030{
67492200 1031 Lisp_Object window;
f95464e4 1032 struct check_window_data cw;
341f3858
KS
1033 enum window_part dummy;
1034
1035 if (part == 0)
1036 part = &dummy;
5500c422 1037
67492200 1038 window = Qnil;
9173a8fb 1039 cw.window = &window, cw.x = x, cw.y = y; cw.part = part;
f95464e4 1040 foreach_window (f, check_window_containing, &cw);
177c0ea7 1041
67492200
GM
1042 /* If not found above, see if it's in the tool bar window, if a tool
1043 bar exists. */
1044 if (NILP (window)
1045 && tool_bar_p
1046 && WINDOWP (f->tool_bar_window)
949cf20f 1047 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0
9173a8fb 1048 && (coordinates_in_window (XWINDOW (f->tool_bar_window), x, y)
7442878f 1049 != ON_NOTHING))
5500c422 1050 {
341f3858 1051 *part = ON_TEXT;
67492200 1052 window = f->tool_bar_window;
5500c422 1053 }
37962e60 1054
67492200 1055 return window;
7ab12479
JB
1056}
1057
ab17c3f2 1058DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
fdb82f93
PJ
1059 doc: /* Return window containing coordinates X and Y on FRAME.
1060If omitted, FRAME defaults to the currently selected frame.
1061The top left corner of the frame is considered to be row 0,
1062column 0. */)
5842a27b 1063 (Lisp_Object x, Lisp_Object y, Lisp_Object frame)
7ab12479 1064{
5500c422 1065 struct frame *f;
7ab12479 1066
44fa5b1e 1067 if (NILP (frame))
1ae1a37d 1068 frame = selected_frame;
b7826503 1069 CHECK_LIVE_FRAME (frame);
5500c422 1070 f = XFRAME (frame);
7ab12479 1071
5500c422 1072 /* Check that arguments are integers or floats. */
b7826503
PJ
1073 CHECK_NUMBER_OR_FLOAT (x);
1074 CHECK_NUMBER_OR_FLOAT (y);
5500c422 1075
177c0ea7 1076 return window_from_coordinates (f,
2c77cf3b
RS
1077 (FRAME_PIXEL_X_FROM_CANON_X (f, x)
1078 + FRAME_INTERNAL_BORDER_WIDTH (f)),
1079 (FRAME_PIXEL_Y_FROM_CANON_Y (f, y)
1080 + FRAME_INTERNAL_BORDER_WIDTH (f)),
9173a8fb 1081 0, 0);
7ab12479
JB
1082}
1083
1084DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
fdb82f93 1085 doc: /* Return current value of point in WINDOW.
c85322d0
EZ
1086WINDOW defaults to the selected window.
1087
fdb82f93
PJ
1088For a nonselected window, this is the value point would have
1089if that window were selected.
1090
1091Note that, when WINDOW is the selected window and its buffer
1092is also currently selected, the value returned is the same as (point).
1093It would be more strictly correct to return the `top-level' value
1094of point, outside of any save-excursion forms.
1095But that is hard to define. */)
5842a27b 1096 (Lisp_Object window)
7ab12479
JB
1097{
1098 register struct window *w = decode_window (window);
1099
1100 if (w == XWINDOW (selected_window)
1101 && current_buffer == XBUFFER (w->buffer))
1102 return Fpoint ();
1103 return Fmarker_position (w->pointm);
1104}
1105
1106DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
fdb82f93 1107 doc: /* Return position at which display currently starts in WINDOW.
c85322d0 1108WINDOW defaults to the selected window.
fdb82f93 1109This is updated by redisplay or by calling `set-window-start'. */)
5842a27b 1110 (Lisp_Object window)
7ab12479
JB
1111{
1112 return Fmarker_position (decode_window (window)->start);
1113}
1114
8646118f
RS
1115/* This is text temporarily removed from the doc string below.
1116
fdb82f93
PJ
1117This function returns nil if the position is not currently known.
1118That happens when redisplay is preempted and doesn't finish.
1119If in that case you want to compute where the end of the window would
1120have been if redisplay had finished, do this:
1121 (save-excursion
1122 (goto-char (window-start window))
1123 (vertical-motion (1- (window-height window)) window)
8646118f
RS
1124 (point))") */
1125
478292ed 1126DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
fdb82f93 1127 doc: /* Return position at which display currently ends in WINDOW.
c85322d0 1128WINDOW defaults to the selected window.
fdb82f93
PJ
1129This is updated by redisplay, when it runs to completion.
1130Simply changing the buffer text or setting `window-start'
1131does not update this value.
a0a37a6f
LT
1132Return nil if there is no recorded value. \(This can happen if the
1133last redisplay of WINDOW was preempted, and did not finish.)
fdb82f93
PJ
1134If UPDATE is non-nil, compute the up-to-date position
1135if it isn't already recorded. */)
5842a27b 1136 (Lisp_Object window, Lisp_Object update)
7ab12479
JB
1137{
1138 Lisp_Object value;
1139 struct window *w = decode_window (window);
5a41ab94 1140 Lisp_Object buf;
31790df3 1141 struct buffer *b;
5a41ab94
RS
1142
1143 buf = w->buffer;
b7826503 1144 CHECK_BUFFER (buf);
b3a10345 1145 b = XBUFFER (buf);
5a41ab94 1146
8646118f 1147#if 0 /* This change broke some things. We should make it later. */
7250968e
RS
1148 /* If we don't know the end position, return nil.
1149 The user can compute it with vertical-motion if he wants to.
1150 It would be nicer to do it automatically,
1151 but that's so slow that it would probably bother people. */
1152 if (NILP (w->window_end_valid))
1153 return Qnil;
8646118f 1154#endif
7250968e 1155
478292ed
RS
1156 if (! NILP (update)
1157 && ! (! NILP (w->window_end_valid)
dfc265a3 1158 && XFASTINT (w->last_modified) >= BUF_MODIFF (b)
4c9564e8 1159 && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (b))
41791a20 1160 && !noninteractive)
478292ed 1161 {
cbc099e5
GM
1162 struct text_pos startp;
1163 struct it it;
b3a10345
KS
1164 struct buffer *old_buffer = NULL;
1165
1166 /* Cannot use Fvertical_motion because that function doesn't
1167 cope with variable-height lines. */
1168 if (b != current_buffer)
1169 {
1170 old_buffer = current_buffer;
1171 set_buffer_internal (b);
1172 }
2d6d9df0
GM
1173
1174 /* In case W->start is out of the range, use something
cb795ec4 1175 reasonable. This situation occurred when loading a file with
2d6d9df0
GM
1176 `-l' containing a call to `rmail' with subsequent other
1177 commands. At the end, W->start happened to be BEG, while
cbc099e5 1178 rmail had already narrowed the buffer. */
2d6d9df0 1179 if (XMARKER (w->start)->charpos < BEGV)
cbc099e5 1180 SET_TEXT_POS (startp, BEGV, BEGV_BYTE);
2d6d9df0 1181 else if (XMARKER (w->start)->charpos > ZV)
cbc099e5 1182 SET_TEXT_POS (startp, ZV, ZV_BYTE);
2d6d9df0 1183 else
cbc099e5
GM
1184 SET_TEXT_POS_FROM_MARKER (startp, w->start);
1185
cbc099e5
GM
1186 start_display (&it, w, startp);
1187 move_it_vertically (&it, window_box_height (w));
c3c45f65
GM
1188 if (it.current_y < it.last_visible_y)
1189 move_it_past_eol (&it);
cbc099e5 1190 value = make_number (IT_CHARPOS (it));
177c0ea7 1191
99593a9d
GM
1192 if (old_buffer)
1193 set_buffer_internal (old_buffer);
478292ed
RS
1194 }
1195 else
b3a10345 1196 XSETINT (value, BUF_Z (b) - XFASTINT (w->window_end_pos));
7ab12479
JB
1197
1198 return value;
1199}
1200
16a97296 1201DEFUE ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
a0a37a6f
LT
1202 doc: /* Make point value in WINDOW be at position POS in WINDOW's buffer.
1203Return POS. */)
5842a27b 1204 (Lisp_Object window, Lisp_Object pos)
7ab12479
JB
1205{
1206 register struct window *w = decode_window (window);
1207
b7826503 1208 CHECK_NUMBER_COERCE_MARKER (pos);
e90c4fe6
RS
1209 if (w == XWINDOW (selected_window)
1210 && XBUFFER (w->buffer) == current_buffer)
7ab12479
JB
1211 Fgoto_char (pos);
1212 else
1213 set_marker_restricted (w->pointm, pos, w->buffer);
799417bd 1214
0685cb3c
GM
1215 /* We have to make sure that redisplay updates the window to show
1216 the new value of point. */
1217 if (!EQ (window, selected_window))
799417bd 1218 ++windows_or_buffers_changed;
177c0ea7 1219
7ab12479
JB
1220 return pos;
1221}
1222
1223DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
fdb82f93 1224 doc: /* Make display in WINDOW start at position POS in WINDOW's buffer.
d653c8cc
MR
1225WINDOW defaults to the selected window. Return POS.
1226Optional third arg NOFORCE non-nil inhibits next redisplay from
1227overriding motion of point in order to display at this exact start. */)
5842a27b 1228 (Lisp_Object window, Lisp_Object pos, Lisp_Object noforce)
7ab12479
JB
1229{
1230 register struct window *w = decode_window (window);
1231
b7826503 1232 CHECK_NUMBER_COERCE_MARKER (pos);
7ab12479
JB
1233 set_marker_restricted (w->start, pos, w->buffer);
1234 /* this is not right, but much easier than doing what is right. */
1235 w->start_at_line_beg = Qnil;
265a9e55 1236 if (NILP (noforce))
7ab12479
JB
1237 w->force_start = Qt;
1238 w->update_mode_line = Qt;
d834a2e9 1239 XSETFASTINT (w->last_modified, 0);
3cd21523 1240 XSETFASTINT (w->last_overlay_modified, 0);
62c07cc7
JB
1241 if (!EQ (window, selected_window))
1242 windows_or_buffers_changed++;
ce7fae7d 1243
7ab12479
JB
1244 return pos;
1245}
1246
d653c8cc 1247
16a97296 1248DEFUE ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
d653c8cc
MR
1249 0, 1, 0,
1250 doc: /* Return non-nil when WINDOW is dedicated to its buffer.
12bb3111 1251More precisely, return the value assigned by the last call of
7bfac547
MR
1252`set-window-dedicated-p' for WINDOW. Return nil if that function was
1253never called with WINDOW as its argument, or the value set by that
1254function was internally reset since its last call. WINDOW defaults to
1255the selected window.
1256
1257When a window is dedicated to its buffer, `display-buffer' will refrain
1258from displaying another buffer in it. `get-lru-window' and
1259`get-largest-window' treat dedicated windows specially.
1260`delete-windows-on', `replace-buffer-in-windows', `quit-window' and
1261`kill-buffer' can delete a dedicated window and the containing frame.
1262
1263Functions like `set-window-buffer' may change the buffer displayed by a
1264window, unless that window is "strongly" dedicated to its buffer, that
1265is the value returned by `window-dedicated-p' is t. */)
5842a27b 1266 (Lisp_Object window)
7ab12479
JB
1267{
1268 return decode_window (window)->dedicated;
1269}
1270
d207b766
RS
1271DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p,
1272 Sset_window_dedicated_p, 2, 2, 0,
d653c8cc
MR
1273 doc: /* Mark WINDOW as dedicated according to FLAG.
1274WINDOW defaults to the selected window. FLAG non-nil means mark WINDOW
12bb3111 1275as dedicated to its buffer. FLAG nil means mark WINDOW as non-dedicated.
d653c8cc
MR
1276Return FLAG.
1277
7bfac547
MR
1278When a window is dedicated to its buffer, `display-buffer' will refrain
1279from displaying another buffer in it. `get-lru-window' and
1280`get-largest-window' treat dedicated windows specially.
1281`delete-windows-on', `replace-buffer-in-windows', `quit-window' and
1282`kill-buffer' can delete a dedicated window and the containing
1283frame.
1284
1285As a special case, if FLAG is t, mark WINDOW as "strongly" dedicated to
1286its buffer. Functions like `set-window-buffer' may change the buffer
1287displayed by a window, unless that window is strongly dedicated to its
1288buffer. If and when `set-window-buffer' displays another buffer in a
1289window, it also makes sure that the window is not marked as dedicated. */)
5842a27b 1290 (Lisp_Object window, Lisp_Object flag)
7ab12479
JB
1291{
1292 register struct window *w = decode_window (window);
1293
d653c8cc 1294 w->dedicated = flag;
7ab12479
JB
1295 return w->dedicated;
1296}
1297
d653c8cc 1298
cfbb2395
JB
1299DEFUN ("window-parameters", Fwindow_parameters, Swindow_parameters,
1300 0, 1, 0,
d653c8cc
MR
1301 doc: /* Return the parameters of WINDOW and their values.
1302WINDOW defaults to the selected window. The return value is a list of
1303elements of the form (PARAMETER . VALUE). */)
5842a27b 1304 (Lisp_Object window)
cfbb2395 1305{
927abf37 1306 return Fcopy_alist (decode_window (window)->window_parameters);
cfbb2395
JB
1307}
1308
1309DEFUN ("window-parameter", Fwindow_parameter, Swindow_parameter,
1310 2, 2, 0,
d653c8cc
MR
1311 doc: /* Return WINDOW's value for PARAMETER.
1312WINDOW defaults to the selected window. */)
5842a27b 1313 (Lisp_Object window, Lisp_Object parameter)
cfbb2395 1314{
927abf37
JB
1315 Lisp_Object result;
1316
1317 result = Fassq (parameter, decode_window (window)->window_parameters);
1318 return CDR_SAFE (result);
cfbb2395
JB
1319}
1320
cfbb2395
JB
1321DEFUN ("set-window-parameter", Fset_window_parameter,
1322 Sset_window_parameter, 3, 3, 0,
d653c8cc
MR
1323 doc: /* Set WINDOW's value of PARAMETER to VALUE.
1324WINDOW defaults to the selected window. Return VALUE. */)
5842a27b 1325 (Lisp_Object window, Lisp_Object parameter, Lisp_Object value)
cfbb2395
JB
1326{
1327 register struct window *w = decode_window (window);
1328 Lisp_Object old_alist_elt;
1329
1330 old_alist_elt = Fassq (parameter, w->window_parameters);
12bb3111 1331 if (NILP (old_alist_elt))
cfbb2395
JB
1332 w->window_parameters = Fcons (Fcons (parameter, value), w->window_parameters);
1333 else
1334 Fsetcdr (old_alist_elt, value);
927abf37 1335 return value;
cfbb2395
JB
1336}
1337
1338
7ab12479
JB
1339DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
1340 0, 1, 0,
c85322d0
EZ
1341 doc: /* Return the display-table that WINDOW is using.
1342WINDOW defaults to the selected window. */)
5842a27b 1343 (Lisp_Object window)
7ab12479
JB
1344{
1345 return decode_window (window)->display_table;
1346}
1347
5500c422
GM
1348/* Get the display table for use on window W. This is either W's
1349 display table or W's buffer's display table. Ignore the specified
1350 tables if they are not valid; if no valid table is specified,
1351 return 0. */
7ab12479 1352
319315f1 1353struct Lisp_Char_Table *
971de7fb 1354window_display_table (struct window *w)
7ab12479 1355{
c756cdbe
GM
1356 struct Lisp_Char_Table *dp = NULL;
1357
1358 if (DISP_TABLE_P (w->display_table))
1359 dp = XCHAR_TABLE (w->display_table);
1360 else if (BUFFERP (w->buffer))
1361 {
1362 struct buffer *b = XBUFFER (w->buffer);
177c0ea7 1363
4b4deea2
TT
1364 if (DISP_TABLE_P (BVAR (b, display_table)))
1365 dp = XCHAR_TABLE (BVAR (b, display_table));
c756cdbe
GM
1366 else if (DISP_TABLE_P (Vstandard_display_table))
1367 dp = XCHAR_TABLE (Vstandard_display_table);
1368 }
171d003c 1369
c756cdbe 1370 return dp;
7ab12479
JB
1371}
1372
3a2712f9 1373DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_display_table, 2, 2, 0,
fdb82f93 1374 doc: /* Set WINDOW's display-table to TABLE. */)
5842a27b 1375 (register Lisp_Object window, Lisp_Object table)
7ab12479
JB
1376{
1377 register struct window *w;
7ab12479
JB
1378
1379 w = decode_window (window);
1380 w->display_table = table;
1381 return table;
1382}
1383\f
2f7c71a1
AS
1384static void delete_window (Lisp_Object);
1385
7ab12479
JB
1386/* Record info on buffer window w is displaying
1387 when it is about to cease to display that buffer. */
dfcf069d 1388static void
971de7fb 1389unshow_buffer (register struct window *w)
7ab12479 1390{
12cae7c0 1391 Lisp_Object buf;
b73ea88e 1392 struct buffer *b;
7ab12479 1393
12cae7c0 1394 buf = w->buffer;
b73ea88e
RS
1395 b = XBUFFER (buf);
1396 if (b != XMARKER (w->pointm)->buffer)
7ab12479
JB
1397 abort ();
1398
573f41ab 1399#if 0
7ab12479
JB
1400 if (w == XWINDOW (selected_window)
1401 || ! EQ (buf, XWINDOW (selected_window)->buffer))
1402 /* Do this except when the selected window's buffer
1403 is being removed from some other window. */
573f41ab
RS
1404#endif
1405 /* last_window_start records the start position that this buffer
1406 had in the last window to be disconnected from it.
1407 Now that this statement is unconditional,
1408 it is possible for the buffer to be displayed in the
1409 selected window, while last_window_start reflects another
1410 window which was recently showing the same buffer.
1411 Some people might say that might be a good thing. Let's see. */
b73ea88e 1412 b->last_window_start = marker_position (w->start);
7ab12479
JB
1413
1414 /* Point in the selected window's buffer
1415 is actually stored in that buffer, and the window's pointm isn't used.
1416 So don't clobber point in that buffer. */
719eaeb1
GM
1417 if (! EQ (buf, XWINDOW (selected_window)->buffer)
1418 /* This line helps to fix Horsley's testbug.el bug. */
4b4deea2
TT
1419 && !(WINDOWP (BVAR (b, last_selected_window))
1420 && w != XWINDOW (BVAR (b, last_selected_window))
1421 && EQ (buf, XWINDOW (BVAR (b, last_selected_window))->buffer)))
b73ea88e
RS
1422 temp_set_point_both (b,
1423 clip_to_bounds (BUF_BEGV (b),
1424 XMARKER (w->pointm)->charpos,
1425 BUF_ZV (b)),
1426 clip_to_bounds (BUF_BEGV_BYTE (b),
1427 marker_byte_position (w->pointm),
1428 BUF_ZV_BYTE (b)));
177c0ea7 1429
4b4deea2
TT
1430 if (WINDOWP (BVAR (b, last_selected_window))
1431 && w == XWINDOW (BVAR (b, last_selected_window)))
1432 BVAR (b, last_selected_window) = Qnil;
7ab12479
JB
1433}
1434
1435/* Put replacement into the window structure in place of old. */
dfcf069d 1436static void
971de7fb 1437replace_window (Lisp_Object old, Lisp_Object replacement)
7ab12479
JB
1438{
1439 register Lisp_Object tem;
1440 register struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
1441
44fa5b1e
JB
1442 /* If OLD is its frame's root_window, then replacement is the new
1443 root_window for that frame. */
7ab12479 1444
7f4161e0 1445 if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
44fa5b1e 1446 FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
7ab12479 1447
949cf20f
KS
1448 p->left_col = o->left_col;
1449 p->top_line = o->top_line;
1450 p->total_cols = o->total_cols;
1451 p->total_lines = o->total_lines;
5500c422
GM
1452 p->desired_matrix = p->current_matrix = 0;
1453 p->vscroll = 0;
72af86bd
AS
1454 memset (&p->cursor, 0, sizeof (p->cursor));
1455 memset (&p->last_cursor, 0, sizeof (p->last_cursor));
1456 memset (&p->phys_cursor, 0, sizeof (p->phys_cursor));
5500c422 1457 p->phys_cursor_type = -1;
4b26579e 1458 p->phys_cursor_width = -1;
5500c422
GM
1459 p->must_be_updated_p = 0;
1460 p->pseudo_window_p = 0;
1461 XSETFASTINT (p->window_end_vpos, 0);
1462 XSETFASTINT (p->window_end_pos, 0);
1463 p->window_end_valid = Qnil;
7bbb5782 1464 p->frozen_window_start_p = 0;
949cf20f 1465 p->orig_top_line = p->orig_total_lines = Qnil;
7ab12479
JB
1466
1467 p->next = tem = o->next;
265a9e55 1468 if (!NILP (tem))
7ab12479
JB
1469 XWINDOW (tem)->prev = replacement;
1470
1471 p->prev = tem = o->prev;
265a9e55 1472 if (!NILP (tem))
7ab12479
JB
1473 XWINDOW (tem)->next = replacement;
1474
1475 p->parent = tem = o->parent;
265a9e55 1476 if (!NILP (tem))
7ab12479
JB
1477 {
1478 if (EQ (XWINDOW (tem)->vchild, old))
1479 XWINDOW (tem)->vchild = replacement;
1480 if (EQ (XWINDOW (tem)->hchild, old))
1481 XWINDOW (tem)->hchild = replacement;
1482 }
1483
1484/*** Here, if replacement is a vertical combination
1485and so is its new parent, we should make replacement's
1486children be children of that parent instead. ***/
1487}
1488
16a97296 1489DEFUE ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
8fef9de1
MR
1490 doc: /* Remove WINDOW from its frame.
1491WINDOW defaults to the selected window. Return nil.
1492Signal an error when WINDOW is the only window on its frame. */)
5842a27b 1493 (register Lisp_Object window)
543f5fb1 1494{
eeca6f6f
SM
1495 struct frame *f;
1496 if (NILP (window))
1497 window = selected_window;
dbf64827
JB
1498 else
1499 CHECK_LIVE_WINDOW (window);
1500
eeca6f6f 1501 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
543f5fb1
RS
1502 delete_window (window);
1503
eeca6f6f 1504 run_window_configuration_change_hook (f);
543f5fb1
RS
1505
1506 return Qnil;
1507}
1508
2f7c71a1 1509static void
971de7fb 1510delete_window (register Lisp_Object window)
7ab12479
JB
1511{
1512 register Lisp_Object tem, parent, sib;
1513 register struct window *p;
1514 register struct window *par;
951f9df5 1515 struct frame *f;
7ab12479 1516
605be8af
JB
1517 /* Because this function is called by other C code on non-leaf
1518 windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
1519 so we can't decode_window here. */
eeca6f6f 1520 CHECK_WINDOW (window);
7ab12479 1521 p = XWINDOW (window);
605be8af 1522
0d384044 1523 /* It's a no-op to delete an already-deleted window. */
605be8af
JB
1524 if (NILP (p->buffer)
1525 && NILP (p->hchild)
1526 && NILP (p->vchild))
296b535c 1527 return;
605be8af 1528
7ab12479 1529 parent = p->parent;
265a9e55 1530 if (NILP (parent))
7ab12479
JB
1531 error ("Attempt to delete minibuffer or sole ordinary window");
1532 par = XWINDOW (parent);
1533
1534 windows_or_buffers_changed++;
67492200 1535 Vwindow_list = Qnil;
951f9df5
GM
1536 f = XFRAME (WINDOW_FRAME (p));
1537 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
7ab12479 1538
605be8af
JB
1539 /* Are we trying to delete any frame's selected window? */
1540 {
192c3131 1541 Lisp_Object swindow, pwindow;
605be8af 1542
0def0403
RS
1543 /* See if the frame's selected window is either WINDOW
1544 or any subwindow of it, by finding all that window's parents
1545 and comparing each one with WINDOW. */
192c3131 1546 swindow = FRAME_SELECTED_WINDOW (f);
0def0403 1547
192c3131 1548 while (1)
0def0403 1549 {
192c3131
RS
1550 pwindow = swindow;
1551 while (!NILP (pwindow))
1552 {
1553 if (EQ (window, pwindow))
1554 break;
1555 pwindow = XWINDOW (pwindow)->parent;
1556 }
1557
1558 /* If the window being deleted is not a parent of SWINDOW,
1559 then SWINDOW is ok as the new selected window. */
1560 if (!EQ (window, pwindow))
0def0403 1561 break;
192c3131 1562 /* Otherwise, try another window for SWINDOW. */
3b8c0c70 1563 swindow = Fnext_window (swindow, Qlambda, Qnil);
192c3131
RS
1564
1565 /* If we get back to the frame's selected window,
1566 it means there was no acceptable alternative,
1567 so we cannot delete. */
1568 if (EQ (swindow, FRAME_SELECTED_WINDOW (f)))
1569 error ("Cannot delete window");
0def0403
RS
1570 }
1571
192c3131
RS
1572 /* If we need to change SWINDOW, do it. */
1573 if (! EQ (swindow, FRAME_SELECTED_WINDOW (f)))
605be8af 1574 {
605be8af
JB
1575 /* If we're about to delete the selected window on the
1576 selected frame, then we should use Fselect_window to select
1577 the new window. On the other hand, if we're about to
1578 delete the selected window on any other frame, we shouldn't do
1579 anything but set the frame's selected_window slot. */
192c3131 1580 if (EQ (FRAME_SELECTED_WINDOW (f), selected_window))
14d87dc9 1581 Fselect_window (swindow, Qnil);
605be8af 1582 else
192c3131 1583 FRAME_SELECTED_WINDOW (f) = swindow;
605be8af
JB
1584 }
1585 }
7ab12479 1586
0d384044
RS
1587 /* Now we know we can delete this one. */
1588 window_deletion_count++;
1589
7ab12479
JB
1590 tem = p->buffer;
1591 /* tem is null for dummy parent windows
1592 (which have inferiors but not any contents themselves) */
265a9e55 1593 if (!NILP (tem))
7ab12479
JB
1594 {
1595 unshow_buffer (p);
2d0834cc
SM
1596 unchain_marker (XMARKER (p->pointm));
1597 unchain_marker (XMARKER (p->start));
7ab12479
JB
1598 }
1599
05e71564
GM
1600 /* Free window glyph matrices. It is sure that they are allocated
1601 again when ADJUST_GLYPHS is called. Block input so that expose
1602 events and other events that access glyph matrices are not
1603 processed while we are changing them. */
1604 BLOCK_INPUT;
951f9df5 1605 free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (f)));
5500c422 1606
7ab12479 1607 tem = p->next;
265a9e55 1608 if (!NILP (tem))
7ab12479
JB
1609 XWINDOW (tem)->prev = p->prev;
1610
1611 tem = p->prev;
265a9e55 1612 if (!NILP (tem))
7ab12479
JB
1613 XWINDOW (tem)->next = p->next;
1614
1615 if (EQ (window, par->hchild))
1616 par->hchild = p->next;
1617 if (EQ (window, par->vchild))
1618 par->vchild = p->next;
1619
1620 /* Find one of our siblings to give our space to. */
1621 sib = p->prev;
265a9e55 1622 if (NILP (sib))
7ab12479
JB
1623 {
1624 /* If p gives its space to its next sibling, that sibling needs
1625 to have its top/left side pulled back to where p's is.
1626 set_window_{height,width} will re-position the sibling's
1627 children. */
1628 sib = p->next;
949cf20f
KS
1629 XWINDOW (sib)->top_line = p->top_line;
1630 XWINDOW (sib)->left_col = p->left_col;
7ab12479
JB
1631 }
1632
1633 /* Stretch that sibling. */
265a9e55 1634 if (!NILP (par->vchild))
7ab12479 1635 set_window_height (sib,
949cf20f 1636 XFASTINT (XWINDOW (sib)->total_lines) + XFASTINT (p->total_lines),
7ab12479 1637 1);
265a9e55 1638 if (!NILP (par->hchild))
7ab12479 1639 set_window_width (sib,
949cf20f 1640 XFASTINT (XWINDOW (sib)->total_cols) + XFASTINT (p->total_cols),
7ab12479
JB
1641 1);
1642
1643 /* If parent now has only one child,
1644 put the child into the parent's place. */
7ab12479 1645 tem = par->hchild;
265a9e55 1646 if (NILP (tem))
7ab12479 1647 tem = par->vchild;
5494d7bc 1648 if (NILP (XWINDOW (tem)->next)) {
7ab12479 1649 replace_window (parent, tem);
5494d7bc
JD
1650 par = XWINDOW (tem);
1651 }
605be8af
JB
1652
1653 /* Since we may be deleting combination windows, we must make sure that
1654 not only p but all its children have been marked as deleted. */
1655 if (! NILP (p->hchild))
1656 delete_all_subwindows (XWINDOW (p->hchild));
1657 else if (! NILP (p->vchild))
1658 delete_all_subwindows (XWINDOW (p->vchild));
1659
1660 /* Mark this window as deleted. */
1661 p->buffer = p->hchild = p->vchild = Qnil;
5500c422 1662
5494d7bc
JD
1663 if (! NILP (par->parent))
1664 par = XWINDOW (par->parent);
1665
1666 /* Check if we have a v/hchild with a v/hchild. In that case remove
1667 one of them. */
ae12ecd7 1668
5494d7bc
JD
1669 if (! NILP (par->vchild) && ! NILP (XWINDOW (par->vchild)->vchild))
1670 {
1671 p = XWINDOW (par->vchild);
1672 par->vchild = p->vchild;
1673 tem = p->vchild;
1674 }
1675 else if (! NILP (par->hchild) && ! NILP (XWINDOW (par->hchild)->hchild))
1676 {
1677 p = XWINDOW (par->hchild);
1678 par->hchild = p->hchild;
1679 tem = p->hchild;
1680 }
1681 else
1682 p = 0;
1683
1684 if (p)
1685 {
1686 while (! NILP (tem)) {
1687 XWINDOW (tem)->parent = p->parent;
1688 if (NILP (XWINDOW (tem)->next))
1689 break;
1690 tem = XWINDOW (tem)->next;
1691 }
1692 if (! NILP (tem)) {
1693 /* The next of the v/hchild we are removing is now the next of the
1694 last child for the v/hchild:
1695 Before v/hchild -> v/hchild -> next1 -> next2
1696 |
1697 -> next3
1698 After: v/hchild -> next1 -> next2 -> next3
1699 */
1700 XWINDOW (tem)->next = p->next;
1701 if (! NILP (p->next))
1702 XWINDOW (p->next)->prev = tem;
1703 }
1704 p->next = p->prev = p->vchild = p->hchild = p->buffer = Qnil;
1705 }
1706
1707
5500c422 1708 /* Adjust glyph matrices. */
951f9df5 1709 adjust_glyphs (f);
05e71564 1710 UNBLOCK_INPUT;
7ab12479 1711}
67492200
GM
1712
1713
7ab12479 1714\f
67492200
GM
1715/***********************************************************************
1716 Window List
1717 ***********************************************************************/
1718
f95464e4
GM
1719/* Add window W to *USER_DATA. USER_DATA is actually a Lisp_Object
1720 pointer. This is a callback function for foreach_window, used in
1721 function window_list. */
67492200
GM
1722
1723static int
971de7fb 1724add_window_to_list (struct window *w, void *user_data)
67492200 1725{
f95464e4 1726 Lisp_Object *list = (Lisp_Object *) user_data;
67492200
GM
1727 Lisp_Object window;
1728 XSETWINDOW (window, w);
212116d6 1729 *list = Fcons (window, *list);
67492200
GM
1730 return 1;
1731}
1732
1733
1734/* Return a list of all windows, for use by next_window. If
1735 Vwindow_list is a list, return that list. Otherwise, build a new
1736 list, cache it in Vwindow_list, and return that. */
1737
1738static Lisp_Object
971de7fb 1739window_list (void)
67492200
GM
1740{
1741 if (!CONSP (Vwindow_list))
1742 {
1743 Lisp_Object tail;
212116d6 1744
67492200
GM
1745 Vwindow_list = Qnil;
1746 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
212116d6
GM
1747 {
1748 Lisp_Object args[2];
1749
1750 /* We are visiting windows in canonical order, and add
1751 new windows at the front of args[1], which means we
1752 have to reverse this list at the end. */
1753 args[1] = Qnil;
1754 foreach_window (XFRAME (XCAR (tail)), add_window_to_list, &args[1]);
1755 args[0] = Vwindow_list;
1756 args[1] = Fnreverse (args[1]);
1757 Vwindow_list = Fnconc (2, args);
1758 }
67492200 1759 }
177c0ea7 1760
67492200
GM
1761 return Vwindow_list;
1762}
1763
1764
118ea242
GM
1765/* Value is non-zero if WINDOW satisfies the constraints given by
1766 OWINDOW, MINIBUF and ALL_FRAMES.
67492200 1767
118ea242
GM
1768 MINIBUF t means WINDOW may be minibuffer windows.
1769 `lambda' means WINDOW may not be a minibuffer window.
1770 a window means a specific minibuffer window
67492200 1771
118ea242
GM
1772 ALL_FRAMES t means search all frames,
1773 nil means search just current frame,
aa248733
MS
1774 `visible' means search just visible frames on the
1775 current terminal,
1776 0 means search visible and iconified frames on the
1777 current terminal,
118ea242
GM
1778 a window means search the frame that window belongs to,
1779 a frame means consider windows on that frame, only. */
67492200
GM
1780
1781static int
971de7fb 1782candidate_window_p (Lisp_Object window, Lisp_Object owindow, Lisp_Object minibuf, Lisp_Object all_frames)
67492200
GM
1783{
1784 struct window *w = XWINDOW (window);
1785 struct frame *f = XFRAME (w->frame);
1786 int candidate_p = 1;
1787
1788 if (!BUFFERP (w->buffer))
1789 candidate_p = 0;
1790 else if (MINI_WINDOW_P (w)
1791 && (EQ (minibuf, Qlambda)
1792 || (WINDOWP (minibuf) && !EQ (minibuf, window))))
1793 {
1794 /* If MINIBUF is `lambda' don't consider any mini-windows.
1795 If it is a window, consider only that one. */
1796 candidate_p = 0;
1797 }
118ea242
GM
1798 else if (EQ (all_frames, Qt))
1799 candidate_p = 1;
67492200 1800 else if (NILP (all_frames))
118ea242
GM
1801 {
1802 xassert (WINDOWP (owindow));
1803 candidate_p = EQ (w->frame, XWINDOW (owindow)->frame);
1804 }
67492200
GM
1805 else if (EQ (all_frames, Qvisible))
1806 {
1807 FRAME_SAMPLE_VISIBILITY (f);
de509a60
SM
1808 candidate_p = FRAME_VISIBLE_P (f)
1809 && (FRAME_TERMINAL (XFRAME (w->frame))
1810 == FRAME_TERMINAL (XFRAME (selected_frame)));
1811
67492200
GM
1812 }
1813 else if (INTEGERP (all_frames) && XINT (all_frames) == 0)
1814 {
1815 FRAME_SAMPLE_VISIBILITY (f);
ca2d5566
SM
1816 candidate_p = (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f)
1817#ifdef HAVE_X_WINDOWS
1818 /* Yuck!! If we've just created the frame and the
1819 window-manager requested the user to place it
1820 manually, the window may still not be considered
1821 `visible'. I'd argue it should be at least
1822 something like `iconified', but don't know how to do
1823 that yet. --Stef */
1824 || (FRAME_X_P (f) && f->output_data.x->asked_for_visible
1825 && !f->output_data.x->has_been_visible)
1826#endif
de509a60
SM
1827 )
1828 && (FRAME_TERMINAL (XFRAME (w->frame))
1829 == FRAME_TERMINAL (XFRAME (selected_frame)));
67492200 1830 }
67492200
GM
1831 else if (WINDOWP (all_frames))
1832 candidate_p = (EQ (FRAME_MINIBUF_WINDOW (f), all_frames)
1833 || EQ (XWINDOW (all_frames)->frame, w->frame)
1834 || EQ (XWINDOW (all_frames)->frame, FRAME_FOCUS_FRAME (f)));
118ea242
GM
1835 else if (FRAMEP (all_frames))
1836 candidate_p = EQ (all_frames, w->frame);
67492200
GM
1837
1838 return candidate_p;
1839}
1840
1841
1842/* Decode arguments as allowed by Fnext_window, Fprevious_window, and
aa248733
MS
1843 Fwindow_list. See candidate_window_p for the meaning of WINDOW,
1844 MINIBUF, and ALL_FRAMES. */
67492200
GM
1845
1846static void
971de7fb 1847decode_next_window_args (Lisp_Object *window, Lisp_Object *minibuf, Lisp_Object *all_frames)
67492200
GM
1848{
1849 if (NILP (*window))
1850 *window = selected_window;
1851 else
b7826503 1852 CHECK_LIVE_WINDOW (*window);
177c0ea7 1853
67492200
GM
1854 /* MINIBUF nil may or may not include minibuffers. Decide if it
1855 does. */
1856 if (NILP (*minibuf))
1857 *minibuf = minibuf_level ? minibuf_window : Qlambda;
1858 else if (!EQ (*minibuf, Qt))
1859 *minibuf = Qlambda;
177c0ea7 1860
67492200
GM
1861 /* Now *MINIBUF can be t => count all minibuffer windows, `lambda'
1862 => count none of them, or a specific minibuffer window (the
1863 active one) to count. */
1864
1865 /* ALL_FRAMES nil doesn't specify which frames to include. */
1866 if (NILP (*all_frames))
1867 *all_frames = (!EQ (*minibuf, Qlambda)
1868 ? FRAME_MINIBUF_WINDOW (XFRAME (XWINDOW (*window)->frame))
1869 : Qnil);
1870 else if (EQ (*all_frames, Qvisible))
1871 ;
0f8fe9a2 1872 else if (EQ (*all_frames, make_number (0)))
67492200
GM
1873 ;
1874 else if (FRAMEP (*all_frames))
1875 ;
1876 else if (!EQ (*all_frames, Qt))
1877 *all_frames = Qnil;
67492200
GM
1878}
1879
1880
ab6d1131 1881/* Return the next or previous window of WINDOW in cyclic ordering
67492200
GM
1882 of windows. NEXT_P non-zero means return the next window. See the
1883 documentation string of next-window for the meaning of MINIBUF and
1884 ALL_FRAMES. */
1885
1886static Lisp_Object
971de7fb 1887next_window (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames, int next_p)
67492200
GM
1888{
1889 decode_next_window_args (&window, &minibuf, &all_frames);
177c0ea7 1890
67492200
GM
1891 /* If ALL_FRAMES is a frame, and WINDOW isn't on that frame, just
1892 return the first window on the frame. */
1893 if (FRAMEP (all_frames)
1894 && !EQ (all_frames, XWINDOW (window)->frame))
1895 return Fframe_first_window (all_frames);
177c0ea7 1896
212116d6 1897 if (next_p)
67492200
GM
1898 {
1899 Lisp_Object list;
177c0ea7 1900
67492200
GM
1901 /* Find WINDOW in the list of all windows. */
1902 list = Fmemq (window, window_list ());
1903
1904 /* Scan forward from WINDOW to the end of the window list. */
1905 if (CONSP (list))
1906 for (list = XCDR (list); CONSP (list); list = XCDR (list))
118ea242 1907 if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
67492200
GM
1908 break;
1909
1910 /* Scan from the start of the window list up to WINDOW. */
1911 if (!CONSP (list))
1912 for (list = Vwindow_list;
1913 CONSP (list) && !EQ (XCAR (list), window);
1914 list = XCDR (list))
118ea242 1915 if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
67492200
GM
1916 break;
1917
1918 if (CONSP (list))
1919 window = XCAR (list);
1920 }
1921 else
1922 {
1923 Lisp_Object candidate, list;
177c0ea7 1924
67492200
GM
1925 /* Scan through the list of windows for candidates. If there are
1926 candidate windows in front of WINDOW, the last one of these
1927 is the one we want. If there are candidates following WINDOW
1928 in the list, again the last one of these is the one we want. */
1929 candidate = Qnil;
1930 for (list = window_list (); CONSP (list); list = XCDR (list))
1931 {
1932 if (EQ (XCAR (list), window))
1933 {
1934 if (WINDOWP (candidate))
1935 break;
1936 }
118ea242
GM
1937 else if (candidate_window_p (XCAR (list), window, minibuf,
1938 all_frames))
67492200
GM
1939 candidate = XCAR (list);
1940 }
1941
1942 if (WINDOWP (candidate))
1943 window = candidate;
1944 }
1945
1946 return window;
1947}
7ab12479 1948
7ab12479 1949
16a97296 1950DEFUE ("next-window", Fnext_window, Snext_window, 0, 3, 0,
ab6d1131
MR
1951 doc: /* Return window following WINDOW in cyclic ordering of windows.
1952WINDOW defaults to the selected window. The optional arguments
1953MINIBUF and ALL-FRAMES specify the set of windows to consider.
fdb82f93 1954
ab6d1131
MR
1955MINIBUF t means consider the minibuffer window even if the
1956minibuffer is not active. MINIBUF nil or omitted means consider
1957the minibuffer window only if the minibuffer is active. Any
1958other value means do not consider the minibuffer window even if
1959the minibuffer is active.
fdb82f93
PJ
1960
1961Several frames may share a single minibuffer; if the minibuffer
ab6d1131
MR
1962is active, all windows on all frames that share that minibuffer
1963are considered too. Therefore, if you are using a separate
1964minibuffer frame and the minibuffer is active and MINIBUF says it
1965counts, `next-window' considers the windows in the frame from
1966which you entered the minibuffer, as well as the minibuffer
1967window.
1968
1969ALL-FRAMES nil or omitted means consider all windows on WINDOW's
1970 frame, plus the minibuffer window if specified by the MINIBUF
1971 argument, see above. If the minibuffer counts, consider all
1972 windows on all frames that share that minibuffer too.
1973ALL-FRAMES t means consider all windows on all existing frames.
1974ALL-FRAMES `visible' means consider all windows on all visible
aa248733 1975 frames on the current terminal.
ab6d1131 1976ALL-FRAMES 0 means consider all windows on all visible and
aa248733 1977 iconified frames on the current terminal.
ab6d1131
MR
1978ALL-FRAMES a frame means consider all windows on that frame only.
1979Anything else means consider all windows on WINDOW's frame and no
1980 others.
fdb82f93
PJ
1981
1982If you use consistent values for MINIBUF and ALL-FRAMES, you can use
1983`next-window' to iterate through the entire cycle of acceptable
1984windows, eventually ending up back at the window you started with.
1985`previous-window' traverses the same cycle, in the reverse order. */)
5842a27b 1986 (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames)
7ab12479 1987{
67492200 1988 return next_window (window, minibuf, all_frames, 1);
7ab12479
JB
1989}
1990
67492200 1991
26f6279d 1992DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
ab6d1131
MR
1993 doc: /* Return window preceding WINDOW in cyclic ordering of windows.
1994WINDOW defaults to the selected window. The optional arguments
1995MINIBUF and ALL-FRAMES specify the set of windows to consider.
1996For the precise meaning of these arguments see `next-window'.
1997
1998If you use consistent values for MINIBUF and ALL-FRAMES, you can
1999use `previous-window' to iterate through the entire cycle of
2000acceptable windows, eventually ending up back at the window you
2001started with. `next-window' traverses the same cycle, in the
2002reverse order. */)
5842a27b 2003 (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames)
7ab12479 2004{
67492200 2005 return next_window (window, minibuf, all_frames, 0);
7ab12479
JB
2006}
2007
67492200 2008
62c07cc7 2009DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
ab6d1131
MR
2010 doc: /* Select another window in cyclic ordering of windows.
2011COUNT specifies the number of windows to skip, starting with the
2012selected window, before making the selection. If COUNT is
2013positive, skip COUNT windows forwards. If COUNT is negative,
2014skip -COUNT windows backwards. COUNT zero means do not skip any
2015window, so select the selected window. In an interactive call,
2016COUNT is the numeric prefix argument. Return nil.
2017
2018This function uses `next-window' for finding the window to select.
2019The argument ALL-FRAMES has the same meaning as in `next-window',
2020but the MINIBUF argument of `next-window' is always effectively
2021nil. */)
5842a27b 2022 (Lisp_Object count, Lisp_Object all_frames)
7ab12479 2023{
67492200
GM
2024 Lisp_Object window;
2025 int i;
7ab12479 2026
ab6d1131 2027 CHECK_NUMBER (count);
67492200 2028 window = selected_window;
177c0ea7 2029
ab6d1131 2030 for (i = XINT (count); i > 0; --i)
67492200
GM
2031 window = Fnext_window (window, Qnil, all_frames);
2032 for (; i < 0; ++i)
2033 window = Fprevious_window (window, Qnil, all_frames);
50e88778 2034
14d87dc9 2035 Fselect_window (window, Qnil);
7ab12479
JB
2036 return Qnil;
2037}
67492200
GM
2038
2039
2040DEFUN ("window-list", Fwindow_list, Swindow_list, 0, 3, 0,
fdb82f93
PJ
2041 doc: /* Return a list of windows on FRAME, starting with WINDOW.
2042FRAME nil or omitted means use the selected frame.
2043WINDOW nil or omitted means use the selected window.
2044MINIBUF t means include the minibuffer window, even if it isn't active.
2045MINIBUF nil or omitted means include the minibuffer window only
2046if it's active.
2047MINIBUF neither nil nor t means never include the minibuffer window. */)
5842a27b 2048 (Lisp_Object frame, Lisp_Object minibuf, Lisp_Object window)
cd2904bd 2049{
cd2904bd 2050 if (NILP (window))
acc6289a
SM
2051 window = FRAMEP (frame) ? XFRAME (frame)->selected_window : selected_window;
2052 CHECK_WINDOW (window);
cd2904bd
GM
2053 if (NILP (frame))
2054 frame = selected_frame;
2055
2056 if (!EQ (frame, XWINDOW (window)->frame))
2057 error ("Window is on a different frame");
2058
2059 return window_list_1 (window, minibuf, frame);
2060}
2061
2062
ab6d1131 2063/* Return a list of windows in cyclic ordering. Arguments are like
cd2904bd
GM
2064 for `next-window'. */
2065
2066static Lisp_Object
971de7fb 2067window_list_1 (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames)
67492200 2068{
403de3b4 2069 Lisp_Object tail, list, rest;
67492200
GM
2070
2071 decode_next_window_args (&window, &minibuf, &all_frames);
2072 list = Qnil;
177c0ea7 2073
67492200 2074 for (tail = window_list (); CONSP (tail); tail = XCDR (tail))
118ea242 2075 if (candidate_window_p (XCAR (tail), window, minibuf, all_frames))
67492200 2076 list = Fcons (XCAR (tail), list);
177c0ea7 2077
403de3b4
RS
2078 /* Rotate the list to start with WINDOW. */
2079 list = Fnreverse (list);
2080 rest = Fmemq (window, list);
2081 if (!NILP (rest) && !EQ (rest, list))
2082 {
1725a7c9 2083 for (tail = list; !EQ (XCDR (tail), rest); tail = XCDR (tail))
403de3b4
RS
2084 ;
2085 XSETCDR (tail, Qnil);
2086 list = nconc2 (rest, list);
2087 }
2088 return list;
67492200
GM
2089}
2090
2091
7ab12479
JB
2092\f
2093/* Look at all windows, performing an operation specified by TYPE
2094 with argument OBJ.
75d8f668 2095 If FRAMES is Qt, look at all frames;
75d8f668 2096 Qnil, look at just the selected frame;
89bca612 2097 Qvisible, look at visible frames;
75d8f668 2098 a frame, just look at windows on that frame.
85fe3b5e 2099 If MINI is non-zero, perform the operation on minibuffer windows too. */
7ab12479
JB
2100
2101enum window_loop
2102{
2103 WINDOW_LOOP_UNUSED,
2104 GET_BUFFER_WINDOW, /* Arg is buffer */
2105 GET_LRU_WINDOW, /* Arg is t for full-width windows only */
2106 DELETE_OTHER_WINDOWS, /* Arg is window not to delete */
2107 DELETE_BUFFER_WINDOWS, /* Arg is buffer */
2108 GET_LARGEST_WINDOW,
3f8ab7bd 2109 UNSHOW_BUFFER, /* Arg is buffer */
6b61353c 2110 REDISPLAY_BUFFER_WINDOWS, /* Arg is buffer */
3f8ab7bd 2111 CHECK_ALL_WINDOWS
7ab12479
JB
2112};
2113
2114static Lisp_Object
971de7fb 2115window_loop (enum window_loop type, Lisp_Object obj, int mini, Lisp_Object frames)
7ab12479 2116{
118ea242
GM
2117 Lisp_Object window, windows, best_window, frame_arg;
2118 struct frame *f;
ffdc852d 2119 struct gcpro gcpro1;
177c0ea7 2120
44fa5b1e
JB
2121 /* If we're only looping through windows on a particular frame,
2122 frame points to that frame. If we're looping through windows
2123 on all frames, frame is 0. */
2124 if (FRAMEP (frames))
118ea242 2125 f = XFRAME (frames);
44fa5b1e 2126 else if (NILP (frames))
118ea242 2127 f = SELECTED_FRAME ();
7ab12479 2128 else
118ea242 2129 f = NULL;
177c0ea7 2130
118ea242 2131 if (f)
89bca612 2132 frame_arg = Qlambda;
0f8fe9a2 2133 else if (EQ (frames, make_number (0)))
f812f9c6 2134 frame_arg = frames;
89bca612
RS
2135 else if (EQ (frames, Qvisible))
2136 frame_arg = frames;
118ea242
GM
2137 else
2138 frame_arg = Qt;
7ab12479 2139
89bca612
RS
2140 /* frame_arg is Qlambda to stick to one frame,
2141 Qvisible to consider all visible frames,
2142 or Qt otherwise. */
2143
7ab12479 2144 /* Pick a window to start with. */
017b2bad 2145 if (WINDOWP (obj))
118ea242
GM
2146 window = obj;
2147 else if (f)
2148 window = FRAME_SELECTED_WINDOW (f);
7ab12479 2149 else
118ea242 2150 window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
4b206065 2151
cd2904bd 2152 windows = window_list_1 (window, mini ? Qt : Qnil, frame_arg);
118ea242 2153 GCPRO1 (windows);
7ab12479 2154 best_window = Qnil;
118ea242 2155
e67a1dea 2156 for (; CONSP (windows); windows = XCDR (windows))
7ab12479 2157 {
118ea242 2158 struct window *w;
177c0ea7 2159
118ea242
GM
2160 window = XCAR (windows);
2161 w = XWINDOW (window);
177c0ea7 2162
118ea242
GM
2163 /* Note that we do not pay attention here to whether the frame
2164 is visible, since Fwindow_list skips non-visible frames if
2165 that is desired, under the control of frame_arg. */
2166 if (!MINI_WINDOW_P (w)
65a04b96
RS
2167 /* For UNSHOW_BUFFER, we must always consider all windows. */
2168 || type == UNSHOW_BUFFER
7ab12479
JB
2169 || (mini && minibuf_level > 0))
2170 switch (type)
2171 {
2172 case GET_BUFFER_WINDOW:
118ea242 2173 if (EQ (w->buffer, obj)
5c204627
RS
2174 /* Don't find any minibuffer window
2175 except the one that is currently in use. */
118ea242
GM
2176 && (MINI_WINDOW_P (w)
2177 ? EQ (window, minibuf_window)
2178 : 1))
2179 {
5ddc1b75
GM
2180 if (NILP (best_window))
2181 best_window = window;
2182 else if (EQ (window, selected_window))
ca2d5566
SM
2183 /* Prefer to return selected-window. */
2184 RETURN_UNGCPRO (window);
2185 else if (EQ (Fwindow_frame (window), selected_frame))
2186 /* Prefer windows on the current frame. */
5ddc1b75 2187 best_window = window;
118ea242 2188 }
7ab12479
JB
2189 break;
2190
2191 case GET_LRU_WINDOW:
20b69789
SM
2192 /* `obj' is an integer encoding a bitvector.
2193 `obj & 1' means consider only full-width windows.
2194 `obj & 2' means consider also dedicated windows. */
2195 if (((XINT (obj) & 1) && !WINDOW_FULL_WIDTH_P (w))
3f489dc7 2196 || (!(XINT (obj) & 2) && !NILP (w->dedicated))
20b69789
SM
2197 /* Minibuffer windows are always ignored. */
2198 || MINI_WINDOW_P (w))
7ab12479 2199 break;
265a9e55 2200 if (NILP (best_window)
7ab12479 2201 || (XFASTINT (XWINDOW (best_window)->use_time)
118ea242
GM
2202 > XFASTINT (w->use_time)))
2203 best_window = window;
7ab12479
JB
2204 break;
2205
2206 case DELETE_OTHER_WINDOWS:
118ea242
GM
2207 if (!EQ (window, obj))
2208 Fdelete_window (window);
7ab12479
JB
2209 break;
2210
2211 case DELETE_BUFFER_WINDOWS:
118ea242 2212 if (EQ (w->buffer, obj))
7ab12479 2213 {
4554d213 2214 struct frame *fr = XFRAME (WINDOW_FRAME (w));
3548e138
RS
2215
2216 /* If this window is dedicated, and in a frame of its own,
2217 kill the frame. */
4554d213 2218 if (EQ (window, FRAME_ROOT_WINDOW (fr))
118ea242 2219 && !NILP (w->dedicated)
4554d213 2220 && other_visible_frames (fr))
7ab12479 2221 {
3548e138
RS
2222 /* Skip the other windows on this frame.
2223 There might be one, the minibuffer! */
118ea242
GM
2224 while (CONSP (XCDR (windows))
2225 && EQ (XWINDOW (XCAR (windows))->frame,
2226 XWINDOW (XCAR (XCDR (windows)))->frame))
2227 windows = XCDR (windows);
177c0ea7 2228
3548e138 2229 /* Now we can safely delete the frame. */
56f2de10 2230 delete_frame (w->frame, Qnil);
118ea242
GM
2231 }
2232 else if (NILP (w->parent))
2233 {
2234 /* If we're deleting the buffer displayed in the
2235 only window on the frame, find a new buffer to
2236 display there. */
2237 Lisp_Object buffer;
2238 buffer = Fother_buffer (obj, Qnil, w->frame);
1c33c906
MR
2239 /* Reset dedicated state of window. */
2240 w->dedicated = Qnil;
949cf20f 2241 Fset_window_buffer (window, buffer, Qnil);
118ea242
GM
2242 if (EQ (window, selected_window))
2243 Fset_buffer (w->buffer);
7ab12479
JB
2244 }
2245 else
118ea242 2246 Fdelete_window (window);
7ab12479
JB
2247 }
2248 break;
2249
2250 case GET_LARGEST_WINDOW:
20b69789 2251 { /* nil `obj' means to ignore dedicated windows. */
118ea242 2252 /* Ignore dedicated windows and minibuffers. */
3f489dc7 2253 if (MINI_WINDOW_P (w) || (NILP (obj) && !NILP (w->dedicated)))
118ea242 2254 break;
177c0ea7 2255
c930dfab 2256 if (NILP (best_window))
118ea242 2257 best_window = window;
c930dfab
GM
2258 else
2259 {
2260 struct window *b = XWINDOW (best_window);
949cf20f
KS
2261 if (XFASTINT (w->total_lines) * XFASTINT (w->total_cols)
2262 > XFASTINT (b->total_lines) * XFASTINT (b->total_cols))
c930dfab
GM
2263 best_window = window;
2264 }
7ab12479
JB
2265 }
2266 break;
2267
2268 case UNSHOW_BUFFER:
118ea242 2269 if (EQ (w->buffer, obj))
7ab12479 2270 {
118ea242 2271 Lisp_Object buffer;
4554d213 2272 struct frame *fr = XFRAME (w->frame);
177c0ea7 2273
7ab12479 2274 /* Find another buffer to show in this window. */
118ea242 2275 buffer = Fother_buffer (obj, Qnil, w->frame);
177c0ea7 2276
38ab08d1
RS
2277 /* If this window is dedicated, and in a frame of its own,
2278 kill the frame. */
4554d213 2279 if (EQ (window, FRAME_ROOT_WINDOW (fr))
118ea242 2280 && !NILP (w->dedicated)
4554d213 2281 && other_visible_frames (fr))
45945a7b
RS
2282 {
2283 /* Skip the other windows on this frame.
2284 There might be one, the minibuffer! */
118ea242
GM
2285 while (CONSP (XCDR (windows))
2286 && EQ (XWINDOW (XCAR (windows))->frame,
2287 XWINDOW (XCAR (XCDR (windows)))->frame))
2288 windows = XCDR (windows);
177c0ea7 2289
45945a7b 2290 /* Now we can safely delete the frame. */
56f2de10 2291 delete_frame (w->frame, Qnil);
45945a7b 2292 }
a5731348
SM
2293 else if (!NILP (w->dedicated) && !NILP (w->parent))
2294 {
4554d213
PE
2295 Lisp_Object window_to_delete;
2296 XSETWINDOW (window_to_delete, w);
a5731348
SM
2297 /* If this window is dedicated and not the only window
2298 in its frame, then kill it. */
4554d213 2299 Fdelete_window (window_to_delete);
a5731348 2300 }
38ab08d1 2301 else
38ab08d1
RS
2302 {
2303 /* Otherwise show a different buffer in the window. */
118ea242 2304 w->dedicated = Qnil;
949cf20f 2305 Fset_window_buffer (window, buffer, Qnil);
118ea242
GM
2306 if (EQ (window, selected_window))
2307 Fset_buffer (w->buffer);
38ab08d1 2308 }
7ab12479
JB
2309 }
2310 break;
3f8ab7bd 2311
6b61353c
KH
2312 case REDISPLAY_BUFFER_WINDOWS:
2313 if (EQ (w->buffer, obj))
2314 {
2315 mark_window_display_accurate (window, 0);
2316 w->update_mode_line = Qt;
2317 XBUFFER (obj)->prevent_redisplay_optimizations_p = 1;
2318 ++update_mode_lines;
2319 best_window = window;
2320 }
2321 break;
2322
3f8ab7bd
RS
2323 /* Check for a window that has a killed buffer. */
2324 case CHECK_ALL_WINDOWS:
118ea242 2325 if (! NILP (w->buffer)
4b4deea2 2326 && NILP (BVAR (XBUFFER (w->buffer), name)))
3f8ab7bd 2327 abort ();
118ea242 2328 break;
6bbd7a29
GM
2329
2330 case WINDOW_LOOP_UNUSED:
2331 break;
7ab12479 2332 }
7ab12479 2333 }
7ab12479 2334
118ea242 2335 UNGCPRO;
7ab12479 2336 return best_window;
37962e60 2337}
605be8af 2338
3f8ab7bd
RS
2339/* Used for debugging. Abort if any window has a dead buffer. */
2340
233a4a2c 2341void
971de7fb 2342check_all_windows (void)
3f8ab7bd
RS
2343{
2344 window_loop (CHECK_ALL_WINDOWS, Qnil, 1, Qt);
2345}
2346
a048073e
MR
2347DEFUN ("window-use-time", Fwindow_use_time, Swindow_use_time, 0, 1, 0,
2348 doc: /* Return WINDOW's use time.
2349WINDOW defaults to the selected window. The window with the highest use
2350time is the most recently selected one. The window with the lowest use
2351time is the least recently selected one. */)
2352 (Lisp_Object window)
2353{
2354 return decode_window (window)->use_time;
2355}
2356
3cbb13c8 2357DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 2, 0,
fdb82f93 2358 doc: /* Return the window least recently selected or used for display.
a55ca73c
EZ
2359\(LRU means Least Recently Used.)
2360
6b61353c 2361Return a full-width window if possible.
c2755926 2362A minibuffer window is never a candidate.
3cbb13c8
SM
2363A dedicated window is never a candidate, unless DEDICATED is non-nil,
2364 so if all windows are dedicated, the value is nil.
fdb82f93
PJ
2365If optional argument FRAME is `visible', search all visible frames.
2366If FRAME is 0, search all visible and iconified frames.
2367If FRAME is t, search all frames.
2368If FRAME is nil, search only the selected frame.
2369If FRAME is a frame, search only that frame. */)
5842a27b 2370 (Lisp_Object frame, Lisp_Object dedicated)
7ab12479
JB
2371{
2372 register Lisp_Object w;
2373 /* First try for a window that is full-width */
20b69789
SM
2374 w = window_loop (GET_LRU_WINDOW,
2375 NILP (dedicated) ? make_number (1) : make_number (3),
2376 0, frame);
265a9e55 2377 if (!NILP (w) && !EQ (w, selected_window))
7ab12479
JB
2378 return w;
2379 /* If none of them, try the rest */
20b69789
SM
2380 return window_loop (GET_LRU_WINDOW,
2381 NILP (dedicated) ? make_number (0) : make_number (2),
2382 0, frame);
7ab12479
JB
2383}
2384
3cbb13c8 2385DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 2, 0,
fdb82f93 2386 doc: /* Return the largest window in area.
c2755926 2387A minibuffer window is never a candidate.
3cbb13c8
SM
2388A dedicated window is never a candidate unless DEDICATED is non-nil,
2389 so if all windows are dedicated, the value is nil.
fdb82f93
PJ
2390If optional argument FRAME is `visible', search all visible frames.
2391If FRAME is 0, search all visible and iconified frames.
2392If FRAME is t, search all frames.
2393If FRAME is nil, search only the selected frame.
2394If FRAME is a frame, search only that frame. */)
5842a27b 2395 (Lisp_Object frame, Lisp_Object dedicated)
7ab12479 2396{
20b69789 2397 return window_loop (GET_LARGEST_WINDOW, dedicated, 0,
44fa5b1e 2398 frame);
7ab12479
JB
2399}
2400
16a97296 2401DEFUE ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 0, 2, 0,
fec89261
MR
2402 doc: /* Return a window currently displaying BUFFER-OR-NAME, or nil if none.
2403BUFFER-OR-NAME may be a buffer or a buffer name and defaults to the
2404current buffer.
fdb82f93
PJ
2405If optional argument FRAME is `visible', search all visible frames.
2406If optional argument FRAME is 0, search all visible and iconified frames.
2407If FRAME is t, search all frames.
2408If FRAME is nil, search only the selected frame.
2409If FRAME is a frame, search only that frame. */)
5842a27b 2410 (Lisp_Object buffer_or_name, Lisp_Object frame)
7ab12479 2411{
fec89261
MR
2412 Lisp_Object buffer;
2413
2414 if (NILP (buffer_or_name))
2415 buffer = Fcurrent_buffer ();
2416 else
2417 buffer = Fget_buffer (buffer_or_name);
2418
017b2bad 2419 if (BUFFERP (buffer))
44fa5b1e 2420 return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame);
7ab12479
JB
2421 else
2422 return Qnil;
2423}
2424
2425DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
fdb82f93
PJ
2426 0, 1, "",
2427 doc: /* Make WINDOW (or the selected window) fill its frame.
2428Only the frame WINDOW is on is affected.
fec89261
MR
2429This function tries to reduce display jumps by keeping the text
2430previously visible in WINDOW in the same place on the frame. Doing this
2431depends on the value of (window-start WINDOW), so if calling this
2432function in a program gives strange scrolling, make sure the
2433window-start value is reasonable when this function is called. */)
5842a27b 2434 (Lisp_Object window)
7ab12479
JB
2435{
2436 struct window *w;
2452438f 2437 EMACS_INT startpos;
85fe3b5e 2438 int top, new_top;
7ab12479 2439
265a9e55 2440 if (NILP (window))
7ab12479
JB
2441 window = selected_window;
2442 else
b7826503 2443 CHECK_LIVE_WINDOW (window);
7ab12479 2444 w = XWINDOW (window);
a2b38b3c 2445
00d3d838 2446 startpos = marker_position (w->start);
949cf20f 2447 top = WINDOW_TOP_EDGE_LINE (w) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
7ab12479 2448
a2b38b3c
RS
2449 if (MINI_WINDOW_P (w) && top > 0)
2450 error ("Can't expand minibuffer to full frame");
2451
70728a80 2452 window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_FRAME (w));
7ab12479 2453
00d3d838
KH
2454 /* Try to minimize scrolling, by setting the window start to the point
2455 will cause the text at the old window start to be at the same place
2456 on the frame. But don't try to do this if the window start is
2457 outside the visible portion (as might happen when the display is
2458 not current, due to typeahead). */
949cf20f 2459 new_top = WINDOW_TOP_EDGE_LINE (w) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
85fe3b5e
GM
2460 if (new_top != top
2461 && startpos >= BUF_BEGV (XBUFFER (w->buffer))
00d3d838
KH
2462 && startpos <= BUF_ZV (XBUFFER (w->buffer)))
2463 {
2464 struct position pos;
2465 struct buffer *obuf = current_buffer;
2466
2467 Fset_buffer (w->buffer);
2468 /* This computation used to temporarily move point, but that can
2469 have unwanted side effects due to text properties. */
0383eb57 2470 pos = *vmotion (startpos, -top, w);
4d047f50 2471
b73ea88e 2472 set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
85fe3b5e 2473 w->window_end_valid = Qnil;
b73ea88e
RS
2474 w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
2475 || FETCH_BYTE (pos.bytepos - 1) == '\n') ? Qt
00d3d838 2476 : Qnil);
80622eec
RS
2477 /* We need to do this, so that the window-scroll-functions
2478 get called. */
4d047f50 2479 w->optional_new_start = Qt;
00d3d838
KH
2480
2481 set_buffer_internal (obuf);
2482 }
5500c422 2483
7ab12479
JB
2484 return Qnil;
2485}
2486
2487DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
fec89261
MR
2488 0, 2, "bDelete windows on (buffer): ",
2489 doc: /* Delete all windows showing BUFFER-OR-NAME.
2490BUFFER-OR-NAME may be a buffer or the name of an existing buffer and
2491defaults to the current buffer.
2492
fdb82f93
PJ
2493Optional second argument FRAME controls which frames are affected.
2494If optional argument FRAME is `visible', search all visible frames.
2495If FRAME is 0, search all visible and iconified frames.
2496If FRAME is nil, search all frames.
2497If FRAME is t, search only the selected frame.
d653c8cc 2498If FRAME is a frame, search only that frame.
fec89261
MR
2499When a window showing BUFFER-OR-NAME is dedicated and the only window of
2500its frame, that frame is deleted when there are other frames left. */)
5842a27b 2501 (Lisp_Object buffer_or_name, Lisp_Object frame)
7ab12479 2502{
fec89261
MR
2503 Lisp_Object buffer;
2504
26f6279d
JB
2505 /* FRAME uses t and nil to mean the opposite of what window_loop
2506 expects. */
c520265e
RS
2507 if (NILP (frame))
2508 frame = Qt;
2509 else if (EQ (frame, Qt))
2510 frame = Qnil;
26f6279d 2511
fec89261
MR
2512 if (NILP (buffer_or_name))
2513 buffer = Fcurrent_buffer ();
2514 else
7ab12479 2515 {
fec89261 2516 buffer = Fget_buffer (buffer_or_name);
b7826503 2517 CHECK_BUFFER (buffer);
7ab12479 2518 }
177c0ea7 2519
fec89261
MR
2520 window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
2521
7ab12479
JB
2522 return Qnil;
2523}
2524
2525DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
fdb82f93 2526 Sreplace_buffer_in_windows,
fec89261
MR
2527 0, 1, "bReplace buffer in windows: ",
2528 doc: /* Replace BUFFER-OR-NAME with some other buffer in all windows showing it.
2529BUFFER-OR-NAME may be a buffer or the name of an existing buffer and
2530defaults to the current buffer.
2531
2532When a window showing BUFFER-OR-NAME is dedicated that window is
2533deleted. If that window is the only window on its frame, that frame is
2534deleted too when there are other frames left. If there are no other
2535frames left, some other buffer is displayed in that window. */)
5842a27b 2536 (Lisp_Object buffer_or_name)
fec89261
MR
2537{
2538 Lisp_Object buffer;
2539
2540 if (NILP (buffer_or_name))
2541 buffer = Fcurrent_buffer ();
2542 else
7ab12479 2543 {
fec89261 2544 buffer = Fget_buffer (buffer_or_name);
b7826503 2545 CHECK_BUFFER (buffer);
7ab12479 2546 }
fec89261
MR
2547
2548 window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
2549
7ab12479
JB
2550 return Qnil;
2551}
ff58478b
RS
2552
2553/* Replace BUFFER with some other buffer in all windows
2554 of all frames, even those on other keyboards. */
2555
2556void
971de7fb 2557replace_buffer_in_all_windows (Lisp_Object buffer)
ff58478b
RS
2558{
2559 Lisp_Object tail, frame;
2560
ff58478b
RS
2561 /* A single call to window_loop won't do the job
2562 because it only considers frames on the current keyboard.
2563 So loop manually over frames, and handle each one. */
2564 FOR_EACH_FRAME (tail, frame)
db7f721d 2565 window_loop (UNSHOW_BUFFER, buffer, 1, frame);
ff58478b 2566}
7ab12479
JB
2567\f
2568/* Set the height of WINDOW and all its inferiors. */
a481b3ea
JB
2569
2570/* The smallest acceptable dimensions for a window. Anything smaller
2571 might crash Emacs. */
5500c422 2572
a481b3ea 2573#define MIN_SAFE_WINDOW_WIDTH (2)
dc1ab1ee 2574#define MIN_SAFE_WINDOW_HEIGHT (1)
a481b3ea 2575
047aaeb9
MR
2576/* For wp non-zero the total number of columns of window w. Otherwise
2577 the total number of lines of w. */
a481b3ea 2578
047aaeb9
MR
2579#define WINDOW_TOTAL_SIZE(w, wp) \
2580 (wp ? WINDOW_TOTAL_COLS (w) : WINDOW_TOTAL_LINES (w))
a481b3ea
JB
2581
2582/* If *ROWS or *COLS are too small a size for FRAME, set them to the
2583 minimum allowable size. */
5500c422 2584
605be8af 2585void
971de7fb 2586check_frame_size (FRAME_PTR frame, int *rows, int *cols)
a481b3ea 2587{
628df3bf 2588 /* For height, we have to see:
54b8bcb5
RS
2589 how many windows the frame has at minimum (one or two),
2590 and whether it has a menu bar or other special stuff at the top. */
2591 int min_height
2592 = ((FRAME_MINIBUF_ONLY_P (frame) || ! FRAME_HAS_MINIBUF_P (frame))
2593 ? MIN_SAFE_WINDOW_HEIGHT
2594 : 2 * MIN_SAFE_WINDOW_HEIGHT);
177c0ea7 2595
5500c422
GM
2596 if (FRAME_TOP_MARGIN (frame) > 0)
2597 min_height += FRAME_TOP_MARGIN (frame);
a481b3ea
JB
2598
2599 if (*rows < min_height)
2600 *rows = min_height;
2601 if (*cols < MIN_SAFE_WINDOW_WIDTH)
2602 *cols = MIN_SAFE_WINDOW_WIDTH;
2603}
2604
233a4a2c
GM
2605/* Value is non-zero if window W is fixed-size. WIDTH_P non-zero means
2606 check if W's width can be changed, otherwise check W's height.
2607 CHECK_SIBLINGS_P non-zero means check resizablity of WINDOW's
2608 siblings, too. If none of the siblings is resizable, WINDOW isn't
2609 either. */
c1636aa6 2610
233a4a2c 2611static int
971de7fb 2612window_fixed_size_p (struct window *w, int width_p, int check_siblings_p)
233a4a2c
GM
2613{
2614 int fixed_p;
2615 struct window *c;
177c0ea7 2616
233a4a2c
GM
2617 if (!NILP (w->hchild))
2618 {
2619 c = XWINDOW (w->hchild);
177c0ea7 2620
233a4a2c
GM
2621 if (width_p)
2622 {
047aaeb9 2623 /* A horizontal combination is fixed-width if all of if its
233a4a2c
GM
2624 children are. */
2625 while (c && window_fixed_size_p (c, width_p, 0))
2626 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2627 fixed_p = c == NULL;
2628 }
2629 else
2630 {
047aaeb9 2631 /* A horizontal combination is fixed-height if one of if its
233a4a2c
GM
2632 children is. */
2633 while (c && !window_fixed_size_p (c, width_p, 0))
2634 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2635 fixed_p = c != NULL;
2636 }
2637 }
2638 else if (!NILP (w->vchild))
2639 {
2640 c = XWINDOW (w->vchild);
177c0ea7 2641
233a4a2c
GM
2642 if (width_p)
2643 {
047aaeb9 2644 /* A vertical combination is fixed-width if one of if its
233a4a2c
GM
2645 children is. */
2646 while (c && !window_fixed_size_p (c, width_p, 0))
2647 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2648 fixed_p = c != NULL;
2649 }
2650 else
2651 {
047aaeb9 2652 /* A vertical combination is fixed-height if all of if its
233a4a2c
GM
2653 children are. */
2654 while (c && window_fixed_size_p (c, width_p, 0))
2655 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2656 fixed_p = c == NULL;
2657 }
2658 }
2659 else if (BUFFERP (w->buffer))
2660 {
3df0580e
AS
2661 struct buffer *old = current_buffer;
2662 Lisp_Object val;
177c0ea7 2663
3df0580e
AS
2664 current_buffer = XBUFFER (w->buffer);
2665 val = find_symbol_value (Qwindow_size_fixed);
2666 current_buffer = old;
a34dfd12 2667
3df0580e
AS
2668 fixed_p = 0;
2669 if (!EQ (val, Qunbound))
2670 {
2671 fixed_p = !NILP (val);
177c0ea7 2672
3df0580e
AS
2673 if (fixed_p
2674 && ((EQ (val, Qheight) && width_p)
2675 || (EQ (val, Qwidth) && !width_p)))
2676 fixed_p = 0;
233a4a2c
GM
2677 }
2678
2679 /* Can't tell if this one is resizable without looking at
2680 siblings. If all siblings are fixed-size this one is too. */
2681 if (!fixed_p && check_siblings_p && WINDOWP (w->parent))
2682 {
2683 Lisp_Object child;
177c0ea7 2684
9beb8baa 2685 for (child = w->prev; WINDOWP (child); child = XWINDOW (child)->prev)
233a4a2c
GM
2686 if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
2687 break;
2688
2689 if (NILP (child))
9beb8baa 2690 for (child = w->next; WINDOWP (child); child = XWINDOW (child)->next)
233a4a2c
GM
2691 if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
2692 break;
2693
2694 if (NILP (child))
2695 fixed_p = 1;
2696 }
2697 }
2698 else
2699 fixed_p = 1;
2700
2701 return fixed_p;
2702}
177c0ea7 2703
047aaeb9
MR
2704/* Return minimum size of leaf window W. WIDTH_P non-zero means return
2705 the minimum width of W, WIDTH_P zero means return the minimum height
2706 of W. SAFE_P non-zero means ignore window-min-height|width but just
2707 return values that won't crash Emacs and don't hide components like
2708 fringes, scrollbars, or modelines. If WIDTH_P is zero and W is the
2709 minibuffer window, always return 1. */
f1de8c77
MR
2710
2711static int
971de7fb 2712window_min_size_2 (struct window *w, int width_p, int safe_p)
f1de8c77 2713{
047aaeb9
MR
2714 /* We should consider buffer-local values of window_min_height and
2715 window_min_width here. */
f1de8c77 2716 if (width_p)
047aaeb9
MR
2717 {
2718 int safe_size = (MIN_SAFE_WINDOW_WIDTH
12bb3111 2719 + WINDOW_FRINGE_COLS (w)
047aaeb9
MR
2720 + WINDOW_SCROLL_BAR_COLS (w));
2721
2722 return safe_p ? safe_size : max (window_min_width, safe_size);
2723 }
f1de8c77 2724 else if (MINI_WINDOW_P (w))
047aaeb9 2725 return 1;
f1de8c77 2726 else
047aaeb9
MR
2727 {
2728 int safe_size = (MIN_SAFE_WINDOW_HEIGHT
2729 + ((BUFFERP (w->buffer)
4b4deea2 2730 && !NILP (BVAR (XBUFFER (w->buffer), mode_line_format)))
047aaeb9 2731 ? 1 : 0));
f1de8c77 2732
047aaeb9
MR
2733 return safe_p ? safe_size : max (window_min_height, safe_size);
2734 }
f1de8c77 2735}
233a4a2c 2736
047aaeb9
MR
2737/* Return minimum size of window W, not taking fixed-width windows into
2738 account. WIDTH_P non-zero means return the minimum width, otherwise
2739 return the minimum height. SAFE_P non-zero means ignore
2740 window-min-height|width but just return values that won't crash Emacs
2741 and don't hide components like fringes, scrollbars, or modelines. If
2742 W is a combination window, compute the minimum size from the minimum
2743 sizes of W's children. */
233a4a2c
GM
2744
2745static int
971de7fb 2746window_min_size_1 (struct window *w, int width_p, int safe_p)
c1636aa6 2747{
233a4a2c 2748 struct window *c;
c1636aa6 2749 int size;
177c0ea7 2750
233a4a2c
GM
2751 if (!NILP (w->hchild))
2752 {
047aaeb9 2753 /* W is a horizontal combination. */
233a4a2c
GM
2754 c = XWINDOW (w->hchild);
2755 size = 0;
177c0ea7 2756
233a4a2c
GM
2757 if (width_p)
2758 {
047aaeb9
MR
2759 /* The minimum width of a horizontal combination is the sum of
2760 the minimum widths of its children. */
233a4a2c
GM
2761 while (c)
2762 {
047aaeb9 2763 size += window_min_size_1 (c, 1, safe_p);
233a4a2c
GM
2764 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2765 }
2766 }
2767 else
2768 {
047aaeb9
MR
2769 /* The minimum height of a horizontal combination is the
2770 maximum of the minimum heights of its children. */
233a4a2c
GM
2771 while (c)
2772 {
047aaeb9 2773 size = max (window_min_size_1 (c, 0, safe_p), size);
233a4a2c
GM
2774 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2775 }
2776 }
2777 }
2778 else if (!NILP (w->vchild))
2779 {
047aaeb9 2780 /* W is a vertical combination. */
233a4a2c
GM
2781 c = XWINDOW (w->vchild);
2782 size = 0;
177c0ea7 2783
233a4a2c
GM
2784 if (width_p)
2785 {
047aaeb9
MR
2786 /* The minimum width of a vertical combination is the maximum
2787 of the minimum widths of its children. */
233a4a2c
GM
2788 while (c)
2789 {
047aaeb9 2790 size = max (window_min_size_1 (c, 1, safe_p), size);
233a4a2c
GM
2791 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2792 }
2793 }
2794 else
2795 {
047aaeb9
MR
2796 /* The minimum height of a vertical combination is the sum of
2797 the minimum height of its children. */
233a4a2c
GM
2798 while (c)
2799 {
047aaeb9 2800 size += window_min_size_1 (c, 0, safe_p);
233a4a2c
GM
2801 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2802 }
2803 }
2804 }
c1636aa6 2805 else
047aaeb9
MR
2806 /* W is a leaf window. */
2807 size = window_min_size_2 (w, width_p, safe_p);
c1636aa6
GM
2808
2809 return size;
2810}
2811
233a4a2c 2812/* Return the minimum size of window W, taking fixed-size windows into
047aaeb9
MR
2813 account. WIDTH_P non-zero means return the minimum width, otherwise
2814 return the minimum height. SAFE_P non-zero means ignore
2815 window-min-height|width but just return values that won't crash Emacs
2816 and don't hide components like fringes, scrollbars, or modelines.
2817 IGNORE_FIXED_P non-zero means ignore if W is fixed-size. Set *FIXED
2818 to 1 if W is fixed-size unless FIXED is null. */
7ab12479 2819
233a4a2c 2820static int
971de7fb 2821window_min_size (struct window *w, int width_p, int safe_p, int ignore_fixed_p, int *fixed)
233a4a2c
GM
2822{
2823 int size, fixed_p;
2824
f984d4fc
GM
2825 if (ignore_fixed_p)
2826 fixed_p = 0;
2827 else
2828 fixed_p = window_fixed_size_p (w, width_p, 1);
177c0ea7 2829
233a4a2c
GM
2830 if (fixed)
2831 *fixed = fixed_p;
177c0ea7 2832
233a4a2c 2833 if (fixed_p)
047aaeb9 2834 size = WINDOW_TOTAL_SIZE (w, width_p);
233a4a2c 2835 else
047aaeb9 2836 size = window_min_size_1 (w, width_p, safe_p);
177c0ea7 2837
233a4a2c
GM
2838 return size;
2839}
2840
2841
79fd290e 2842/* Adjust the margins of window W if text area is too small.
949cf20f
KS
2843 Return 1 if window width is ok after adjustment; 0 if window
2844 is still too narrow. */
2845
2846static int
971de7fb 2847adjust_window_margins (struct window *w)
949cf20f
KS
2848{
2849 int box_cols = (WINDOW_TOTAL_COLS (w)
2850 - WINDOW_FRINGE_COLS (w)
2851 - WINDOW_SCROLL_BAR_COLS (w));
2852 int margin_cols = (WINDOW_LEFT_MARGIN_COLS (w)
2853 + WINDOW_RIGHT_MARGIN_COLS (w));
2854
2855 if (box_cols - margin_cols >= MIN_SAFE_WINDOW_WIDTH)
2856 return 1;
2857
2858 if (margin_cols < 0 || box_cols < MIN_SAFE_WINDOW_WIDTH)
2859 return 0;
2860
2861 /* Window's text area is too narrow, but reducing the window
2862 margins will fix that. */
2863 margin_cols = box_cols - MIN_SAFE_WINDOW_WIDTH;
2864 if (WINDOW_RIGHT_MARGIN_COLS (w) > 0)
2865 {
2866 if (WINDOW_LEFT_MARGIN_COLS (w) > 0)
2867 w->left_margin_cols = w->right_margin_cols
2868 = make_number (margin_cols/2);
2869 else
2870 w->right_margin_cols = make_number (margin_cols);
2871 }
2872 else
2873 w->left_margin_cols = make_number (margin_cols);
2874 return 1;
2875}
2876
047aaeb9
MR
2877/* Calculate new sizes for windows in the list FORWARD when their
2878 compound size goes from TOTAL to SIZE. TOTAL must be greater than
2879 SIZE. The number of windows in FORWARD is NCHILDREN, and the number
2880 that can shrink is SHRINKABLE. Fixed-size windows may be shrunk if
2881 and only if RESIZE_FIXED_P is non-zero. WIDTH_P non-zero means
2882 shrink columns, otherwise shrink lines.
6b61353c 2883
047aaeb9
MR
2884 SAFE_P zero means windows may be sized down to window-min-height
2885 lines (window-min-window columns for WIDTH_P non-zero). SAFE_P
2886 non-zero means windows may be sized down to their minimum safe sizes
2887 taking into account the space needed to display modelines, fringes,
2888 and scrollbars.
6b61353c 2889
047aaeb9
MR
2890 This function returns an allocated array of new sizes that the caller
2891 must free. A size -1 means the window is fixed and RESIZE_FIXED_P is
2892 zero. A size zero means the window shall be deleted. Array index 0
2893 refers to the first window in FORWARD, 1 to the second, and so on.
2894
2895 This function resizes windows proportionally to their size. It also
2896 tries to preserve smaller windows by resizing larger windows before
2897 resizing any window to zero. If resize_proportionally is non-nil for
2898 a specific window, it will attempt to strictly resize that window
2899 proportionally, even at the expense of deleting smaller windows. */
6b61353c 2900static int *
ed3751c8 2901shrink_windows (int total, int size, int nchildren, int shrinkable,
dd4c5104 2902 int resize_fixed_p, Lisp_Object forward, int width_p, int safe_p)
6b61353c
KH
2903{
2904 int available_resize = 0;
047aaeb9 2905 int *new_sizes, *min_sizes;
6b61353c
KH
2906 struct window *c;
2907 Lisp_Object child;
2908 int smallest = total;
2909 int total_removed = 0;
2910 int total_shrink = total - size;
2911 int i;
2912
2913 new_sizes = xmalloc (sizeof (*new_sizes) * nchildren);
047aaeb9 2914 min_sizes = xmalloc (sizeof (*min_sizes) * nchildren);
6b61353c
KH
2915
2916 for (i = 0, child = forward; !NILP (child); child = c->next, ++i)
2917 {
2918 int child_size;
2919
2920 c = XWINDOW (child);
047aaeb9 2921 child_size = WINDOW_TOTAL_SIZE (c, width_p);
6b61353c 2922
047aaeb9 2923 if (!resize_fixed_p && window_fixed_size_p (c, width_p, 0))
6b61353c
KH
2924 new_sizes[i] = -1;
2925 else
2926 {
2927 new_sizes[i] = child_size;
047aaeb9
MR
2928 min_sizes[i] = window_min_size_1 (c, width_p, safe_p);
2929 if (child_size > min_sizes[i]
2930 && NILP (c->resize_proportionally))
2931 available_resize += child_size - min_sizes[i];
6b61353c
KH
2932 }
2933 }
2934 /* We might need to shrink some windows to zero. Find the smallest
2935 windows and set them to 0 until we can fulfil the new size. */
2936
2937 while (shrinkable > 1 && size + available_resize < total)
2938 {
2939 for (i = 0; i < nchildren; ++i)
2940 if (new_sizes[i] > 0 && smallest > new_sizes[i])
2941 smallest = new_sizes[i];
2942
2943 for (i = 0; i < nchildren; ++i)
2944 if (new_sizes[i] == smallest)
2945 {
2946 /* Resize this window down to zero. */
2947 new_sizes[i] = 0;
047aaeb9
MR
2948 if (smallest > min_sizes[i])
2949 available_resize -= smallest - min_sizes[i];
6b61353c
KH
2950 available_resize += smallest;
2951 --shrinkable;
2952 total_removed += smallest;
2953
ef614e04
JD
2954 /* We don't know what the smallest is now. */
2955 smallest = total;
2956
6b61353c
KH
2957 /* Out of for, just remove one window at the time and
2958 check again if we have enough space. */
2959 break;
2960 }
2961 }
2962
2963 /* Now, calculate the new sizes. Try to shrink each window
2964 proportional to its size. */
2965 for (i = 0; i < nchildren; ++i)
2966 {
047aaeb9 2967 if (new_sizes[i] > min_sizes[i])
6b61353c 2968 {
047aaeb9
MR
2969 int to_shrink = total_shrink * new_sizes[i] / total;
2970
2971 if (new_sizes[i] - to_shrink < min_sizes[i])
2972 to_shrink = new_sizes[i] - min_sizes[i];
6b61353c
KH
2973 new_sizes[i] -= to_shrink;
2974 total_removed += to_shrink;
2975 }
2976 }
2977
2978 /* Any reminder due to rounding, we just subtract from windows
2979 that are left and still can be shrunk. */
2980 while (total_shrink > total_removed)
2981 {
ef614e04 2982 int nonzero_sizes = 0;
ef614e04
JD
2983
2984 for (i = 0; i < nchildren; ++i)
2985 if (new_sizes[i] > 0)
c499e557 2986 ++nonzero_sizes;
c49a0495 2987
6b61353c 2988 for (i = 0; i < nchildren; ++i)
047aaeb9 2989 if (new_sizes[i] > min_sizes[i])
6b61353c
KH
2990 {
2991 --new_sizes[i];
2992 ++total_removed;
2993
2994 /* Out of for, just shrink one window at the time and
2995 check again if we have enough space. */
2996 break;
2997 }
ef614e04 2998
ef614e04
JD
2999 /* Special case, only one window left. */
3000 if (nonzero_sizes == 1)
3001 break;
3002 }
3003
3004 /* Any surplus due to rounding, we add to windows that are left. */
3005 while (total_shrink < total_removed)
3006 {
3007 for (i = 0; i < nchildren; ++i)
3008 {
3009 if (new_sizes[i] != 0 && total_shrink < total_removed)
3010 {
3011 ++new_sizes[i];
3012 --total_removed;
3013 break;
3014 }
3015 }
6b61353c
KH
3016 }
3017
047aaeb9
MR
3018 xfree (min_sizes);
3019
6b61353c
KH
3020 return new_sizes;
3021}
949cf20f 3022
233a4a2c 3023/* Set WINDOW's height or width to SIZE. WIDTH_P non-zero means set
047aaeb9
MR
3024 WINDOW's width. Resize WINDOW's children, if any, so that they keep
3025 their proportionate size relative to WINDOW.
5fe0b054
RS
3026
3027 If FIRST_ONLY is 1, change only the first of WINDOW's children when
3028 they are in series. If LAST_ONLY is 1, change only the last of
3029 WINDOW's children when they are in series.
3030
3031 Propagate WINDOW's top or left edge position to children. Delete
047aaeb9
MR
3032 windows that become too small unless NODELETE_P is 1. When
3033 NODELETE_P equals 2 do not honor settings for window-min-height and
3034 window-min-width when resizing windows but use safe defaults instead.
3035 This should give better behavior when resizing frames. */
233a4a2c
GM
3036
3037static void
971de7fb 3038size_window (Lisp_Object window, int size, int width_p, int nodelete_p, int first_only, int last_only)
7ab12479 3039{
233a4a2c
GM
3040 struct window *w = XWINDOW (window);
3041 struct window *c;
3042 Lisp_Object child, *forward, *sideward;
047aaeb9 3043 int old_size = WINDOW_TOTAL_SIZE (w, width_p);
7ab12479 3044
7ae2f10f 3045 size = max (0, size);
177c0ea7 3046
047aaeb9
MR
3047 /* Delete WINDOW if it's too small. */
3048 if (nodelete_p != 1 && !NILP (w->parent)
3049 && size < window_min_size_1 (w, width_p, nodelete_p == 2))
233a4a2c 3050 {
047aaeb9
MR
3051 delete_window (window);
3052 return;
7ab12479
JB
3053 }
3054
233a4a2c 3055 /* Set redisplay hints. */
7ae2f10f
GM
3056 w->last_modified = make_number (0);
3057 w->last_overlay_modified = make_number (0);
7ab12479 3058 windows_or_buffers_changed++;
7ae2f10f 3059 FRAME_WINDOW_SIZES_CHANGED (XFRAME (w->frame)) = 1;
29aeee73 3060
233a4a2c
GM
3061 if (width_p)
3062 {
3063 sideward = &w->vchild;
3064 forward = &w->hchild;
949cf20f
KS
3065 w->total_cols = make_number (size);
3066 adjust_window_margins (w);
233a4a2c
GM
3067 }
3068 else
3069 {
3070 sideward = &w->hchild;
3071 forward = &w->vchild;
949cf20f
KS
3072 w->total_lines = make_number (size);
3073 w->orig_total_lines = Qnil;
233a4a2c
GM
3074 }
3075
3076 if (!NILP (*sideward))
7ab12479 3077 {
5fe0b054 3078 /* We have a chain of parallel siblings whose size should all change. */
233a4a2c 3079 for (child = *sideward; !NILP (child); child = c->next)
7ab12479 3080 {
233a4a2c
GM
3081 c = XWINDOW (child);
3082 if (width_p)
949cf20f 3083 c->left_col = w->left_col;
233a4a2c 3084 else
949cf20f 3085 c->top_line = w->top_line;
5fe0b054
RS
3086 size_window (child, size, width_p, nodelete_p,
3087 first_only, last_only);
7ab12479
JB
3088 }
3089 }
5fe0b054
RS
3090 else if (!NILP (*forward) && last_only)
3091 {
3092 /* Change the last in a series of siblings. */
3093 Lisp_Object last_child;
3094 int child_size;
3095
3096 for (child = *forward; !NILP (child); child = c->next)
3097 {
3098 c = XWINDOW (child);
3099 last_child = child;
3100 }
3101
047aaeb9
MR
3102 child_size = WINDOW_TOTAL_SIZE (c, width_p);
3103 size_window (last_child, size - old_size + child_size,
5fe0b054
RS
3104 width_p, nodelete_p, first_only, last_only);
3105 }
3106 else if (!NILP (*forward) && first_only)
3107 {
3108 /* Change the first in a series of siblings. */
3109 int child_size;
3110
3111 child = *forward;
3112 c = XWINDOW (child);
3113
3114 if (width_p)
3115 c->left_col = w->left_col;
3116 else
3117 c->top_line = w->top_line;
3118
047aaeb9
MR
3119 child_size = WINDOW_TOTAL_SIZE (c, width_p);
3120 size_window (child, size - old_size + child_size,
5fe0b054
RS
3121 width_p, nodelete_p, first_only, last_only);
3122 }
233a4a2c 3123 else if (!NILP (*forward))
7ab12479 3124 {
d6550a9f 3125 int fixed_size, each IF_LINT (= 0), extra IF_LINT (= 0), n;
233a4a2c 3126 int resize_fixed_p, nfixed;
8b6d9dc9 3127 int last_pos, first_pos, nchildren, total;
6b61353c 3128 int *new_sizes = NULL;
233a4a2c 3129
5fe0b054 3130 /* Determine the fixed-size portion of this window, and the
233a4a2c 3131 number of child windows. */
8b6d9dc9 3132 fixed_size = nchildren = nfixed = total = 0;
233a4a2c 3133 for (child = *forward; !NILP (child); child = c->next, ++nchildren)
7ab12479 3134 {
8b6d9dc9 3135 int child_size;
177c0ea7 3136
7ab12479 3137 c = XWINDOW (child);
047aaeb9 3138 child_size = WINDOW_TOTAL_SIZE (c, width_p);
8b6d9dc9 3139 total += child_size;
177c0ea7 3140
233a4a2c
GM
3141 if (window_fixed_size_p (c, width_p, 0))
3142 {
8b6d9dc9 3143 fixed_size += child_size;
233a4a2c
GM
3144 ++nfixed;
3145 }
3146 }
7ab12479 3147
233a4a2c
GM
3148 /* If the new size is smaller than fixed_size, or if there
3149 aren't any resizable windows, allow resizing fixed-size
3150 windows. */
3151 resize_fixed_p = nfixed == nchildren || size < fixed_size;
3152
6b61353c 3153 /* Compute how many lines/columns to add/remove to each child. The
233a4a2c
GM
3154 value of extra takes care of rounding errors. */
3155 n = resize_fixed_p ? nchildren : nchildren - nfixed;
6b61353c 3156 if (size < total && n > 1)
047aaeb9
MR
3157 new_sizes = shrink_windows (total, size, nchildren, n,
3158 resize_fixed_p, *forward, width_p,
3159 nodelete_p == 2);
6b61353c
KH
3160 else
3161 {
3162 each = (size - total) / n;
3163 extra = (size - total) - n * each;
3164 }
233a4a2c
GM
3165
3166 /* Compute new children heights and edge positions. */
949cf20f 3167 first_pos = width_p ? XINT (w->left_col) : XINT (w->top_line);
233a4a2c 3168 last_pos = first_pos;
6b61353c 3169 for (n = 0, child = *forward; !NILP (child); child = c->next, ++n)
233a4a2c 3170 {
4554d213 3171 int new_child_size, old_child_size;
177c0ea7 3172
233a4a2c 3173 c = XWINDOW (child);
4554d213
PE
3174 old_child_size = WINDOW_TOTAL_SIZE (c, width_p);
3175 new_child_size = old_child_size;
7ab12479 3176
233a4a2c
GM
3177 /* The top or left edge position of this child equals the
3178 bottom or right edge of its predecessor. */
3179 if (width_p)
949cf20f 3180 c->left_col = make_number (last_pos);
233a4a2c 3181 else
949cf20f 3182 c->top_line = make_number (last_pos);
7ab12479 3183
233a4a2c
GM
3184 /* If this child can be resized, do it. */
3185 if (resize_fixed_p || !window_fixed_size_p (c, width_p, 0))
3186 {
4554d213
PE
3187 new_child_size =
3188 new_sizes ? new_sizes[n] : old_child_size + each + extra;
233a4a2c
GM
3189 extra = 0;
3190 }
177c0ea7 3191
047aaeb9 3192 /* Set new size. Note that size_window also propagates
233a4a2c
GM
3193 edge positions to children, so it's not a no-op if we
3194 didn't change the child's size. */
4554d213
PE
3195 size_window (child, new_child_size, width_p, 1,
3196 first_only, last_only);
233a4a2c
GM
3197
3198 /* Remember the bottom/right edge position of this child; it
3199 will be used to set the top/left edge of the next child. */
4554d213 3200 last_pos += new_child_size;
7ab12479 3201 }
233a4a2c 3202
70fdbb46 3203 xfree (new_sizes);
6b61353c 3204
233a4a2c
GM
3205 /* We should have covered the parent exactly with child windows. */
3206 xassert (size == last_pos - first_pos);
177c0ea7 3207
7ab12479 3208 /* Now delete any children that became too small. */
047aaeb9 3209 if (nodelete_p != 1)
233a4a2c 3210 for (child = *forward; !NILP (child); child = c->next)
7ab12479 3211 {
233a4a2c 3212 int child_size;
047aaeb9 3213
233a4a2c 3214 c = XWINDOW (child);
047aaeb9
MR
3215 child_size = WINDOW_TOTAL_SIZE (c, width_p);
3216 size_window (child, child_size, width_p, nodelete_p,
3217 first_only, last_only);
7ab12479
JB
3218 }
3219 }
3220}
3221
233a4a2c 3222/* Set WINDOW's height to HEIGHT, and recursively change the height of
047aaeb9
MR
3223 WINDOW's children. NODELETE zero means windows that have become
3224 smaller than window-min-height in the process may be deleted.
3225 NODELETE 1 means never delete windows that become too small in the
3226 process. (The caller should check later and do so if appropriate.)
3227 NODELETE 2 means delete only windows that have become too small to be
3228 displayed correctly. */
7ab12479 3229
5e14b1fc 3230void
971de7fb 3231set_window_height (Lisp_Object window, int height, int nodelete)
7ab12479 3232{
5fe0b054 3233 size_window (window, height, 0, nodelete, 0, 0);
233a4a2c 3234}
7ab12479 3235
233a4a2c 3236/* Set WINDOW's width to WIDTH, and recursively change the width of
047aaeb9
MR
3237 WINDOW's children. NODELETE zero means windows that have become
3238 smaller than window-min-width in the process may be deleted.
3239 NODELETE 1 means never delete windows that become too small in the
3240 process. (The caller should check later and do so if appropriate.)
3241 NODELETE 2 means delete only windows that have become too small to be
3242 displayed correctly. */
7ab12479 3243
233a4a2c 3244void
971de7fb 3245set_window_width (Lisp_Object window, int width, int nodelete)
233a4a2c 3246{
5fe0b054 3247 size_window (window, width, 1, nodelete, 0, 0);
7ab12479 3248}
233a4a2c 3249
cdbc7fec
KS
3250/* Change window heights in windows rooted in WINDOW by N lines. */
3251
3252void
971de7fb 3253change_window_heights (Lisp_Object window, int n)
cdbc7fec
KS
3254{
3255 struct window *w = XWINDOW (window);
3256
949cf20f
KS
3257 XSETFASTINT (w->top_line, XFASTINT (w->top_line) + n);
3258 XSETFASTINT (w->total_lines, XFASTINT (w->total_lines) - n);
cdbc7fec 3259
949cf20f
KS
3260 if (INTEGERP (w->orig_top_line))
3261 XSETFASTINT (w->orig_top_line, XFASTINT (w->orig_top_line) + n);
3262 if (INTEGERP (w->orig_total_lines))
3263 XSETFASTINT (w->orig_total_lines, XFASTINT (w->orig_total_lines) - n);
cdbc7fec
KS
3264
3265 /* Handle just the top child in a vertical split. */
3266 if (!NILP (w->vchild))
3267 change_window_heights (w->vchild, n);
3268
3269 /* Adjust all children in a horizontal split. */
3270 for (window = w->hchild; !NILP (window); window = w->next)
3271 {
3272 w = XWINDOW (window);
3273 change_window_heights (window, n);
3274 }
3275}
3276
7ab12479 3277\f
1d8d96fa 3278int window_select_count;
7ab12479 3279
16a97296
PE
3280INFUN (Fset_window_margins, 3);
3281INFUN (Fset_window_fringes, 4);
3282INFUN (Fset_window_scroll_bars, 4);
3283INFUN (Fset_window_vscroll, 3);
7ab12479 3284
6a44ffb3
SM
3285static void
3286run_funs (Lisp_Object funs)
3287{
3288 for (; CONSP (funs); funs = XCDR (funs))
3289 if (!EQ (XCAR (funs), Qt))
3290 call0 (XCAR (funs));
3291}
3292
3293static Lisp_Object select_window_norecord (Lisp_Object window);
c6932ecd 3294static Lisp_Object select_frame_norecord (Lisp_Object frame);
6a44ffb3 3295
ef264c42
SM
3296void
3297run_window_configuration_change_hook (struct frame *f)
3298{
fec89261 3299 int count = SPECPDL_INDEX ();
6a44ffb3
SM
3300 Lisp_Object frame, global_wcch
3301 = Fdefault_value (Qwindow_configuration_change_hook);
3302 XSETFRAME (frame, f);
3303
3304 if (NILP (Vrun_hooks))
3305 return;
3306
fec89261
MR
3307 if (SELECTED_FRAME () != f)
3308 {
c6932ecd
MR
3309 record_unwind_protect (select_frame_norecord, Fselected_frame ());
3310 Fselect_frame (frame, Qt);
fec89261 3311 }
6a44ffb3
SM
3312
3313 /* Use the right buffer. Matters when running the local hooks. */
3314 if (current_buffer != XBUFFER (Fwindow_buffer (Qnil)))
3315 {
3316 record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
3317 Fset_buffer (Fwindow_buffer (Qnil));
3318 }
3319
3320 /* Look for buffer-local values. */
3321 {
3322 Lisp_Object windows = Fwindow_list (frame, Qlambda, Qnil);
3323 for (; CONSP (windows); windows = XCDR (windows))
3324 {
3325 Lisp_Object window = XCAR (windows);
3326 Lisp_Object buffer = Fwindow_buffer (window);
3327 if (!NILP (Flocal_variable_p (Qwindow_configuration_change_hook,
3328 buffer)))
3329 {
4554d213 3330 int count1 = SPECPDL_INDEX ();
6a44ffb3
SM
3331 record_unwind_protect (select_window_norecord, Fselected_window ());
3332 select_window_norecord (window);
3333 run_funs (Fbuffer_local_value (Qwindow_configuration_change_hook,
3334 buffer));
4554d213 3335 unbind_to (count1, Qnil);
fec89261 3336 }
6a44ffb3
SM
3337 }
3338 }
047aaeb9 3339
6a44ffb3
SM
3340 run_funs (global_wcch);
3341 unbind_to (count, Qnil);
ef264c42
SM
3342}
3343
5500c422
GM
3344/* Make WINDOW display BUFFER as its contents. RUN_HOOKS_P non-zero
3345 means it's allowed to run hooks. See make_frame for a case where
949cf20f
KS
3346 it's not allowed. KEEP_MARGINS_P non-zero means that the current
3347 margins, fringes, and scroll-bar settings of the window are not
3348 reset from the buffer's local settings. */
7ab12479 3349
5500c422 3350void
971de7fb 3351set_window_buffer (Lisp_Object window, Lisp_Object buffer, int run_hooks_p, int keep_margins_p)
5500c422
GM
3352{
3353 struct window *w = XWINDOW (window);
3354 struct buffer *b = XBUFFER (buffer);
aed13378 3355 int count = SPECPDL_INDEX ();
c3b232e4 3356 int samebuf = EQ (buffer, w->buffer);
7ab12479
JB
3357
3358 w->buffer = buffer;
86e48436
RS
3359
3360 if (EQ (window, selected_window))
4b4deea2 3361 BVAR (b, last_selected_window) = window;
beb4e312 3362
c49a0495
KS
3363 /* Let redisplay errors through. */
3364 b->display_error_modiff = 0;
3365
beb4e312 3366 /* Update time stamps of buffer display. */
4b4deea2
TT
3367 if (INTEGERP (BVAR (b, display_count)))
3368 XSETINT (BVAR (b, display_count), XINT (BVAR (b, display_count)) + 1);
3369 BVAR (b, display_time) = Fcurrent_time ();
86e48436 3370
d834a2e9 3371 XSETFASTINT (w->window_end_pos, 0);
5500c422 3372 XSETFASTINT (w->window_end_vpos, 0);
72af86bd 3373 memset (&w->last_cursor, 0, sizeof w->last_cursor);
5a41ab94 3374 w->window_end_valid = Qnil;
c3b232e4 3375 if (!(keep_margins_p && samebuf))
23fe745a 3376 { /* If we're not actually changing the buffer, don't reset hscroll and
c3b232e4
SM
3377 vscroll. This case happens for example when called from
3378 change_frame_size_1, where we use a dummy call to
3379 Fset_window_buffer on the frame's selected window (and no other)
3380 just in order to run window-configuration-change-hook.
3381 Resetting hscroll and vscroll here is problematic for things like
3382 image-mode and doc-view-mode since it resets the image's position
3383 whenever we resize the frame. */
3384 w->hscroll = w->min_hscroll = make_number (0);
3385 w->vscroll = 0;
3386 set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
3387 set_marker_restricted (w->start,
3388 make_number (b->last_window_start),
3389 buffer);
3390 w->start_at_line_beg = Qnil;
3391 w->force_start = Qnil;
3392 XSETFASTINT (w->last_modified, 0);
3393 XSETFASTINT (w->last_overlay_modified, 0);
3394 }
3395 /* Maybe we could move this into the `if' but it's not obviously safe and
3396 I doubt it's worth the trouble. */
7ab12479 3397 windows_or_buffers_changed++;
5b03d3c0 3398
da39107c 3399 /* We must select BUFFER for running the window-scroll-functions. */
5b03d3c0
RS
3400 /* We can't check ! NILP (Vwindow_scroll_functions) here
3401 because that might itself be a local variable. */
da39107c 3402 if (window_initialized)
5b03d3c0 3403 {
da39107c 3404 record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
5b03d3c0
RS
3405 Fset_buffer (buffer);
3406 }
3407
a1562258
SM
3408 XMARKER (w->pointm)->insertion_type = !NILP (Vwindow_point_insertion_type);
3409
949cf20f
KS
3410 if (!keep_margins_p)
3411 {
3412 /* Set left and right marginal area width etc. from buffer. */
3413
79fd290e 3414 /* This may call adjust_window_margins three times, so
949cf20f 3415 temporarily disable window margins. */
6b61353c
KH
3416 Lisp_Object save_left = w->left_margin_cols;
3417 Lisp_Object save_right = w->right_margin_cols;
3418
949cf20f
KS
3419 w->left_margin_cols = w->right_margin_cols = Qnil;
3420
3421 Fset_window_fringes (window,
4b4deea2
TT
3422 BVAR (b, left_fringe_width), BVAR (b, right_fringe_width),
3423 BVAR (b, fringes_outside_margins));
949cf20f
KS
3424
3425 Fset_window_scroll_bars (window,
4b4deea2
TT
3426 BVAR (b, scroll_bar_width),
3427 BVAR (b, vertical_scroll_bar_type), Qnil);
949cf20f 3428
6b61353c
KH
3429 w->left_margin_cols = save_left;
3430 w->right_margin_cols = save_right;
3431
949cf20f 3432 Fset_window_margins (window,
4b4deea2 3433 BVAR (b, left_margin_cols), BVAR (b, right_margin_cols));
949cf20f 3434 }
7ab12479 3435
5500c422
GM
3436 if (run_hooks_p)
3437 {
3438 if (! NILP (Vwindow_scroll_functions))
3439 run_hook_with_args_2 (Qwindow_scroll_functions, window,
3440 Fmarker_position (w->start));
ef264c42 3441 run_window_configuration_change_hook (XFRAME (WINDOW_FRAME (w)));
5500c422 3442 }
543f5fb1 3443
5b03d3c0 3444 unbind_to (count, Qnil);
5500c422 3445}
5b03d3c0 3446
5500c422 3447
16a97296 3448DEFUE ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 3, 0,
d653c8cc
MR
3449 doc: /* Make WINDOW display BUFFER-OR-NAME as its contents.
3450WINDOW defaults to the selected window. BUFFER-OR-NAME must be a buffer
3451or the name of an existing buffer. Optional third argument KEEP-MARGINS
3452non-nil means that WINDOW's current display margins, fringe widths, and
3453scroll bar settings are preserved; the default is to reset these from
fec89261 3454the local settings for BUFFER-OR-NAME or the frame defaults. Return nil.
d653c8cc 3455
7bfac547
MR
3456This function throws an error when WINDOW is strongly dedicated to its
3457buffer (that is `window-dedicated-p' returns t for WINDOW) and does not
3458already display BUFFER-OR-NAME.
6cb4a892 3459
8fef9de1
MR
3460This function runs `window-scroll-functions' before running
3461`window-configuration-change-hook'. */)
5842a27b 3462 (register Lisp_Object window, Lisp_Object buffer_or_name, Lisp_Object keep_margins)
5500c422 3463{
d653c8cc 3464 register Lisp_Object tem, buffer;
5500c422 3465 register struct window *w = decode_window (window);
5500c422 3466
bed0c171 3467 XSETWINDOW (window, w);
d653c8cc 3468 buffer = Fget_buffer (buffer_or_name);
b7826503 3469 CHECK_BUFFER (buffer);
4b4deea2 3470 if (NILP (BVAR (XBUFFER (buffer), name)))
5500c422
GM
3471 error ("Attempt to display deleted buffer");
3472
3473 tem = w->buffer;
aac0c6e3
MR
3474 if (NILP (tem))
3475 error ("Window is deleted");
3476 else if (!EQ (tem, Qt))
d653c8cc 3477 /* w->buffer is t when the window is first being set up. */
5500c422 3478 {
ef1b0ba7
SM
3479 if (EQ (tem, buffer))
3480 return Qnil;
3481 else if (EQ (w->dedicated, Qt))
4b4deea2 3482 error ("Window is dedicated to `%s'", SDATA (BVAR (XBUFFER (tem), name)));
ef1b0ba7
SM
3483 else
3484 w->dedicated = Qnil;
5500c422
GM
3485
3486 unshow_buffer (w);
3487 }
3488
949cf20f 3489 set_window_buffer (window, buffer, 1, !NILP (keep_margins));
7ab12479
JB
3490 return Qnil;
3491}
3492
e6b84b30
MR
3493/* If select_window is called with inhibit_point_swap non-zero it will
3494 not store point of the old selected window's buffer back into that
3495 window's pointm slot. This is needed by Fset_window_configuration to
3496 avoid that the display routine is called with selected_window set to
3497 Qnil causing a subsequent crash. */
2d0834cc 3498
e6b84b30 3499static Lisp_Object
7c82f3e2 3500select_window (Lisp_Object window, Lisp_Object norecord, int inhibit_point_swap)
7ab12479
JB
3501{
3502 register struct window *w;
719eaeb1 3503 register struct window *ow;
1ae1a37d 3504 struct frame *sf;
7ab12479 3505
b7826503 3506 CHECK_LIVE_WINDOW (window);
7ab12479
JB
3507
3508 w = XWINDOW (window);
50e88778 3509 w->frozen_window_start_p = 0;
7ab12479 3510
4e822bdc
MR
3511 if (NILP (norecord))
3512 {
3513 ++window_select_count;
3514 XSETFASTINT (w->use_time, window_select_count);
13b5221f 3515 record_buffer (w->buffer);
4e822bdc
MR
3516 }
3517
bae1fa42 3518 if (EQ (window, selected_window) && !inhibit_point_swap)
7ab12479
JB
3519 return window;
3520
ca2d5566
SM
3521 sf = SELECTED_FRAME ();
3522 if (XFRAME (WINDOW_FRAME (w)) != sf)
3523 {
3524 XFRAME (WINDOW_FRAME (w))->selected_window = window;
3525 /* Use this rather than Fhandle_switch_frame
3526 so that FRAME_FOCUS_FRAME is moved appropriately as we
3527 move around in the state where a minibuffer in a separate
3528 frame is active. */
c6932ecd 3529 Fselect_frame (WINDOW_FRAME (w), norecord);
ca2d5566
SM
3530 /* Fselect_frame called us back so we've done all the work already. */
3531 eassert (EQ (window, selected_window));
3532 return window;
3533 }
3534 else
3535 sf->selected_window = window;
3536
a46c0153
RS
3537 /* Store the current buffer's actual point into the
3538 old selected window. It belongs to that window,
3539 and when the window is not selected, must be in the window. */
e6b84b30 3540 if (!inhibit_point_swap)
719eaeb1
GM
3541 {
3542 ow = XWINDOW (selected_window);
3543 if (! NILP (ow->buffer))
3544 set_marker_both (ow->pointm, ow->buffer,
3545 BUF_PT (XBUFFER (ow->buffer)),
3546 BUF_PT_BYTE (XBUFFER (ow->buffer)));
3547 }
7ab12479
JB
3548
3549 selected_window = window;
7ab12479 3550
7ab12479
JB
3551 Fset_buffer (w->buffer);
3552
4b4deea2 3553 BVAR (XBUFFER (w->buffer), last_selected_window) = window;
86e48436 3554
7ab12479
JB
3555 /* Go to the point recorded in the window.
3556 This is important when the buffer is in more
3557 than one window. It also matters when
3558 redisplay_window has altered point after scrolling,
3559 because it makes the change only in the window. */
3560 {
2452438f 3561 register EMACS_INT new_point = marker_position (w->pointm);
7ab12479
JB
3562 if (new_point < BEGV)
3563 SET_PT (BEGV);
a9c95e08 3564 else if (new_point > ZV)
7ab12479
JB
3565 SET_PT (ZV);
3566 else
3567 SET_PT (new_point);
3568 }
3569
3570 windows_or_buffers_changed++;
3571 return window;
3572}
14d87dc9 3573
e6b84b30
MR
3574
3575/* Note that selected_window can be nil when this is called from
3576 Fset_window_configuration. */
3577
16a97296 3578DEFUE ("select-window", Fselect_window, Sselect_window, 1, 2, 0,
e6b84b30
MR
3579 doc: /* Select WINDOW. Most editing will apply to WINDOW's buffer.
3580If WINDOW is not already selected, make WINDOW's buffer current
3581and make WINDOW the frame's selected window. Return WINDOW.
3582Optional second arg NORECORD non-nil means do not put this buffer
3583at the front of the list of recently selected ones and do not
3584make this window the most recently selected one.
3585
3586Note that the main editor command loop selects the buffer of the
3587selected window before each command. */)
7c82f3e2 3588 (register Lisp_Object window, Lisp_Object norecord)
e6b84b30 3589{
29feb0e9 3590 return select_window (window, norecord, 0);
e6b84b30
MR
3591}
3592
14d87dc9 3593static Lisp_Object
971de7fb 3594select_window_norecord (Lisp_Object window)
14d87dc9 3595{
ab6d1131
MR
3596 return WINDOW_LIVE_P (window)
3597 ? Fselect_window (window, Qt) : selected_window;
14d87dc9 3598}
c6932ecd
MR
3599
3600static Lisp_Object
971de7fb 3601select_frame_norecord (Lisp_Object frame)
c6932ecd
MR
3602{
3603 return FRAME_LIVE_P (XFRAME (frame))
3604 ? Fselect_frame (frame, Qt) : selected_frame;
3605}
b7354ddf 3606\f
7e5cf297 3607static Lisp_Object
971de7fb 3608display_buffer (Lisp_Object buffer, Lisp_Object not_this_window_p, Lisp_Object override_frame)
d07f802a 3609{
87478b52 3610 return call3 (Qdisplay_buffer, buffer, not_this_window_p, override_frame);
d07f802a
RS
3611}
3612
6b61353c
KH
3613DEFUN ("force-window-update", Fforce_window_update, Sforce_window_update,
3614 0, 1, 0,
5a1048a5 3615 doc: /* Force all windows to be updated on next redisplay.
6b61353c 3616If optional arg OBJECT is a window, force redisplay of that window only.
0cc1039f 3617If OBJECT is a buffer or buffer name, force redisplay of all windows
6b61353c 3618displaying that buffer. */)
5842a27b 3619 (Lisp_Object object)
6b61353c
KH
3620{
3621 if (NILP (object))
3622 {
3623 windows_or_buffers_changed++;
3624 update_mode_lines++;
3625 return Qt;
3626 }
3627
3628 if (WINDOWP (object))
3629 {
3630 struct window *w = XWINDOW (object);
3631 mark_window_display_accurate (object, 0);
3632 w->update_mode_line = Qt;
3633 if (BUFFERP (w->buffer))
3634 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
3635 ++update_mode_lines;
3636 return Qt;
3637 }
0cc1039f 3638
6b61353c
KH
3639 if (STRINGP (object))
3640 object = Fget_buffer (object);
4b4deea2 3641 if (BUFFERP (object) && !NILP (BVAR (XBUFFER (object), name)))
6b61353c
KH
3642 {
3643 /* Walk all windows looking for buffer, and force update
3644 of each of those windows. */
3645
3646 object = window_loop (REDISPLAY_BUFFER_WINDOWS, object, 0, Qvisible);
3647 return NILP (object) ? Qnil : Qt;
3648 }
3649
3650 /* If nothing suitable was found, just return.
3651 We could signal an error, but this feature will typically be used
3652 asynchronously in timers or process sentinels, so we don't. */
3653 return Qnil;
3654}
3655
3656
7ab12479 3657void
971de7fb 3658temp_output_buffer_show (register Lisp_Object buf)
7ab12479
JB
3659{
3660 register struct buffer *old = current_buffer;
3661 register Lisp_Object window;
3662 register struct window *w;
3663
4b4deea2 3664 BVAR (XBUFFER (buf), directory) = BVAR (current_buffer, directory);
bccd3dd1 3665
7ab12479 3666 Fset_buffer (buf);
c6367666 3667 BUF_SAVE_MODIFF (XBUFFER (buf)) = MODIFF;
7ab12479
JB
3668 BEGV = BEG;
3669 ZV = Z;
3670 SET_PT (BEG);
7ab12479
JB
3671 set_buffer_internal (old);
3672
e67a1dea 3673 if (!NILP (Vtemp_buffer_show_function))
7ab12479
JB
3674 call1 (Vtemp_buffer_show_function, buf);
3675 else
3676 {
87478b52 3677 window = display_buffer (buf, Qnil, Qnil);
7ab12479 3678
1ae1a37d 3679 if (!EQ (XWINDOW (window)->frame, selected_frame))
44fa5b1e 3680 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
7ab12479
JB
3681 Vminibuf_scroll_window = window;
3682 w = XWINDOW (window);
d834a2e9 3683 XSETFASTINT (w->hscroll, 0);
ea68264b 3684 XSETFASTINT (w->min_hscroll, 0);
2d0834cc
SM
3685 set_marker_restricted_both (w->start, buf, BEG, BEG);
3686 set_marker_restricted_both (w->pointm, buf, BEG, BEG);
a58ec57d 3687
beb4e312 3688 /* Run temp-buffer-show-hook, with the chosen window selected
a5731348 3689 and its buffer current. */
dee091a3
JD
3690 {
3691 int count = SPECPDL_INDEX ();
3692 Lisp_Object prev_window, prev_buffer;
3693 prev_window = selected_window;
3694 XSETBUFFER (prev_buffer, old);
3695
3696 /* Select the window that was chosen, for running the hook.
3697 Note: Both Fselect_window and select_window_norecord may
3698 set-buffer to the buffer displayed in the window,
3699 so we need to save the current buffer. --stef */
3700 record_unwind_protect (Fset_buffer, prev_buffer);
3701 record_unwind_protect (select_window_norecord, prev_window);
3702 Fselect_window (window, Qt);
3703 Fset_buffer (w->buffer);
3704 Frun_hooks (1, &Qtemp_buffer_show_hook);
3705 unbind_to (count, Qnil);
3706 }
2cccc823 3707 }
7ab12479 3708}
3e21b6a7
SM
3709
3710DEFUN ("internal-temp-output-buffer-show",
3711 Ftemp_output_buffer_show, Stemp_output_buffer_show,
3712 1, 1, 0,
3713 doc: /* Internal function for `with-output-to-temp-buffer''. */)
3714 (Lisp_Object buf)
3715{
3716 temp_output_buffer_show (buf);
3717 return Qnil;
3718}
7ab12479 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)",
5fdb398c 3808 (int) (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)",
5fdb398c 3825 (int) (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. */
4554d213 4127 Lisp_Object start, tem;
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 {
4554d213 4137 Lisp_Object next1 = XWINDOW (tem)->next;
dc1ab1ee 4138 delete_window (tem);
4554d213 4139 tem = next1;
dc1ab1ee
RS
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 {
4554d213 4148 Lisp_Object next1 = XWINDOW (tem)->next;
dc1ab1ee 4149 delete_window (tem);
4554d213 4150 tem = next1;
daf516d3
RS
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
1344aad4
TT
4838 || !SYMBOLP (KVAR (current_kboard, Vlast_command))
4839 || NILP (Fget (KVAR (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)
e4cc2dfc 4872 move_it_by_lines (&it, -1);
e856c216 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)
e4cc2dfc 4882 move_it_by_lines (&it, 1);
bed83ee4 4883 }
5500c422
GM
4884 }
4885 else
e4cc2dfc 4886 move_it_by_lines (&it, n);
5500c422 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;
e4cc2dfc 4997 move_it_by_lines (&it, 1);
e9b2c961
RS
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 {
e4cc2dfc 5031 move_it_by_lines (&it, 1);
aed328bf
KS
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 {
e4cc2dfc 5058 move_it_by_lines (&it, -2);
5cdb3cf3
MB
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
1344aad4
TT
5095 || !SYMBOLP (KVAR (current_kboard, Vlast_command))
5096 || NILP (Fget (KVAR (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
16a97296 5506DEFUE ("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;
d6550a9f 5528 int iarg IF_LINT (= 0);
f6b43440 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. */
e4cc2dfc 5601 move_it_by_lines (&it, 0);
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;
e4cc2dfc 5608 move_it_by_lines (&it, nlines);
d466fa4d 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)
e4cc2dfc 5647 move_it_by_lines (&it, 1);
f204989e 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
16a97296 5859DEFUE ("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;
4b4deea2 5882 if (NILP (BVAR (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 {
4b4deea2 6067 if (!NILP (BVAR (XBUFFER (p->buffer), name)))
fd482be5
JB
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);
4b4deea2 6074 Fset_marker (BVAR (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 }
4b4deea2 6084 else if (NILP (w->buffer) || NILP (BVAR (XBUFFER (w->buffer), name)))
52a68e98 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);
4b4deea2 6125 BVAR (XBUFFER (XWINDOW (selected_window)->buffer), last_selected_window)
396a830c 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
4b4deea2 6326 tem = BVAR (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
16a97296 6356DEFUE ("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
94e16dd5
KS
6404\f
6405/***********************************************************************
6406 Window Split Tree
6407 ***********************************************************************/
6408
6409static Lisp_Object
971de7fb 6410window_tree (struct window *w)
94e16dd5
KS
6411{
6412 Lisp_Object tail = Qnil;
6413 Lisp_Object result = Qnil;
6414
6415 while (w)
6416 {
6417 Lisp_Object wn;
6418
6419 XSETWINDOW (wn, w);
6420 if (!NILP (w->hchild))
6421 wn = Fcons (Qnil, Fcons (Fwindow_edges (wn),
c16e1cc3 6422 window_tree (XWINDOW (w->hchild))));
94e16dd5
KS
6423 else if (!NILP (w->vchild))
6424 wn = Fcons (Qt, Fcons (Fwindow_edges (wn),
c16e1cc3 6425 window_tree (XWINDOW (w->vchild))));
94e16dd5
KS
6426
6427 if (NILP (result))
6428 {
6429 result = tail = Fcons (wn, Qnil);
6430 }
6431 else
6432 {
6433 XSETCDR (tail, Fcons (wn, Qnil));
6434 tail = XCDR (tail);
6435 }
6436
6437 w = NILP (w->next) ? 0 : XWINDOW (w->next);
6438 }
6439
6440 return result;
6441}
6442
6443
6444
c16e1cc3 6445DEFUN ("window-tree", Fwindow_tree, Swindow_tree,
94e16dd5 6446 0, 1, 0,
c16e1cc3 6447 doc: /* Return the window tree for frame FRAME.
94e16dd5
KS
6448
6449The return value is a list of the form (ROOT MINI), where ROOT
c16e1cc3 6450represents the window tree of the frame's root window, and MINI
94e16dd5
KS
6451is the frame's minibuffer window.
6452
6453If the root window is not split, ROOT is the root window itself.
6454Otherwise, ROOT is a list (DIR EDGES W1 W2 ...) where DIR is nil for a
008171a4 6455horizontal split, and t for a vertical split, EDGES gives the combined
94e16dd5
KS
6456size and position of the subwindows in the split, and the rest of the
6457elements are the subwindows in the split. Each of the subwindows may
6458again be a window or a list representing a window split, and so on.
6459EDGES is a list \(LEFT TOP RIGHT BOTTOM) as returned by `window-edges'.
6460
6461If FRAME is nil or omitted, return information on the currently
6462selected frame. */)
5842a27b 6463 (Lisp_Object frame)
94e16dd5 6464{
94e16dd5
KS
6465 FRAME_PTR f;
6466
6467 if (NILP (frame))
6468 frame = selected_frame;
6469
6470 CHECK_FRAME (frame);
6471 f = XFRAME (frame);
6472
6473 if (!FRAME_LIVE_P (f))
6474 return Qnil;
6475
c16e1cc3 6476 return window_tree (XWINDOW (FRAME_ROOT_WINDOW (f)));
94e16dd5
KS
6477}
6478
5500c422
GM
6479\f
6480/***********************************************************************
6481 Marginal Areas
6482 ***********************************************************************/
6483
6484DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
a7bdfc08 6485 2, 3, 0,
fdb82f93 6486 doc: /* Set width of marginal areas of window WINDOW.
6b61353c
KH
6487If WINDOW is nil, set margins of the currently selected window.
6488Second arg LEFT-WIDTH specifies the number of character cells to
6489reserve for the left marginal area. Optional third arg RIGHT-WIDTH
6490does the same for the right marginal area. A nil width parameter
6491means no margin. */)
5842a27b 6492 (Lisp_Object window, Lisp_Object left_width, Lisp_Object right_width)
5500c422
GM
6493{
6494 struct window *w = decode_window (window);
5500c422 6495
6b61353c
KH
6496 /* Translate negative or zero widths to nil.
6497 Margins that are too wide have to be checked elsewhere. */
949cf20f 6498
c10ce82e 6499 if (!NILP (left_width))
6b61353c 6500 {
c10ce82e
JB
6501 CHECK_NUMBER (left_width);
6502 if (XINT (left_width) <= 0)
6503 left_width = Qnil;
6b61353c 6504 }
5500c422 6505
c10ce82e 6506 if (!NILP (right_width))
6b61353c 6507 {
c10ce82e
JB
6508 CHECK_NUMBER (right_width);
6509 if (XINT (right_width) <= 0)
6510 right_width = Qnil;
6b61353c 6511 }
5500c422 6512
c10ce82e
JB
6513 if (!EQ (w->left_margin_cols, left_width)
6514 || !EQ (w->right_margin_cols, right_width))
949cf20f 6515 {
c10ce82e
JB
6516 w->left_margin_cols = left_width;
6517 w->right_margin_cols = right_width;
949cf20f
KS
6518
6519 adjust_window_margins (w);
6520
6521 ++windows_or_buffers_changed;
6522 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6523 }
5500c422 6524
5500c422
GM
6525 return Qnil;
6526}
6527
6528
6529DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
6530 0, 1, 0,
fdb82f93
PJ
6531 doc: /* Get width of marginal areas of window WINDOW.
6532If WINDOW is omitted or nil, use the currently selected window.
6533Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).
6534If a marginal area does not exist, its width will be returned
6535as nil. */)
5842a27b 6536 (Lisp_Object window)
5500c422
GM
6537{
6538 struct window *w = decode_window (window);
949cf20f
KS
6539 return Fcons (w->left_margin_cols, w->right_margin_cols);
6540}
6541
6542
6543\f
6544/***********************************************************************
6545 Fringes
6546 ***********************************************************************/
6547
16a97296 6548DEFUE ("set-window-fringes", Fset_window_fringes, Sset_window_fringes,
949cf20f 6549 2, 4, 0,
6b61353c
KH
6550 doc: /* Set the fringe widths of window WINDOW.
6551If WINDOW is nil, set the fringe widths of the currently selected
6552window.
6553Second arg LEFT-WIDTH specifies the number of pixels to reserve for
6554the left fringe. Optional third arg RIGHT-WIDTH specifies the right
6555fringe width. If a fringe width arg is nil, that means to use the
6556frame's default fringe width. Default fringe widths can be set with
6557the command `set-fringe-style'.
6558If optional fourth arg OUTSIDE-MARGINS is non-nil, draw the fringes
6559outside of the display margins. By default, fringes are drawn between
6560display marginal areas and the text area. */)
5842a27b 6561 (Lisp_Object window, Lisp_Object left_width, Lisp_Object right_width, Lisp_Object outside_margins)
949cf20f
KS
6562{
6563 struct window *w = decode_window (window);
6564
c10ce82e
JB
6565 if (!NILP (left_width))
6566 CHECK_NATNUM (left_width);
6567 if (!NILP (right_width))
6568 CHECK_NATNUM (right_width);
5a857365 6569
017e297e 6570 /* Do nothing on a tty. */
d46c6df5
NR
6571 if (FRAME_WINDOW_P (WINDOW_XFRAME (w))
6572 && (!EQ (w->left_fringe_width, left_width)
6573 || !EQ (w->right_fringe_width, right_width)
6574 || !EQ (w->fringes_outside_margins, outside_margins)))
949cf20f 6575 {
c10ce82e
JB
6576 w->left_fringe_width = left_width;
6577 w->right_fringe_width = right_width;
949cf20f
KS
6578 w->fringes_outside_margins = outside_margins;
6579
6580 adjust_window_margins (w);
6581
6582 clear_glyph_matrix (w->current_matrix);
6583 w->window_end_valid = Qnil;
6584
6585 ++windows_or_buffers_changed;
6586 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6587 }
6588
6589 return Qnil;
6590}
6591
6592
6593DEFUN ("window-fringes", Fwindow_fringes, Swindow_fringes,
6594 0, 1, 0,
6595 doc: /* Get width of fringes of window WINDOW.
6596If WINDOW is omitted or nil, use the currently selected window.
6b61353c 6597Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS). */)
5842a27b 6598 (Lisp_Object window)
949cf20f
KS
6599{
6600 struct window *w = decode_window (window);
d46c6df5 6601
949cf20f
KS
6602 return Fcons (make_number (WINDOW_LEFT_FRINGE_WIDTH (w)),
6603 Fcons (make_number (WINDOW_RIGHT_FRINGE_WIDTH (w)),
d46c6df5
NR
6604 Fcons ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
6605 ? Qt : Qnil), Qnil)));
949cf20f
KS
6606}
6607
6608
6609\f
6610/***********************************************************************
6611 Scroll bars
6612 ***********************************************************************/
6613
16a97296
PE
6614DEFUE ("set-window-scroll-bars", Fset_window_scroll_bars,
6615 Sset_window_scroll_bars, 2, 4, 0,
949cf20f
KS
6616 doc: /* Set width and type of scroll bars of window WINDOW.
6617If window is nil, set scroll bars of the currently selected window.
6618Second parameter WIDTH specifies the pixel width for the scroll bar;
6619this is automatically adjusted to a multiple of the frame column width.
6620Third parameter VERTICAL-TYPE specifies the type of the vertical scroll
6621bar: left, right, or nil.
6b61353c 6622If WIDTH is nil, use the frame's scroll-bar width.
a53d44a8
JB
6623If VERTICAL-TYPE is t, use the frame's scroll-bar type.
6624Fourth parameter HORIZONTAL-TYPE is currently unused. */)
5842a27b 6625 (Lisp_Object window, Lisp_Object width, Lisp_Object vertical_type, Lisp_Object horizontal_type)
949cf20f
KS
6626{
6627 struct window *w = decode_window (window);
6628
6629 if (!NILP (width))
0f8fe9a2
SM
6630 {
6631 CHECK_NATNUM (width);
949cf20f 6632
0f8fe9a2
SM
6633 if (XINT (width) == 0)
6634 vertical_type = Qnil;
6635 }
949cf20f 6636
413a79ad 6637 if (!(NILP (vertical_type)
0cc1039f 6638 || EQ (vertical_type, Qleft)
6b61353c
KH
6639 || EQ (vertical_type, Qright)
6640 || EQ (vertical_type, Qt)))
6641 error ("Invalid type of vertical scroll bar");
6642
949cf20f
KS
6643 if (!EQ (w->scroll_bar_width, width)
6644 || !EQ (w->vertical_scroll_bar_type, vertical_type))
6645 {
6646 w->scroll_bar_width = width;
6647 w->vertical_scroll_bar_type = vertical_type;
6648
6649 adjust_window_margins (w);
6650
6651 clear_glyph_matrix (w->current_matrix);
6652 w->window_end_valid = Qnil;
6653
6654 ++windows_or_buffers_changed;
6655 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6656 }
6657
6658 return Qnil;
6659}
6660
6661
6662DEFUN ("window-scroll-bars", Fwindow_scroll_bars, Swindow_scroll_bars,
6663 0, 1, 0,
6664 doc: /* Get width and type of scroll bars of window WINDOW.
6665If WINDOW is omitted or nil, use the currently selected window.
6b61353c
KH
6666Value is a list of the form (WIDTH COLS VERTICAL-TYPE HORIZONTAL-TYPE).
6667If WIDTH is nil or TYPE is t, the window is using the frame's corresponding
6668value. */)
5842a27b 6669 (Lisp_Object window)
949cf20f
KS
6670{
6671 struct window *w = decode_window (window);
6672 return Fcons (make_number ((WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
6673 ? WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
6674 : WINDOW_SCROLL_BAR_AREA_WIDTH (w))),
6675 Fcons (make_number (WINDOW_SCROLL_BAR_COLS (w)),
6676 Fcons (w->vertical_scroll_bar_type,
6677 Fcons (Qnil, Qnil))));
5500c422
GM
6678}
6679
6680
7ab12479 6681\f
5500c422
GM
6682/***********************************************************************
6683 Smooth scrolling
6684 ***********************************************************************/
6685
0cc1039f 6686DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 2, 0,
fdb82f93
PJ
6687 doc: /* Return the amount by which WINDOW is scrolled vertically.
6688Use the selected window if WINDOW is nil or omitted.
0cc1039f 6689Normally, value is a multiple of the canonical character height of WINDOW;
8cd0d661 6690optional second arg PIXELS-P means value is measured in pixels. */)
5842a27b 6691 (Lisp_Object window, Lisp_Object pixels_p)
5500c422 6692{
47004952 6693 Lisp_Object result;
5500c422
GM
6694 struct frame *f;
6695 struct window *w;
177c0ea7 6696
5500c422
GM
6697 if (NILP (window))
6698 window = selected_window;
47004952 6699 else
b7826503 6700 CHECK_WINDOW (window);
5500c422
GM
6701 w = XWINDOW (window);
6702 f = XFRAME (w->frame);
177c0ea7 6703
5500c422 6704 if (FRAME_WINDOW_P (f))
0cc1039f
KS
6705 result = (NILP (pixels_p)
6706 ? FRAME_CANON_Y_FROM_PIXEL_Y (f, -w->vscroll)
6707 : make_number (-w->vscroll));
5500c422 6708 else
47004952
GM
6709 result = make_number (0);
6710 return result;
5500c422
GM
6711}
6712
6713
6714DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
0cc1039f 6715 2, 3, 0,
fdb82f93 6716 doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL.
0cc1039f
KS
6717WINDOW nil means use the selected window. Normally, VSCROLL is a
6718non-negative multiple of the canonical character height of WINDOW;
8cd0d661 6719optional third arg PIXELS-P non-nil means that VSCROLL is in pixels.
a0a37a6f
LT
6720If PIXELS-P is nil, VSCROLL may have to be rounded so that it
6721corresponds to an integral number of pixels. The return value is the
6722result of this rounding.
6723If PIXELS-P is non-nil, the return value is VSCROLL. */)
5842a27b 6724 (Lisp_Object window, Lisp_Object vscroll, Lisp_Object pixels_p)
5500c422
GM
6725{
6726 struct window *w;
6727 struct frame *f;
177c0ea7 6728
5500c422
GM
6729 if (NILP (window))
6730 window = selected_window;
47004952 6731 else
b7826503
PJ
6732 CHECK_WINDOW (window);
6733 CHECK_NUMBER_OR_FLOAT (vscroll);
177c0ea7 6734
5500c422
GM
6735 w = XWINDOW (window);
6736 f = XFRAME (w->frame);
6737
6738 if (FRAME_WINDOW_P (f))
6739 {
6740 int old_dy = w->vscroll;
177c0ea7 6741
0cc1039f
KS
6742 w->vscroll = - (NILP (pixels_p)
6743 ? FRAME_LINE_HEIGHT (f) * XFLOATINT (vscroll)
6744 : XFLOATINT (vscroll));
47004952 6745 w->vscroll = min (w->vscroll, 0);
5500c422 6746
e56263e5
KS
6747 if (w->vscroll != old_dy)
6748 {
6749 /* Adjust glyph matrix of the frame if the virtual display
6750 area becomes larger than before. */
6751 if (w->vscroll < 0 && w->vscroll < old_dy)
6752 adjust_glyphs (f);
177c0ea7 6753
e56263e5
KS
6754 /* Prevent redisplay shortcuts. */
6755 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
6756 }
5500c422 6757 }
177c0ea7 6758
0cc1039f 6759 return Fwindow_vscroll (window, pixels_p);
5500c422 6760}
177c0ea7 6761
7bbb5782
GM
6762\f
6763/* Call FN for all leaf windows on frame F. FN is called with the
6764 first argument being a pointer to the leaf window, and with
f95464e4 6765 additional argument USER_DATA. Stops when FN returns 0. */
7bbb5782 6766
2f7c71a1
AS
6767static void
6768foreach_window (struct frame *f, int (*fn) (struct window *, void *),
6769 void *user_data)
7bbb5782 6770{
56f2de10 6771 /* delete_frame may set FRAME_ROOT_WINDOW (f) to Qnil. */
76fb556f
YM
6772 if (WINDOWP (FRAME_ROOT_WINDOW (f)))
6773 foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data);
7bbb5782
GM
6774}
6775
6776
6777/* Helper function for foreach_window. Call FN for all leaf windows
6778 reachable from W. FN is called with the first argument being a
f95464e4 6779 pointer to the leaf window, and with additional argument USER_DATA.
67492200 6780 Stop when FN returns 0. Value is 0 if stopped by FN. */
7bbb5782 6781
67492200 6782static int
971de7fb 6783foreach_window_1 (struct window *w, int (*fn) (struct window *, void *), void *user_data)
7bbb5782 6784{
67492200 6785 int cont;
177c0ea7 6786
67492200 6787 for (cont = 1; w && cont;)
7bbb5782
GM
6788 {
6789 if (!NILP (w->hchild))
f95464e4 6790 cont = foreach_window_1 (XWINDOW (w->hchild), fn, user_data);
7bbb5782 6791 else if (!NILP (w->vchild))
f95464e4 6792 cont = foreach_window_1 (XWINDOW (w->vchild), fn, user_data);
177c0ea7 6793 else
0f532a9a 6794 cont = fn (w, user_data);
177c0ea7 6795
7bbb5782
GM
6796 w = NILP (w->next) ? 0 : XWINDOW (w->next);
6797 }
67492200
GM
6798
6799 return cont;
7bbb5782
GM
6800}
6801
6802
6d194a45 6803/* Freeze or unfreeze the window start of W unless it is a
f95464e4 6804 mini-window or the selected window. FREEZE_P non-null means freeze
7bbb5782
GM
6805 the window start. */
6806
67492200 6807static int
971de7fb 6808freeze_window_start (struct window *w, void *freeze_p)
7bbb5782 6809{
08c1d235
SM
6810 if (MINI_WINDOW_P (w)
6811 || (WINDOWP (selected_window) /* Can be nil in corner cases. */
6812 && (w == XWINDOW (selected_window)
6813 || (MINI_WINDOW_P (XWINDOW (selected_window))
6814 && ! NILP (Vminibuf_scroll_window)
6815 && w == XWINDOW (Vminibuf_scroll_window)))))
f95464e4 6816 freeze_p = NULL;
177c0ea7 6817
f95464e4 6818 w->frozen_window_start_p = freeze_p != NULL;
67492200 6819 return 1;
7bbb5782
GM
6820}
6821
6822
6823/* Freeze or unfreeze the window starts of all leaf windows on frame
6824 F, except the selected window and a mini-window. FREEZE_P non-zero
6825 means freeze the window start. */
6826
6827void
971de7fb 6828freeze_window_starts (struct frame *f, int freeze_p)
7bbb5782 6829{
cbccabec 6830 foreach_window (f, freeze_window_start, (void *) (freeze_p ? f : 0));
7bbb5782 6831}
5500c422
GM
6832
6833\f
6834/***********************************************************************
6835 Initialization
6836 ***********************************************************************/
6837
cbff28e8 6838/* Return 1 if window configurations C1 and C2
9d14503e 6839 describe the same state of affairs. This is used by Fequal. */
cbff28e8
RS
6840
6841int
971de7fb 6842compare_window_configurations (Lisp_Object c1, Lisp_Object c2, int ignore_positions)
cbff28e8
RS
6843{
6844 register struct save_window_data *d1, *d2;
6845 struct Lisp_Vector *sw1, *sw2;
6846 int i;
6847
663fbbba
KS
6848 CHECK_WINDOW_CONFIGURATION (c1);
6849 CHECK_WINDOW_CONFIGURATION (c2);
177c0ea7 6850
cbff28e8
RS
6851 d1 = (struct save_window_data *) XVECTOR (c1);
6852 d2 = (struct save_window_data *) XVECTOR (c2);
6853 sw1 = XVECTOR (d1->saved_windows);
6854 sw2 = XVECTOR (d2->saved_windows);
6855
b05b4e27 6856 if (d1->frame_cols != d2->frame_cols)
cbff28e8 6857 return 0;
b05b4e27 6858 if (d1->frame_lines != d2->frame_lines)
cbff28e8 6859 return 0;
b05b4e27 6860 if (d1->frame_menu_bar_lines != d2->frame_menu_bar_lines)
cbff28e8
RS
6861 return 0;
6862 if (! EQ (d1->selected_frame, d2->selected_frame))
6863 return 0;
6864 /* Don't compare the current_window field directly.
6865 Instead see w1_is_current and w2_is_current, below. */
6866 if (! EQ (d1->current_buffer, d2->current_buffer))
6867 return 0;
2f8274be 6868 if (! ignore_positions)
3f49fddc
KS
6869 {
6870 if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
6871 return 0;
6872 if (! EQ (d1->minibuf_selected_window, d2->minibuf_selected_window))
6873 return 0;
6874 }
cbff28e8
RS
6875 /* Don't compare the root_window field.
6876 We don't require the two configurations
6877 to use the same window object,
6878 and the two root windows must be equivalent
6879 if everything else compares equal. */
6880 if (! EQ (d1->focus_frame, d2->focus_frame))
6881 return 0;
cbff28e8
RS
6882
6883 /* Verify that the two confis have the same number of windows. */
6884 if (sw1->size != sw2->size)
6885 return 0;
6886
6887 for (i = 0; i < sw1->size; i++)
6888 {
6889 struct saved_window *p1, *p2;
6890 int w1_is_current, w2_is_current;
6891
6892 p1 = SAVED_WINDOW_N (sw1, i);
6893 p2 = SAVED_WINDOW_N (sw2, i);
6894
6895 /* Verify that the current windows in the two
6896 configurations correspond to each other. */
6897 w1_is_current = EQ (d1->current_window, p1->window);
6898 w2_is_current = EQ (d2->current_window, p2->window);
6899
6900 if (w1_is_current != w2_is_current)
6901 return 0;
6902
6903 /* Verify that the corresponding windows do match. */
6904 if (! EQ (p1->buffer, p2->buffer))
6905 return 0;
949cf20f 6906 if (! EQ (p1->left_col, p2->left_col))
cbff28e8 6907 return 0;
949cf20f 6908 if (! EQ (p1->top_line, p2->top_line))
cbff28e8 6909 return 0;
949cf20f 6910 if (! EQ (p1->total_cols, p2->total_cols))
cbff28e8 6911 return 0;
949cf20f 6912 if (! EQ (p1->total_lines, p2->total_lines))
cbff28e8 6913 return 0;
cbff28e8
RS
6914 if (! EQ (p1->display_table, p2->display_table))
6915 return 0;
6916 if (! EQ (p1->parent, p2->parent))
6917 return 0;
6918 if (! EQ (p1->prev, p2->prev))
6919 return 0;
2f8274be
RS
6920 if (! ignore_positions)
6921 {
6922 if (! EQ (p1->hscroll, p2->hscroll))
6923 return 0;
ea68264b
GM
6924 if (!EQ (p1->min_hscroll, p2->min_hscroll))
6925 return 0;
2f8274be
RS
6926 if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
6927 return 0;
6928 if (NILP (Fequal (p1->start, p2->start)))
6929 return 0;
6930 if (NILP (Fequal (p1->pointm, p2->pointm)))
6931 return 0;
6932 if (NILP (Fequal (p1->mark, p2->mark)))
6933 return 0;
6934 }
949cf20f
KS
6935 if (! EQ (p1->left_margin_cols, p2->left_margin_cols))
6936 return 0;
6937 if (! EQ (p1->right_margin_cols, p2->right_margin_cols))
6938 return 0;
6939 if (! EQ (p1->left_fringe_width, p2->left_fringe_width))
6940 return 0;
6941 if (! EQ (p1->right_fringe_width, p2->right_fringe_width))
6942 return 0;
6943 if (! EQ (p1->fringes_outside_margins, p2->fringes_outside_margins))
6944 return 0;
6945 if (! EQ (p1->scroll_bar_width, p2->scroll_bar_width))
6946 return 0;
6947 if (! EQ (p1->vertical_scroll_bar_type, p2->vertical_scroll_bar_type))
6948 return 0;
cbff28e8
RS
6949 }
6950
6951 return 1;
6952}
2f8274be
RS
6953
6954DEFUN ("compare-window-configurations", Fcompare_window_configurations,
6955 Scompare_window_configurations, 2, 2, 0,
fdb82f93
PJ
6956 doc: /* Compare two window configurations as regards the structure of windows.
6957This function ignores details such as the values of point and mark
6958and scrolling positions. */)
5842a27b 6959 (Lisp_Object x, Lisp_Object y)
2f8274be
RS
6960{
6961 if (compare_window_configurations (x, y, 1))
6962 return Qt;
6963 return Qnil;
6964}
cbff28e8 6965\f
dfcf069d 6966void
971de7fb 6967init_window_once (void)
7ab12479 6968{
3224dac1 6969 struct frame *f = make_initial_frame ();
1ae1a37d
GM
6970 XSETFRAME (selected_frame, f);
6971 Vterminal_frame = selected_frame;
6972 minibuf_window = f->minibuffer_window;
6973 selected_window = f->selected_window;
6974 last_nonminibuf_frame = f;
5b03d3c0
RS
6975
6976 window_initialized = 1;
7ab12479
JB
6977}
6978
67492200 6979void
971de7fb 6980init_window (void)
67492200
GM
6981{
6982 Vwindow_list = Qnil;
6983}
6984
dfcf069d 6985void
971de7fb 6986syms_of_window (void)
7ab12479 6987{
d67b4f80 6988 Qscroll_up = intern_c_string ("scroll-up");
c525d842
CY
6989 staticpro (&Qscroll_up);
6990
d67b4f80 6991 Qscroll_down = intern_c_string ("scroll-down");
c525d842
CY
6992 staticpro (&Qscroll_down);
6993
a4b000fb
JL
6994 Qscroll_command = intern_c_string ("scroll-command");
6995 staticpro (&Qscroll_command);
6996
6997 Fput (Qscroll_up, Qscroll_command, Qt);
6998 Fput (Qscroll_down, Qscroll_command, Qt);
6999
d67b4f80 7000 Qwindow_size_fixed = intern_c_string ("window-size-fixed");
8a37516b 7001 staticpro (&Qwindow_size_fixed);
c0e7ccd3 7002 Fset (Qwindow_size_fixed, Qnil);
177c0ea7 7003
543f5fb1
RS
7004 staticpro (&Qwindow_configuration_change_hook);
7005 Qwindow_configuration_change_hook
d67b4f80 7006 = intern_c_string ("window-configuration-change-hook");
543f5fb1 7007
d67b4f80 7008 Qwindowp = intern_c_string ("windowp");
7ab12479
JB
7009 staticpro (&Qwindowp);
7010
d67b4f80 7011 Qwindow_configuration_p = intern_c_string ("window-configuration-p");
3f8ab7bd
RS
7012 staticpro (&Qwindow_configuration_p);
7013
d67b4f80 7014 Qwindow_live_p = intern_c_string ("window-live-p");
806b4d9b 7015 staticpro (&Qwindow_live_p);
605be8af 7016
d67b4f80 7017 Qdisplay_buffer = intern_c_string ("display-buffer");
87478b52
SM
7018 staticpro (&Qdisplay_buffer);
7019
d67b4f80 7020 Qtemp_buffer_show_hook = intern_c_string ("temp-buffer-show-hook");
a58ec57d
RS
7021 staticpro (&Qtemp_buffer_show_hook);
7022
67492200 7023 staticpro (&Vwindow_list);
8bfb170b
KS
7024
7025 minibuf_selected_window = Qnil;
3dbab091 7026 staticpro (&minibuf_selected_window);
67492200 7027
c876b227 7028 window_scroll_pixel_based_preserve_x = -1;
66fe93d1 7029 window_scroll_pixel_based_preserve_y = -1;
c876b227
SM
7030 window_scroll_preserve_hpos = -1;
7031 window_scroll_preserve_vpos = -1;
66d43aea 7032
29208e82 7033 DEFVAR_LISP ("temp-buffer-show-function", Vtemp_buffer_show_function,
fdb82f93
PJ
7034 doc: /* Non-nil means call as function to display a help buffer.
7035The function is called with one argument, the buffer to be displayed.
7036Used by `with-output-to-temp-buffer'.
7037If this function is used, then it must do the entire job of showing
7038the buffer; `temp-buffer-show-hook' is not run unless this function runs it. */);
7ab12479
JB
7039 Vtemp_buffer_show_function = Qnil;
7040
29208e82 7041 DEFVAR_LISP ("minibuffer-scroll-window", Vminibuf_scroll_window,
fdb82f93 7042 doc: /* Non-nil means it is the window that C-M-v in minibuffer should scroll. */);
7ab12479
JB
7043 Vminibuf_scroll_window = Qnil;
7044
29208e82 7045 DEFVAR_BOOL ("mode-line-in-non-selected-windows", mode_line_in_non_selected_windows,
26124d5e 7046 doc: /* Non-nil means to use `mode-line-inactive' face in non-selected windows.
cc91894c
KS
7047If the minibuffer is active, the `minibuffer-scroll-window' mode line
7048is displayed in the `mode-line' face. */);
7049 mode_line_in_non_selected_windows = 1;
26124d5e 7050
29208e82 7051 DEFVAR_LISP ("other-window-scroll-buffer", Vother_window_scroll_buffer,
fdb82f93 7052 doc: /* If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window. */);
7ab12479
JB
7053 Vother_window_scroll_buffer = Qnil;
7054
29208e82 7055 DEFVAR_BOOL ("auto-window-vscroll", auto_window_vscroll_p,
e56263e5
KS
7056 doc: /* *Non-nil means to automatically adjust `window-vscroll' to view tall lines. */);
7057 auto_window_vscroll_p = 1;
7058
29208e82 7059 DEFVAR_INT ("next-screen-context-lines", next_screen_context_lines,
fdb82f93 7060 doc: /* *Number of lines of continuity when scrolling by screenfuls. */);
7ab12479
JB
7061 next_screen_context_lines = 2;
7062
29208e82 7063 DEFVAR_INT ("window-min-height", window_min_height,
047aaeb9
MR
7064 doc: /* Allow deleting windows less than this tall.
7065The value is measured in line units. If a window wants a modeline it
7066is counted as one line.
7067
7068Emacs honors settings of this variable when enlarging or shrinking
7069windows vertically. A value less than 1 is invalid. */);
7ab12479
JB
7070 window_min_height = 4;
7071
29208e82 7072 DEFVAR_INT ("window-min-width", window_min_width,
047aaeb9
MR
7073 doc: /* Allow deleting windows less than this wide.
7074The value is measured in characters and includes any fringes or
7075the scrollbar.
7076
7077Emacs honors settings of this variable when enlarging or shrinking
7078windows horizontally. A value less than 2 is invalid. */);
7ab12479
JB
7079 window_min_width = 10;
7080
5500c422 7081 DEFVAR_LISP ("scroll-preserve-screen-position",
29208e82 7082 Vscroll_preserve_screen_position,
c876b227 7083 doc: /* *Controls if scroll commands move point to keep its screen position unchanged.
bdf4ec93
RS
7084A value of nil means point does not keep its screen position except
7085at the scroll margin or window boundary respectively.
7086A value of t means point keeps its screen position if the scroll
7087command moved it vertically out of the window, e.g. when scrolling
7088by full screens.
9013a7f8 7089Any other value means point always keeps its screen position.
a4b000fb
JL
7090Scroll commands should have the `scroll-command' property
7091on their symbols to be controlled by this variable. */);
5500c422 7092 Vscroll_preserve_screen_position = Qnil;
9317a85d 7093
29208e82 7094 DEFVAR_LISP ("window-point-insertion-type", Vwindow_point_insertion_type,
a1562258
SM
7095 doc: /* Type of marker to use for `window-point'. */);
7096 Vwindow_point_insertion_type = Qnil;
7097
543f5fb1 7098 DEFVAR_LISP ("window-configuration-change-hook",
29208e82 7099 Vwindow_configuration_change_hook,
fdb82f93 7100 doc: /* Functions to call when window configuration changes.
6a44ffb3
SM
7101The buffer-local part is run once per window, with the relevant window
7102selected; while the global part is run only once for the modified frame,
7103with the relevant frame selected. */);
543f5fb1
RS
7104 Vwindow_configuration_change_hook = Qnil;
7105
29208e82 7106 DEFVAR_LISP ("recenter-redisplay", Vrecenter_redisplay,
666e158e 7107 doc: /* If non-nil, then the `recenter' command with a nil argument
6e6e5760 7108will redraw the entire frame; the special value `tty' causes the
666e158e
MB
7109frame to be redrawn only if it is a tty frame. */);
7110 Vrecenter_redisplay = Qtty;
7111
7112
7ab12479
JB
7113 defsubr (&Sselected_window);
7114 defsubr (&Sminibuffer_window);
7115 defsubr (&Swindow_minibuffer_p);
7116 defsubr (&Swindowp);
806b4d9b 7117 defsubr (&Swindow_live_p);
7ab12479 7118 defsubr (&Spos_visible_in_window_p);
536833ab 7119 defsubr (&Swindow_line_height);
7ab12479
JB
7120 defsubr (&Swindow_buffer);
7121 defsubr (&Swindow_height);
7122 defsubr (&Swindow_width);
35ea56c9 7123 defsubr (&Swindow_full_width_p);
7ab12479
JB
7124 defsubr (&Swindow_hscroll);
7125 defsubr (&Sset_window_hscroll);
190eb263
RS
7126 defsubr (&Swindow_redisplay_end_trigger);
7127 defsubr (&Sset_window_redisplay_end_trigger);
7ab12479 7128 defsubr (&Swindow_edges);
c99a9eb3 7129 defsubr (&Swindow_pixel_edges);
9d5405ec 7130 defsubr (&Swindow_absolute_pixel_edges);
c99a9eb3
RS
7131 defsubr (&Swindow_inside_edges);
7132 defsubr (&Swindow_inside_pixel_edges);
9d5405ec 7133 defsubr (&Swindow_inside_absolute_pixel_edges);
d5783c40
JB
7134 defsubr (&Scoordinates_in_window_p);
7135 defsubr (&Swindow_at);
7ab12479
JB
7136 defsubr (&Swindow_point);
7137 defsubr (&Swindow_start);
7138 defsubr (&Swindow_end);
7139 defsubr (&Sset_window_point);
7140 defsubr (&Sset_window_start);
7141 defsubr (&Swindow_dedicated_p);
d207b766 7142 defsubr (&Sset_window_dedicated_p);
7ab12479
JB
7143 defsubr (&Swindow_display_table);
7144 defsubr (&Sset_window_display_table);
7145 defsubr (&Snext_window);
7146 defsubr (&Sprevious_window);
7147 defsubr (&Sother_window);
7148 defsubr (&Sget_lru_window);
f1aab3ff 7149 defsubr (&Swindow_use_time);
7ab12479
JB
7150 defsubr (&Sget_largest_window);
7151 defsubr (&Sget_buffer_window);
7152 defsubr (&Sdelete_other_windows);
7153 defsubr (&Sdelete_windows_on);
7154 defsubr (&Sreplace_buffer_in_windows);
7155 defsubr (&Sdelete_window);
7156 defsubr (&Sset_window_buffer);
7157 defsubr (&Sselect_window);
6b61353c 7158 defsubr (&Sforce_window_update);
3e21b6a7 7159 defsubr (&Stemp_output_buffer_show);
7ab12479
JB
7160 defsubr (&Ssplit_window);
7161 defsubr (&Senlarge_window);
7162 defsubr (&Sshrink_window);
0d384044 7163 defsubr (&Sadjust_window_trailing_edge);
7ab12479
JB
7164 defsubr (&Sscroll_up);
7165 defsubr (&Sscroll_down);
7166 defsubr (&Sscroll_left);
7167 defsubr (&Sscroll_right);
ccd0664b 7168 defsubr (&Sother_window_for_scrolling);
7ab12479 7169 defsubr (&Sscroll_other_window);
fa832261 7170 defsubr (&Sminibuffer_selected_window);
7ab12479 7171 defsubr (&Srecenter);
81fe0836 7172 defsubr (&Swindow_text_height);
7ab12479
JB
7173 defsubr (&Smove_to_window_line);
7174 defsubr (&Swindow_configuration_p);
3f8ab7bd 7175 defsubr (&Swindow_configuration_frame);
7ab12479
JB
7176 defsubr (&Sset_window_configuration);
7177 defsubr (&Scurrent_window_configuration);
c16e1cc3 7178 defsubr (&Swindow_tree);
5500c422
GM
7179 defsubr (&Sset_window_margins);
7180 defsubr (&Swindow_margins);
949cf20f
KS
7181 defsubr (&Sset_window_fringes);
7182 defsubr (&Swindow_fringes);
7183 defsubr (&Sset_window_scroll_bars);
7184 defsubr (&Swindow_scroll_bars);
5500c422
GM
7185 defsubr (&Swindow_vscroll);
7186 defsubr (&Sset_window_vscroll);
2f8274be 7187 defsubr (&Scompare_window_configurations);
67492200 7188 defsubr (&Swindow_list);
cfbb2395
JB
7189 defsubr (&Swindow_parameters);
7190 defsubr (&Swindow_parameter);
7191 defsubr (&Sset_window_parameter);
7192
7ab12479
JB
7193}
7194
dfcf069d 7195void
971de7fb 7196keys_of_window (void)
7ab12479
JB
7197{
7198 initial_define_key (control_x_map, '1', "delete-other-windows");
7199 initial_define_key (control_x_map, '2', "split-window");
7200 initial_define_key (control_x_map, '0', "delete-window");
7201 initial_define_key (control_x_map, 'o', "other-window");
7202 initial_define_key (control_x_map, '^', "enlarge-window");
7203 initial_define_key (control_x_map, '<', "scroll-left");
7204 initial_define_key (control_x_map, '>', "scroll-right");
7205
32129746 7206 initial_define_key (global_map, Ctl ('V'), "scroll-up-command");
7ab12479 7207 initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
32129746 7208 initial_define_key (meta_map, 'v', "scroll-down-command");
7ab12479 7209}