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