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