(readevalloop): If READCHARFUN sets point to ZV, arrange
[bpt/emacs.git] / src / window.c
CommitLineData
7ab12479
JB
1/* Window creation, deletion and examination for GNU Emacs.
2 Does not include redisplay.
4a2f9c6a 3 Copyright (C) 1985,86,87,93,94,95,96,97,1998 Free Software Foundation, Inc.
7ab12479
JB
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
1113d9db 9the Free Software Foundation; either version 2, or (at your option)
7ab12479
JB
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
7ab12479 21
18160b98 22#include <config.h>
7ab12479
JB
23#include "lisp.h"
24#include "buffer.h"
44fa5b1e 25#include "frame.h"
7ab12479
JB
26#include "window.h"
27#include "commands.h"
28#include "indent.h"
29#include "termchar.h"
30#include "disptab.h"
f8026fd8 31#include "keyboard.h"
dfcf069d 32#include "dispextern.h"
5500c422
GM
33#include "blockinput.h"
34#include "intervals.h"
35
6d55d620 36#ifdef HAVE_X_WINDOWS
dfcf069d 37#include "xterm.h"
5500c422 38#endif /* HAVE_X_WINDOWS */
8f23f280
AI
39#ifdef WINDOWSNT
40#include "w32term.h"
41#endif
1e3c8885
EZ
42#ifdef MSDOS
43#include "msdos.h"
44#endif
5500c422
GM
45
46#ifndef max
47#define max(a, b) ((a) < (b) ? (b) : (a))
dfcf069d 48#endif
7ab12479 49
5500c422 50
3f8ab7bd 51Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
8a37516b 52Lisp_Object Qwindow_size_fixed, Qleft_bitmap_area, Qright_bitmap_area;
233a4a2c 53extern Lisp_Object Qheight, Qwidth;
7ab12479 54
5e14b1fc 55static struct window *decode_window P_ ((Lisp_Object));
b7354ddf 56static Lisp_Object select_window_1 P_ ((Lisp_Object, int));
5500c422
GM
57static int count_windows P_ ((struct window *));
58static int get_leaf_windows P_ ((struct window *, struct window **, int));
59static void window_scroll P_ ((Lisp_Object, int, int, int));
60static void window_scroll_pixel_based P_ ((Lisp_Object, int, int, int));
61static void window_scroll_line_based P_ ((Lisp_Object, int, int, int));
233a4a2c 62static int window_min_size_1 P_ ((struct window *, int));
f984d4fc 63static int window_min_size P_ ((struct window *, int, int, int *));
233a4a2c 64static void size_window P_ ((Lisp_Object, int, int, int));
7bbb5782
GM
65static void foreach_window_1 P_ ((struct window *, void (*fn) (), int, int,
66 int, int));
67static void freeze_window_start P_ ((struct window *, int));
f984d4fc 68static int window_fixed_size_p P_ ((struct window *, int, int));
86c8e823 69static void enlarge_window P_ ((Lisp_Object, int, int));
5500c422 70
b7354ddf 71
7ab12479
JB
72/* This is the window in which the terminal's cursor should
73 be left when nothing is being done with it. This must
74 always be a leaf window, and its buffer is selected by
75 the top level editing loop at the end of each command.
76
77 This value is always the same as
44fa5b1e 78 FRAME_SELECTED_WINDOW (selected_frame). */
7ab12479
JB
79
80Lisp_Object selected_window;
81
5500c422
GM
82/* The mini-buffer window of the selected frame.
83 Note that you cannot test for mini-bufferness of an arbitrary window
84 by comparing against this; but you can test for mini-bufferness of
7ab12479 85 the selected window. */
5500c422 86
7ab12479
JB
87Lisp_Object minibuf_window;
88
89/* Non-nil means it is the window for C-M-v to scroll
5500c422
GM
90 when the mini-buffer is selected. */
91
7ab12479
JB
92Lisp_Object Vminibuf_scroll_window;
93
94/* Non-nil means this is the buffer whose window C-M-v should scroll. */
5500c422 95
7ab12479
JB
96Lisp_Object Vother_window_scroll_buffer;
97
7ab12479 98/* Non-nil means it's function to call to display temp buffers. */
5500c422 99
7ab12479
JB
100Lisp_Object Vtemp_buffer_show_function;
101
102/* If a window gets smaller than either of these, it is removed. */
5500c422 103
7ab12479
JB
104int window_min_height;
105int window_min_width;
106
107/* Nonzero implies Fdisplay_buffer should create windows. */
5500c422 108
7ab12479
JB
109int pop_up_windows;
110
44fa5b1e 111/* Nonzero implies make new frames for Fdisplay_buffer. */
5500c422 112
44fa5b1e 113int pop_up_frames;
7ab12479
JB
114
115/* Non-nil means use this function instead of default */
5500c422 116
44fa5b1e 117Lisp_Object Vpop_up_frame_function;
7ab12479
JB
118
119/* Function to call to handle Fdisplay_buffer. */
5500c422 120
7ab12479
JB
121Lisp_Object Vdisplay_buffer_function;
122
a90712c2 123/* List of buffer *names* for buffers that should have their own frames. */
5500c422 124
a90712c2
RS
125Lisp_Object Vspecial_display_buffer_names;
126
127/* List of regexps for buffer names that should have their own frames. */
5500c422 128
a90712c2
RS
129Lisp_Object Vspecial_display_regexps;
130
131/* Function to pop up a special frame. */
5500c422 132
a90712c2
RS
133Lisp_Object Vspecial_display_function;
134
855d8627 135/* List of buffer *names* for buffers to appear in selected window. */
5500c422 136
855d8627
RS
137Lisp_Object Vsame_window_buffer_names;
138
139/* List of regexps for buffer names to appear in selected window. */
5500c422 140
855d8627
RS
141Lisp_Object Vsame_window_regexps;
142
a58ec57d 143/* Hook run at end of temp_output_buffer_show. */
5500c422 144
a58ec57d
RS
145Lisp_Object Qtemp_buffer_show_hook;
146
37962e60 147/* Fdisplay_buffer always splits the largest window
7ab12479 148 if that window is more than this high. */
5500c422 149
7ab12479
JB
150int split_height_threshold;
151
152/* Number of lines of continuity in scrolling by screenfuls. */
5500c422 153
7ab12479
JB
154int next_screen_context_lines;
155
156/* Incremented for each window created. */
5500c422 157
7ab12479
JB
158static int sequence_number;
159
5b03d3c0 160/* Nonzero after init_window_once has finished. */
5500c422 161
5b03d3c0
RS
162static int window_initialized;
163
543f5fb1 164/* Hook to run when window config changes. */
5500c422 165
543f5fb1
RS
166Lisp_Object Qwindow_configuration_change_hook;
167Lisp_Object Vwindow_configuration_change_hook;
168
9317a85d
RS
169/* Nonzero means scroll commands try to put point
170 at the same screen height as previously. */
9317a85d 171
5500c422
GM
172Lisp_Object Vscroll_preserve_screen_position;
173
174#if 0 /* This isn't used anywhere. */
91a78190 175/* Nonzero means we can split a frame even if it is "unsplittable". */
eddd51c2 176static int inhibit_frame_unsplittable;
5500c422 177#endif /* 0 */
7d601aaa 178
7ab12479 179#define min(a, b) ((a) < (b) ? (a) : (b))
dba06815 180
9317a85d
RS
181extern int scroll_margin;
182
dba06815 183extern Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
7ab12479
JB
184\f
185DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
413430c5
EN
186 "Returns t if OBJECT is a window.")
187 (object)
188 Lisp_Object object;
7ab12479 189{
413430c5 190 return WINDOWP (object) ? Qt : Qnil;
7ab12479
JB
191}
192
806b4d9b 193DEFUN ("window-live-p", Fwindow_live_p, Swindow_live_p, 1, 1, 0,
413430c5
EN
194 "Returns t if OBJECT is a window which is currently visible.")
195 (object)
196 Lisp_Object object;
605be8af 197{
413430c5 198 return (WINDOWP (object) && ! NILP (XWINDOW (object)->buffer) ? Qt : Qnil);
605be8af
JB
199}
200
7ab12479
JB
201Lisp_Object
202make_window ()
203{
cffec418 204 Lisp_Object val;
7ab12479 205 register struct window *p;
cffec418
KH
206 register struct Lisp_Vector *vec;
207 int i;
208
209 vec = allocate_vectorlike ((EMACS_INT) VECSIZE (struct window));
210 for (i = 0; i < VECSIZE (struct window); i++)
211 vec->contents[i] = Qnil;
212 vec->size = VECSIZE (struct window);
5500c422 213 p = (struct window *) vec;
d834a2e9
KH
214 XSETFASTINT (p->sequence_number, ++sequence_number);
215 XSETFASTINT (p->left, 0);
216 XSETFASTINT (p->top, 0);
217 XSETFASTINT (p->height, 0);
218 XSETFASTINT (p->width, 0);
219 XSETFASTINT (p->hscroll, 0);
f984d4fc 220 p->orig_top = p->orig_height = Qnil;
7ab12479
JB
221 p->start = Fmake_marker ();
222 p->pointm = Fmake_marker ();
d834a2e9 223 XSETFASTINT (p->use_time, 0);
44fa5b1e 224 p->frame = Qnil;
7ab12479
JB
225 p->display_table = Qnil;
226 p->dedicated = Qnil;
5500c422
GM
227 p->pseudo_window_p = 0;
228 bzero (&p->cursor, sizeof (p->cursor));
229 bzero (&p->last_cursor, sizeof (p->last_cursor));
230 bzero (&p->phys_cursor, sizeof (p->phys_cursor));
231 p->desired_matrix = p->current_matrix = 0;
232 p->phys_cursor_type = -1;
233 p->must_be_updated_p = 0;
234 XSETFASTINT (p->window_end_vpos, 0);
235 XSETFASTINT (p->window_end_pos, 0);
236 p->window_end_valid = Qnil;
237 p->vscroll = 0;
cffec418 238 XSETWINDOW (val, p);
5500c422 239 XSETFASTINT (p->last_point, 0);
7bbb5782 240 p->frozen_window_start_p = 0;
7ab12479
JB
241 return val;
242}
243
244DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0,
245 "Return the window that the cursor now appears in and commands apply to.")
246 ()
247{
248 return selected_window;
249}
250
83762ba4
JB
251DEFUN ("minibuffer-window", Fminibuffer_window, Sminibuffer_window, 0, 1, 0,
252 "Return the window used now for minibuffers.\n\
253If the optional argument FRAME is specified, return the minibuffer window\n\
254used by that frame.")
255 (frame)
256 Lisp_Object frame;
7ab12479 257{
83762ba4 258 if (NILP (frame))
1ae1a37d
GM
259 frame = selected_frame;
260 CHECK_LIVE_FRAME (frame, 0);
83762ba4 261 return FRAME_MINIBUF_WINDOW (XFRAME (frame));
7ab12479
JB
262}
263
605be8af 264DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1, 0,
7ab12479
JB
265 "Returns non-nil if WINDOW is a minibuffer window.")
266 (window)
267 Lisp_Object window;
268{
269 struct window *w = decode_window (window);
270 return (MINI_WINDOW_P (w) ? Qt : Qnil);
271}
272
273DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
274 Spos_visible_in_window_p, 0, 2, 0,
44fa5b1e 275 "Return t if position POS is currently on the frame in WINDOW.\n\
7ab12479
JB
276Returns nil if that position is scrolled vertically out of view.\n\
277POS defaults to point; WINDOW, to the selected window.")
278 (pos, window)
279 Lisp_Object pos, window;
280{
281 register struct window *w;
7ab12479
JB
282 register int posint;
283 register struct buffer *buf;
9a132b1f
GM
284 struct text_pos top;
285 Lisp_Object in_window;
7ab12479 286
265a9e55 287 if (NILP (pos))
5ce7b543 288 posint = PT;
7ab12479
JB
289 else
290 {
291 CHECK_NUMBER_COERCE_MARKER (pos, 0);
292 posint = XINT (pos);
293 }
294
605be8af 295 w = decode_window (window);
9a132b1f 296 buf = XBUFFER (w->buffer);
5500c422 297 SET_TEXT_POS_FROM_MARKER (top, w->start);
7ab12479 298
5500c422
GM
299 /* If position above window, it's not visible. */
300 if (posint < CHARPOS (top))
9a132b1f
GM
301 in_window = Qnil;
302 else if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf)
303 && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (buf)
304 && posint < BUF_Z (buf) - XFASTINT (w->window_end_pos))
305 /* If frame is up to date, and POSINT is < window end pos, use
306 that info. This doesn't work for POSINT == end pos, because
307 the window end pos is actually the position _after_ the last
308 char in the window. */
309 in_window = Qt;
310 else if (posint > BUF_ZV (buf))
311 in_window = Qnil;
312 else if (CHARPOS (top) < BUF_BEGV (buf) || CHARPOS (top) > BUF_ZV (buf))
313 /* If window start is out of range, do something reasonable. */
314 in_window = Qnil;
7ab12479
JB
315 else
316 {
5500c422 317 struct it it;
5500c422
GM
318 start_display (&it, w, top);
319 move_it_to (&it, posint, 0, it.last_visible_y, -1,
9a132b1f
GM
320 MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
321 in_window = IT_CHARPOS (it) == posint ? Qt : Qnil;
7ab12479 322 }
9a132b1f
GM
323
324 return in_window;
7ab12479
JB
325}
326\f
327static struct window *
328decode_window (window)
329 register Lisp_Object window;
330{
265a9e55 331 if (NILP (window))
7ab12479
JB
332 return XWINDOW (selected_window);
333
605be8af 334 CHECK_LIVE_WINDOW (window, 0);
7ab12479
JB
335 return XWINDOW (window);
336}
337
338DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
339 "Return the buffer that WINDOW is displaying.")
340 (window)
341 Lisp_Object window;
342{
343 return decode_window (window)->buffer;
344}
345
346DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0,
347 "Return the number of lines in WINDOW (including its mode line).")
348 (window)
349 Lisp_Object window;
350{
351 return decode_window (window)->height;
352}
353
354DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
3b5908ef
RS
355 "Return the number of display columns in WINDOW.\n\
356This is the width that is usable columns available for text in WINDOW.\n\
357If you want to find out how many columns WINDOW takes up,\n\
358use (let ((edges (window-edges))) (- (nth 2 edges) (nth 0 edges))).")
7ab12479
JB
359 (window)
360 Lisp_Object window;
361{
ee61d94e 362 return make_number (window_internal_width (decode_window (window)));
7ab12479
JB
363}
364
365DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
366 "Return the number of columns by which WINDOW is scrolled from left margin.")
367 (window)
368 Lisp_Object window;
369{
370 return decode_window (window)->hscroll;
371}
372
373DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
374 "Set number of columns WINDOW is scrolled from left margin to NCOL.\n\
375NCOL should be zero or positive.")
376 (window, ncol)
377 register Lisp_Object window, ncol;
378{
379 register struct window *w;
380
381 CHECK_NUMBER (ncol, 1);
d834a2e9 382 if (XINT (ncol) < 0) XSETFASTINT (ncol, 0);
7ab12479 383 w = decode_window (window);
7f4161e0 384 if (XINT (w->hscroll) != XINT (ncol))
b1599b4c
GM
385 /* Prevent redisplay shortcuts */
386 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
7ab12479
JB
387 w->hscroll = ncol;
388 return ncol;
389}
390
190eb263
RS
391DEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger,
392 Swindow_redisplay_end_trigger, 0, 1, 0,
393 "Return WINDOW's redisplay end trigger value.\n\
394See `set-window-redisplay-end-trigger' for more information.")
395 (window)
396 Lisp_Object window;
397{
398 return decode_window (window)->redisplay_end_trigger;
399}
400
401DEFUN ("set-window-redisplay-end-trigger", Fset_window_redisplay_end_trigger,
402 Sset_window_redisplay_end_trigger, 2, 2, 0,
403 "Set WINDOW's redisplay end trigger value to VALUE.\n\
404VALUE should be a buffer position (typically a marker) or nil.\n\
76854cf2
RS
405If it is a buffer position, then if redisplay in WINDOW reaches a position\n\
406beyond VALUE, the functions in `redisplay-end-trigger-functions' are called\n\
407with two arguments: WINDOW, and the end trigger value.\n\
408Afterwards the end-trigger value is reset to nil.")
190eb263
RS
409 (window, value)
410 register Lisp_Object window, value;
411{
412 register struct window *w;
413
414 w = decode_window (window);
415 w->redisplay_end_trigger = value;
416 return value;
417}
418
7ab12479
JB
419DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0,
420 "Return a list of the edge coordinates of WINDOW.\n\
44fa5b1e 421\(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.\n\
7ab12479
JB
422RIGHT is one more than the rightmost column used by WINDOW,\n\
423and BOTTOM is one more than the bottommost row used by WINDOW\n\
424 and its mode-line.")
425 (window)
426 Lisp_Object window;
427{
428 register struct window *w = decode_window (window);
429
430 return Fcons (w->left, Fcons (w->top,
111e5992 431 Fcons (make_number (WINDOW_RIGHT_EDGE (w)),
7ab12479
JB
432 Fcons (make_number (XFASTINT (w->top)
433 + XFASTINT (w->height)),
434 Qnil))));
435}
436
fbad6f9a 437/* Test if the character at column *X, row *Y is within window W.
d5783c40
JB
438 If it is not, return 0;
439 if it is in the window's text area,
440 set *x and *y to its location relative to the upper left corner
441 of the window, and
442 return 1;
443 if it is on the window's modeline, return 2;
444 if it is on the border between the window and its right sibling,
5500c422
GM
445 return 3.
446 if it is on the window's top line, return 4;
fbad6f9a
GM
447 if it is in the bitmap area to the left/right of the window,
448 return 5 or 6, and convert *X and *Y to window-relative corrdinates.
5500c422
GM
449
450 X and Y are frame relative pixel coordinates. */
451
d5783c40
JB
452static int
453coordinates_in_window (w, x, y)
454 register struct window *w;
455 register int *x, *y;
456{
5500c422
GM
457 struct frame *f = XFRAME (WINDOW_FRAME (w));
458 int left_x, right_x, top_y, bottom_y;
b46dfc64 459 int flags_area_width = FRAME_LEFT_FLAGS_AREA_WIDTH (f);
d5783c40 460
466539bc
EZ
461 /* In what's below, we subtract 1 when computing right_x because we
462 want the rightmost pixel, which is given by left_pixel+width-1. */
5500c422
GM
463 if (w->pseudo_window_p)
464 {
465 left_x = 0;
466539bc 466 right_x = XFASTINT (w->width) * CANON_Y_UNIT (f) - 1;
5500c422
GM
467 top_y = WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
468 bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
469 }
470 else
471 {
2add4349 472 left_x = (WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w)
50df5e5a 473 - FRAME_INTERNAL_BORDER_WIDTH_SAFE (f));
466539bc 474 right_x = WINDOW_DISPLAY_RIGHT_EDGE_PIXEL_X (w) - 1;
2add4349 475 top_y = (WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w)
50df5e5a 476 - FRAME_INTERNAL_BORDER_WIDTH_SAFE (f));
5500c422
GM
477 bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
478 }
37962e60 479
5500c422
GM
480 if (*y < top_y
481 || *y >= bottom_y
482 || *x < (left_x
483 - flags_area_width
484 - (FRAME_LEFT_SCROLL_BAR_WIDTH (f)
485 * CANON_X_UNIT (f)))
486 || *x > right_x + flags_area_width)
487 /* Completely outside anything interesting. */
488 return 0;
489 else if (WINDOW_WANTS_MODELINE_P (w)
490 && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
491 /* On the mode line. */
492 return 2;
045dee35
GM
493 else if (WINDOW_WANTS_HEADER_LINE_P (w)
494 && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
5500c422
GM
495 /* On the top line. */
496 return 4;
497 else if (*x < left_x || *x >= right_x)
fbad6f9a
GM
498 {
499 /* Other lines than the mode line don't include flags areas and
500 scroll bars on the left. */
501
502 /* Convert X and Y to window-relative pixel coordinates. */
503 *x -= left_x;
504 *y -= top_y;
505 return *x < left_x ? 5 : 6;
506 }
5500c422
GM
507 else if (!w->pseudo_window_p
508 && !WINDOW_RIGHTMOST_P (w)
509 && *x >= right_x - CANON_X_UNIT (f))
510 /* On the border on the right side of the window? Assume that
511 this area begins at RIGHT_X minus a canonical char width. */
512 return 3;
513 else
514 {
515 /* Convert X and Y to window-relative pixel coordinates. */
516 *x -= left_x;
517 *y -= top_y;
518 return 1;
519 }
d5783c40
JB
520}
521
522DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
523 Scoordinates_in_window_p, 2, 2, 0,
524 "Return non-nil if COORDINATES are in WINDOW.\n\
1113d9db 525COORDINATES is a cons of the form (X . Y), X and Y being distances\n\
44fa5b1e 526measured in characters from the upper-left corner of the frame.\n\
1113d9db 527(0 . 0) denotes the character in the upper left corner of the\n\
44fa5b1e 528frame.\n\
d5783c40
JB
529If COORDINATES are in the text portion of WINDOW,\n\
530 the coordinates relative to the window are returned.\n\
e5d77022 531If they are in the mode line of WINDOW, `mode-line' is returned.\n\
045dee35 532If they are in the top mode line of WINDOW, `header-line' is returned.\n\
fbad6f9a
GM
533If they are in the bitmap-area to the left of the window,\n\
534 `left-bitmap-area' is returned, if they are in the area on the right of\n\
535 the window, `right-bitmap-area' is returned.\n\
d5783c40 536If they are on the border between WINDOW and its right sibling,\n\
e5d77022 537 `vertical-line' is returned.")
d5783c40
JB
538 (coordinates, window)
539 register Lisp_Object coordinates, window;
540{
5500c422
GM
541 struct window *w;
542 struct frame *f;
d5783c40 543 int x, y;
5500c422 544 Lisp_Object lx, ly;
d5783c40 545
605be8af 546 CHECK_LIVE_WINDOW (window, 0);
5500c422
GM
547 w = XWINDOW (window);
548 f = XFRAME (w->frame);
d5783c40 549 CHECK_CONS (coordinates, 1);
5500c422
GM
550 lx = Fcar (coordinates);
551 ly = Fcdr (coordinates);
552 CHECK_NUMBER_OR_FLOAT (lx, 1);
553 CHECK_NUMBER_OR_FLOAT (ly, 1);
554 x = PIXEL_X_FROM_CANON_X (f, lx);
555 y = PIXEL_Y_FROM_CANON_Y (f, ly);
556
557 switch (coordinates_in_window (w, &x, &y))
d5783c40
JB
558 {
559 case 0: /* NOT in window at all. */
560 return Qnil;
561
562 case 1: /* In text part of window. */
5500c422
GM
563 /* X and Y are now window relative pixel coordinates.
564 Convert them to canonical char units before returning
565 them. */
566 return Fcons (CANON_X_FROM_PIXEL_X (f, x),
567 CANON_Y_FROM_PIXEL_Y (f, y));
d5783c40
JB
568
569 case 2: /* In mode line of window. */
570 return Qmode_line;
37962e60 571
d5783c40 572 case 3: /* On right border of window. */
e5d77022 573 return Qvertical_line;
d5783c40 574
5500c422 575 case 4:
045dee35 576 return Qheader_line;
5500c422 577
fbad6f9a
GM
578 case 5:
579 return Qleft_bitmap_area;
580
581 case 6:
582 return Qright_bitmap_area;
583
d5783c40
JB
584 default:
585 abort ();
586 }
587}
588
5500c422
GM
589/* Find the window containing frame-relative pixel position X/Y and
590 return it as a Lisp_Object. If X, Y is on the window's modeline,
591 set *PART to 1; if it is on the separating line between the window
592 and its right sibling, set it to 2; otherwise set it to 0. If
593 there is no window under X, Y return nil and leave *PART
9ea173e8 594 unmodified. TOOL_BAR_P non-zero means detect tool-bar windows. */
5500c422 595
7ab12479 596Lisp_Object
9ea173e8 597window_from_coordinates (frame, x, y, part, tool_bar_p)
44fa5b1e 598 FRAME_PTR frame;
7ab12479 599 int x, y;
d5783c40 600 int *part;
9ea173e8 601 int tool_bar_p;
7ab12479
JB
602{
603 register Lisp_Object tem, first;
5500c422 604 int found;
7ab12479 605
44fa5b1e 606 tem = first = FRAME_SELECTED_WINDOW (frame);
7ab12479 607
d5783c40 608 do
7ab12479 609 {
5500c422 610 found = coordinates_in_window (XWINDOW (tem), &x, &y);
7ab12479
JB
611
612 if (found)
613 {
d5783c40 614 *part = found - 1;
7ab12479
JB
615 return tem;
616 }
617
d5783c40 618 tem = Fnext_window (tem, Qt, Qlambda);
7ab12479 619 }
5500c422
GM
620 while (!EQ (tem, first));
621
9ea173e8
GM
622 /* See if it's in the tool bar window, if a tool bar exists. */
623 if (tool_bar_p
624 && WINDOWP (frame->tool_bar_window)
625 && XFASTINT (XWINDOW (frame->tool_bar_window)->height)
626 && coordinates_in_window (XWINDOW (frame->tool_bar_window), &x, &y))
5500c422
GM
627 {
628 *part = 0;
9ea173e8 629 return frame->tool_bar_window;
5500c422 630 }
37962e60 631
d5783c40 632 return Qnil;
7ab12479
JB
633}
634
ab17c3f2 635DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
b0c33a94 636 "Return window containing coordinates X and Y on FRAME.\n\
44fa5b1e
JB
637If omitted, FRAME defaults to the currently selected frame.\n\
638The top left corner of the frame is considered to be row 0,\n\
95605e15 639column 0.")
b0c33a94
RS
640 (x, y, frame)
641 Lisp_Object x, y, frame;
7ab12479
JB
642{
643 int part;
5500c422 644 struct frame *f;
7ab12479 645
44fa5b1e 646 if (NILP (frame))
1ae1a37d
GM
647 frame = selected_frame;
648 CHECK_LIVE_FRAME (frame, 2);
5500c422 649 f = XFRAME (frame);
7ab12479 650
5500c422
GM
651 /* Check that arguments are integers or floats. */
652 CHECK_NUMBER_OR_FLOAT (x, 0);
653 CHECK_NUMBER_OR_FLOAT (y, 1);
654
655 return window_from_coordinates (f,
656 PIXEL_X_FROM_CANON_X (f, x),
657 PIXEL_Y_FROM_CANON_Y (f, y),
658 &part, 0);
7ab12479
JB
659}
660
661DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
662 "Return current value of point in WINDOW.\n\
663For a nonselected window, this is the value point would have\n\
664if that window were selected.\n\
665\n\
666Note that, when WINDOW is the selected window and its buffer\n\
667is also currently selected, the value returned is the same as (point).\n\
668It would be more strictly correct to return the `top-level' value\n\
669of point, outside of any save-excursion forms.\n\
670But that is hard to define.")
671 (window)
672 Lisp_Object window;
673{
674 register struct window *w = decode_window (window);
675
676 if (w == XWINDOW (selected_window)
677 && current_buffer == XBUFFER (w->buffer))
678 return Fpoint ();
679 return Fmarker_position (w->pointm);
680}
681
682DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
0fea6c40
RS
683 "Return position at which display currently starts in WINDOW.\n\
684This is updated by redisplay or by calling `set-window-start'.")
7ab12479
JB
685 (window)
686 Lisp_Object window;
687{
688 return Fmarker_position (decode_window (window)->start);
689}
690
8646118f
RS
691/* This is text temporarily removed from the doc string below.
692
7250968e
RS
693This function returns nil if the position is not currently known.\n\
694That happens when redisplay is preempted and doesn't finish.\n\
695If in that case you want to compute where the end of the window would\n\
696have been if redisplay had finished, do this:\n\
697 (save-excursion\n\
698 (goto-char (window-start window))\n\
699 (vertical-motion (1- (window-height window)) window)\n\
8646118f
RS
700 (point))") */
701
478292ed 702DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
8646118f
RS
703 "Return position at which display currently ends in WINDOW.\n\
704This is updated by redisplay, when it runs to completion.\n\
705Simply changing the buffer text or setting `window-start'\n\
478292ed
RS
706does not update this value.\n\
707If UP-TO-DATE is non-nil, compute the up-to-date position\n\
708if it isn't already recorded.")
709 (window, update)
710 Lisp_Object window, update;
7ab12479
JB
711{
712 Lisp_Object value;
713 struct window *w = decode_window (window);
5a41ab94
RS
714 Lisp_Object buf;
715
716 buf = w->buffer;
717 CHECK_BUFFER (buf, 0);
718
8646118f 719#if 0 /* This change broke some things. We should make it later. */
7250968e
RS
720 /* If we don't know the end position, return nil.
721 The user can compute it with vertical-motion if he wants to.
722 It would be nicer to do it automatically,
723 but that's so slow that it would probably bother people. */
724 if (NILP (w->window_end_valid))
725 return Qnil;
8646118f 726#endif
7250968e 727
478292ed
RS
728 if (! NILP (update)
729 && ! (! NILP (w->window_end_valid)
730 && XFASTINT (w->last_modified) >= MODIFF))
731 {
732 int opoint = PT, opoint_byte = PT_BYTE;
2d6d9df0
GM
733
734 /* In case W->start is out of the range, use something
735 reasonable. This situation occured when loading a file with
736 `-l' containing a call to `rmail' with subsequent other
737 commands. At the end, W->start happened to be BEG, while
738 rmail had already narrowed the buffer. This leads to an
739 abort in temp_set_pt_both. */
740 if (XMARKER (w->start)->charpos < BEGV)
741 TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
742 else if (XMARKER (w->start)->charpos > ZV)
743 TEMP_SET_PT_BOTH (ZV, ZV_BYTE);
744 else
745 TEMP_SET_PT_BOTH (XMARKER (w->start)->charpos,
746 XMARKER (w->start)->bytepos);
747
478292ed
RS
748 Fvertical_motion (make_number (window_internal_height (w)), Qnil);
749 XSETINT (value, PT);
750 TEMP_SET_PT_BOTH (opoint, opoint_byte);
751 }
752 else
753 XSETINT (value,
754 BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
7ab12479
JB
755
756 return value;
757}
758
759DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
760 "Make point value in WINDOW be at position POS in WINDOW's buffer.")
761 (window, pos)
762 Lisp_Object window, pos;
763{
764 register struct window *w = decode_window (window);
765
766 CHECK_NUMBER_COERCE_MARKER (pos, 1);
e90c4fe6
RS
767 if (w == XWINDOW (selected_window)
768 && XBUFFER (w->buffer) == current_buffer)
7ab12479
JB
769 Fgoto_char (pos);
770 else
771 set_marker_restricted (w->pointm, pos, w->buffer);
ce7fae7d 772
7ab12479
JB
773 return pos;
774}
775
776DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
777 "Make display in WINDOW start at position POS in WINDOW's buffer.\n\
778Optional third arg NOFORCE non-nil inhibits next redisplay\n\
779from overriding motion of point in order to display at this exact start.")
780 (window, pos, noforce)
781 Lisp_Object window, pos, noforce;
782{
783 register struct window *w = decode_window (window);
784
785 CHECK_NUMBER_COERCE_MARKER (pos, 1);
786 set_marker_restricted (w->start, pos, w->buffer);
787 /* this is not right, but much easier than doing what is right. */
788 w->start_at_line_beg = Qnil;
265a9e55 789 if (NILP (noforce))
7ab12479
JB
790 w->force_start = Qt;
791 w->update_mode_line = Qt;
d834a2e9 792 XSETFASTINT (w->last_modified, 0);
3cd21523 793 XSETFASTINT (w->last_overlay_modified, 0);
62c07cc7
JB
794 if (!EQ (window, selected_window))
795 windows_or_buffers_changed++;
ce7fae7d 796
7ab12479
JB
797 return pos;
798}
799
800DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
801 1, 1, 0,
802 "Return WINDOW's dedicated object, usually t or nil.\n\
1f18c48f 803See also `set-window-dedicated-p'.")
7ab12479
JB
804 (window)
805 Lisp_Object window;
806{
807 return decode_window (window)->dedicated;
808}
809
d207b766
RS
810DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p,
811 Sset_window_dedicated_p, 2, 2, 0,
812 "Control whether WINDOW is dedicated to the buffer it displays.\n\
813If it is dedicated, Emacs will not automatically change\n\
814which buffer appears in it.\n\
815The second argument is the new value for the dedication flag;\n\
816non-nil means yes.")
7ab12479
JB
817 (window, arg)
818 Lisp_Object window, arg;
819{
820 register struct window *w = decode_window (window);
821
265a9e55 822 if (NILP (arg))
7ab12479
JB
823 w->dedicated = Qnil;
824 else
d207b766 825 w->dedicated = Qt;
7ab12479
JB
826
827 return w->dedicated;
828}
829
830DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
831 0, 1, 0,
832 "Return the display-table that WINDOW is using.")
833 (window)
834 Lisp_Object window;
835{
836 return decode_window (window)->display_table;
837}
838
5500c422
GM
839/* Get the display table for use on window W. This is either W's
840 display table or W's buffer's display table. Ignore the specified
841 tables if they are not valid; if no valid table is specified,
842 return 0. */
7ab12479 843
319315f1 844struct Lisp_Char_Table *
7ab12479
JB
845window_display_table (w)
846 struct window *w;
847{
848 Lisp_Object tem;
849 tem = w->display_table;
319315f1
RS
850 if (DISP_TABLE_P (tem))
851 return XCHAR_TABLE (tem);
171d003c
RS
852 if (NILP (w->buffer))
853 return 0;
854
7ab12479 855 tem = XBUFFER (w->buffer)->display_table;
319315f1
RS
856 if (DISP_TABLE_P (tem))
857 return XCHAR_TABLE (tem);
7ab12479 858 tem = Vstandard_display_table;
319315f1
RS
859 if (DISP_TABLE_P (tem))
860 return XCHAR_TABLE (tem);
7ab12479
JB
861 return 0;
862}
863
3a2712f9 864DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_display_table, 2, 2, 0,
7ab12479
JB
865 "Set WINDOW's display-table to TABLE.")
866 (window, table)
867 register Lisp_Object window, table;
868{
869 register struct window *w;
7ab12479
JB
870
871 w = decode_window (window);
872 w->display_table = table;
873 return table;
874}
875\f
876/* Record info on buffer window w is displaying
877 when it is about to cease to display that buffer. */
dfcf069d 878static void
7ab12479
JB
879unshow_buffer (w)
880 register struct window *w;
881{
12cae7c0 882 Lisp_Object buf;
b73ea88e 883 struct buffer *b;
7ab12479 884
12cae7c0 885 buf = w->buffer;
b73ea88e
RS
886 b = XBUFFER (buf);
887 if (b != XMARKER (w->pointm)->buffer)
7ab12479
JB
888 abort ();
889
573f41ab 890#if 0
7ab12479
JB
891 if (w == XWINDOW (selected_window)
892 || ! EQ (buf, XWINDOW (selected_window)->buffer))
893 /* Do this except when the selected window's buffer
894 is being removed from some other window. */
573f41ab
RS
895#endif
896 /* last_window_start records the start position that this buffer
897 had in the last window to be disconnected from it.
898 Now that this statement is unconditional,
899 it is possible for the buffer to be displayed in the
900 selected window, while last_window_start reflects another
901 window which was recently showing the same buffer.
902 Some people might say that might be a good thing. Let's see. */
b73ea88e 903 b->last_window_start = marker_position (w->start);
7ab12479
JB
904
905 /* Point in the selected window's buffer
906 is actually stored in that buffer, and the window's pointm isn't used.
907 So don't clobber point in that buffer. */
719eaeb1
GM
908 if (! EQ (buf, XWINDOW (selected_window)->buffer)
909 /* This line helps to fix Horsley's testbug.el bug. */
8801a864
KR
910 && !(WINDOWP (b->last_selected_window)
911 && w != XWINDOW (b->last_selected_window)
719eaeb1 912 && EQ (buf, XWINDOW (b->last_selected_window)->buffer)))
b73ea88e
RS
913 temp_set_point_both (b,
914 clip_to_bounds (BUF_BEGV (b),
915 XMARKER (w->pointm)->charpos,
916 BUF_ZV (b)),
917 clip_to_bounds (BUF_BEGV_BYTE (b),
918 marker_byte_position (w->pointm),
919 BUF_ZV_BYTE (b)));
719eaeb1 920
8801a864
KR
921 if (WINDOWP (b->last_selected_window)
922 && w == XWINDOW (b->last_selected_window))
719eaeb1 923 b->last_selected_window = Qnil;
7ab12479
JB
924}
925
926/* Put replacement into the window structure in place of old. */
dfcf069d 927static void
7ab12479
JB
928replace_window (old, replacement)
929 Lisp_Object old, replacement;
930{
931 register Lisp_Object tem;
932 register struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
933
44fa5b1e
JB
934 /* If OLD is its frame's root_window, then replacement is the new
935 root_window for that frame. */
7ab12479 936
7f4161e0 937 if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
44fa5b1e 938 FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
7ab12479
JB
939
940 p->left = o->left;
941 p->top = o->top;
942 p->width = o->width;
943 p->height = o->height;
5500c422
GM
944 p->desired_matrix = p->current_matrix = 0;
945 p->vscroll = 0;
946 bzero (&p->cursor, sizeof (p->cursor));
947 bzero (&p->last_cursor, sizeof (p->last_cursor));
948 bzero (&p->phys_cursor, sizeof (p->phys_cursor));
949 p->phys_cursor_type = -1;
950 p->must_be_updated_p = 0;
951 p->pseudo_window_p = 0;
952 XSETFASTINT (p->window_end_vpos, 0);
953 XSETFASTINT (p->window_end_pos, 0);
954 p->window_end_valid = Qnil;
7bbb5782 955 p->frozen_window_start_p = 0;
f984d4fc 956 p->orig_top = p->orig_height = Qnil;
7ab12479
JB
957
958 p->next = tem = o->next;
265a9e55 959 if (!NILP (tem))
7ab12479
JB
960 XWINDOW (tem)->prev = replacement;
961
962 p->prev = tem = o->prev;
265a9e55 963 if (!NILP (tem))
7ab12479
JB
964 XWINDOW (tem)->next = replacement;
965
966 p->parent = tem = o->parent;
265a9e55 967 if (!NILP (tem))
7ab12479
JB
968 {
969 if (EQ (XWINDOW (tem)->vchild, old))
970 XWINDOW (tem)->vchild = replacement;
971 if (EQ (XWINDOW (tem)->hchild, old))
972 XWINDOW (tem)->hchild = replacement;
973 }
974
975/*** Here, if replacement is a vertical combination
976and so is its new parent, we should make replacement's
977children be children of that parent instead. ***/
978}
979
980DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
981 "Remove WINDOW from the display. Default is selected window.")
982 (window)
983 register Lisp_Object window;
543f5fb1
RS
984{
985 delete_window (window);
986
987 if (! NILP (Vwindow_configuration_change_hook)
988 && ! NILP (Vrun_hooks))
989 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
990
991 return Qnil;
992}
993
5e14b1fc 994void
543f5fb1
RS
995delete_window (window)
996 register Lisp_Object window;
7ab12479
JB
997{
998 register Lisp_Object tem, parent, sib;
999 register struct window *p;
1000 register struct window *par;
5500c422 1001 FRAME_PTR frame;
7ab12479 1002
605be8af
JB
1003 /* Because this function is called by other C code on non-leaf
1004 windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
1005 so we can't decode_window here. */
265a9e55 1006 if (NILP (window))
7ab12479
JB
1007 window = selected_window;
1008 else
1009 CHECK_WINDOW (window, 0);
7ab12479 1010 p = XWINDOW (window);
605be8af
JB
1011
1012 /* It's okay to delete an already-deleted window. */
1013 if (NILP (p->buffer)
1014 && NILP (p->hchild)
1015 && NILP (p->vchild))
296b535c 1016 return;
605be8af 1017
7ab12479 1018 parent = p->parent;
265a9e55 1019 if (NILP (parent))
7ab12479
JB
1020 error ("Attempt to delete minibuffer or sole ordinary window");
1021 par = XWINDOW (parent);
1022
1023 windows_or_buffers_changed++;
5500c422
GM
1024 frame = XFRAME (WINDOW_FRAME (p));
1025 FRAME_WINDOW_SIZES_CHANGED (frame) = 1;
7ab12479 1026
605be8af
JB
1027 /* Are we trying to delete any frame's selected window? */
1028 {
0def0403 1029 Lisp_Object frame, pwindow;
605be8af 1030
0def0403
RS
1031 /* See if the frame's selected window is either WINDOW
1032 or any subwindow of it, by finding all that window's parents
1033 and comparing each one with WINDOW. */
1034 frame = WINDOW_FRAME (XWINDOW (window));
1035 pwindow = FRAME_SELECTED_WINDOW (XFRAME (frame));
1036
1037 while (!NILP (pwindow))
1038 {
1039 if (EQ (window, pwindow))
1040 break;
1041 pwindow = XWINDOW (pwindow)->parent;
1042 }
1043
1044 if (EQ (window, pwindow))
605be8af 1045 {
89bca612
RS
1046 Lisp_Object alternative;
1047 alternative = Fnext_window (window, Qlambda, Qnil);
605be8af
JB
1048
1049 /* If we're about to delete the selected window on the
1050 selected frame, then we should use Fselect_window to select
1051 the new window. On the other hand, if we're about to
1052 delete the selected window on any other frame, we shouldn't do
1053 anything but set the frame's selected_window slot. */
1054 if (EQ (window, selected_window))
1055 Fselect_window (alternative);
1056 else
0def0403 1057 FRAME_SELECTED_WINDOW (XFRAME (frame)) = alternative;
605be8af
JB
1058 }
1059 }
7ab12479
JB
1060
1061 tem = p->buffer;
1062 /* tem is null for dummy parent windows
1063 (which have inferiors but not any contents themselves) */
265a9e55 1064 if (!NILP (tem))
7ab12479
JB
1065 {
1066 unshow_buffer (p);
1067 unchain_marker (p->pointm);
1068 unchain_marker (p->start);
7ab12479
JB
1069 }
1070
05e71564
GM
1071 /* Free window glyph matrices. It is sure that they are allocated
1072 again when ADJUST_GLYPHS is called. Block input so that expose
1073 events and other events that access glyph matrices are not
1074 processed while we are changing them. */
1075 BLOCK_INPUT;
5500c422
GM
1076 free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (frame)));
1077
7ab12479 1078 tem = p->next;
265a9e55 1079 if (!NILP (tem))
7ab12479
JB
1080 XWINDOW (tem)->prev = p->prev;
1081
1082 tem = p->prev;
265a9e55 1083 if (!NILP (tem))
7ab12479
JB
1084 XWINDOW (tem)->next = p->next;
1085
1086 if (EQ (window, par->hchild))
1087 par->hchild = p->next;
1088 if (EQ (window, par->vchild))
1089 par->vchild = p->next;
1090
1091 /* Find one of our siblings to give our space to. */
1092 sib = p->prev;
265a9e55 1093 if (NILP (sib))
7ab12479
JB
1094 {
1095 /* If p gives its space to its next sibling, that sibling needs
1096 to have its top/left side pulled back to where p's is.
1097 set_window_{height,width} will re-position the sibling's
1098 children. */
1099 sib = p->next;
7f4161e0
JB
1100 XWINDOW (sib)->top = p->top;
1101 XWINDOW (sib)->left = p->left;
7ab12479
JB
1102 }
1103
1104 /* Stretch that sibling. */
265a9e55 1105 if (!NILP (par->vchild))
7ab12479
JB
1106 set_window_height (sib,
1107 XFASTINT (XWINDOW (sib)->height) + XFASTINT (p->height),
1108 1);
265a9e55 1109 if (!NILP (par->hchild))
7ab12479
JB
1110 set_window_width (sib,
1111 XFASTINT (XWINDOW (sib)->width) + XFASTINT (p->width),
1112 1);
1113
1114 /* If parent now has only one child,
1115 put the child into the parent's place. */
7ab12479 1116 tem = par->hchild;
265a9e55 1117 if (NILP (tem))
7ab12479 1118 tem = par->vchild;
265a9e55 1119 if (NILP (XWINDOW (tem)->next))
7ab12479 1120 replace_window (parent, tem);
605be8af
JB
1121
1122 /* Since we may be deleting combination windows, we must make sure that
1123 not only p but all its children have been marked as deleted. */
1124 if (! NILP (p->hchild))
1125 delete_all_subwindows (XWINDOW (p->hchild));
1126 else if (! NILP (p->vchild))
1127 delete_all_subwindows (XWINDOW (p->vchild));
1128
1129 /* Mark this window as deleted. */
1130 p->buffer = p->hchild = p->vchild = Qnil;
5500c422
GM
1131
1132 /* Adjust glyph matrices. */
1133 adjust_glyphs (frame);
05e71564 1134 UNBLOCK_INPUT;
7ab12479
JB
1135}
1136\f
7ab12479 1137
44fa5b1e 1138extern Lisp_Object next_frame (), prev_frame ();
7ab12479 1139
26f6279d
JB
1140/* This comment supplies the doc string for `next-window',
1141 for make-docfile to see. We cannot put this in the real DEFUN
1142 due to limits in the Unix cpp.
1143
1144DEFUN ("next-window", Ffoo, Sfoo, 0, 3, 0,
7ab12479 1145 "Return next window after WINDOW in canonical ordering of windows.\n\
d5783c40
JB
1146If omitted, WINDOW defaults to the selected window.\n\
1147\n\
1148Optional second arg MINIBUF t means count the minibuffer window even\n\
1149if not active. MINIBUF nil or omitted means count the minibuffer iff\n\
1150it is active. MINIBUF neither t nor nil means not to count the\n\
1151minibuffer even if it is active.\n\
1152\n\
44fa5b1e
JB
1153Several frames may share a single minibuffer; if the minibuffer\n\
1154counts, all windows on all frames that share that minibuffer count\n\
ed160f1f 1155too. Therefore, `next-window' can be used to iterate through the\n\
44fa5b1e
JB
1156set of windows even when the minibuffer is on another frame. If the\n\
1157minibuffer does not count, only windows from WINDOW's frame count.\n\
d5783c40 1158\n\
44fa5b1e
JB
1159Optional third arg ALL-FRAMES t means include windows on all frames.\n\
1160ALL-FRAMES nil or omitted means cycle within the frames as specified\n\
89bca612 1161above. ALL-FRAMES = `visible' means include windows on all visible frames.\n\
f812f9c6 1162ALL-FRAMES = 0 means include windows on all visible and iconified frames.\n\
1f4c5d09 1163If ALL-FRAMES is a frame, restrict search to windows on that frame.\n\
89bca612 1164Anything else means restrict to WINDOW's frame.\n\
dbc4e1c1
JB
1165\n\
1166If you use consistent values for MINIBUF and ALL-FRAMES, you can use\n\
1167`next-window' to iterate through the entire cycle of acceptable\n\
1168windows, eventually ending up back at the window you started with.\n\
1169`previous-window' traverses the same cycle, in the reverse order.")
26f6279d
JB
1170 (window, minibuf, all_frames) */
1171
1172DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
1173 0)
44fa5b1e
JB
1174 (window, minibuf, all_frames)
1175 register Lisp_Object window, minibuf, all_frames;
7ab12479
JB
1176{
1177 register Lisp_Object tem;
d5783c40 1178 Lisp_Object start_window;
7ab12479 1179
265a9e55 1180 if (NILP (window))
7ab12479
JB
1181 window = selected_window;
1182 else
605be8af 1183 CHECK_LIVE_WINDOW (window, 0);
7ab12479 1184
d5783c40
JB
1185 start_window = window;
1186
1187 /* minibuf == nil may or may not include minibuffers.
1188 Decide if it does. */
265a9e55 1189 if (NILP (minibuf))
fbdc1545
RS
1190 minibuf = (minibuf_level ? minibuf_window : Qlambda);
1191 else if (! EQ (minibuf, Qt))
1192 minibuf = Qlambda;
1193 /* Now minibuf can be t => count all minibuffer windows,
1194 lambda => count none of them,
1195 or a specific minibuffer window (the active one) to count. */
d5783c40 1196
1bb80f72 1197 /* all_frames == nil doesn't specify which frames to include. */
44fa5b1e 1198 if (NILP (all_frames))
fbdc1545 1199 all_frames = (! EQ (minibuf, Qlambda)
1bb80f72
RS
1200 ? (FRAME_MINIBUF_WINDOW
1201 (XFRAME
1202 (WINDOW_FRAME
1203 (XWINDOW (window)))))
1204 : Qnil);
89bca612
RS
1205 else if (EQ (all_frames, Qvisible))
1206 ;
f812f9c6
RS
1207 else if (XFASTINT (all_frames) == 0)
1208 ;
1f4c5d09
RS
1209 else if (FRAMEP (all_frames) && ! EQ (all_frames, Fwindow_frame (window)))
1210 /* If all_frames is a frame and window arg isn't on that frame, just
1211 return the first window on the frame. */
1212 return Fframe_first_window (all_frames);
44fa5b1e
JB
1213 else if (! EQ (all_frames, Qt))
1214 all_frames = Qnil;
644b477c
RS
1215 /* Now all_frames is t meaning search all frames,
1216 nil meaning search just current frame,
f812f9c6
RS
1217 visible meaning search just visible frames,
1218 0 meaning search visible and iconified frames,
644b477c 1219 or a window, meaning search the frame that window belongs to. */
7ab12479
JB
1220
1221 /* Do this loop at least once, to get the next window, and perhaps
1222 again, if we hit the minibuffer and that is not acceptable. */
1223 do
1224 {
1225 /* Find a window that actually has a next one. This loop
1226 climbs up the tree. */
265a9e55
JB
1227 while (tem = XWINDOW (window)->next, NILP (tem))
1228 if (tem = XWINDOW (window)->parent, !NILP (tem))
7ab12479 1229 window = tem;
d5783c40 1230 else
7ab12479 1231 {
44fa5b1e
JB
1232 /* We've reached the end of this frame.
1233 Which other frames are acceptable? */
1234 tem = WINDOW_FRAME (XWINDOW (window));
44fa5b1e 1235 if (! NILP (all_frames))
1bb80f72
RS
1236 {
1237 Lisp_Object tem1;
1238
1239 tem1 = tem;
1240 tem = next_frame (tem, all_frames);
1241 /* In the case where the minibuffer is active,
1242 and we include its frame as well as the selected one,
1243 next_frame may get stuck in that frame.
1244 If that happens, go back to the selected frame
1245 so we can complete the cycle. */
1246 if (EQ (tem, tem1))
1ae1a37d 1247 tem = selected_frame;
1bb80f72 1248 }
44fa5b1e 1249 tem = FRAME_ROOT_WINDOW (XFRAME (tem));
d5783c40 1250
7ab12479
JB
1251 break;
1252 }
1253
1254 window = tem;
d5783c40 1255
7ab12479
JB
1256 /* If we're in a combination window, find its first child and
1257 recurse on that. Otherwise, we've found the window we want. */
1258 while (1)
1259 {
265a9e55 1260 if (!NILP (XWINDOW (window)->hchild))
7ab12479 1261 window = XWINDOW (window)->hchild;
265a9e55 1262 else if (!NILP (XWINDOW (window)->vchild))
7ab12479
JB
1263 window = XWINDOW (window)->vchild;
1264 else break;
1265 }
2a3d7146
GM
1266
1267 QUIT;
7ab12479 1268 }
5c4d25a6 1269 /* Which windows are acceptable?
d5783c40 1270 Exit the loop and accept this window if
fbdc1545
RS
1271 this isn't a minibuffer window,
1272 or we're accepting all minibuffer windows,
1273 or this is the active minibuffer and we are accepting that one, or
d5783c40 1274 we've come all the way around and we're back at the original window. */
7ab12479 1275 while (MINI_WINDOW_P (XWINDOW (window))
d5783c40 1276 && ! EQ (minibuf, Qt)
fbdc1545 1277 && ! EQ (minibuf, window)
7f4161e0 1278 && ! EQ (window, start_window));
7ab12479
JB
1279
1280 return window;
1281}
1282
26f6279d
JB
1283/* This comment supplies the doc string for `previous-window',
1284 for make-docfile to see. We cannot put this in the real DEFUN
1285 due to limits in the Unix cpp.
1286
1287DEFUN ("previous-window", Ffoo, Sfoo, 0, 3, 0,
5c4d25a6 1288 "Return the window preceding WINDOW in canonical ordering of windows.\n\
d5783c40
JB
1289If omitted, WINDOW defaults to the selected window.\n\
1290\n\
1291Optional second arg MINIBUF t means count the minibuffer window even\n\
1292if not active. MINIBUF nil or omitted means count the minibuffer iff\n\
1293it is active. MINIBUF neither t nor nil means not to count the\n\
1294minibuffer even if it is active.\n\
1295\n\
44fa5b1e
JB
1296Several frames may share a single minibuffer; if the minibuffer\n\
1297counts, all windows on all frames that share that minibuffer count\n\
ed160f1f 1298too. Therefore, `previous-window' can be used to iterate through\n\
44fa5b1e 1299the set of windows even when the minibuffer is on another frame. If\n\
ed160f1f 1300the minibuffer does not count, only windows from WINDOW's frame count\n\
d5783c40 1301\n\
44fa5b1e
JB
1302Optional third arg ALL-FRAMES t means include windows on all frames.\n\
1303ALL-FRAMES nil or omitted means cycle within the frames as specified\n\
89bca612 1304above. ALL-FRAMES = `visible' means include windows on all visible frames.\n\
f812f9c6 1305ALL-FRAMES = 0 means include windows on all visible and iconified frames.\n\
1f4c5d09 1306If ALL-FRAMES is a frame, restrict search to windows on that frame.\n\
89bca612 1307Anything else means restrict to WINDOW's frame.\n\
dbc4e1c1
JB
1308\n\
1309If you use consistent values for MINIBUF and ALL-FRAMES, you can use\n\
1310`previous-window' to iterate through the entire cycle of acceptable\n\
1311windows, eventually ending up back at the window you started with.\n\
1312`next-window' traverses the same cycle, in the reverse order.")
26f6279d
JB
1313 (window, minibuf, all_frames) */
1314
1315
1316DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
1317 0)
44fa5b1e
JB
1318 (window, minibuf, all_frames)
1319 register Lisp_Object window, minibuf, all_frames;
7ab12479
JB
1320{
1321 register Lisp_Object tem;
d5783c40 1322 Lisp_Object start_window;
7ab12479 1323
265a9e55 1324 if (NILP (window))
7ab12479
JB
1325 window = selected_window;
1326 else
605be8af 1327 CHECK_LIVE_WINDOW (window, 0);
7ab12479 1328
d5783c40
JB
1329 start_window = window;
1330
1331 /* minibuf == nil may or may not include minibuffers.
1332 Decide if it does. */
265a9e55 1333 if (NILP (minibuf))
fbdc1545
RS
1334 minibuf = (minibuf_level ? minibuf_window : Qlambda);
1335 else if (! EQ (minibuf, Qt))
1336 minibuf = Qlambda;
1337 /* Now minibuf can be t => count all minibuffer windows,
1338 lambda => count none of them,
1339 or a specific minibuffer window (the active one) to count. */
d5783c40 1340
44fa5b1e
JB
1341 /* all_frames == nil doesn't specify which frames to include.
1342 Decide which frames it includes. */
1343 if (NILP (all_frames))
fbdc1545 1344 all_frames = (! EQ (minibuf, Qlambda)
44fa5b1e
JB
1345 ? (FRAME_MINIBUF_WINDOW
1346 (XFRAME
1347 (WINDOW_FRAME
d5783c40
JB
1348 (XWINDOW (window)))))
1349 : Qnil);
89bca612
RS
1350 else if (EQ (all_frames, Qvisible))
1351 ;
f812f9c6
RS
1352 else if (XFASTINT (all_frames) == 0)
1353 ;
1f4c5d09
RS
1354 else if (FRAMEP (all_frames) && ! EQ (all_frames, Fwindow_frame (window)))
1355 /* If all_frames is a frame and window arg isn't on that frame, just
1356 return the first window on the frame. */
1357 return Fframe_first_window (all_frames);
44fa5b1e
JB
1358 else if (! EQ (all_frames, Qt))
1359 all_frames = Qnil;
644b477c
RS
1360 /* Now all_frames is t meaning search all frames,
1361 nil meaning search just current frame,
f812f9c6
RS
1362 visible meaning search just visible frames,
1363 0 meaning search visible and iconified frames,
644b477c 1364 or a window, meaning search the frame that window belongs to. */
7ab12479
JB
1365
1366 /* Do this loop at least once, to get the previous window, and perhaps
1367 again, if we hit the minibuffer and that is not acceptable. */
1368 do
1369 {
1370 /* Find a window that actually has a previous one. This loop
1371 climbs up the tree. */
265a9e55
JB
1372 while (tem = XWINDOW (window)->prev, NILP (tem))
1373 if (tem = XWINDOW (window)->parent, !NILP (tem))
7ab12479 1374 window = tem;
d5783c40 1375 else
7ab12479 1376 {
44fa5b1e
JB
1377 /* We have found the top window on the frame.
1378 Which frames are acceptable? */
1379 tem = WINDOW_FRAME (XWINDOW (window));
44fa5b1e 1380 if (! NILP (all_frames))
dbc4e1c1
JB
1381 /* It's actually important that we use prev_frame here,
1382 rather than next_frame. All the windows acceptable
1383 according to the given parameters should form a ring;
1384 Fnext_window and Fprevious_window should go back and
1385 forth around the ring. If we use next_frame here,
1386 then Fnext_window and Fprevious_window take different
1387 paths through the set of acceptable windows.
1388 window_loop assumes that these `ring' requirement are
1389 met. */
1bb80f72
RS
1390 {
1391 Lisp_Object tem1;
1392
1393 tem1 = tem;
1394 tem = prev_frame (tem, all_frames);
1395 /* In the case where the minibuffer is active,
1396 and we include its frame as well as the selected one,
1397 next_frame may get stuck in that frame.
1398 If that happens, go back to the selected frame
1399 so we can complete the cycle. */
1400 if (EQ (tem, tem1))
1ae1a37d 1401 tem = selected_frame;
1bb80f72 1402 }
644b477c
RS
1403 /* If this frame has a minibuffer, find that window first,
1404 because it is conceptually the last window in that frame. */
5e12e32f
JB
1405 if (FRAME_HAS_MINIBUF_P (XFRAME (tem)))
1406 tem = FRAME_MINIBUF_WINDOW (XFRAME (tem));
1407 else
644b477c 1408 tem = FRAME_ROOT_WINDOW (XFRAME (tem));
d5783c40 1409
7ab12479
JB
1410 break;
1411 }
1412
1413 window = tem;
1414 /* If we're in a combination window, find its last child and
1415 recurse on that. Otherwise, we've found the window we want. */
1416 while (1)
1417 {
265a9e55 1418 if (!NILP (XWINDOW (window)->hchild))
7ab12479 1419 window = XWINDOW (window)->hchild;
265a9e55 1420 else if (!NILP (XWINDOW (window)->vchild))
7ab12479
JB
1421 window = XWINDOW (window)->vchild;
1422 else break;
265a9e55 1423 while (tem = XWINDOW (window)->next, !NILP (tem))
7ab12479
JB
1424 window = tem;
1425 }
1426 }
5c4d25a6 1427 /* Which windows are acceptable?
d5783c40 1428 Exit the loop and accept this window if
fbdc1545
RS
1429 this isn't a minibuffer window,
1430 or we're accepting all minibuffer windows,
1431 or this is the active minibuffer and we are accepting that one, or
d5783c40 1432 we've come all the way around and we're back at the original window. */
7ab12479 1433 while (MINI_WINDOW_P (XWINDOW (window))
fbdc1545
RS
1434 && ! EQ (minibuf, Qt)
1435 && ! EQ (minibuf, window)
1436 && ! EQ (window, start_window));
7ab12479
JB
1437
1438 return window;
1439}
1440
62c07cc7 1441DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
44fa5b1e
JB
1442 "Select the ARG'th different window on this frame.\n\
1443All windows on current frame are arranged in a cyclic order.\n\
7ab12479
JB
1444This command selects the window ARG steps away in that order.\n\
1445A negative ARG moves in the opposite order. If the optional second\n\
44fa5b1e 1446argument ALL_FRAMES is non-nil, cycle through all frames.")
413430c5
EN
1447 (arg, all_frames)
1448 register Lisp_Object arg, all_frames;
7ab12479
JB
1449{
1450 register int i;
1451 register Lisp_Object w;
1452
413430c5 1453 CHECK_NUMBER (arg, 0);
7ab12479 1454 w = selected_window;
413430c5 1455 i = XINT (arg);
7ab12479
JB
1456
1457 while (i > 0)
1458 {
44fa5b1e 1459 w = Fnext_window (w, Qnil, all_frames);
7ab12479
JB
1460 i--;
1461 }
1462 while (i < 0)
1463 {
44fa5b1e 1464 w = Fprevious_window (w, Qnil, all_frames);
7ab12479
JB
1465 i++;
1466 }
1467 Fselect_window (w);
1468 return Qnil;
1469}
1470\f
1471/* Look at all windows, performing an operation specified by TYPE
1472 with argument OBJ.
75d8f668 1473 If FRAMES is Qt, look at all frames;
75d8f668 1474 Qnil, look at just the selected frame;
89bca612 1475 Qvisible, look at visible frames;
75d8f668 1476 a frame, just look at windows on that frame.
7ab12479
JB
1477 If MINI is non-zero, perform the operation on minibuffer windows too.
1478*/
1479
1480enum window_loop
1481{
1482 WINDOW_LOOP_UNUSED,
1483 GET_BUFFER_WINDOW, /* Arg is buffer */
1484 GET_LRU_WINDOW, /* Arg is t for full-width windows only */
1485 DELETE_OTHER_WINDOWS, /* Arg is window not to delete */
1486 DELETE_BUFFER_WINDOWS, /* Arg is buffer */
1487 GET_LARGEST_WINDOW,
3f8ab7bd
RS
1488 UNSHOW_BUFFER, /* Arg is buffer */
1489 CHECK_ALL_WINDOWS
7ab12479
JB
1490};
1491
1492static Lisp_Object
44fa5b1e 1493window_loop (type, obj, mini, frames)
7ab12479 1494 enum window_loop type;
44fa5b1e 1495 register Lisp_Object obj, frames;
7ab12479
JB
1496 int mini;
1497{
1498 register Lisp_Object w;
1499 register Lisp_Object best_window;
1500 register Lisp_Object next_window;
4b206065 1501 register Lisp_Object last_window;
44fa5b1e 1502 FRAME_PTR frame;
89bca612
RS
1503 Lisp_Object frame_arg;
1504 frame_arg = Qt;
44fa5b1e
JB
1505
1506 /* If we're only looping through windows on a particular frame,
1507 frame points to that frame. If we're looping through windows
1508 on all frames, frame is 0. */
1509 if (FRAMEP (frames))
1510 frame = XFRAME (frames);
1511 else if (NILP (frames))
1ae1a37d 1512 frame = SELECTED_FRAME ();
7ab12479 1513 else
44fa5b1e 1514 frame = 0;
89bca612
RS
1515 if (frame)
1516 frame_arg = Qlambda;
f812f9c6
RS
1517 else if (XFASTINT (frames) == 0)
1518 frame_arg = frames;
89bca612
RS
1519 else if (EQ (frames, Qvisible))
1520 frame_arg = frames;
7ab12479 1521
89bca612
RS
1522 /* frame_arg is Qlambda to stick to one frame,
1523 Qvisible to consider all visible frames,
1524 or Qt otherwise. */
1525
7ab12479 1526 /* Pick a window to start with. */
017b2bad 1527 if (WINDOWP (obj))
4b206065 1528 w = obj;
44fa5b1e 1529 else if (frame)
4b206065 1530 w = FRAME_SELECTED_WINDOW (frame);
7ab12479 1531 else
1ae1a37d 1532 w = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
4b206065
JB
1533
1534 /* Figure out the last window we're going to mess with. Since
1535 Fnext_window, given the same options, is guaranteed to go in a
1536 ring, we can just use Fprevious_window to find the last one.
1537
1538 We can't just wait until we hit the first window again, because
1539 it might be deleted. */
1540
89bca612 1541 last_window = Fprevious_window (w, mini ? Qt : Qnil, frame_arg);
7ab12479 1542
7ab12479 1543 best_window = Qnil;
4b206065 1544 for (;;)
7ab12479
JB
1545 {
1546 /* Pick the next window now, since some operations will delete
1547 the current window. */
89bca612 1548 next_window = Fnext_window (w, mini ? Qt : Qnil, frame_arg);
7ab12479 1549
d29a5631
RS
1550 /* Note that we do not pay attention here to whether
1551 the frame is visible, since Fnext_window skips non-visible frames
1552 if that is desired, under the control of frame_arg. */
75d8f668 1553 if (! MINI_WINDOW_P (XWINDOW (w))
65a04b96
RS
1554 /* For UNSHOW_BUFFER, we must always consider all windows. */
1555 || type == UNSHOW_BUFFER
7ab12479
JB
1556 || (mini && minibuf_level > 0))
1557 switch (type)
1558 {
1559 case GET_BUFFER_WINDOW:
5c204627
RS
1560 if (XBUFFER (XWINDOW (w)->buffer) == XBUFFER (obj)
1561 /* Don't find any minibuffer window
1562 except the one that is currently in use. */
1563 && (MINI_WINDOW_P (XWINDOW (w))
1564 ? EQ (w, minibuf_window) : 1))
7ab12479
JB
1565 return w;
1566 break;
1567
1568 case GET_LRU_WINDOW:
1569 /* t as arg means consider only full-width windows */
111e5992 1570 if (!NILP (obj) && !WINDOW_FULL_WIDTH_P (XWINDOW (w)))
7ab12479 1571 break;
7ab12479
JB
1572 /* Ignore dedicated windows and minibuffers. */
1573 if (MINI_WINDOW_P (XWINDOW (w))
265a9e55 1574 || !NILP (XWINDOW (w)->dedicated))
7ab12479 1575 break;
265a9e55 1576 if (NILP (best_window)
7ab12479
JB
1577 || (XFASTINT (XWINDOW (best_window)->use_time)
1578 > XFASTINT (XWINDOW (w)->use_time)))
1579 best_window = w;
1580 break;
1581
1582 case DELETE_OTHER_WINDOWS:
1583 if (XWINDOW (w) != XWINDOW (obj))
1584 Fdelete_window (w);
1585 break;
1586
1587 case DELETE_BUFFER_WINDOWS:
1588 if (EQ (XWINDOW (w)->buffer, obj))
1589 {
3548e138
RS
1590 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
1591
1592 /* If this window is dedicated, and in a frame of its own,
1593 kill the frame. */
1594 if (EQ (w, FRAME_ROOT_WINDOW (f))
1595 && !NILP (XWINDOW (w)->dedicated)
1596 && other_visible_frames (f))
7ab12479 1597 {
3548e138
RS
1598 /* Skip the other windows on this frame.
1599 There might be one, the minibuffer! */
1600 if (! EQ (w, last_window))
1601 while (f == XFRAME (WINDOW_FRAME (XWINDOW (next_window))))
1602 {
1603 /* As we go, check for the end of the loop.
1604 We mustn't start going around a second time. */
1605 if (EQ (next_window, last_window))
1606 {
1607 last_window = w;
1608 break;
1609 }
1610 next_window = Fnext_window (next_window,
1611 mini ? Qt : Qnil,
1612 frame_arg);
1613 }
1614 /* Now we can safely delete the frame. */
1615 Fdelete_frame (WINDOW_FRAME (XWINDOW (w)), Qnil);
7ab12479
JB
1616 }
1617 else
3548e138
RS
1618 /* If we're deleting the buffer displayed in the only window
1619 on the frame, find a new buffer to display there. */
1620 if (NILP (XWINDOW (w)->parent))
1621 {
1622 Lisp_Object new_buffer;
b7354ddf
RS
1623 new_buffer = Fother_buffer (obj, Qnil,
1624 XWINDOW (w)->frame);
3548e138
RS
1625 if (NILP (new_buffer))
1626 new_buffer
1627 = Fget_buffer_create (build_string ("*scratch*"));
1628 Fset_window_buffer (w, new_buffer);
1629 if (EQ (w, selected_window))
1630 Fset_buffer (XWINDOW (w)->buffer);
1631 }
1632 else
1633 Fdelete_window (w);
7ab12479
JB
1634 }
1635 break;
1636
1637 case GET_LARGEST_WINDOW:
7ab12479
JB
1638 /* Ignore dedicated windows and minibuffers. */
1639 if (MINI_WINDOW_P (XWINDOW (w))
8801a864
KR
1640 || !NILP (XWINDOW (w)->dedicated)
1641 || NILP (best_window))
7ab12479
JB
1642 break;
1643 {
1644 struct window *best_window_ptr = XWINDOW (best_window);
1645 struct window *w_ptr = XWINDOW (w);
6b54027b
RS
1646 if (NILP (best_window)
1647 || (XFASTINT (w_ptr->height) * XFASTINT (w_ptr->width)
1648 > (XFASTINT (best_window_ptr->height)
1649 * XFASTINT (best_window_ptr->width))))
7ab12479
JB
1650 best_window = w;
1651 }
1652 break;
1653
1654 case UNSHOW_BUFFER:
1655 if (EQ (XWINDOW (w)->buffer, obj))
1656 {
1657 /* Find another buffer to show in this window. */
12cae7c0 1658 Lisp_Object another_buffer;
38ab08d1 1659 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
b7354ddf 1660 another_buffer = Fother_buffer (obj, Qnil, XWINDOW (w)->frame);
265a9e55 1661 if (NILP (another_buffer))
7ab12479
JB
1662 another_buffer
1663 = Fget_buffer_create (build_string ("*scratch*"));
38ab08d1
RS
1664 /* If this window is dedicated, and in a frame of its own,
1665 kill the frame. */
1666 if (EQ (w, FRAME_ROOT_WINDOW (f))
596122a7 1667 && !NILP (XWINDOW (w)->dedicated)
38ab08d1 1668 && other_visible_frames (f))
45945a7b
RS
1669 {
1670 /* Skip the other windows on this frame.
1671 There might be one, the minibuffer! */
1672 if (! EQ (w, last_window))
1673 while (f == XFRAME (WINDOW_FRAME (XWINDOW (next_window))))
1674 {
1675 /* As we go, check for the end of the loop.
1676 We mustn't start going around a second time. */
1677 if (EQ (next_window, last_window))
1678 {
1679 last_window = w;
1680 break;
1681 }
1682 next_window = Fnext_window (next_window,
1683 mini ? Qt : Qnil,
1684 frame_arg);
1685 }
1686 /* Now we can safely delete the frame. */
1687 Fdelete_frame (WINDOW_FRAME (XWINDOW (w)), Qnil);
1688 }
38ab08d1 1689 else
38ab08d1
RS
1690 {
1691 /* Otherwise show a different buffer in the window. */
1692 XWINDOW (w)->dedicated = Qnil;
1693 Fset_window_buffer (w, another_buffer);
1694 if (EQ (w, selected_window))
1695 Fset_buffer (XWINDOW (w)->buffer);
1696 }
7ab12479
JB
1697 }
1698 break;
3f8ab7bd
RS
1699
1700 /* Check for a window that has a killed buffer. */
1701 case CHECK_ALL_WINDOWS:
1702 if (! NILP (XWINDOW (w)->buffer)
1703 && NILP (XBUFFER (XWINDOW (w)->buffer)->name))
1704 abort ();
7ab12479 1705 }
4b206065
JB
1706
1707 if (EQ (w, last_window))
1708 break;
1709
7ab12479
JB
1710 w = next_window;
1711 }
7ab12479
JB
1712
1713 return best_window;
37962e60 1714}
605be8af 1715
3f8ab7bd
RS
1716/* Used for debugging. Abort if any window has a dead buffer. */
1717
233a4a2c 1718void
3f8ab7bd
RS
1719check_all_windows ()
1720{
1721 window_loop (CHECK_ALL_WINDOWS, Qnil, 1, Qt);
1722}
1723
7ab12479
JB
1724DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
1725 "Return the window least recently selected or used for display.\n\
89bca612 1726If optional argument FRAME is `visible', search all visible frames.\n\
cee67da9 1727If FRAME is 0, search all visible and iconified frames.\n\
89bca612
RS
1728If FRAME is t, search all frames.\n\
1729If FRAME is nil, search only the selected frame.\n\
1730If FRAME is a frame, search only that frame.")
1731 (frame)
1732 Lisp_Object frame;
7ab12479
JB
1733{
1734 register Lisp_Object w;
1735 /* First try for a window that is full-width */
89bca612 1736 w = window_loop (GET_LRU_WINDOW, Qt, 0, frame);
265a9e55 1737 if (!NILP (w) && !EQ (w, selected_window))
7ab12479
JB
1738 return w;
1739 /* If none of them, try the rest */
89bca612 1740 return window_loop (GET_LRU_WINDOW, Qnil, 0, frame);
7ab12479
JB
1741}
1742
1743DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 1, 0,
1744 "Return the largest window in area.\n\
89bca612 1745If optional argument FRAME is `visible', search all visible frames.\n\
cee67da9 1746If FRAME is 0, search all visible and iconified frames.\n\
89bca612
RS
1747If FRAME is t, search all frames.\n\
1748If FRAME is nil, search only the selected frame.\n\
1749If FRAME is a frame, search only that frame.")
44fa5b1e
JB
1750 (frame)
1751 Lisp_Object frame;
7ab12479
JB
1752{
1753 return window_loop (GET_LARGEST_WINDOW, Qnil, 0,
44fa5b1e 1754 frame);
7ab12479
JB
1755}
1756
1757DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 1, 2, 0,
1758 "Return a window currently displaying BUFFER, or nil if none.\n\
89bca612 1759If optional argument FRAME is `visible', search all visible frames.\n\
f812f9c6 1760If optional argument FRAME is 0, search all visible and iconified frames.\n\
89bca612 1761If FRAME is t, search all frames.\n\
1bc981d2 1762If FRAME is nil, search only the selected frame.\n\
89bca612 1763If FRAME is a frame, search only that frame.")
44fa5b1e
JB
1764 (buffer, frame)
1765 Lisp_Object buffer, frame;
7ab12479
JB
1766{
1767 buffer = Fget_buffer (buffer);
017b2bad 1768 if (BUFFERP (buffer))
44fa5b1e 1769 return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame);
7ab12479
JB
1770 else
1771 return Qnil;
1772}
1773
1774DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
1775 0, 1, "",
44fa5b1e 1776 "Make WINDOW (or the selected window) fill its frame.\n\
f16a1ed3
RS
1777Only the frame WINDOW is on is affected.\n\
1778This function tries to reduce display jumps\n\
1779by keeping the text previously visible in WINDOW\n\
1780in the same place on the frame. Doing this depends on\n\
1781the value of (window-start WINDOW), so if calling this function\n\
1782in a program gives strange scrolling, make sure the window-start\n\
1783value is reasonable when this function is called.")
7ab12479
JB
1784 (window)
1785 Lisp_Object window;
1786{
1787 struct window *w;
00d3d838 1788 int startpos;
7ab12479
JB
1789 int top;
1790
265a9e55 1791 if (NILP (window))
7ab12479
JB
1792 window = selected_window;
1793 else
605be8af 1794 CHECK_LIVE_WINDOW (window, 0);
7ab12479
JB
1795
1796 w = XWINDOW (window);
a2b38b3c 1797
00d3d838 1798 startpos = marker_position (w->start);
5500c422 1799 top = XFASTINT (w->top) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
7ab12479 1800
a2b38b3c
RS
1801 if (MINI_WINDOW_P (w) && top > 0)
1802 error ("Can't expand minibuffer to full frame");
1803
70728a80 1804 window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_FRAME (w));
7ab12479 1805
00d3d838
KH
1806 /* Try to minimize scrolling, by setting the window start to the point
1807 will cause the text at the old window start to be at the same place
1808 on the frame. But don't try to do this if the window start is
1809 outside the visible portion (as might happen when the display is
1810 not current, due to typeahead). */
1811 if (startpos >= BUF_BEGV (XBUFFER (w->buffer))
1812 && startpos <= BUF_ZV (XBUFFER (w->buffer)))
1813 {
1814 struct position pos;
1815 struct buffer *obuf = current_buffer;
1816
1817 Fset_buffer (w->buffer);
1818 /* This computation used to temporarily move point, but that can
1819 have unwanted side effects due to text properties. */
0383eb57 1820 pos = *vmotion (startpos, -top, w);
4d047f50 1821
b73ea88e
RS
1822 set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
1823 w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
1824 || FETCH_BYTE (pos.bytepos - 1) == '\n') ? Qt
00d3d838 1825 : Qnil);
80622eec
RS
1826 /* We need to do this, so that the window-scroll-functions
1827 get called. */
4d047f50 1828 w->optional_new_start = Qt;
00d3d838
KH
1829
1830 set_buffer_internal (obuf);
1831 }
5500c422 1832
7ab12479
JB
1833 return Qnil;
1834}
1835
1836DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
3cbbb729 1837 1, 2, "bDelete windows on (buffer): ",
26f6279d
JB
1838 "Delete all windows showing BUFFER.\n\
1839Optional second argument FRAME controls which frames are affected.\n\
c520265e
RS
1840If optional argument FRAME is `visible', search all visible frames.\n\
1841If FRAME is 0, search all visible and iconified frames.\n\
1842If FRAME is nil, search all frames.\n\
1843If FRAME is t, search only the selected frame.\n\
1844If FRAME is a frame, search only that frame.")
26f6279d
JB
1845 (buffer, frame)
1846 Lisp_Object buffer, frame;
7ab12479 1847{
26f6279d
JB
1848 /* FRAME uses t and nil to mean the opposite of what window_loop
1849 expects. */
c520265e
RS
1850 if (NILP (frame))
1851 frame = Qt;
1852 else if (EQ (frame, Qt))
1853 frame = Qnil;
26f6279d 1854
265a9e55 1855 if (!NILP (buffer))
7ab12479
JB
1856 {
1857 buffer = Fget_buffer (buffer);
1858 CHECK_BUFFER (buffer, 0);
26f6279d 1859 window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
7ab12479 1860 }
5500c422 1861
7ab12479
JB
1862 return Qnil;
1863}
1864
1865DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
1866 Sreplace_buffer_in_windows,
1867 1, 1, "bReplace buffer in windows: ",
1868 "Replace BUFFER with some other buffer in all windows showing it.")
1869 (buffer)
1870 Lisp_Object buffer;
1871{
265a9e55 1872 if (!NILP (buffer))
7ab12479
JB
1873 {
1874 buffer = Fget_buffer (buffer);
1875 CHECK_BUFFER (buffer, 0);
1876 window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
1877 }
1878 return Qnil;
1879}
ff58478b
RS
1880
1881/* Replace BUFFER with some other buffer in all windows
1882 of all frames, even those on other keyboards. */
1883
1884void
1885replace_buffer_in_all_windows (buffer)
1886 Lisp_Object buffer;
1887{
27abb84f 1888#ifdef MULTI_KBOARD
ff58478b
RS
1889 Lisp_Object tail, frame;
1890
ff58478b
RS
1891 /* A single call to window_loop won't do the job
1892 because it only considers frames on the current keyboard.
1893 So loop manually over frames, and handle each one. */
1894 FOR_EACH_FRAME (tail, frame)
db7f721d 1895 window_loop (UNSHOW_BUFFER, buffer, 1, frame);
ff58478b 1896#else
db7f721d 1897 window_loop (UNSHOW_BUFFER, buffer, 1, Qt);
ff58478b
RS
1898#endif
1899}
7ab12479
JB
1900\f
1901/* Set the height of WINDOW and all its inferiors. */
a481b3ea
JB
1902
1903/* The smallest acceptable dimensions for a window. Anything smaller
1904 might crash Emacs. */
5500c422 1905
a481b3ea
JB
1906#define MIN_SAFE_WINDOW_WIDTH (2)
1907#define MIN_SAFE_WINDOW_HEIGHT (2)
1908
1909/* Make sure that window_min_height and window_min_width are
1910 not too small; if they are, set them to safe minima. */
1911
1912static void
1913check_min_window_sizes ()
1914{
1915 /* Smaller values might permit a crash. */
1916 if (window_min_width < MIN_SAFE_WINDOW_WIDTH)
1917 window_min_width = MIN_SAFE_WINDOW_WIDTH;
1918 if (window_min_height < MIN_SAFE_WINDOW_HEIGHT)
1919 window_min_height = MIN_SAFE_WINDOW_HEIGHT;
1920}
1921
1922/* If *ROWS or *COLS are too small a size for FRAME, set them to the
1923 minimum allowable size. */
5500c422 1924
605be8af 1925void
a481b3ea 1926check_frame_size (frame, rows, cols)
605be8af
JB
1927 FRAME_PTR frame;
1928 int *rows, *cols;
a481b3ea 1929{
628df3bf 1930 /* For height, we have to see:
37962e60 1931 whether the frame has a minibuffer,
628df3bf
JB
1932 whether it wants a mode line, and
1933 whether it has a menu bar. */
a481b3ea 1934 int min_height =
79f92720
JB
1935 (FRAME_MINIBUF_ONLY_P (frame) ? MIN_SAFE_WINDOW_HEIGHT - 1
1936 : (! FRAME_HAS_MINIBUF_P (frame)) ? MIN_SAFE_WINDOW_HEIGHT
a481b3ea 1937 : 2 * MIN_SAFE_WINDOW_HEIGHT - 1);
5500c422
GM
1938
1939 if (FRAME_TOP_MARGIN (frame) > 0)
1940 min_height += FRAME_TOP_MARGIN (frame);
a481b3ea
JB
1941
1942 if (*rows < min_height)
1943 *rows = min_height;
1944 if (*cols < MIN_SAFE_WINDOW_WIDTH)
1945 *cols = MIN_SAFE_WINDOW_WIDTH;
1946}
1947
c1636aa6 1948
233a4a2c
GM
1949/* Value is non-zero if window W is fixed-size. WIDTH_P non-zero means
1950 check if W's width can be changed, otherwise check W's height.
1951 CHECK_SIBLINGS_P non-zero means check resizablity of WINDOW's
1952 siblings, too. If none of the siblings is resizable, WINDOW isn't
1953 either. */
c1636aa6 1954
233a4a2c
GM
1955static int
1956window_fixed_size_p (w, width_p, check_siblings_p)
1957 struct window *w;
1958 int width_p, check_siblings_p;
1959{
1960 int fixed_p;
1961 struct window *c;
1962
1963 if (!NILP (w->hchild))
1964 {
1965 c = XWINDOW (w->hchild);
1966
1967 if (width_p)
1968 {
1969 /* A horiz. combination is fixed-width if all of if its
1970 children are. */
1971 while (c && window_fixed_size_p (c, width_p, 0))
1972 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
1973 fixed_p = c == NULL;
1974 }
1975 else
1976 {
1977 /* A horiz. combination is fixed-height if one of if its
1978 children is. */
1979 while (c && !window_fixed_size_p (c, width_p, 0))
1980 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
1981 fixed_p = c != NULL;
1982 }
1983 }
1984 else if (!NILP (w->vchild))
1985 {
1986 c = XWINDOW (w->vchild);
1987
1988 if (width_p)
1989 {
1990 /* A vert. combination is fixed-width if one of if its
1991 children is. */
1992 while (c && !window_fixed_size_p (c, width_p, 0))
1993 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
1994 fixed_p = c != NULL;
1995 }
1996 else
1997 {
1998 /* A vert. combination is fixed-height if all of if its
1999 children are. */
2000 while (c && window_fixed_size_p (c, width_p, 0))
2001 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2002 fixed_p = c == NULL;
2003 }
2004 }
2005 else if (BUFFERP (w->buffer))
2006 {
a34dfd12
GM
2007 if (w->height_fixed_p && !width_p)
2008 fixed_p = 1;
2009 else
233a4a2c 2010 {
a34dfd12
GM
2011 struct buffer *old = current_buffer;
2012 Lisp_Object val;
2013
2014 current_buffer = XBUFFER (w->buffer);
2015 val = find_symbol_value (Qwindow_size_fixed);
2016 current_buffer = old;
2017
2018 fixed_p = 0;
2019 if (!EQ (val, Qunbound))
2020 {
2021 fixed_p = !NILP (val);
2022
2023 if (fixed_p
2024 && ((EQ (val, Qheight) && width_p)
2025 || (EQ (val, Qwidth) && !width_p)))
2026 fixed_p = 0;
2027 }
233a4a2c
GM
2028 }
2029
2030 /* Can't tell if this one is resizable without looking at
2031 siblings. If all siblings are fixed-size this one is too. */
2032 if (!fixed_p && check_siblings_p && WINDOWP (w->parent))
2033 {
2034 Lisp_Object child;
2035
2036 for (child = w->prev; !NILP (child); child = XWINDOW (child)->prev)
2037 if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
2038 break;
2039
2040 if (NILP (child))
2041 for (child = w->next; !NILP (child); child = XWINDOW (child)->next)
2042 if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
2043 break;
2044
2045 if (NILP (child))
2046 fixed_p = 1;
2047 }
2048 }
2049 else
2050 fixed_p = 1;
2051
2052 return fixed_p;
2053}
2054
2055
2056/* Return the minimum size of window W, not taking fixed-width windows
2057 into account. WIDTH_P non-zero means return the minimum width,
2058 otherwise return the minimum height. If W is a combination window,
2059 compute the minimum size from the minimum sizes of W's children. */
2060
2061static int
2062window_min_size_1 (w, width_p)
c1636aa6
GM
2063 struct window *w;
2064 int width_p;
2065{
233a4a2c 2066 struct window *c;
c1636aa6
GM
2067 int size;
2068
233a4a2c
GM
2069 if (!NILP (w->hchild))
2070 {
2071 c = XWINDOW (w->hchild);
2072 size = 0;
2073
2074 if (width_p)
2075 {
2076 /* The min width of a horizontal combination is
2077 the sum of the min widths of its children. */
2078 while (c)
2079 {
2080 size += window_min_size_1 (c, width_p);
2081 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2082 }
2083 }
2084 else
2085 {
2086 /* The min height a horizontal combination equals
2087 the maximum of all min height of its children. */
2088 while (c)
2089 {
2090 int min_size = window_min_size_1 (c, width_p);
2091 size = max (min_size, size);
2092 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2093 }
2094 }
2095 }
2096 else if (!NILP (w->vchild))
2097 {
2098 c = XWINDOW (w->vchild);
2099 size = 0;
2100
2101 if (width_p)
2102 {
2103 /* The min width of a vertical combination is
2104 the maximum of the min widths of its children. */
2105 while (c)
2106 {
2107 int min_size = window_min_size_1 (c, width_p);
2108 size = max (min_size, size);
2109 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2110 }
2111 }
2112 else
2113 {
2114 /* The min height of a vertical combination equals
2115 the sum of the min height of its children. */
2116 while (c)
2117 {
2118 size += window_min_size_1 (c, width_p);
2119 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2120 }
2121 }
2122 }
c1636aa6
GM
2123 else
2124 {
233a4a2c
GM
2125 if (width_p)
2126 size = window_min_width;
c1636aa6 2127 else
233a4a2c
GM
2128 {
2129 if (MINI_WINDOW_P (w)
2130 || (!WINDOW_WANTS_MODELINE_P (w)
045dee35 2131 && !WINDOW_WANTS_HEADER_LINE_P (w)))
233a4a2c
GM
2132 size = 1;
2133 else
2134 size = window_min_height;
2135 }
c1636aa6
GM
2136 }
2137
2138 return size;
2139}
2140
2141
233a4a2c
GM
2142/* Return the minimum size of window W, taking fixed-size windows into
2143 account. WIDTH_P non-zero means return the minimum width,
f984d4fc
GM
2144 otherwise return the minimum height. IGNORE_FIXED_P non-zero means
2145 ignore if W is fixed-size. Set *FIXED to 1 if W is fixed-size
2146 unless FIXED is null. */
7ab12479 2147
233a4a2c 2148static int
f984d4fc 2149window_min_size (w, width_p, ignore_fixed_p, fixed)
233a4a2c 2150 struct window *w;
f984d4fc 2151 int width_p, ignore_fixed_p, *fixed;
233a4a2c
GM
2152{
2153 int size, fixed_p;
2154
f984d4fc
GM
2155 if (ignore_fixed_p)
2156 fixed_p = 0;
2157 else
2158 fixed_p = window_fixed_size_p (w, width_p, 1);
2159
233a4a2c
GM
2160 if (fixed)
2161 *fixed = fixed_p;
2162
2163 if (fixed_p)
2164 size = width_p ? XFASTINT (w->width) : XFASTINT (w->height);
2165 else
2166 size = window_min_size_1 (w, width_p);
f984d4fc 2167
233a4a2c
GM
2168 return size;
2169}
2170
2171
2172/* Set WINDOW's height or width to SIZE. WIDTH_P non-zero means set
2173 WINDOW's width. Resize WINDOW's children, if any, so that they
2174 keep their proportionate size relative to WINDOW. Propagate
2175 WINDOW's top or left edge position to children. Delete windows
2176 that become too small unless NODELETE_P is non-zero. */
2177
2178static void
2179size_window (window, size, width_p, nodelete_p)
7ab12479 2180 Lisp_Object window;
233a4a2c 2181 int size, width_p, nodelete_p;
7ab12479 2182{
233a4a2c
GM
2183 struct window *w = XWINDOW (window);
2184 struct window *c;
2185 Lisp_Object child, *forward, *sideward;
2186 int old_size, min_size;
7ab12479 2187
a481b3ea 2188 check_min_window_sizes ();
233a4a2c 2189
b5f05b50
GM
2190 /* If the window has been "too small" at one point,
2191 don't delete it for being "too small" in the future.
2192 Preserve it as long as that is at all possible. */
233a4a2c
GM
2193 if (width_p)
2194 {
2195 old_size = XFASTINT (w->width);
2196 min_size = window_min_width;
2197 }
2198 else
2199 {
2200 old_size = XFASTINT (w->height);
2201 min_size = window_min_height;
2202 }
2203
2204 if (old_size < window_min_width)
b5f05b50
GM
2205 w->too_small_ok = Qt;
2206
233a4a2c
GM
2207 /* Maybe delete WINDOW if it's too small. */
2208 if (!nodelete_p && !NILP (w->parent))
7ab12479 2209 {
233a4a2c 2210 int min_size;
b5f05b50
GM
2211
2212 if (!MINI_WINDOW_P (w) && !NILP (w->too_small_ok))
233a4a2c 2213 min_size = width_p ? MIN_SAFE_WINDOW_WIDTH : MIN_SAFE_WINDOW_HEIGHT;
b5f05b50 2214 else
233a4a2c 2215 min_size = width_p ? window_min_width : window_min_height;
b5f05b50 2216
233a4a2c 2217 if (size < min_size)
c1636aa6
GM
2218 {
2219 delete_window (window);
2220 return;
2221 }
7ab12479
JB
2222 }
2223
233a4a2c 2224 /* Set redisplay hints. */
d834a2e9 2225 XSETFASTINT (w->last_modified, 0);
3cd21523 2226 XSETFASTINT (w->last_overlay_modified, 0);
7ab12479 2227 windows_or_buffers_changed++;
29aeee73
RS
2228 FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
2229
233a4a2c
GM
2230 if (width_p)
2231 {
2232 sideward = &w->vchild;
2233 forward = &w->hchild;
2234 XSETFASTINT (w->width, size);
2235 }
2236 else
2237 {
2238 sideward = &w->hchild;
2239 forward = &w->vchild;
2240 XSETFASTINT (w->height, size);
2241 }
2242
2243 if (!NILP (*sideward))
7ab12479 2244 {
233a4a2c 2245 for (child = *sideward; !NILP (child); child = c->next)
7ab12479 2246 {
233a4a2c
GM
2247 c = XWINDOW (child);
2248 if (width_p)
2249 c->left = w->left;
2250 else
2251 c->top = w->top;
2252 size_window (child, size, width_p, nodelete_p);
7ab12479
JB
2253 }
2254 }
233a4a2c 2255 else if (!NILP (*forward))
7ab12479 2256 {
233a4a2c
GM
2257 int fixed_size, each, extra, n;
2258 int resize_fixed_p, nfixed;
2259 int last_pos, first_pos, nchildren;
2260
2261 /* Determine the fixed-size portion of the this window, and the
2262 number of child windows. */
2263 fixed_size = nchildren = nfixed = 0;
2264 for (child = *forward; !NILP (child); child = c->next, ++nchildren)
7ab12479
JB
2265 {
2266 c = XWINDOW (child);
233a4a2c
GM
2267 if (window_fixed_size_p (c, width_p, 0))
2268 {
2269 fixed_size += (width_p
2270 ? XFASTINT (c->width) : XFASTINT (c->height));
2271 ++nfixed;
2272 }
2273 }
7ab12479 2274
233a4a2c
GM
2275 /* If the new size is smaller than fixed_size, or if there
2276 aren't any resizable windows, allow resizing fixed-size
2277 windows. */
2278 resize_fixed_p = nfixed == nchildren || size < fixed_size;
2279
2280 /* Compute how many lines/columns to add to each child. The
2281 value of extra takes care of rounding errors. */
2282 n = resize_fixed_p ? nchildren : nchildren - nfixed;
2283 each = (size - old_size) / n;
2284 extra = (size - old_size) - n * each;
2285
2286 /* Compute new children heights and edge positions. */
2287 first_pos = width_p ? XFASTINT (w->left) : XFASTINT (w->top);
2288 last_pos = first_pos;
2289 for (child = *forward; !NILP (child); child = c->next)
2290 {
2291 int new_size, old_size;
2292
2293 c = XWINDOW (child);
2294 old_size = width_p ? XFASTINT (c->width) : XFASTINT (c->height);
2295 new_size = old_size;
7ab12479 2296
233a4a2c
GM
2297 /* The top or left edge position of this child equals the
2298 bottom or right edge of its predecessor. */
2299 if (width_p)
2300 c->left = make_number (last_pos);
2301 else
2302 c->top = make_number (last_pos);
7ab12479 2303
233a4a2c
GM
2304 /* If this child can be resized, do it. */
2305 if (resize_fixed_p || !window_fixed_size_p (c, width_p, 0))
2306 {
2307 new_size = old_size + each + extra;
2308 extra = 0;
2309 }
2310
2311 /* Set new height. Note that size_window also propagates
2312 edge positions to children, so it's not a no-op if we
2313 didn't change the child's size. */
2314 size_window (child, new_size, width_p, 1);
2315
2316 /* Remember the bottom/right edge position of this child; it
2317 will be used to set the top/left edge of the next child. */
2318 last_pos += new_size;
7ab12479 2319 }
233a4a2c
GM
2320
2321 /* We should have covered the parent exactly with child windows. */
2322 xassert (size == last_pos - first_pos);
2323
7ab12479 2324 /* Now delete any children that became too small. */
233a4a2c
GM
2325 if (!nodelete_p)
2326 for (child = *forward; !NILP (child); child = c->next)
7ab12479 2327 {
233a4a2c
GM
2328 int child_size;
2329 c = XWINDOW (child);
2330 child_size = width_p ? XFASTINT (c->width) : XFASTINT (c->height);
2331 size_window (child, child_size, width_p, 0);
7ab12479
JB
2332 }
2333 }
2334}
2335
233a4a2c
GM
2336/* Set WINDOW's height to HEIGHT, and recursively change the height of
2337 WINDOW's children. NODELETE non-zero means don't delete windows
2338 that become too small in the process. (The caller should check
2339 later and do so if appropriate.) */
7ab12479 2340
5e14b1fc 2341void
233a4a2c 2342set_window_height (window, height, nodelete)
7ab12479 2343 Lisp_Object window;
233a4a2c 2344 int height;
7ab12479
JB
2345 int nodelete;
2346{
233a4a2c
GM
2347 size_window (window, height, 0, nodelete);
2348}
7ab12479 2349
7ab12479 2350
233a4a2c
GM
2351/* Set WINDOW's width to WIDTH, and recursively change the width of
2352 WINDOW's children. NODELETE non-zero means don't delete windows
2353 that become too small in the process. (The caller should check
2354 later and do so if appropriate.) */
7ab12479 2355
233a4a2c
GM
2356void
2357set_window_width (window, width, nodelete)
2358 Lisp_Object window;
2359 int width;
2360 int nodelete;
2361{
2362 size_window (window, width, 1, nodelete);
7ab12479 2363}
233a4a2c 2364
7ab12479 2365\f
1d8d96fa 2366int window_select_count;
7ab12479 2367
5b03d3c0
RS
2368Lisp_Object
2369Fset_window_buffer_unwind (obuf)
2370 Lisp_Object obuf;
2371{
2372 Fset_buffer (obuf);
2373 return Qnil;
2374}
2375
7ab12479 2376
5500c422
GM
2377/* Make WINDOW display BUFFER as its contents. RUN_HOOKS_P non-zero
2378 means it's allowed to run hooks. See make_frame for a case where
2379 it's not allowed. */
7ab12479 2380
5500c422
GM
2381void
2382set_window_buffer (window, buffer, run_hooks_p)
2383 Lisp_Object window, buffer;
2384 int run_hooks_p;
2385{
2386 struct window *w = XWINDOW (window);
2387 struct buffer *b = XBUFFER (buffer);
2388 int count = specpdl_ptr - specpdl;
7ab12479
JB
2389
2390 w->buffer = buffer;
86e48436
RS
2391
2392 if (EQ (window, selected_window))
5500c422 2393 b->last_selected_window = window;
beb4e312
RS
2394
2395 /* Update time stamps of buffer display. */
5500c422
GM
2396 if (INTEGERP (b->display_count))
2397 XSETINT (b->display_count, XINT (b->display_count) + 1);
2398 b->display_time = Fcurrent_time ();
86e48436 2399
d834a2e9 2400 XSETFASTINT (w->window_end_pos, 0);
5500c422
GM
2401 XSETFASTINT (w->window_end_vpos, 0);
2402 bzero (&w->last_cursor, sizeof w->last_cursor);
5a41ab94 2403 w->window_end_valid = Qnil;
dba06815 2404 XSETFASTINT (w->hscroll, 0);
5500c422 2405 set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
7ab12479 2406 set_marker_restricted (w->start,
5500c422 2407 make_number (b->last_window_start),
7ab12479
JB
2408 buffer);
2409 w->start_at_line_beg = Qnil;
e36ab06b 2410 w->force_start = Qnil;
d834a2e9 2411 XSETFASTINT (w->last_modified, 0);
3cd21523 2412 XSETFASTINT (w->last_overlay_modified, 0);
7ab12479 2413 windows_or_buffers_changed++;
5b03d3c0
RS
2414
2415 /* We must select BUFFER for running the window-scroll-functions.
2416 If WINDOW is selected, switch permanently.
2417 Otherwise, switch but go back to the ambient buffer afterward. */
7ab12479
JB
2418 if (EQ (window, selected_window))
2419 Fset_buffer (buffer);
5b03d3c0
RS
2420 /* We can't check ! NILP (Vwindow_scroll_functions) here
2421 because that might itself be a local variable. */
2422 else if (window_initialized)
2423 {
2424 record_unwind_protect (Fset_window_buffer_unwind, Fcurrent_buffer ());
2425 Fset_buffer (buffer);
2426 }
2427
5500c422 2428 /* Set left and right marginal area width from buffer. */
cfa22082 2429 Fset_window_margins (window, b->left_margin_width, b->right_margin_width);
7ab12479 2430
5500c422
GM
2431 if (run_hooks_p)
2432 {
2433 if (! NILP (Vwindow_scroll_functions))
2434 run_hook_with_args_2 (Qwindow_scroll_functions, window,
2435 Fmarker_position (w->start));
2436
2437 if (! NILP (Vwindow_configuration_change_hook)
2438 && ! NILP (Vrun_hooks))
2439 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
2440 }
543f5fb1 2441
5b03d3c0 2442 unbind_to (count, Qnil);
5500c422 2443}
5b03d3c0 2444
5500c422
GM
2445
2446DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 2, 0,
2447 "Make WINDOW display BUFFER as its contents.\n\
2448BUFFER can be a buffer or buffer name.")
2449 (window, buffer)
2450 register Lisp_Object window, buffer;
2451{
2452 register Lisp_Object tem;
2453 register struct window *w = decode_window (window);
5500c422 2454
bed0c171 2455 XSETWINDOW (window, w);
5500c422
GM
2456 buffer = Fget_buffer (buffer);
2457 CHECK_BUFFER (buffer, 1);
2458
2459 if (NILP (XBUFFER (buffer)->name))
2460 error ("Attempt to display deleted buffer");
2461
2462 tem = w->buffer;
2463 if (NILP (tem))
2464 error ("Window is deleted");
2465 else if (! EQ (tem, Qt)) /* w->buffer is t when the window
2466 is first being set up. */
2467 {
2468 if (!NILP (w->dedicated) && !EQ (tem, buffer))
2469 error ("Window is dedicated to `%s'",
2470 XSTRING (XBUFFER (tem)->name)->data);
2471
2472 unshow_buffer (w);
2473 }
2474
2475 set_window_buffer (window, buffer, 1);
7ab12479
JB
2476 return Qnil;
2477}
2478
2479DEFUN ("select-window", Fselect_window, Sselect_window, 1, 1, 0,
2480 "Select WINDOW. Most editing will apply to WINDOW's buffer.\n\
beb4e312
RS
2481If WINDOW is not already selected, also make WINDOW's buffer current.\n\
2482Note that the main editor command loop\n\
2483selects the buffer of the selected window before each command.")
7ab12479
JB
2484 (window)
2485 register Lisp_Object window;
b7354ddf
RS
2486{
2487 return select_window_1 (window, 1);
2488}
2489\f
719eaeb1
GM
2490/* Note that selected_window can be nil
2491 when this is called from Fset_window_configuration. */
2492
b7354ddf
RS
2493static Lisp_Object
2494select_window_1 (window, recordflag)
2495 register Lisp_Object window;
2496 int recordflag;
7ab12479
JB
2497{
2498 register struct window *w;
719eaeb1 2499 register struct window *ow;
1ae1a37d 2500 struct frame *sf;
7ab12479 2501
605be8af 2502 CHECK_LIVE_WINDOW (window, 0);
7ab12479
JB
2503
2504 w = XWINDOW (window);
2505
265a9e55 2506 if (NILP (w->buffer))
7ab12479
JB
2507 error ("Trying to select deleted window or non-leaf window");
2508
d834a2e9 2509 XSETFASTINT (w->use_time, ++window_select_count);
7ab12479
JB
2510 if (EQ (window, selected_window))
2511 return window;
2512
719eaeb1
GM
2513 if (!NILP (selected_window))
2514 {
2515 ow = XWINDOW (selected_window);
2516 if (! NILP (ow->buffer))
2517 set_marker_both (ow->pointm, ow->buffer,
2518 BUF_PT (XBUFFER (ow->buffer)),
2519 BUF_PT_BYTE (XBUFFER (ow->buffer)));
2520 }
7ab12479
JB
2521
2522 selected_window = window;
1ae1a37d
GM
2523 sf = SELECTED_FRAME ();
2524 if (XFRAME (WINDOW_FRAME (w)) != sf)
7ab12479 2525 {
44fa5b1e 2526 XFRAME (WINDOW_FRAME (w))->selected_window = window;
147a6615
RS
2527 /* Use this rather than Fhandle_switch_frame
2528 so that FRAME_FOCUS_FRAME is moved appropriately as we
2529 move around in the state where a minibuffer in a separate
2530 frame is active. */
2531 Fselect_frame (WINDOW_FRAME (w), Qnil);
7ab12479
JB
2532 }
2533 else
1ae1a37d 2534 sf->selected_window = window;
7ab12479 2535
b7354ddf
RS
2536 if (recordflag)
2537 record_buffer (w->buffer);
7ab12479
JB
2538 Fset_buffer (w->buffer);
2539
86e48436
RS
2540 XBUFFER (w->buffer)->last_selected_window = window;
2541
7ab12479
JB
2542 /* Go to the point recorded in the window.
2543 This is important when the buffer is in more
2544 than one window. It also matters when
2545 redisplay_window has altered point after scrolling,
2546 because it makes the change only in the window. */
2547 {
2548 register int new_point = marker_position (w->pointm);
2549 if (new_point < BEGV)
2550 SET_PT (BEGV);
a9c95e08 2551 else if (new_point > ZV)
7ab12479
JB
2552 SET_PT (ZV);
2553 else
2554 SET_PT (new_point);
2555 }
2556
2557 windows_or_buffers_changed++;
2558 return window;
2559}
b7354ddf 2560\f
441a127e
RS
2561/* Deiconify the frame containing the window WINDOW,
2562 unless it is the selected frame;
2563 then return WINDOW.
2564
2565 The reason for the exception for the selected frame
2566 is that it seems better not to change the selected frames visibility
2567 merely because of displaying a different buffer in it.
2568 The deiconification is useful when a buffer gets shown in
2569 another frame that you were not using lately. */
d07f802a
RS
2570
2571static Lisp_Object
2572display_buffer_1 (window)
2573 Lisp_Object window;
2574{
1ae1a37d
GM
2575 Lisp_Object frame = XWINDOW (window)->frame;
2576 FRAME_PTR f = XFRAME (frame);
2577
d07f802a 2578 FRAME_SAMPLE_VISIBILITY (f);
1ae1a37d
GM
2579
2580 if (!EQ (frame, selected_frame))
60117126
RS
2581 {
2582 if (FRAME_ICONIFIED_P (f))
1ae1a37d 2583 Fmake_frame_visible (frame);
37962e60 2584 else if (FRAME_VISIBLE_P (f))
1ae1a37d 2585 Fraise_frame (frame);
60117126 2586 }
1ae1a37d 2587
d07f802a
RS
2588 return window;
2589}
2590
4628f7a4 2591DEFUN ("special-display-p", Fspecial_display_p, Sspecial_display_p, 1, 1, 0,
0f7d64d2
GV
2592 "Returns non-nil if a buffer named BUFFER-NAME would be created specially.\n\
2593The value is actually t if the frame should be called with default frame\n\
2594parameters, and a list of frame parameters if they were specified.\n\
4628f7a4
EN
2595See `special-display-buffer-names', and `special-display-regexps'.")
2596 (buffer_name)
2597 Lisp_Object buffer_name;
2598{
2599 Lisp_Object tem;
2600
2601 CHECK_STRING (buffer_name, 1);
2602
2603 tem = Fmember (buffer_name, Vspecial_display_buffer_names);
2604 if (!NILP (tem))
2605 return Qt;
2606
2607 tem = Fassoc (buffer_name, Vspecial_display_buffer_names);
2608 if (!NILP (tem))
2609 return XCDR (tem);
2610
2611 for (tem = Vspecial_display_regexps; CONSP (tem); tem = XCDR (tem))
2612 {
2613 Lisp_Object car = XCAR (tem);
2614 if (STRINGP (car)
2615 && fast_string_match (car, buffer_name) >= 0)
2616 return Qt;
2617 else if (CONSP (car)
2618 && STRINGP (XCAR (car))
2619 && fast_string_match (XCAR (car), buffer_name) >= 0)
0057b00a 2620 return XCDR (car);
4628f7a4
EN
2621 }
2622 return Qnil;
2623}
2624
2625DEFUN ("same-window-p", Fsame_window_p, Ssame_window_p, 1, 1, 0,
0f7d64d2 2626 "Returns non-nil if a new buffer named BUFFER-NAME would use the same window.\n\
4628f7a4
EN
2627See `same-window-buffer-names' and `same-window-regexps'.")
2628 (buffer_name)
2629 Lisp_Object buffer_name;
2630{
2631 Lisp_Object tem;
2632
2633 CHECK_STRING (buffer_name, 1);
2634
2635 tem = Fmember (buffer_name, Vsame_window_buffer_names);
2636 if (!NILP (tem))
2637 return Qt;
2638
2639 tem = Fassoc (buffer_name, Vsame_window_buffer_names);
2640 if (!NILP (tem))
2641 return Qt;
2642
2643 for (tem = Vsame_window_regexps; CONSP (tem); tem = XCDR (tem))
2644 {
2645 Lisp_Object car = XCAR (tem);
2646 if (STRINGP (car)
2647 && fast_string_match (car, buffer_name) >= 0)
2648 return Qt;
2649 else if (CONSP (car)
2650 && STRINGP (XCAR (car))
2651 && fast_string_match (XCAR (car), buffer_name) >= 0)
2652 return Qt;
2653 }
2654 return Qnil;
2655}
2656
53f76081
RS
2657 /* Use B so the default is (other-buffer). */
2658DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 3,
2659 "BDisplay buffer: \nP",
7ab12479
JB
2660 "Make BUFFER appear in some window but don't select it.\n\
2661BUFFER can be a buffer or a buffer name.\n\
2662If BUFFER is shown already in some window, just use that one,\n\
2663unless the window is the selected window and the optional second\n\
46d3268a 2664argument NOT-THIS-WINDOW is non-nil (interactively, with prefix arg).\n\
5141b901 2665If `pop-up-frames' is non-nil, make a new frame if no window shows BUFFER.\n\
5abcf432
RS
2666Returns the window displaying BUFFER.\n\
2667\n\
2668The variables `special-display-buffer-names', `special-display-regexps',\n\
2669`same-window-buffer-names', and `same-window-regexps' customize how certain\n\
53f76081
RS
2670buffer names are handled.\n\
2671\n\
2672If optional argument FRAME is `visible', search all visible frames.\n\
2673If FRAME is 0, search all visible and iconified frames.\n\
2674If FRAME is t, search all frames.\n\
2675If FRAME is a frame, search only that frame.\n\
2676If FRAME is nil, search only the selected frame\n\
2677 (actually the last nonminibuffer frame),\n\
2678 unless `pop-up-frames' is non-nil,\n\
2679 which means search visible and iconified frames.")
2680 (buffer, not_this_window, frame)
2681 register Lisp_Object buffer, not_this_window, frame;
7ab12479 2682{
aee631c2 2683 register Lisp_Object window, tem, swp;
1ae1a37d 2684 struct frame *f;
7ab12479 2685
aee631c2 2686 swp = Qnil;
7ab12479
JB
2687 buffer = Fget_buffer (buffer);
2688 CHECK_BUFFER (buffer, 0);
2689
265a9e55 2690 if (!NILP (Vdisplay_buffer_function))
7ab12479
JB
2691 return call2 (Vdisplay_buffer_function, buffer, not_this_window);
2692
265a9e55 2693 if (NILP (not_this_window)
7ab12479 2694 && XBUFFER (XWINDOW (selected_window)->buffer) == XBUFFER (buffer))
d07f802a 2695 return display_buffer_1 (selected_window);
7ab12479 2696
855d8627
RS
2697 /* See if the user has specified this buffer should appear
2698 in the selected window. */
2699 if (NILP (not_this_window))
2700 {
aee631c2
RS
2701 swp = Fsame_window_p (XBUFFER (buffer)->name);
2702 if (!NILP (swp) && !no_switch_window (selected_window))
c63dc4a2
RS
2703 {
2704 Fswitch_to_buffer (buffer, Qnil);
d07f802a 2705 return display_buffer_1 (selected_window);
c63dc4a2 2706 }
855d8627
RS
2707 }
2708
e8edb3ae 2709 /* If pop_up_frames,
73dc5198
KH
2710 look for a window showing BUFFER on any visible or iconified frame.
2711 Otherwise search only the current frame. */
53f76081
RS
2712 if (! NILP (frame))
2713 tem = frame;
2714 else if (pop_up_frames || last_nonminibuf_frame == 0)
73dc5198
KH
2715 XSETFASTINT (tem, 0);
2716 else
73dc5198
KH
2717 XSETFRAME (tem, last_nonminibuf_frame);
2718 window = Fget_buffer_window (buffer, tem);
265a9e55
JB
2719 if (!NILP (window)
2720 && (NILP (not_this_window) || !EQ (window, selected_window)))
f812f9c6 2721 {
d07f802a 2722 return display_buffer_1 (window);
f812f9c6 2723 }
7ab12479 2724
a90712c2 2725 /* Certain buffer names get special handling. */
aee631c2 2726 if (!NILP (Vspecial_display_function) && NILP (swp))
a90712c2 2727 {
4628f7a4
EN
2728 tem = Fspecial_display_p (XBUFFER (buffer)->name);
2729 if (EQ (tem, Qt))
a90712c2 2730 return call1 (Vspecial_display_function, buffer);
4628f7a4
EN
2731 if (CONSP (tem))
2732 return call2 (Vspecial_display_function, buffer, tem);
a90712c2
RS
2733 }
2734
44fa5b1e
JB
2735 /* If there are no frames open that have more than a minibuffer,
2736 we need to create a new frame. */
2737 if (pop_up_frames || last_nonminibuf_frame == 0)
7ab12479 2738 {
a90712c2 2739 window = Fframe_selected_window (call0 (Vpop_up_frame_function));
7ab12479 2740 Fset_window_buffer (window, buffer);
d07f802a 2741 return display_buffer_1 (window);
7ab12479 2742 }
7ab12479 2743
1ae1a37d 2744 f = SELECTED_FRAME ();
43bad991 2745 if (pop_up_windows
1ae1a37d 2746 || FRAME_MINIBUF_ONLY_P (f)
cee67da9
RS
2747 /* If the current frame is a special display frame,
2748 don't try to reuse its windows. */
1ae1a37d 2749 || !NILP (XWINDOW (FRAME_ROOT_WINDOW (f))->dedicated))
7ab12479 2750 {
12cae7c0
KH
2751 Lisp_Object frames;
2752
37962e60 2753 frames = Qnil;
1ae1a37d 2754 if (FRAME_MINIBUF_ONLY_P (f))
74112613 2755 XSETFRAME (frames, last_nonminibuf_frame);
7ab12479
JB
2756 /* Don't try to create a window if would get an error */
2757 if (split_height_threshold < window_min_height << 1)
2758 split_height_threshold = window_min_height << 1;
2759
cee67da9
RS
2760 /* Note that both Fget_largest_window and Fget_lru_window
2761 ignore minibuffers and dedicated windows.
2762 This means they can return nil. */
7ab12479 2763
cee67da9
RS
2764 /* If the frame we would try to split cannot be split,
2765 try other frames. */
1ae1a37d 2766 if (FRAME_NO_SPLIT_P (NILP (frames) ? f : last_nonminibuf_frame))
cee67da9
RS
2767 {
2768 /* Try visible frames first. */
2769 window = Fget_largest_window (Qvisible);
2770 /* If that didn't work, try iconified frames. */
2771 if (NILP (window))
2772 window = Fget_largest_window (make_number (0));
2773 if (NILP (window))
2774 window = Fget_largest_window (Qt);
2775 }
2776 else
2777 window = Fget_largest_window (frames);
2778
92cca945
RS
2779 /* If we got a tall enough full-width window that can be split,
2780 split it. */
265a9e55 2781 if (!NILP (window)
92cca945 2782 && ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
7ab12479 2783 && window_height (window) >= split_height_threshold
111e5992 2784 && WINDOW_FULL_WIDTH_P (XWINDOW (window)))
7ab12479
JB
2785 window = Fsplit_window (window, Qnil, Qnil);
2786 else
2787 {
1942f68f
RS
2788 Lisp_Object upper, lower, other;
2789
44fa5b1e 2790 window = Fget_lru_window (frames);
92cca945
RS
2791 /* If the LRU window is selected, and big enough,
2792 and can be split, split it. */
cee67da9 2793 if (!NILP (window)
92cca945 2794 && ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
cee67da9
RS
2795 && (EQ (window, selected_window)
2796 || EQ (XWINDOW (window)->parent, Qnil))
7ab12479
JB
2797 && window_height (window) >= window_min_height << 1)
2798 window = Fsplit_window (window, Qnil, Qnil);
cee67da9 2799 /* If Fget_lru_window returned nil, try other approaches. */
48d9379d 2800
cee67da9 2801 /* Try visible frames first. */
48d9379d
RS
2802 if (NILP (window))
2803 window = Fget_buffer_window (buffer, Qvisible);
cee67da9
RS
2804 if (NILP (window))
2805 window = Fget_largest_window (Qvisible);
2806 /* If that didn't work, try iconified frames. */
48d9379d
RS
2807 if (NILP (window))
2808 window = Fget_buffer_window (buffer, make_number (0));
cee67da9
RS
2809 if (NILP (window))
2810 window = Fget_largest_window (make_number (0));
2811 /* Try invisible frames. */
48d9379d
RS
2812 if (NILP (window))
2813 window = Fget_buffer_window (buffer, Qt);
cee67da9
RS
2814 if (NILP (window))
2815 window = Fget_largest_window (Qt);
2816 /* As a last resort, make a new frame. */
2817 if (NILP (window))
2818 window = Fframe_selected_window (call0 (Vpop_up_frame_function));
1942f68f
RS
2819 /* If window appears above or below another,
2820 even out their heights. */
cac66e4f 2821 other = upper = lower = Qnil;
1942f68f
RS
2822 if (!NILP (XWINDOW (window)->prev))
2823 other = upper = XWINDOW (window)->prev, lower = window;
2824 if (!NILP (XWINDOW (window)->next))
2825 other = lower = XWINDOW (window)->next, upper = window;
2826 if (!NILP (other)
2827 /* Check that OTHER and WINDOW are vertically arrayed. */
296b535c
KH
2828 && !EQ (XWINDOW (other)->top, XWINDOW (window)->top)
2829 && (XFASTINT (XWINDOW (other)->height)
2830 > XFASTINT (XWINDOW (window)->height)))
1942f68f 2831 {
296b535c
KH
2832 int total = (XFASTINT (XWINDOW (other)->height)
2833 + XFASTINT (XWINDOW (window)->height));
86c8e823
GM
2834 enlarge_window (upper,
2835 total / 2 - XFASTINT (XWINDOW (upper)->height),
f984d4fc 2836 0);
1942f68f 2837 }
7ab12479
JB
2838 }
2839 }
2840 else
2841 window = Fget_lru_window (Qnil);
2842
2843 Fset_window_buffer (window, buffer);
d07f802a 2844 return display_buffer_1 (window);
7ab12479
JB
2845}
2846
2847void
2848temp_output_buffer_show (buf)
2849 register Lisp_Object buf;
2850{
2851 register struct buffer *old = current_buffer;
2852 register Lisp_Object window;
2853 register struct window *w;
2854
bccd3dd1
RS
2855 XBUFFER (buf)->directory = current_buffer->directory;
2856
7ab12479 2857 Fset_buffer (buf);
c6367666 2858 BUF_SAVE_MODIFF (XBUFFER (buf)) = MODIFF;
7ab12479
JB
2859 BEGV = BEG;
2860 ZV = Z;
2861 SET_PT (BEG);
b1599b4c 2862 XBUFFER (buf)->prevent_redisplay_optimizations_p = 1;
7ab12479
JB
2863 set_buffer_internal (old);
2864
2865 if (!EQ (Vtemp_buffer_show_function, Qnil))
2866 call1 (Vtemp_buffer_show_function, buf);
2867 else
2868 {
53f76081 2869 window = Fdisplay_buffer (buf, Qnil, Qnil);
7ab12479 2870
1ae1a37d 2871 if (!EQ (XWINDOW (window)->frame, selected_frame))
44fa5b1e 2872 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
7ab12479
JB
2873 Vminibuf_scroll_window = window;
2874 w = XWINDOW (window);
d834a2e9 2875 XSETFASTINT (w->hscroll, 0);
b73ea88e
RS
2876 set_marker_restricted_both (w->start, buf, 1, 1);
2877 set_marker_restricted_both (w->pointm, buf, 1, 1);
a58ec57d 2878
beb4e312
RS
2879 /* Run temp-buffer-show-hook, with the chosen window selected
2880 and it sbuffer current. */
f52cca03 2881 if (!NILP (Vrun_hooks))
2cccc823 2882 {
f52cca03
RS
2883 Lisp_Object tem;
2884 tem = Fboundp (Qtemp_buffer_show_hook);
2cccc823
RS
2885 if (!NILP (tem))
2886 {
f52cca03
RS
2887 tem = Fsymbol_value (Qtemp_buffer_show_hook);
2888 if (!NILP (tem))
2889 {
2890 int count = specpdl_ptr - specpdl;
b7354ddf
RS
2891 Lisp_Object prev_window;
2892 prev_window = selected_window;
2cccc823 2893
f52cca03 2894 /* Select the window that was chosen, for running the hook. */
65a04b96 2895 record_unwind_protect (Fselect_window, prev_window);
b7354ddf 2896 select_window_1 (window, 0);
beb4e312 2897 Fset_buffer (w->buffer);
f52cca03 2898 call1 (Vrun_hooks, Qtemp_buffer_show_hook);
b7354ddf 2899 select_window_1 (prev_window, 0);
f52cca03
RS
2900 unbind_to (count, Qnil);
2901 }
2cccc823
RS
2902 }
2903 }
2904 }
7ab12479
JB
2905}
2906\f
dfcf069d 2907static void
7ab12479
JB
2908make_dummy_parent (window)
2909 Lisp_Object window;
2910{
cffec418 2911 Lisp_Object new;
7ab12479 2912 register struct window *o, *p;
cffec418
KH
2913 register struct Lisp_Vector *vec;
2914 int i;
7ab12479 2915
cffec418
KH
2916 o = XWINDOW (window);
2917 vec = allocate_vectorlike ((EMACS_INT)VECSIZE (struct window));
2918 for (i = 0; i < VECSIZE (struct window); ++i)
2919 vec->contents[i] = ((struct Lisp_Vector *)o)->contents[i];
2920 vec->size = VECSIZE (struct window);
2921 p = (struct window *)vec;
2922 XSETWINDOW (new, p);
7ab12479 2923
d834a2e9 2924 XSETFASTINT (p->sequence_number, ++sequence_number);
7ab12479
JB
2925
2926 /* Put new into window structure in place of window */
2927 replace_window (window, new);
2928
2929 o->next = Qnil;
2930 o->prev = Qnil;
2931 o->vchild = Qnil;
2932 o->hchild = Qnil;
2933 o->parent = new;
2934
2935 p->start = Qnil;
2936 p->pointm = Qnil;
2937 p->buffer = Qnil;
2938}
2939
2940DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
2941 "Split WINDOW, putting SIZE lines in the first of the pair.\n\
2942WINDOW defaults to selected one and SIZE to half its size.\n\
77ae0fe3 2943If optional third arg HORFLAG is non-nil, split side by side\n\
10f96191
RS
2944and put SIZE columns in the first of the pair. In that case,\n\
2945SIZE includes that window's scroll bar, or the divider column to its right.")
77ae0fe3
KH
2946 (window, size, horflag)
2947 Lisp_Object window, size, horflag;
7ab12479
JB
2948{
2949 register Lisp_Object new;
2950 register struct window *o, *p;
c0807608 2951 FRAME_PTR fo;
77ae0fe3 2952 register int size_int;
7ab12479 2953
265a9e55 2954 if (NILP (window))
7ab12479
JB
2955 window = selected_window;
2956 else
605be8af 2957 CHECK_LIVE_WINDOW (window, 0);
7ab12479
JB
2958
2959 o = XWINDOW (window);
c0807608 2960 fo = XFRAME (WINDOW_FRAME (o));
7ab12479 2961
77ae0fe3 2962 if (NILP (size))
7ab12479 2963 {
265a9e55 2964 if (!NILP (horflag))
c0807608 2965 /* Calculate the size of the left-hand window, by dividing
25b33244
KH
2966 the usable space in columns by two.
2967 We round up, since the left-hand window may include
2968 a dividing line, while the right-hand may not. */
2969 size_int = (XFASTINT (o->width) + 1) >> 1;
7ab12479 2970 else
77ae0fe3 2971 size_int = XFASTINT (o->height) >> 1;
7ab12479
JB
2972 }
2973 else
2974 {
77ae0fe3
KH
2975 CHECK_NUMBER (size, 1);
2976 size_int = XINT (size);
7ab12479
JB
2977 }
2978
2979 if (MINI_WINDOW_P (o))
2980 error ("Attempt to split minibuffer window");
233a4a2c
GM
2981 else if (window_fixed_size_p (o, !NILP (horflag), 0))
2982 error ("Attempt to split fixed-size window");
7ab12479 2983
a481b3ea 2984 check_min_window_sizes ();
7ab12479 2985
265a9e55 2986 if (NILP (horflag))
7ab12479 2987 {
77ae0fe3
KH
2988 if (size_int < window_min_height)
2989 error ("Window height %d too small (after splitting)", size_int);
2990 if (size_int + window_min_height > XFASTINT (o->height))
37962e60 2991 error ("Window height %d too small (after splitting)",
77ae0fe3 2992 XFASTINT (o->height) - size_int);
265a9e55
JB
2993 if (NILP (o->parent)
2994 || NILP (XWINDOW (o->parent)->vchild))
7ab12479
JB
2995 {
2996 make_dummy_parent (window);
2997 new = o->parent;
2998 XWINDOW (new)->vchild = window;
2999 }
3000 }
3001 else
3002 {
77ae0fe3
KH
3003 if (size_int < window_min_width)
3004 error ("Window width %d too small (after splitting)", size_int);
a59fed7e
RS
3005
3006 if (size_int + window_min_width > XFASTINT (o->width))
37962e60 3007 error ("Window width %d too small (after splitting)",
a59fed7e 3008 XFASTINT (o->width) - size_int);
265a9e55
JB
3009 if (NILP (o->parent)
3010 || NILP (XWINDOW (o->parent)->hchild))
7ab12479
JB
3011 {
3012 make_dummy_parent (window);
3013 new = o->parent;
3014 XWINDOW (new)->hchild = window;
3015 }
3016 }
3017
3018 /* Now we know that window's parent is a vertical combination
3019 if we are dividing vertically, or a horizontal combination
3020 if we are making side-by-side windows */
3021
3022 windows_or_buffers_changed++;
c0807608 3023 FRAME_WINDOW_SIZES_CHANGED (fo) = 1;
7ab12479
JB
3024 new = make_window ();
3025 p = XWINDOW (new);
3026
44fa5b1e 3027 p->frame = o->frame;
7ab12479 3028 p->next = o->next;
265a9e55 3029 if (!NILP (p->next))
7ab12479
JB
3030 XWINDOW (p->next)->prev = new;
3031 p->prev = window;
3032 o->next = new;
3033 p->parent = o->parent;
3034 p->buffer = Qt;
5500c422
GM
3035 p->window_end_valid = Qnil;
3036 bzero (&p->last_cursor, sizeof p->last_cursor);
7ab12479 3037
44fa5b1e 3038 /* Apportion the available frame space among the two new windows */
7ab12479 3039
265a9e55 3040 if (!NILP (horflag))
7ab12479
JB
3041 {
3042 p->height = o->height;
3043 p->top = o->top;
a59fed7e 3044 XSETFASTINT (p->width, XFASTINT (o->width) - size_int);
77ae0fe3
KH
3045 XSETFASTINT (o->width, size_int);
3046 XSETFASTINT (p->left, XFASTINT (o->left) + size_int);
7ab12479
JB
3047 }
3048 else
3049 {
3050 p->left = o->left;
3051 p->width = o->width;
77ae0fe3
KH
3052 XSETFASTINT (p->height, XFASTINT (o->height) - size_int);
3053 XSETFASTINT (o->height, size_int);
3054 XSETFASTINT (p->top, XFASTINT (o->top) + size_int);
7ab12479
JB
3055 }
3056
5500c422
GM
3057 /* Adjust glyph matrices. */
3058 adjust_glyphs (fo);
543f5fb1 3059 Fset_window_buffer (new, o->buffer);
7ab12479
JB
3060 return new;
3061}
3062\f
3063DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
3064 "Make current window ARG lines bigger.\n\
3065From program, optional second arg non-nil means grow sideways ARG columns.")
413430c5
EN
3066 (arg, side)
3067 register Lisp_Object arg, side;
7ab12479 3068{
413430c5 3069 CHECK_NUMBER (arg, 0);
86c8e823 3070 enlarge_window (selected_window, XINT (arg), !NILP (side));
543f5fb1
RS
3071
3072 if (! NILP (Vwindow_configuration_change_hook))
3073 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
3074
7ab12479
JB
3075 return Qnil;
3076}
3077
3078DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
3079 "Make current window ARG lines smaller.\n\
413430c5
EN
3080From program, optional second arg non-nil means shrink sideways arg columns.")
3081 (arg, side)
3082 register Lisp_Object arg, side;
7ab12479 3083{
413430c5 3084 CHECK_NUMBER (arg, 0);
86c8e823 3085 enlarge_window (selected_window, -XINT (arg), !NILP (side));
543f5fb1
RS
3086
3087 if (! NILP (Vwindow_configuration_change_hook))
3088 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
3089
7ab12479
JB
3090 return Qnil;
3091}
3092
3093int
3094window_height (window)
3095 Lisp_Object window;
3096{
3097 register struct window *p = XWINDOW (window);
3098 return XFASTINT (p->height);
3099}
3100
3101int
3102window_width (window)
3103 Lisp_Object window;
3104{
3105 register struct window *p = XWINDOW (window);
3106 return XFASTINT (p->width);
3107}
3108
c1636aa6 3109
7ab12479 3110#define CURBEG(w) \
3578db3c 3111 *(widthflag ? &(XWINDOW (w)->left) : &(XWINDOW (w)->top))
7ab12479
JB
3112
3113#define CURSIZE(w) \
3578db3c 3114 *(widthflag ? &(XWINDOW (w)->width) : &(XWINDOW (w)->height))
7ab12479 3115
233a4a2c
GM
3116
3117/* Enlarge selected_window by DELTA. WIDTHFLAG non-zero means
3118 increase its width. Siblings of the selected window are resized to
3119 fullfil the size request. If they become too small in the process,
3120 they will be deleted. */
7ab12479 3121
f984d4fc 3122static void
86c8e823
GM
3123enlarge_window (window, delta, widthflag)
3124 Lisp_Object window;
233a4a2c 3125 int delta, widthflag;
7ab12479 3126{
86c8e823 3127 Lisp_Object parent, next, prev;
233a4a2c 3128 struct window *p;
3578db3c
KR
3129 Lisp_Object *sizep;
3130 int maximum;
5e14b1fc
AS
3131 int (*sizefun) P_ ((Lisp_Object))
3132 = widthflag ? window_width : window_height;
233a4a2c 3133 void (*setsizefun) P_ ((Lisp_Object, int, int))
5e14b1fc 3134 = (widthflag ? set_window_width : set_window_height);
7ab12479 3135
233a4a2c
GM
3136 /* Check values of window_min_width and window_min_height for
3137 validity. */
a481b3ea 3138 check_min_window_sizes ();
7ab12479 3139
233a4a2c 3140 /* Give up if this window cannot be resized. */
233a4a2c
GM
3141 if (window_fixed_size_p (XWINDOW (window), widthflag, 1))
3142 error ("Window is not resizable");
3143
3144 /* Find the parent of the selected window. */
7ab12479
JB
3145 while (1)
3146 {
3147 p = XWINDOW (window);
3148 parent = p->parent;
233a4a2c 3149
265a9e55 3150 if (NILP (parent))
7ab12479
JB
3151 {
3152 if (widthflag)
3153 error ("No other window to side of this one");
3154 break;
3155 }
233a4a2c
GM
3156
3157 if (widthflag
3158 ? !NILP (XWINDOW (parent)->hchild)
265a9e55 3159 : !NILP (XWINDOW (parent)->vchild))
7ab12479 3160 break;
233a4a2c 3161
7ab12479
JB
3162 window = parent;
3163 }
3164
05c2896a 3165 sizep = &CURSIZE (window);
7ab12479 3166
7ab12479
JB
3167 {
3168 register int maxdelta;
7ab12479 3169
3578db3c 3170 maxdelta = (!NILP (parent) ? (*sizefun) (parent) - XINT (*sizep)
c1636aa6
GM
3171 : !NILP (p->next) ? ((*sizefun) (p->next)
3172 - window_min_size (XWINDOW (p->next),
f984d4fc 3173 widthflag, 0, 0))
c1636aa6
GM
3174 : !NILP (p->prev) ? ((*sizefun) (p->prev)
3175 - window_min_size (XWINDOW (p->prev),
f984d4fc 3176 widthflag, 0, 0))
44fa5b1e
JB
3177 /* This is a frame with only one window, a minibuffer-only
3178 or a minibufferless frame. */
d5783c40 3179 : (delta = 0));
7ab12479
JB
3180
3181 if (delta > maxdelta)
3182 /* This case traps trying to make the minibuffer
44fa5b1e
JB
3183 the full frame, or make the only window aside from the
3184 minibuffer the full frame. */
7ab12479 3185 delta = maxdelta;
6b54027b 3186 }
d5783c40 3187
3578db3c 3188 if (XINT (*sizep) + delta < window_min_size (XWINDOW (window), widthflag, 0, 0))
6b54027b 3189 {
543f5fb1 3190 delete_window (window);
d5783c40 3191 return;
6b54027b
RS
3192 }
3193
3194 if (delta == 0)
3195 return;
7ab12479 3196
db98a733
RS
3197 /* Find the total we can get from other siblings. */
3198 maximum = 0;
3199 for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
c1636aa6 3200 maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
f984d4fc 3201 widthflag, 0, 0);
db98a733 3202 for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
c1636aa6 3203 maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
f984d4fc 3204 widthflag, 0, 0);
db98a733
RS
3205
3206 /* If we can get it all from them, do so. */
c6b530ed 3207 if (delta <= maximum)
7ab12479 3208 {
db98a733
RS
3209 Lisp_Object first_unaffected;
3210 Lisp_Object first_affected;
233a4a2c 3211 int fixed_p;
db98a733
RS
3212
3213 next = p->next;
3214 prev = p->prev;
3215 first_affected = window;
3216 /* Look at one sibling at a time,
3217 moving away from this window in both directions alternately,
3218 and take as much as we can get without deleting that sibling. */
233a4a2c 3219 while (delta != 0 && (!NILP (next) || !NILP (prev)))
db98a733 3220 {
db98a733
RS
3221 if (! NILP (next))
3222 {
c1636aa6 3223 int this_one = ((*sizefun) (next)
233a4a2c 3224 - window_min_size (XWINDOW (next),
f984d4fc 3225 widthflag, 0, &fixed_p));
233a4a2c
GM
3226 if (!fixed_p)
3227 {
3228 if (this_one > delta)
3229 this_one = delta;
3230
3231 (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
3578db3c 3232 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
db98a733 3233
233a4a2c
GM
3234 delta -= this_one;
3235 }
3236
db98a733
RS
3237 next = XWINDOW (next)->next;
3238 }
233a4a2c 3239
db98a733
RS
3240 if (delta == 0)
3241 break;
233a4a2c 3242
db98a733
RS
3243 if (! NILP (prev))
3244 {
c1636aa6 3245 int this_one = ((*sizefun) (prev)
233a4a2c 3246 - window_min_size (XWINDOW (prev),
f984d4fc 3247 widthflag, 0, &fixed_p));
233a4a2c
GM
3248 if (!fixed_p)
3249 {
3250 if (this_one > delta)
3251 this_one = delta;
3252
3253 first_affected = prev;
3254
3255 (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
3578db3c 3256 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
233a4a2c
GM
3257
3258 delta -= this_one;
3259 }
3260
db98a733
RS
3261 prev = XWINDOW (prev)->prev;
3262 }
3263 }
3264
233a4a2c
GM
3265 xassert (delta == 0);
3266
db98a733
RS
3267 /* Now recalculate the edge positions of all the windows affected,
3268 based on the new sizes. */
3269 first_unaffected = next;
3270 prev = first_affected;
3271 for (next = XWINDOW (prev)->next; ! EQ (next, first_unaffected);
3272 prev = next, next = XWINDOW (next)->next)
3273 {
3578db3c 3274 XSETINT (CURBEG (next), XINT (CURBEG (prev)) + (*sizefun) (prev));
db98a733
RS
3275 /* This does not change size of NEXT,
3276 but it propagates the new top edge to its children */
3277 (*setsizefun) (next, (*sizefun) (next), 0);
3278 }
7ab12479
JB
3279 }
3280 else
3281 {
3282 register int delta1;
3283 register int opht = (*sizefun) (parent);
3284
3285 /* If trying to grow this window to or beyond size of the parent,
3286 make delta1 so big that, on shrinking back down,
3287 all the siblings end up with less than one line and are deleted. */
3578db3c 3288 if (opht <= XINT (*sizep) + delta)
7ab12479 3289 delta1 = opht * opht * 2;
7ab12479 3290 else
233a4a2c
GM
3291 {
3292 /* Otherwise, make delta1 just right so that if we add
3293 delta1 lines to this window and to the parent, and then
3294 shrink the parent back to its original size, the new
3295 proportional size of this window will increase by delta.
3296
3297 The function size_window will compute the new height h'
3298 of the window from delta1 as:
3299
3300 e = delta1/n
3301 x = delta1 - delta1/n * n for the 1st resizable child
3302 h' = h + e + x
3303
3304 where n is the number of children that can be resized.
3305 We can ignore x by choosing a delta1 that is a multiple of
3306 n. We want the height of this window to come out as
3307
3308 h' = h + delta
3309
3310 So, delta1 must be
3311
3312 h + e = h + delta
3313 delta1/n = delta
3314 delta1 = n * delta.
3315
3316 The number of children n rquals the number of resizable
3317 children of this window + 1 because we know window itself
3318 is resizable (otherwise we would have signalled an error. */
3319
3320 struct window *w = XWINDOW (window);
3321 Lisp_Object s;
3322 int n = 1;
3323
3324 for (s = w->next; !NILP (s); s = XWINDOW (s)->next)
3325 if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
3326 ++n;
3327 for (s = w->prev; !NILP (s); s = XWINDOW (s)->prev)
3328 if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
3329 ++n;
3330
3331 delta1 = n * delta;
3332 }
7ab12479
JB
3333
3334 /* Add delta1 lines or columns to this window, and to the parent,
3335 keeping things consistent while not affecting siblings. */
3578db3c
KR
3336 XSETINT (CURSIZE (parent), opht + delta1);
3337 (*setsizefun) (window, XINT (*sizep) + delta1, 0);
7ab12479
JB
3338
3339 /* Squeeze out delta1 lines or columns from our parent,
3340 shriking this window and siblings proportionately.
3341 This brings parent back to correct size.
3342 Delta1 was calculated so this makes this window the desired size,
3343 taking it all out of the siblings. */
3344 (*setsizefun) (parent, opht, 0);
3345 }
3346
d834a2e9 3347 XSETFASTINT (p->last_modified, 0);
3cd21523 3348 XSETFASTINT (p->last_overlay_modified, 0);
5500c422
GM
3349
3350 /* Adjust glyph matrices. */
3351 adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
7ab12479 3352}
c1636aa6 3353
7ab12479
JB
3354#undef CURBEG
3355#undef CURSIZE
3356
5500c422 3357
f984d4fc
GM
3358\f
3359/***********************************************************************
3360 Resizing Mini-Windows
3361 ***********************************************************************/
3362
3363static void shrink_window_lowest_first P_ ((struct window *, int));
f984d4fc 3364
43b4a21f
GM
3365enum save_restore_action
3366{
3367 CHECK_ORIG_SIZES,
3368 SAVE_ORIG_SIZES,
3369 RESTORE_ORIG_SIZES
3370};
3371
3372static int save_restore_orig_size P_ ((struct window *,
3373 enum save_restore_action));
f984d4fc
GM
3374
3375/* Shrink windows rooted in window W to HEIGHT. Take the space needed
3376 from lowest windows first. */
3377
3378static void
3379shrink_window_lowest_first (w, height)
3380 struct window *w;
3381 int height;
3382{
3383 struct window *c;
3384 Lisp_Object child;
3385 int old_height;
3386
3387 xassert (!MINI_WINDOW_P (w));
3388
3389 /* Set redisplay hints. */
3390 XSETFASTINT (w->last_modified, 0);
3391 XSETFASTINT (w->last_overlay_modified, 0);
3392 windows_or_buffers_changed++;
3393 FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
3394
3395 old_height = XFASTINT (w->height);
3396 XSETFASTINT (w->height, height);
3397
3398 if (!NILP (w->hchild))
3399 {
3400 for (child = w->hchild; !NILP (child); child = c->next)
3401 {
3402 c = XWINDOW (child);
3403 c->top = w->top;
3404 shrink_window_lowest_first (c, height);
3405 }
3406 }
3407 else if (!NILP (w->vchild))
3408 {
3409 Lisp_Object last_child;
3410 int delta = old_height - height;
3411 int last_top;
3412
3413 /* Find the last child. We are taking space from lowest windows
3414 first, so we iterate over children from the last child
3415 backwards. */
3416 for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
3417 last_child = child;
3418
3419 /* Assign new heights. We leave only MIN_SAFE_WINDOW_HEIGHT. */
3420 for (child = last_child; delta && !NILP (child); child = c->prev)
3421 {
3422 int this_one;
3423
3424 c = XWINDOW (child);
3425 this_one = XFASTINT (c->height) - MIN_SAFE_WINDOW_HEIGHT;
3426
3427 if (this_one > delta)
3428 this_one = delta;
3429
3430 shrink_window_lowest_first (c, XFASTINT (c->height) - this_one);
3431 delta -= this_one;
3432 }
3433
3434 /* Compute new positions. */
3578db3c 3435 last_top = XINT (w->top);
f984d4fc
GM
3436 for (child = w->vchild; !NILP (child); child = c->next)
3437 {
3438 c = XWINDOW (child);
3439 c->top = make_number (last_top);
3440 shrink_window_lowest_first (c, XFASTINT (c->height));
3441 last_top += XFASTINT (c->height);
3442 }
3443 }
3444}
3445
3446
43b4a21f
GM
3447/* Save, restore, or check positions and sizes in the window tree
3448 rooted at W. ACTION says what to do.
f984d4fc 3449
43b4a21f
GM
3450 If ACTION is CHECK_ORIG_SIZES, check if orig_top and orig_height
3451 members are valid for all windows in the window tree. Value is
3452 non-zero if they are valid.
3453
3454 If ACTION is SAVE_ORIG_SIZES, save members top and height in
3455 orig_top and orig_height for all windows in the tree.
3456
3457 If ACTION is RESTORE_ORIG_SIZES, restore top and height from
3458 values stored in orig_top and orig_height for all windows. */
3459
3460static int
3461save_restore_orig_size (w, action)
f984d4fc 3462 struct window *w;
43b4a21f 3463 enum save_restore_action action;
f984d4fc 3464{
43b4a21f
GM
3465 int success_p = 1;
3466
f984d4fc
GM
3467 while (w)
3468 {
3469 if (!NILP (w->hchild))
43b4a21f
GM
3470 {
3471 if (!save_restore_orig_size (XWINDOW (w->hchild), action))
3472 success_p = 0;
3473 }
f984d4fc 3474 else if (!NILP (w->vchild))
43b4a21f
GM
3475 {
3476 if (!save_restore_orig_size (XWINDOW (w->vchild), action))
3477 success_p = 0;
3478 }
f984d4fc 3479
43b4a21f 3480 switch (action)
f984d4fc 3481 {
43b4a21f
GM
3482 case CHECK_ORIG_SIZES:
3483 if (!INTEGERP (w->orig_top) || !INTEGERP (w->orig_height))
3484 return 0;
3485 break;
3486
3487 case SAVE_ORIG_SIZES:
f984d4fc
GM
3488 w->orig_top = w->top;
3489 w->orig_height = w->height;
43b4a21f
GM
3490 XSETFASTINT (w->last_modified, 0);
3491 XSETFASTINT (w->last_overlay_modified, 0);
3492 break;
3493
3494 case RESTORE_ORIG_SIZES:
f984d4fc
GM
3495 xassert (INTEGERP (w->orig_top) && INTEGERP (w->orig_height));
3496 w->top = w->orig_top;
3497 w->height = w->orig_height;
3498 w->orig_height = w->orig_top = Qnil;
43b4a21f
GM
3499 XSETFASTINT (w->last_modified, 0);
3500 XSETFASTINT (w->last_overlay_modified, 0);
3501 break;
3502
3503 default:
3504 abort ();
f984d4fc 3505 }
43b4a21f 3506
f984d4fc
GM
3507 w = NILP (w->next) ? NULL : XWINDOW (w->next);
3508 }
43b4a21f
GM
3509
3510 return success_p;
f984d4fc
GM
3511}
3512
3513
3514/* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we can
3515 without deleting other windows. */
3516
3517void
3518grow_mini_window (w, delta)
3519 struct window *w;
3520 int delta;
3521{
3522 struct frame *f = XFRAME (w->frame);
3523 struct window *root;
3524
3525 xassert (MINI_WINDOW_P (w));
3526 xassert (delta >= 0);
3527
3528 /* Check values of window_min_width and window_min_height for
3529 validity. */
3530 check_min_window_sizes ();
3531
3532 /* Compute how much we can enlarge the mini-window without deleting
3533 other windows. */
3534 root = XWINDOW (FRAME_ROOT_WINDOW (f));
3535 if (delta)
3536 {
3537 int min_height = window_min_size (root, 0, 0, 0);
3538 if (XFASTINT (root->height) - delta < min_height)
3539 delta = XFASTINT (root->height) - min_height;
3540 }
3541
3542 if (delta)
3543 {
3544 /* Save original window sizes and positions, if not already done. */
43b4a21f
GM
3545 if (!save_restore_orig_size (root, CHECK_ORIG_SIZES))
3546 save_restore_orig_size (root, SAVE_ORIG_SIZES);
f984d4fc
GM
3547
3548 /* Shrink other windows. */
3549 shrink_window_lowest_first (root, XFASTINT (root->height) - delta);
3550
3551 /* Grow the mini-window. */
3578db3c 3552 w->top = make_number (XFASTINT (root->top) + XFASTINT (root->height));
f984d4fc
GM
3553 w->height = make_number (XFASTINT (w->height) + delta);
3554 XSETFASTINT (w->last_modified, 0);
3555 XSETFASTINT (w->last_overlay_modified, 0);
3556
3557 adjust_glyphs (f);
3558 }
3559}
3560
3561
86c8e823
GM
3562/* Shrink mini-window W. If there is recorded info about window sizes
3563 before a call to grow_mini_window, restore recorded window sizes.
3564 Otherwise, if the mini-window is higher than 1 line, resize it to 1
3565 line. */
f984d4fc
GM
3566
3567void
3568shrink_mini_window (w)
3569 struct window *w;
3570{
3571 struct frame *f = XFRAME (w->frame);
3572 struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
3573
43b4a21f 3574 if (save_restore_orig_size (root, CHECK_ORIG_SIZES))
f984d4fc 3575 {
43b4a21f 3576 save_restore_orig_size (root, RESTORE_ORIG_SIZES);
f984d4fc
GM
3577 adjust_glyphs (f);
3578 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
3579 windows_or_buffers_changed = 1;
3580 }
86c8e823
GM
3581 else if (XFASTINT (w->height) > 1)
3582 {
3583 Lisp_Object window;
3584 XSETWINDOW (window, w);
3585 enlarge_window (window, 1 - XFASTINT (w->height), 0);
3586 }
f984d4fc
GM
3587}
3588
3589
3590\f
5500c422
GM
3591/* Mark window cursors off for all windows in the window tree rooted
3592 at W by setting their phys_cursor_on_p flag to zero. Called from
3593 xterm.c, e.g. when a frame is cleared and thereby all cursors on
3594 the frame are cleared. */
3595
3596void
3597mark_window_cursors_off (w)
3598 struct window *w;
3599{
3600 while (w)
3601 {
3602 if (!NILP (w->hchild))
3603 mark_window_cursors_off (XWINDOW (w->hchild));
3604 else if (!NILP (w->vchild))
3605 mark_window_cursors_off (XWINDOW (w->vchild));
3606 else
3607 w->phys_cursor_on_p = 0;
3608
3609 w = NILP (w->next) ? 0 : XWINDOW (w->next);
3610 }
3611}
3612
3613
7ab12479
JB
3614/* Return number of lines of text (not counting mode line) in W. */
3615
3616int
3617window_internal_height (w)
3618 struct window *w;
3619{
3620 int ht = XFASTINT (w->height);
3621
3622 if (MINI_WINDOW_P (w))
3623 return ht;
3624
265a9e55
JB
3625 if (!NILP (w->parent) || !NILP (w->vchild) || !NILP (w->hchild)
3626 || !NILP (w->next) || !NILP (w->prev)
44fa5b1e 3627 || FRAME_WANTS_MODELINE_P (XFRAME (WINDOW_FRAME (w))))
7ab12479
JB
3628 return ht - 1;
3629
3630 return ht;
3631}
3632
535e0b8e
JB
3633
3634/* Return the number of columns in W.
a3c87d4e 3635 Don't count columns occupied by scroll bars or the vertical bar
535e0b8e 3636 separating W from the sibling to its right. */
5500c422 3637
535e0b8e
JB
3638int
3639window_internal_width (w)
3640 struct window *w;
3641{
5500c422 3642 struct frame *f = XFRAME (WINDOW_FRAME (w));
535e0b8e
JB
3643 int width = XINT (w->width);
3644
a3c87d4e 3645 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5500c422
GM
3646 /* Scroll bars occupy a few columns. */
3647 width -= FRAME_SCROLL_BAR_COLS (f);
3648 else if (!WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
3649 /* The column of `|' characters separating side-by-side windows
3650 occupies one column only. */
3651 width -= 1;
3652
3653 /* On window-systems, areas to the left and right of the window
3654 are used to display bitmaps there. */
3655 if (FRAME_WINDOW_P (f))
b46dfc64 3656 width -= FRAME_FLAGS_AREA_COLS (f);
111e5992
RS
3657
3658 return width;
535e0b8e
JB
3659}
3660
5500c422
GM
3661\f
3662/************************************************************************
3663 Window Scrolling
3664 ***********************************************************************/
535e0b8e 3665
5500c422
GM
3666/* Scroll contents of window WINDOW up. If WHOLE is non-zero, scroll
3667 one screen-full, which is defined as the height of the window minus
3668 next_screen_context_lines. If WHOLE is zero, scroll up N lines
3669 instead. Negative values of N mean scroll down. NOERROR non-zero
3670 means don't signal an error if we try to move over BEGV or ZV,
3671 respectively. */
7ab12479 3672
101d1605
RS
3673static void
3674window_scroll (window, n, whole, noerror)
7ab12479
JB
3675 Lisp_Object window;
3676 int n;
101d1605 3677 int whole;
f8026fd8 3678 int noerror;
5500c422
GM
3679{
3680 /* If we must, use the pixel-based version which is much slower than
3681 the line-based one but can handle varying line heights. */
3682 if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
3683 window_scroll_pixel_based (window, n, whole, noerror);
3684 else
3685 window_scroll_line_based (window, n, whole, noerror);
3686}
3687
3688
3689/* Implementation of window_scroll that works based on pixel line
3690 heights. See the comment of window_scroll for parameter
3691 descriptions. */
3692
3693static void
3694window_scroll_pixel_based (window, n, whole, noerror)
3695 Lisp_Object window;
3696 int n;
3697 int whole;
3698 int noerror;
3699{
3700 struct it it;
3701 struct window *w = XWINDOW (window);
3702 struct text_pos start;
3703 Lisp_Object tem;
3704 int this_scroll_margin;
3705 int preserve_y;
3706
3707 SET_TEXT_POS_FROM_MARKER (start, w->start);
3708
3709 /* If PT is not visible in WINDOW, move back one half of
3710 the screen. */
3711 XSETFASTINT (tem, PT);
3712 tem = Fpos_visible_in_window_p (tem, window);
3713 if (NILP (tem))
3714 {
3715 /* Move backward half the height of the window. Performance note:
3716 vmotion used here is about 10% faster, but would give wrong
3717 results for variable height lines. */
3718 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
3719 it.current_y = it.last_visible_y;
3720 move_it_vertically (&it, -it.last_visible_y / 2);
3721
3722 /* The function move_iterator_vertically may move over more than
3723 the specified y-distance. If it->w is small, e.g. a
3724 mini-buffer window, we may end up in front of the window's
3725 display area. This is the case when Start displaying at the
3726 start of the line containing PT in this case. */
3727 if (it.current_y <= 0)
3728 {
3729 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
3730 move_it_vertically (&it, 0);
3731 it.current_y = 0;
3732 }
3733
3734 start = it.current.pos;
3735 }
3736
3737 /* If scroll_preserve_screen_position is non-zero, we try to set
3738 point in the same window line as it is now, so get that line. */
3739 if (!NILP (Vscroll_preserve_screen_position))
3740 {
3741 start_display (&it, w, start);
3742 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
3743 preserve_y = it.current_y;
3744 }
3745 else
3746 preserve_y = -1;
3747
3748 /* Move iterator it from start the specified distance forward or
3749 backward. The result is the new window start. */
3750 start_display (&it, w, start);
3751 if (whole)
3752 {
3753 int screen_full = (it.last_visible_y
3754 - next_screen_context_lines * CANON_Y_UNIT (it.f));
3755 int direction = n < 0 ? -1 : 1;
3756 move_it_vertically (&it, direction * screen_full);
3757 }
3758 else
3759 move_it_by_lines (&it, n, 1);
3760
3761 /* End if we end up at ZV or BEGV. */
3762 if ((n > 0 && IT_CHARPOS (it) == ZV)
3763 || (n < 0 && IT_CHARPOS (it) == CHARPOS (start)))
3764 {
3765 if (noerror)
3766 return;
3767 else if (IT_CHARPOS (it) == ZV)
3768 Fsignal (Qend_of_buffer, Qnil);
3769 else
3770 Fsignal (Qbeginning_of_buffer, Qnil);
3771 }
3772
3773 /* Set the window start, and set up the window for redisplay. */
3774 set_marker_restricted (w->start, make_number (IT_CHARPOS (it)), w->buffer);
3775 w->start_at_line_beg = Fbolp ();
3776 w->update_mode_line = Qt;
3777 XSETFASTINT (w->last_modified, 0);
3778 XSETFASTINT (w->last_overlay_modified, 0);
3779 /* Set force_start so that redisplay_window will run the
3780 window-scroll-functions. */
3781 w->force_start = Qt;
3782
3783 it.current_y = it.vpos = 0;
3784
3785 /* Preserve the screen position if we must. */
3786 if (preserve_y >= 0)
3787 {
3788 move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
3789 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
3790 }
3791 else
3792 {
3793 /* Move PT out of scroll margins. */
3794 this_scroll_margin = max (0, scroll_margin);
3795 this_scroll_margin = min (this_scroll_margin, XFASTINT (w->height) / 4);
3796 this_scroll_margin *= CANON_Y_UNIT (it.f);
3797
3798 if (n > 0)
3799 {
3800 /* We moved the window start towards ZV, so PT may be now
3801 in the scroll margin at the top. */
3802 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
3803 while (it.current_y < this_scroll_margin)
3804 move_it_by_lines (&it, 1, 1);
3805 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
3806 }
3807 else if (n < 0)
3808 {
3809 /* We moved the window start towards BEGV, so PT may be now
3810 in the scroll margin at the bottom. */
3811 move_it_to (&it, PT, -1,
3812 it.last_visible_y - this_scroll_margin - 1, -1,
3813 MOVE_TO_POS | MOVE_TO_Y);
3814
3815 /* Don't put point on a partially visible line at the end. */
3816 if (it.current_y + it.max_ascent + it.max_descent
3817 > it.last_visible_y)
3818 move_it_by_lines (&it, -1, 0);
3819
3820 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
3821 }
3822 }
3823}
3824
3825
3826/* Implementation of window_scroll that works based on screen lines.
3827 See the comment of window_scroll for parameter descriptions. */
3828
3829static void
3830window_scroll_line_based (window, n, whole, noerror)
3831 Lisp_Object window;
3832 int n;
3833 int whole;
3834 int noerror;
7ab12479
JB
3835{
3836 register struct window *w = XWINDOW (window);
5500c422 3837 register int opoint = PT, opoint_byte = PT_BYTE;
b73ea88e 3838 register int pos, pos_byte;
7ab12479
JB
3839 register int ht = window_internal_height (w);
3840 register Lisp_Object tem;
3841 int lose;
5500c422 3842 Lisp_Object bolp;
345d45b2 3843 int startpos;
101d1605
RS
3844 struct position posit;
3845 int original_vpos;
3846
3847 startpos = marker_position (w->start);
3848
3849 posit = *compute_motion (startpos, 0, 0, 0,
3850 PT, ht, 0,
3851 window_internal_width (w), XINT (w->hscroll),
3852 0, w);
3853 original_vpos = posit.vpos;
0a1f771a 3854
d834a2e9 3855 XSETFASTINT (tem, PT);
7ab12479
JB
3856 tem = Fpos_visible_in_window_p (tem, window);
3857
265a9e55 3858 if (NILP (tem))
7ab12479 3859 {
cd2be1dd 3860 Fvertical_motion (make_number (- (ht / 2)), window);
345d45b2 3861 startpos = PT;
7ab12479
JB
3862 }
3863
345d45b2 3864 SET_PT (startpos);
5ce7b543 3865 lose = n < 0 && PT == BEGV;
540b6aa0 3866 Fvertical_motion (make_number (n), window);
5ce7b543 3867 pos = PT;
b73ea88e 3868 pos_byte = PT_BYTE;
7ab12479 3869 bolp = Fbolp ();
b73ea88e 3870 SET_PT_BOTH (opoint, opoint_byte);
7ab12479
JB
3871
3872 if (lose)
f8026fd8
JB
3873 {
3874 if (noerror)
3875 return;
3876 else
3877 Fsignal (Qbeginning_of_buffer, Qnil);
3878 }
7ab12479
JB
3879
3880 if (pos < ZV)
7ab12479 3881 {
0c7da84e
RS
3882 int this_scroll_margin = scroll_margin;
3883
3884 /* Don't use a scroll margin that is negative or too large. */
3885 if (this_scroll_margin < 0)
3886 this_scroll_margin = 0;
3887
3888 if (XINT (w->height) < 4 * scroll_margin)
3889 this_scroll_margin = XINT (w->height) / 4;
3890
b73ea88e 3891 set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
7ab12479
JB
3892 w->start_at_line_beg = bolp;
3893 w->update_mode_line = Qt;
d834a2e9 3894 XSETFASTINT (w->last_modified, 0);
3cd21523 3895 XSETFASTINT (w->last_overlay_modified, 0);
345d45b2
RS
3896 /* Set force_start so that redisplay_window will run
3897 the window-scroll-functions. */
3898 w->force_start = Qt;
0c7da84e 3899
5500c422 3900 if (whole && !NILP (Vscroll_preserve_screen_position))
0c7da84e 3901 {
b73ea88e 3902 SET_PT_BOTH (pos, pos_byte);
101d1605 3903 Fvertical_motion (make_number (original_vpos), window);
0c7da84e 3904 }
101d1605
RS
3905 /* If we scrolled forward, put point enough lines down
3906 that it is outside the scroll margin. */
3907 else if (n > 0)
0c7da84e 3908 {
101d1605
RS
3909 int top_margin;
3910
3911 if (this_scroll_margin > 0)
3912 {
b73ea88e 3913 SET_PT_BOTH (pos, pos_byte);
101d1605
RS
3914 Fvertical_motion (make_number (this_scroll_margin), window);
3915 top_margin = PT;
3916 }
3917 else
3918 top_margin = pos;
3919
3920 if (top_margin <= opoint)
b73ea88e 3921 SET_PT_BOTH (opoint, opoint_byte);
5500c422 3922 else if (!NILP (Vscroll_preserve_screen_position))
101d1605 3923 {
b73ea88e 3924 SET_PT_BOTH (pos, pos_byte);
101d1605
RS
3925 Fvertical_motion (make_number (original_vpos), window);
3926 }
9317a85d 3927 else
335406fc 3928 SET_PT (top_margin);
0c7da84e 3929 }
101d1605 3930 else if (n < 0)
7ab12479 3931 {
101d1605
RS
3932 int bottom_margin;
3933
0c7da84e
RS
3934 /* If we scrolled backward, put point near the end of the window
3935 but not within the scroll margin. */
b73ea88e 3936 SET_PT_BOTH (pos, pos_byte);
0c7da84e 3937 tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
101d1605
RS
3938 if (XFASTINT (tem) == ht - this_scroll_margin)
3939 bottom_margin = PT;
3940 else
3941 bottom_margin = PT + 1;
3942
3943 if (bottom_margin > opoint)
b73ea88e 3944 SET_PT_BOTH (opoint, opoint_byte);
7ab12479 3945 else
101d1605 3946 {
5500c422 3947 if (!NILP (Vscroll_preserve_screen_position))
9317a85d 3948 {
b73ea88e 3949 SET_PT_BOTH (pos, pos_byte);
9317a85d
RS
3950 Fvertical_motion (make_number (original_vpos), window);
3951 }
3952 else
3953 Fvertical_motion (make_number (-1), window);
101d1605 3954 }
7ab12479
JB
3955 }
3956 }
3957 else
f8026fd8
JB
3958 {
3959 if (noerror)
3960 return;
3961 else
3962 Fsignal (Qend_of_buffer, Qnil);
3963 }
7ab12479 3964}
5500c422
GM
3965
3966
3967/* Scroll selected_window up or down. If N is nil, scroll a
3968 screen-full which is defined as the height of the window minus
3969 next_screen_context_lines. If N is the symbol `-', scroll.
3970 DIRECTION may be 1 meaning to scroll down, or -1 meaning to scroll
3971 up. This is the guts of Fscroll_up and Fscroll_down. */
7ab12479
JB
3972
3973static void
3974scroll_command (n, direction)
5500c422 3975 Lisp_Object n;
7ab12479
JB
3976 int direction;
3977{
3978 register int defalt;
3979 int count = specpdl_ptr - specpdl;
3980
5500c422
GM
3981 xassert (abs (direction) == 1);
3982
3983 /* If selected window's buffer isn't current, make it current for
3984 the moment. But don't screw up if window_scroll gets an error. */
7ab12479 3985 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
95605e15
JB
3986 {
3987 record_unwind_protect (save_excursion_restore, save_excursion_save ());
3988 Fset_buffer (XWINDOW (selected_window)->buffer);
5500c422
GM
3989
3990 /* Make redisplay consider other windows than just selected_window. */
3991 ++windows_or_buffers_changed;
95605e15 3992 }
7ab12479
JB
3993
3994 defalt = (window_internal_height (XWINDOW (selected_window))
3995 - next_screen_context_lines);
3996 defalt = direction * (defalt < 1 ? 1 : defalt);
3997
265a9e55 3998 if (NILP (n))
101d1605 3999 window_scroll (selected_window, defalt, 1, 0);
7ab12479 4000 else if (EQ (n, Qminus))
101d1605 4001 window_scroll (selected_window, - defalt, 1, 0);
7ab12479
JB
4002 else
4003 {
4004 n = Fprefix_numeric_value (n);
101d1605 4005 window_scroll (selected_window, XINT (n) * direction, 0, 0);
7ab12479 4006 }
95605e15
JB
4007
4008 unbind_to (count, Qnil);
7ab12479
JB
4009}
4010
4011DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
4012 "Scroll text of current window upward ARG lines; or near full screen if no ARG.\n\
4013A near full screen is `next-screen-context-lines' less than a full screen.\n\
279e0e0c 4014Negative ARG means scroll downward.\n\
dd394ff9
KH
4015If ARG is the atom `-', scroll downward by nearly full screen.\n\
4016When calling from a program, supply as argument a number, nil, or `-'.")
413430c5
EN
4017 (arg)
4018 Lisp_Object arg;
7ab12479 4019{
413430c5 4020 scroll_command (arg, 1);
7ab12479
JB
4021 return Qnil;
4022}
4023
4024DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
a5fcbc4e 4025 "Scroll text of current window down ARG lines; or near full screen if no ARG.\n\
7ab12479 4026A near full screen is `next-screen-context-lines' less than a full screen.\n\
279e0e0c 4027Negative ARG means scroll upward.\n\
dd394ff9
KH
4028If ARG is the atom `-', scroll upward by nearly full screen.\n\
4029When calling from a program, supply as argument a number, nil, or `-'.")
413430c5
EN
4030 (arg)
4031 Lisp_Object arg;
7ab12479 4032{
413430c5 4033 scroll_command (arg, -1);
7ab12479
JB
4034 return Qnil;
4035}
ccd0664b
RS
4036\f
4037DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0,
4038 "Return the other window for \"other window scroll\" commands.\n\
77b24de6 4039If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
ccd0664b
RS
4040specifies the window.\n\
4041If `other-window-scroll-buffer' is non-nil, a window\n\
4042showing that buffer is used.")
eb16ec06 4043 ()
7ab12479 4044{
ccd0664b 4045 Lisp_Object window;
7ab12479
JB
4046
4047 if (MINI_WINDOW_P (XWINDOW (selected_window))
265a9e55 4048 && !NILP (Vminibuf_scroll_window))
7ab12479
JB
4049 window = Vminibuf_scroll_window;
4050 /* If buffer is specified, scroll that buffer. */
265a9e55 4051 else if (!NILP (Vother_window_scroll_buffer))
7ab12479
JB
4052 {
4053 window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
265a9e55 4054 if (NILP (window))
53f76081 4055 window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt, Qnil);
7ab12479
JB
4056 }
4057 else
dbc4e1c1
JB
4058 {
4059 /* Nothing specified; look for a neighboring window on the same
4060 frame. */
4061 window = Fnext_window (selected_window, Qnil, Qnil);
4062
4063 if (EQ (window, selected_window))
4064 /* That didn't get us anywhere; look for a window on another
4065 visible frame. */
4066 do
4067 window = Fnext_window (window, Qnil, Qt);
4068 while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
4069 && ! EQ (window, selected_window));
4070 }
4071
605be8af 4072 CHECK_LIVE_WINDOW (window, 0);
7ab12479
JB
4073
4074 if (EQ (window, selected_window))
4075 error ("There is no other window");
4076
ccd0664b
RS
4077 return window;
4078}
4079
4080DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
4081 "Scroll next window upward ARG lines; or near full screen if no ARG.\n\
dd394ff9 4082A near full screen is `next-screen-context-lines' less than a full screen.\n\
ccd0664b
RS
4083The next window is the one below the current one; or the one at the top\n\
4084if the current one is at the bottom. Negative ARG means scroll downward.\n\
dd394ff9
KH
4085If ARG is the atom `-', scroll downward by nearly full screen.\n\
4086When calling from a program, supply as argument a number, nil, or `-'.\n\
ccd0664b
RS
4087\n\
4088If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
4089specifies the window to scroll.\n\
4090If `other-window-scroll-buffer' is non-nil, scroll the window\n\
4091showing that buffer, popping the buffer up if necessary.")
413430c5
EN
4092 (arg)
4093 register Lisp_Object arg;
ccd0664b
RS
4094{
4095 register Lisp_Object window;
2f787aa3 4096 register int defalt;
ccd0664b
RS
4097 register struct window *w;
4098 register int count = specpdl_ptr - specpdl;
4099
4100 window = Fother_window_for_scrolling ();
4101
7ab12479 4102 w = XWINDOW (window);
2f787aa3
KH
4103 defalt = window_internal_height (w) - next_screen_context_lines;
4104 if (defalt < 1) defalt = 1;
7ab12479
JB
4105
4106 /* Don't screw up if window_scroll gets an error. */
4107 record_unwind_protect (save_excursion_restore, save_excursion_save ());
5500c422 4108 ++windows_or_buffers_changed;
7ab12479
JB
4109
4110 Fset_buffer (w->buffer);
4111 SET_PT (marker_position (w->pointm));
4112
413430c5 4113 if (NILP (arg))
101d1605 4114 window_scroll (window, defalt, 1, 1);
413430c5 4115 else if (EQ (arg, Qminus))
101d1605 4116 window_scroll (window, -defalt, 1, 1);
7ab12479
JB
4117 else
4118 {
413430c5
EN
4119 if (CONSP (arg))
4120 arg = Fcar (arg);
4121 CHECK_NUMBER (arg, 0);
101d1605 4122 window_scroll (window, XINT (arg), 0, 1);
7ab12479
JB
4123 }
4124
b73ea88e 4125 set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
f4e7b2c2 4126 unbind_to (count, Qnil);
7ab12479
JB
4127
4128 return Qnil;
4129}
4130\f
644b477c 4131DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 1, "P",
7ab12479
JB
4132 "Scroll selected window display ARG columns left.\n\
4133Default for ARG is window width minus 2.")
4134 (arg)
4135 register Lisp_Object arg;
4136{
4137
265a9e55 4138 if (NILP (arg))
d834a2e9 4139 XSETFASTINT (arg, window_internal_width (XWINDOW (selected_window)) - 2);
7ab12479
JB
4140 else
4141 arg = Fprefix_numeric_value (arg);
4142
4143 return
4144 Fset_window_hscroll (selected_window,
4145 make_number (XINT (XWINDOW (selected_window)->hscroll)
4146 + XINT (arg)));
4147}
4148
644b477c 4149DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 1, "P",
7ab12479
JB
4150 "Scroll selected window display ARG columns right.\n\
4151Default for ARG is window width minus 2.")
4152 (arg)
4153 register Lisp_Object arg;
4154{
265a9e55 4155 if (NILP (arg))
d834a2e9 4156 XSETFASTINT (arg, window_internal_width (XWINDOW (selected_window)) - 2);
7ab12479
JB
4157 else
4158 arg = Fprefix_numeric_value (arg);
4159
4160 return
4161 Fset_window_hscroll (selected_window,
4162 make_number (XINT (XWINDOW (selected_window)->hscroll)
4163 - XINT (arg)));
4164}
4165
4166DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
44fa5b1e 4167 "Center point in window and redisplay frame. With ARG, put point on line ARG.\n\
7ab12479 4168The desired position of point is always relative to the current window.\n\
44fa5b1e 4169Just C-u as prefix means put point in the center of the window.\n\
413430c5 4170If ARG is omitted or nil, erases the entire frame and then\n\
44fa5b1e 4171redraws with point in the center of the current window.")
413430c5
EN
4172 (arg)
4173 register Lisp_Object arg;
7ab12479
JB
4174{
4175 register struct window *w = XWINDOW (selected_window);
4176 register int ht = window_internal_height (w);
113d9015 4177 struct position pos;
478292ed
RS
4178 struct buffer *buf = XBUFFER (w->buffer);
4179 struct buffer *obuf = current_buffer;
7ab12479 4180
413430c5 4181 if (NILP (arg))
7ab12479 4182 {
44fa5b1e 4183 extern int frame_garbaged;
f02d6d5c
KH
4184 int i;
4185
4186 /* Invalidate pixel data calculated for all compositions. */
4187 for (i = 0; i < n_compositions; i++)
4188 composition_table[i]->font = NULL;
7ab12479 4189
527b6458 4190 Fredraw_frame (w->frame);
44fa5b1e 4191 SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
413430c5 4192 XSETFASTINT (arg, ht / 2);
7ab12479 4193 }
413430c5 4194 else if (CONSP (arg)) /* Just C-u. */
7ab12479 4195 {
413430c5 4196 XSETFASTINT (arg, ht / 2);
7ab12479
JB
4197 }
4198 else
4199 {
413430c5
EN
4200 arg = Fprefix_numeric_value (arg);
4201 CHECK_NUMBER (arg, 0);
7ab12479
JB
4202 }
4203
413430c5
EN
4204 if (XINT (arg) < 0)
4205 XSETINT (arg, XINT (arg) + ht);
7ab12479 4206
478292ed 4207 set_buffer_internal (buf);
6ec8bbd2 4208 pos = *vmotion (PT, - XINT (arg), w);
7ab12479 4209
b73ea88e
RS
4210 set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
4211 w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
4212 || FETCH_BYTE (pos.bytepos - 1) == '\n')
113d9015 4213 ? Qt : Qnil);
7ab12479 4214 w->force_start = Qt;
478292ed 4215 set_buffer_internal (obuf);
7ab12479
JB
4216
4217 return Qnil;
4218}
b7617575
GM
4219
4220
4221/* Value is the number of lines actually displayed in window W,
4222 as opposed to its height. */
4223
4224static int
4225displayed_window_lines (w)
4226 struct window *w;
4227{
4228 struct it it;
4229 struct text_pos start;
4230
4231 SET_TEXT_POS_FROM_MARKER (start, w->start);
4232 start_display (&it, w, start);
4233 move_it_vertically (&it, window_box_height (w));
4234 return it.vpos;
4235}
4236
4237
7ab12479
JB
4238\f
4239DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
4240 1, 1, "P",
4241 "Position point relative to window.\n\
19e3bf0a 4242With no argument, position point at center of window.\n\
d81724c7
RS
4243An argument specifies vertical position within the window;\n\
4244zero means top of window, negative means relative to bottom of window.")
7ab12479 4245 (arg)
b7617575 4246 Lisp_Object arg;
7ab12479 4247{
b7617575
GM
4248 struct window *w = XWINDOW (selected_window);
4249 int lines, start;
540b6aa0 4250 Lisp_Object window;
7ab12479 4251
b7617575 4252 window = selected_window;
7ab12479
JB
4253 start = marker_position (w->start);
4254 if (start < BEGV || start > ZV)
4255 {
b7617575 4256 int height = window_internal_height (w);
cd2be1dd 4257 Fvertical_motion (make_number (- (height / 2)), window);
b73ea88e 4258 set_marker_both (w->start, w->buffer, PT, PT_BYTE);
7ab12479
JB
4259 w->start_at_line_beg = Fbolp ();
4260 w->force_start = Qt;
4261 }
4262 else
b73ea88e 4263 Fgoto_char (w->start);
7ab12479 4264
b7617575
GM
4265 lines = displayed_window_lines (w);
4266 if (NILP (arg))
4267 XSETFASTINT (arg, lines / 2);
4268 else
4269 {
4270 arg = Fprefix_numeric_value (arg);
4271 if (XINT (arg) < 0)
4272 XSETINT (arg, XINT (arg) + lines);
4273 }
4274
540b6aa0 4275 return Fvertical_motion (arg, window);
7ab12479 4276}
5500c422
GM
4277
4278
7ab12479 4279\f
5500c422
GM
4280/***********************************************************************
4281 Window Configuration
4282 ***********************************************************************/
4283
7ab12479
JB
4284struct save_window_data
4285 {
f5ccc0cc 4286 EMACS_INT size_from_Lisp_Vector_struct;
7ab12479 4287 struct Lisp_Vector *next_from_Lisp_Vector_struct;
8f6ea2e9 4288 Lisp_Object frame_width, frame_height, frame_menu_bar_lines;
9ea173e8 4289 Lisp_Object frame_tool_bar_lines;
bdc727bf 4290 Lisp_Object selected_frame;
7ab12479
JB
4291 Lisp_Object current_window;
4292 Lisp_Object current_buffer;
4293 Lisp_Object minibuf_scroll_window;
4294 Lisp_Object root_window;
bdc727bf 4295 Lisp_Object focus_frame;
756b6edc
RS
4296 /* Record the values of window-min-width and window-min-height
4297 so that window sizes remain consistent with them. */
4298 Lisp_Object min_width, min_height;
cbff28e8
RS
4299 /* A vector, each of whose elements is a struct saved_window
4300 for one window. */
7ab12479
JB
4301 Lisp_Object saved_windows;
4302 };
ff06df24 4303
cbff28e8 4304/* This is saved as a Lisp_Vector */
7ab12479
JB
4305struct saved_window
4306 {
4307 /* these first two must agree with struct Lisp_Vector in lisp.h */
f5ccc0cc 4308 EMACS_INT size_from_Lisp_Vector_struct;
7ab12479
JB
4309 struct Lisp_Vector *next_from_Lisp_Vector_struct;
4310
4311 Lisp_Object window;
4312 Lisp_Object buffer, start, pointm, mark;
4313 Lisp_Object left, top, width, height, hscroll;
4314 Lisp_Object parent, prev;
4315 Lisp_Object start_at_line_beg;
4316 Lisp_Object display_table;
4317 };
4318#define SAVED_WINDOW_VECTOR_SIZE 14 /* Arg to Fmake_vector */
4319
4320#define SAVED_WINDOW_N(swv,n) \
4321 ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
4322
4323DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
cbff28e8 4324 "Return t if OBJECT is a window-configuration object.")
413430c5
EN
4325 (object)
4326 Lisp_Object object;
7ab12479 4327{
413430c5 4328 if (WINDOW_CONFIGURATIONP (object))
7ab12479
JB
4329 return Qt;
4330 return Qnil;
4331}
4332
3f8ab7bd
RS
4333DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
4334 "Return the frame that CONFIG, a window-configuration object, is about.")
4335 (config)
4336 Lisp_Object config;
4337{
4338 register struct save_window_data *data;
4339 struct Lisp_Vector *saved_windows;
4340
4341 if (! WINDOW_CONFIGURATIONP (config))
4342 wrong_type_argument (Qwindow_configuration_p, config);
4343
4344 data = (struct save_window_data *) XVECTOR (config);
4345 saved_windows = XVECTOR (data->saved_windows);
4346 return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
4347}
4348
d5b2799e
RS
4349DEFUN ("set-window-configuration", Fset_window_configuration,
4350 Sset_window_configuration, 1, 1, 0,
7ab12479
JB
4351 "Set the configuration of windows and buffers as specified by CONFIGURATION.\n\
4352CONFIGURATION must be a value previously returned\n\
3f8ab7bd
RS
4353by `current-window-configuration' (which see).\n\
4354If CONFIGURATION was made from a frame that is now deleted,\n\
4355only frame-independent values can be restored. In this case,\n\
4356the return value is nil. Otherwise the value is t.")
4357 (configuration)
2f83aebe 4358 Lisp_Object configuration;
7ab12479 4359{
7ab12479
JB
4360 register struct save_window_data *data;
4361 struct Lisp_Vector *saved_windows;
7ab12479 4362 Lisp_Object new_current_buffer;
fd482be5 4363 Lisp_Object frame;
44fa5b1e 4364 FRAME_PTR f;
d2b35234 4365 int old_point = -1;
7ab12479 4366
017b2bad 4367 while (!WINDOW_CONFIGURATIONP (configuration))
3f8ab7bd 4368 wrong_type_argument (Qwindow_configuration_p, configuration);
7ab12479 4369
2f83aebe 4370 data = (struct save_window_data *) XVECTOR (configuration);
7ab12479
JB
4371 saved_windows = XVECTOR (data->saved_windows);
4372
7ab12479 4373 new_current_buffer = data->current_buffer;
265a9e55 4374 if (NILP (XBUFFER (new_current_buffer)->name))
7ab12479 4375 new_current_buffer = Qnil;
d2b35234
RS
4376 else
4377 {
4378 if (XBUFFER (new_current_buffer) == current_buffer)
4379 old_point = PT;
cbff28e8 4380
d2b35234 4381 }
7ab12479 4382
fd482be5
JB
4383 frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
4384 f = XFRAME (frame);
9ace597f 4385
fd482be5
JB
4386 /* If f is a dead frame, don't bother rebuilding its window tree.
4387 However, there is other stuff we should still try to do below. */
4388 if (FRAME_LIVE_P (f))
7ab12479 4389 {
fd482be5
JB
4390 register struct window *w;
4391 register struct saved_window *p;
5500c422
GM
4392 struct window *root_window;
4393 struct window **leaf_windows;
4394 int n_leaf_windows;
4395 int k, i;
fd482be5
JB
4396
4397 /* If the frame has been resized since this window configuration was
4398 made, we change the frame to the size specified in the
4399 configuration, restore the configuration, and then resize it
4400 back. We keep track of the prevailing height in these variables. */
4401 int previous_frame_height = FRAME_HEIGHT (f);
4402 int previous_frame_width = FRAME_WIDTH (f);
8f6ea2e9 4403 int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
9ea173e8 4404 int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
fd482be5 4405
d2b35234
RS
4406 /* The mouse highlighting code could get screwed up
4407 if it runs during this. */
4408 BLOCK_INPUT;
4409
fd482be5
JB
4410 if (XFASTINT (data->frame_height) != previous_frame_height
4411 || XFASTINT (data->frame_width) != previous_frame_width)
f8ad443a 4412 change_frame_size (f, XFASTINT (data->frame_height),
2b653806 4413 XFASTINT (data->frame_width), 0, 0, 0);
e3678b64 4414#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
8f6ea2e9
KH
4415 if (XFASTINT (data->frame_menu_bar_lines)
4416 != previous_frame_menu_bar_lines)
f8ad443a 4417 x_set_menu_bar_lines (f, data->frame_menu_bar_lines, make_number (0));
4314246f 4418#ifdef HAVE_WINDOW_SYSTEM
9ea173e8
GM
4419 if (XFASTINT (data->frame_tool_bar_lines)
4420 != previous_frame_tool_bar_lines)
4421 x_set_tool_bar_lines (f, data->frame_tool_bar_lines, make_number (0));
4314246f 4422#endif
217f2871 4423#endif
fd482be5 4424
719eaeb1
GM
4425 /* "Swap out" point from the selected window
4426 into its buffer. We do this now, before
4427 restoring the window contents, and prevent it from
4428 being done later on when we select a new window. */
596ae0cf
RS
4429 if (! NILP (XWINDOW (selected_window)->buffer))
4430 {
4431 w = XWINDOW (selected_window);
4432 set_marker_both (w->pointm,
4433 w->buffer,
4434 BUF_PT (XBUFFER (w->buffer)),
4435 BUF_PT_BYTE (XBUFFER (w->buffer)));
4436 }
4437
fd482be5 4438 windows_or_buffers_changed++;
29aeee73 4439 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
fd482be5 4440
5500c422
GM
4441 /* Problem: Freeing all matrices and later allocating them again
4442 is a serious redisplay flickering problem. What we would
4443 really like to do is to free only those matrices not reused
4444 below. */
4445 root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
4446 leaf_windows
4447 = (struct window **) alloca (count_windows (root_window)
4448 * sizeof (struct window *));
4449 n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
4450
756b6edc
RS
4451 /* Temporarily avoid any problems with windows that are smaller
4452 than they are supposed to be. */
4453 window_min_height = 1;
4454 window_min_width = 1;
4455
fd482be5
JB
4456 /* Kludge Alert!
4457 Mark all windows now on frame as "deleted".
4458 Restoring the new configuration "undeletes" any that are in it.
37962e60 4459
fd482be5
JB
4460 Save their current buffers in their height fields, since we may
4461 need it later, if a buffer saved in the configuration is now
4462 dead. */
4463 delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
4464
4465 for (k = 0; k < saved_windows->size; k++)
4466 {
4467 p = SAVED_WINDOW_N (saved_windows, k);
4468 w = XWINDOW (p->window);
4469 w->next = Qnil;
7ab12479 4470
fd482be5
JB
4471 if (!NILP (p->parent))
4472 w->parent = SAVED_WINDOW_N (saved_windows,
4473 XFASTINT (p->parent))->window;
4474 else
4475 w->parent = Qnil;
7ab12479 4476
fd482be5 4477 if (!NILP (p->prev))
7ab12479 4478 {
fd482be5
JB
4479 w->prev = SAVED_WINDOW_N (saved_windows,
4480 XFASTINT (p->prev))->window;
4481 XWINDOW (w->prev)->next = p->window;
4482 }
4483 else
4484 {
4485 w->prev = Qnil;
4486 if (!NILP (w->parent))
4487 {
4488 if (EQ (p->width, XWINDOW (w->parent)->width))
4489 {
4490 XWINDOW (w->parent)->vchild = p->window;
4491 XWINDOW (w->parent)->hchild = Qnil;
4492 }
4493 else
4494 {
4495 XWINDOW (w->parent)->hchild = p->window;
4496 XWINDOW (w->parent)->vchild = Qnil;
4497 }
4498 }
4499 }
4500
4501 /* If we squirreled away the buffer in the window's height,
4502 restore it now. */
017b2bad 4503 if (BUFFERP (w->height))
fd482be5
JB
4504 w->buffer = w->height;
4505 w->left = p->left;
4506 w->top = p->top;
4507 w->width = p->width;
4508 w->height = p->height;
4509 w->hscroll = p->hscroll;
4510 w->display_table = p->display_table;
d834a2e9 4511 XSETFASTINT (w->last_modified, 0);
3cd21523 4512 XSETFASTINT (w->last_overlay_modified, 0);
fd482be5
JB
4513
4514 /* Reinstall the saved buffer and pointers into it. */
4515 if (NILP (p->buffer))
4516 w->buffer = p->buffer;
4517 else
4518 {
4519 if (!NILP (XBUFFER (p->buffer)->name))
4520 /* If saved buffer is alive, install it. */
4521 {
4522 w->buffer = p->buffer;
4523 w->start_at_line_beg = p->start_at_line_beg;
b73ea88e
RS
4524 set_marker_restricted (w->start, p->start, w->buffer);
4525 set_marker_restricted (w->pointm, p->pointm, w->buffer);
fd482be5 4526 Fset_marker (XBUFFER (w->buffer)->mark,
b73ea88e 4527 p->mark, w->buffer);
fd482be5
JB
4528
4529 /* As documented in Fcurrent_window_configuration, don't
4530 save the location of point in the buffer which was current
4531 when the window configuration was recorded. */
6b54027b
RS
4532 if (!EQ (p->buffer, new_current_buffer)
4533 && XBUFFER (p->buffer) == current_buffer)
fd482be5
JB
4534 Fgoto_char (w->pointm);
4535 }
52a68e98
RS
4536 else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
4537 /* Else unless window has a live buffer, get one. */
7ab12479 4538 {
fd482be5
JB
4539 w->buffer = Fcdr (Fcar (Vbuffer_alist));
4540 /* This will set the markers to beginning of visible
4541 range. */
4542 set_marker_restricted (w->start, make_number (0), w->buffer);
4543 set_marker_restricted (w->pointm, make_number (0),w->buffer);
4544 w->start_at_line_beg = Qt;
7ab12479
JB
4545 }
4546 else
fd482be5 4547 /* Keeping window's old buffer; make sure the markers
52a68e98 4548 are real. */
7ab12479 4549 {
fd482be5
JB
4550 /* Set window markers at start of visible range. */
4551 if (XMARKER (w->start)->buffer == 0)
4552 set_marker_restricted (w->start, make_number (0),
4553 w->buffer);
4554 if (XMARKER (w->pointm)->buffer == 0)
b73ea88e
RS
4555 set_marker_restricted_both (w->pointm, w->buffer,
4556 BUF_PT (XBUFFER (w->buffer)),
4557 BUF_PT_BYTE (XBUFFER (w->buffer)));
fd482be5 4558 w->start_at_line_beg = Qt;
7ab12479
JB
4559 }
4560 }
4561 }
9ace597f 4562
fd482be5 4563 FRAME_ROOT_WINDOW (f) = data->root_window;
719eaeb1
GM
4564 /* Prevent "swapping out point" in the old selected window
4565 using the buffer that has been restored into it.
4566 That swapping out has already been done,
4567 near the beginning of this function. */
4568 selected_window = Qnil;
fd482be5 4569 Fselect_window (data->current_window);
396a830c
RS
4570 XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
4571 = selected_window;
7ab12479 4572
db269683 4573 if (NILP (data->focus_frame)
017b2bad 4574 || (FRAMEP (data->focus_frame)
db269683
JB
4575 && FRAME_LIVE_P (XFRAME (data->focus_frame))))
4576 Fredirect_frame_focus (frame, data->focus_frame);
7ab12479 4577
fd482be5
JB
4578#if 0 /* I don't understand why this is needed, and it causes problems
4579 when the frame's old selected window has been deleted. */
e4e59717 4580 if (f != selected_frame && FRAME_WINDOW_P (f))
9a7c6fc3
RS
4581 do_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)),
4582 Qnil, 0);
fd482be5
JB
4583#endif
4584
4585 /* Set the screen height to the value it had before this function. */
4586 if (previous_frame_height != FRAME_HEIGHT (f)
4587 || previous_frame_width != FRAME_WIDTH (f))
4588 change_frame_size (f, previous_frame_height, previous_frame_width,
2b653806 4589 0, 0, 0);
e3678b64 4590#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
8f6ea2e9 4591 if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
f8ad443a
AS
4592 x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
4593 make_number (0));
4314246f 4594#ifdef HAVE_WINDOW_SYSTEM
9ea173e8
GM
4595 if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
4596 x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
4597 make_number (0));
4314246f 4598#endif
217f2871 4599#endif
d2b35234 4600
5500c422
GM
4601 /* Now, free glyph matrices in windows that were not reused. */
4602 for (i = 0; i < n_leaf_windows; ++i)
4603 if (NILP (leaf_windows[i]->buffer))
4604 {
4605 /* Assert it's not reused as a combination. */
4606 xassert (NILP (leaf_windows[i]->hchild)
4607 && NILP (leaf_windows[i]->vchild));
4608 free_window_matrices (leaf_windows[i]);
4609 SET_FRAME_GARBAGED (f);
4610 }
4611
4612 adjust_glyphs (f);
4613
d2b35234 4614 UNBLOCK_INPUT;
756b6edc 4615
478292ed
RS
4616 /* Fselect_window will have made f the selected frame, so we
4617 reselect the proper frame here. Fhandle_switch_frame will change the
4618 selected window too, but that doesn't make the call to
4619 Fselect_window above totally superfluous; it still sets f's
4620 selected window. */
4621 if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
4622 do_switch_frame (data->selected_frame, Qnil, 0);
4623
4624 if (! NILP (Vwindow_configuration_change_hook)
4625 && ! NILP (Vrun_hooks))
4626 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
4627 }
bdc727bf
JB
4628
4629 if (!NILP (new_current_buffer))
d2b35234
RS
4630 {
4631 Fset_buffer (new_current_buffer);
4632
4633 /* If the buffer that is current now is the same
4634 that was current before setting the window configuration,
4635 don't alter its PT. */
4636 if (old_point >= 0)
4637 SET_PT (old_point);
4638 }
bdc727bf 4639
478292ed
RS
4640 /* Restore the minimum heights recorded in the configuration. */
4641 window_min_height = XINT (data->min_height);
4642 window_min_width = XINT (data->min_width);
543f5fb1 4643
478292ed 4644 Vminibuf_scroll_window = data->minibuf_scroll_window;
543f5fb1 4645
3f8ab7bd 4646 return (FRAME_LIVE_P (f) ? Qt : Qnil);
7ab12479
JB
4647}
4648
44fa5b1e 4649/* Mark all windows now on frame as deleted
7ab12479
JB
4650 by setting their buffers to nil. */
4651
fd482be5 4652void
7ab12479
JB
4653delete_all_subwindows (w)
4654 register struct window *w;
4655{
265a9e55 4656 if (!NILP (w->next))
7ab12479 4657 delete_all_subwindows (XWINDOW (w->next));
265a9e55 4658 if (!NILP (w->vchild))
7ab12479 4659 delete_all_subwindows (XWINDOW (w->vchild));
265a9e55 4660 if (!NILP (w->hchild))
7ab12479 4661 delete_all_subwindows (XWINDOW (w->hchild));
605be8af
JB
4662
4663 w->height = w->buffer; /* See Fset_window_configuration for excuse. */
4664
86e48436
RS
4665 if (!NILP (w->buffer))
4666 unshow_buffer (w);
4667
605be8af
JB
4668 /* We set all three of these fields to nil, to make sure that we can
4669 distinguish this dead window from any live window. Live leaf
4670 windows will have buffer set, and combination windows will have
4671 vchild or hchild set. */
4672 w->buffer = Qnil;
4673 w->vchild = Qnil;
4674 w->hchild = Qnil;
7ab12479
JB
4675}
4676\f
4677static int
4678count_windows (window)
4679 register struct window *window;
4680{
4681 register int count = 1;
265a9e55 4682 if (!NILP (window->next))
7ab12479 4683 count += count_windows (XWINDOW (window->next));
265a9e55 4684 if (!NILP (window->vchild))
7ab12479 4685 count += count_windows (XWINDOW (window->vchild));
265a9e55 4686 if (!NILP (window->hchild))
7ab12479
JB
4687 count += count_windows (XWINDOW (window->hchild));
4688 return count;
4689}
4690
5500c422
GM
4691
4692/* Fill vector FLAT with leaf windows under W, starting at index I.
4693 Value is last index + 1. */
4694
4695static int
4696get_leaf_windows (w, flat, i)
4697 struct window *w;
4698 struct window **flat;
4699 int i;
4700{
4701 while (w)
4702 {
4703 if (!NILP (w->hchild))
4704 i = get_leaf_windows (XWINDOW (w->hchild), flat, i);
4705 else if (!NILP (w->vchild))
4706 i = get_leaf_windows (XWINDOW (w->vchild), flat, i);
4707 else
4708 flat[i++] = w;
4709
4710 w = NILP (w->next) ? 0 : XWINDOW (w->next);
4711 }
4712
4713 return i;
4714}
4715
4716
4717/* Return a pointer to the glyph W's physical cursor is on. Value is
4718 null if W's current matrix is invalid, so that no meaningfull glyph
4719 can be returned. */
4720
4721struct glyph *
4722get_phys_cursor_glyph (w)
4723 struct window *w;
4724{
4725 struct glyph_row *row;
4726 struct glyph *glyph;
4727
4728 if (w->phys_cursor.vpos >= 0
4729 && w->phys_cursor.vpos < w->current_matrix->nrows
4730 && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
4731 row->enabled_p)
4732 && row->used[TEXT_AREA] > w->phys_cursor.hpos)
4733 glyph = row->glyphs[TEXT_AREA] + w->phys_cursor.hpos;
4734 else
4735 glyph = NULL;
4736
4737 return glyph;
4738}
4739
4740
7ab12479
JB
4741static int
4742save_window_save (window, vector, i)
4743 Lisp_Object window;
4744 struct Lisp_Vector *vector;
4745 int i;
4746{
4747 register struct saved_window *p;
4748 register struct window *w;
4749 register Lisp_Object tem;
4750
265a9e55 4751 for (;!NILP (window); window = w->next)
7ab12479
JB
4752 {
4753 p = SAVED_WINDOW_N (vector, i);
4754 w = XWINDOW (window);
4755
d834a2e9 4756 XSETFASTINT (w->temslot, i++);
7ab12479
JB
4757 p->window = window;
4758 p->buffer = w->buffer;
4759 p->left = w->left;
4760 p->top = w->top;
4761 p->width = w->width;
4762 p->height = w->height;
4763 p->hscroll = w->hscroll;
4764 p->display_table = w->display_table;
265a9e55 4765 if (!NILP (w->buffer))
7ab12479
JB
4766 {
4767 /* Save w's value of point in the window configuration.
4768 If w is the selected window, then get the value of point
4769 from the buffer; pointm is garbage in the selected window. */
4770 if (EQ (window, selected_window))
4771 {
4772 p->pointm = Fmake_marker ();
b73ea88e
RS
4773 set_marker_both (p->pointm, w->buffer,
4774 BUF_PT (XBUFFER (w->buffer)),
4775 BUF_PT_BYTE (XBUFFER (w->buffer)));
7ab12479
JB
4776 }
4777 else
eeb82665 4778 p->pointm = Fcopy_marker (w->pointm, Qnil);
7ab12479 4779
eeb82665 4780 p->start = Fcopy_marker (w->start, Qnil);
7ab12479
JB
4781 p->start_at_line_beg = w->start_at_line_beg;
4782
4783 tem = XBUFFER (w->buffer)->mark;
eeb82665 4784 p->mark = Fcopy_marker (tem, Qnil);
7ab12479
JB
4785 }
4786 else
4787 {
4788 p->pointm = Qnil;
4789 p->start = Qnil;
4790 p->mark = Qnil;
4791 p->start_at_line_beg = Qnil;
4792 }
4793
265a9e55 4794 if (NILP (w->parent))
7ab12479
JB
4795 p->parent = Qnil;
4796 else
4797 p->parent = XWINDOW (w->parent)->temslot;
4798
265a9e55 4799 if (NILP (w->prev))
7ab12479
JB
4800 p->prev = Qnil;
4801 else
4802 p->prev = XWINDOW (w->prev)->temslot;
4803
265a9e55 4804 if (!NILP (w->vchild))
7ab12479 4805 i = save_window_save (w->vchild, vector, i);
265a9e55 4806 if (!NILP (w->hchild))
7ab12479
JB
4807 i = save_window_save (w->hchild, vector, i);
4808 }
4809
4810 return i;
4811}
4812
a0d76c27
EN
4813DEFUN ("current-window-configuration", Fcurrent_window_configuration,
4814 Scurrent_window_configuration, 0, 1, 0,
44fa5b1e
JB
4815 "Return an object representing the current window configuration of FRAME.\n\
4816If FRAME is nil or omitted, use the selected frame.\n\
7ab12479
JB
4817This describes the number of windows, their sizes and current buffers,\n\
4818and for each displayed buffer, where display starts, and the positions of\n\
4819point and mark. An exception is made for point in the current buffer:\n\
bdc727bf
JB
4820its value is -not- saved.\n\
4821This also records the currently selected frame, and FRAME's focus\n\
4822redirection (see `redirect-frame-focus').")
44fa5b1e
JB
4823 (frame)
4824 Lisp_Object frame;
7ab12479
JB
4825{
4826 register Lisp_Object tem;
4827 register int n_windows;
4828 register struct save_window_data *data;
da2792e0 4829 register struct Lisp_Vector *vec;
7ab12479 4830 register int i;
44fa5b1e 4831 FRAME_PTR f;
43bad991 4832
44fa5b1e 4833 if (NILP (frame))
1ae1a37d
GM
4834 frame = selected_frame;
4835 CHECK_LIVE_FRAME (frame, 0);
4836 f = XFRAME (frame);
7ab12479 4837
44fa5b1e 4838 n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
da2792e0
KH
4839 vec = allocate_vectorlike (VECSIZE (struct save_window_data));
4840 for (i = 0; i < VECSIZE (struct save_window_data); i++)
4841 vec->contents[i] = Qnil;
4842 vec->size = VECSIZE (struct save_window_data);
4843 data = (struct save_window_data *)vec;
4844
d834a2e9
KH
4845 XSETFASTINT (data->frame_width, FRAME_WIDTH (f));
4846 XSETFASTINT (data->frame_height, FRAME_HEIGHT (f));
4847 XSETFASTINT (data->frame_menu_bar_lines, FRAME_MENU_BAR_LINES (f));
9ea173e8 4848 XSETFASTINT (data->frame_tool_bar_lines, FRAME_TOOL_BAR_LINES (f));
1ae1a37d 4849 data->selected_frame = selected_frame;
44fa5b1e 4850 data->current_window = FRAME_SELECTED_WINDOW (f);
74112613 4851 XSETBUFFER (data->current_buffer, current_buffer);
7ab12479 4852 data->minibuf_scroll_window = Vminibuf_scroll_window;
44fa5b1e 4853 data->root_window = FRAME_ROOT_WINDOW (f);
bdc727bf 4854 data->focus_frame = FRAME_FOCUS_FRAME (f);
74112613
KH
4855 XSETINT (data->min_height, window_min_height);
4856 XSETINT (data->min_width, window_min_width);
7ab12479
JB
4857 tem = Fmake_vector (make_number (n_windows), Qnil);
4858 data->saved_windows = tem;
4859 for (i = 0; i < n_windows; i++)
4860 XVECTOR (tem)->contents[i]
4861 = Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil);
44fa5b1e 4862 save_window_save (FRAME_ROOT_WINDOW (f),
7ab12479 4863 XVECTOR (tem), 0);
74112613 4864 XSETWINDOW_CONFIGURATION (tem, data);
7ab12479
JB
4865 return (tem);
4866}
4867
4868DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
4869 0, UNEVALLED, 0,
4870 "Execute body, preserving window sizes and contents.\n\
eb16ec06
RS
4871Restore which buffer appears in which window, where display starts,\n\
4872and the value of point and mark for each window.\n\
8ed92cf0 4873Also restore the choice of selected window.\n\
eb16ec06 4874Also restore which buffer is current.\n\
7ab12479
JB
4875Does not restore the value of point in current buffer.")
4876 (args)
4877 Lisp_Object args;
4878{
4879 register Lisp_Object val;
4880 register int count = specpdl_ptr - specpdl;
4881
4882 record_unwind_protect (Fset_window_configuration,
43bad991 4883 Fcurrent_window_configuration (Qnil));
7ab12479
JB
4884 val = Fprogn (args);
4885 return unbind_to (count, val);
4886}
5500c422
GM
4887
4888\f
4889/***********************************************************************
4890 Marginal Areas
4891 ***********************************************************************/
4892
4893DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
a7bdfc08 4894 2, 3, 0,
5500c422 4895 "Set width of marginal areas of window WINDOW.\n\
a7bdfc08 4896If window is nil, set margins of the currently selected window.\n\
5500c422
GM
4897First parameter LEFT-WIDTH specifies the number of character\n\
4898cells to reserve for the left marginal area. Second parameter\n\
4899RIGHT-WIDTH does the same for the right marginal area.\n\
4900A nil width parameter means no margin.")
cfa22082 4901 (window, left, right)
5500c422
GM
4902 Lisp_Object window, left, right;
4903{
4904 struct window *w = decode_window (window);
5500c422
GM
4905
4906 if (!NILP (left))
cfa22082 4907 CHECK_NUMBER_OR_FLOAT (left, 1);
5500c422 4908 if (!NILP (right))
cfa22082 4909 CHECK_NUMBER_OR_FLOAT (right, 2);
5500c422
GM
4910
4911 /* Check widths < 0 and translate a zero width to nil.
4912 Margins that are too wide have to be checked elsewhere. */
4913 if ((INTEGERP (left) && XINT (left) < 0)
7539e11f 4914 || (FLOATP (left) && XFLOAT_DATA (left) <= 0))
5500c422
GM
4915 XSETFASTINT (left, 0);
4916 if (INTEGERP (left) && XFASTINT (left) == 0)
4917 left = Qnil;
4918
4919 if ((INTEGERP (right) && XINT (right) < 0)
7539e11f 4920 || (FLOATP (right) && XFLOAT_DATA (right) <= 0))
5500c422
GM
4921 XSETFASTINT (right, 0);
4922 if (INTEGERP (right) && XFASTINT (right) == 0)
4923 right = Qnil;
4924
4925 w->left_margin_width = left;
4926 w->right_margin_width = right;
4927
4928 ++windows_or_buffers_changed;
4929 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
4930 return Qnil;
4931}
4932
4933
4934DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
4935 0, 1, 0,
4936 "Get width of marginal areas of window WINDOW.\n\
4937If WINDOW is omitted or nil, use the currently selected window.\n\
4938Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).\n\
4939If a marginal area does not exist, its width will be returned\n\
4940as nil.")
4941 (window)
4942 Lisp_Object window;
4943{
4944 struct window *w = decode_window (window);
4945 return Fcons (w->left_margin_width, w->right_margin_width);
4946}
4947
4948
7ab12479 4949\f
5500c422
GM
4950/***********************************************************************
4951 Smooth scrolling
4952 ***********************************************************************/
4953
4954DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 1, 0,
4955 "Return the amount by which WINDOW is scrolled vertically.\n\
4956Use the selected window if WINDOW is nil or omitted.\n\
4957Value is a multiple of the canonical character height of WINDOW.")
4958 (window)
4959 Lisp_Object window;
4960{
47004952 4961 Lisp_Object result;
5500c422
GM
4962 struct frame *f;
4963 struct window *w;
4964
4965 if (NILP (window))
4966 window = selected_window;
47004952
GM
4967 else
4968 CHECK_WINDOW (window, 0);
5500c422
GM
4969 w = XWINDOW (window);
4970 f = XFRAME (w->frame);
4971
4972 if (FRAME_WINDOW_P (f))
47004952 4973 result = CANON_Y_FROM_PIXEL_Y (f, -w->vscroll);
5500c422 4974 else
47004952
GM
4975 result = make_number (0);
4976 return result;
5500c422
GM
4977}
4978
4979
4980DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
47004952
GM
4981 2, 2, 0,
4982 "Set amount by which WINDOW should be scrolled vertically to VSCROLL.\n\
5500c422 4983WINDOW nil or omitted means use the selected window. VSCROLL is a\n\
47004952
GM
4984non-negative multiple of the canonical character height of WINDOW.")
4985 (window, vscroll)
4986 Lisp_Object window, vscroll;
5500c422
GM
4987{
4988 struct window *w;
4989 struct frame *f;
4990
5500c422
GM
4991 if (NILP (window))
4992 window = selected_window;
47004952
GM
4993 else
4994 CHECK_WINDOW (window, 0);
4995 CHECK_NUMBER_OR_FLOAT (vscroll, 1);
4996
5500c422
GM
4997 w = XWINDOW (window);
4998 f = XFRAME (w->frame);
4999
5000 if (FRAME_WINDOW_P (f))
5001 {
5002 int old_dy = w->vscroll;
47004952
GM
5003
5004 w->vscroll = - CANON_Y_UNIT (f) * XFLOATINT (vscroll);
5005 w->vscroll = min (w->vscroll, 0);
5500c422
GM
5006
5007 /* Adjust glyph matrix of the frame if the virtual display
5008 area becomes larger than before. */
5009 if (w->vscroll < 0 && w->vscroll < old_dy)
5010 adjust_glyphs (f);
5011
5012 /* Prevent redisplay shortcuts. */
b1599b4c 5013 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
5500c422
GM
5014 }
5015
47004952 5016 return Fwindow_vscroll (window);
5500c422
GM
5017}
5018
7bbb5782
GM
5019\f
5020/* Call FN for all leaf windows on frame F. FN is called with the
5021 first argument being a pointer to the leaf window, and with
5022 additional arguments A1..A4. */
5023
5024void
5025foreach_window (f, fn, a1, a2, a3, a4)
5026 struct frame *f;
5027 void (* fn) ();
5028 int a1, a2, a3, a4;
5029{
5030 foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, a1, a2, a3, a4);
5031}
5032
5033
5034/* Helper function for foreach_window. Call FN for all leaf windows
5035 reachable from W. FN is called with the first argument being a
5036 pointer to the leaf window, and with additional arguments A1..A4. */
5037
5038static void
5039foreach_window_1 (w, fn, a1, a2, a3, a4)
5040 struct window *w;
5041 void (* fn) ();
5042 int a1, a2, a3, a4;
5043{
5044 while (w)
5045 {
5046 if (!NILP (w->hchild))
5047 foreach_window_1 (XWINDOW (w->hchild), fn, a1, a2, a3, a4);
5048 else if (!NILP (w->vchild))
5049 foreach_window_1 (XWINDOW (w->vchild), fn, a1, a2, a3, a4);
5050 else
5051 fn (w, a1, a2, a3, a4);
5052
5053 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5054 }
5055}
5056
5057
5058/* Freeze or unfreeze the window start of W if unless it is a
5059 mini-window or the selected window. FREEZE_P non-zero means freeze
5060 the window start. */
5061
5062static void
5063freeze_window_start (w, freeze_p)
5064 struct window *w;
5065 int freeze_p;
5066{
5067 if (w == XWINDOW (selected_window)
5068 || MINI_WINDOW_P (w)
5069 || (MINI_WINDOW_P (XWINDOW (selected_window))
24d744ac 5070 && ! NILP (Vminibuf_scroll_window)
7bbb5782
GM
5071 && w == XWINDOW (Vminibuf_scroll_window)))
5072 freeze_p = 0;
5073
5074 w->frozen_window_start_p = freeze_p;
5075}
5076
5077
5078/* Freeze or unfreeze the window starts of all leaf windows on frame
5079 F, except the selected window and a mini-window. FREEZE_P non-zero
5080 means freeze the window start. */
5081
5082void
5083freeze_window_starts (f, freeze_p)
5084 struct frame *f;
5085 int freeze_p;
5086{
5087 foreach_window (f, freeze_window_start, freeze_p);
5088}
5500c422
GM
5089
5090\f
5091/***********************************************************************
5092 Initialization
5093 ***********************************************************************/
5094
cbff28e8
RS
5095/* Return 1 if window configurations C1 and C2
5096 describe the same state of affairs. This is used by Fequal. */
5097
5098int
2f8274be 5099compare_window_configurations (c1, c2, ignore_positions)
cbff28e8 5100 Lisp_Object c1, c2;
2f8274be 5101 int ignore_positions;
cbff28e8
RS
5102{
5103 register struct save_window_data *d1, *d2;
5104 struct Lisp_Vector *sw1, *sw2;
5105 int i;
5106
4d3edcb4
GM
5107 if (!WINDOW_CONFIGURATIONP (c1))
5108 wrong_type_argument (Qwindow_configuration_p, c1);
5109 if (!WINDOW_CONFIGURATIONP (c2))
5110 wrong_type_argument (Qwindow_configuration_p, c2);
5111
cbff28e8
RS
5112 d1 = (struct save_window_data *) XVECTOR (c1);
5113 d2 = (struct save_window_data *) XVECTOR (c2);
5114 sw1 = XVECTOR (d1->saved_windows);
5115 sw2 = XVECTOR (d2->saved_windows);
5116
5117 if (! EQ (d1->frame_width, d2->frame_width))
5118 return 0;
5119 if (! EQ (d1->frame_height, d2->frame_height))
5120 return 0;
5121 if (! EQ (d1->frame_menu_bar_lines, d2->frame_menu_bar_lines))
5122 return 0;
5123 if (! EQ (d1->selected_frame, d2->selected_frame))
5124 return 0;
5125 /* Don't compare the current_window field directly.
5126 Instead see w1_is_current and w2_is_current, below. */
5127 if (! EQ (d1->current_buffer, d2->current_buffer))
5128 return 0;
2f8274be
RS
5129 if (! ignore_positions)
5130 if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
5131 return 0;
cbff28e8
RS
5132 /* Don't compare the root_window field.
5133 We don't require the two configurations
5134 to use the same window object,
5135 and the two root windows must be equivalent
5136 if everything else compares equal. */
5137 if (! EQ (d1->focus_frame, d2->focus_frame))
5138 return 0;
5139 if (! EQ (d1->min_width, d2->min_width))
5140 return 0;
5141 if (! EQ (d1->min_height, d2->min_height))
5142 return 0;
5143
5144 /* Verify that the two confis have the same number of windows. */
5145 if (sw1->size != sw2->size)
5146 return 0;
5147
5148 for (i = 0; i < sw1->size; i++)
5149 {
5150 struct saved_window *p1, *p2;
5151 int w1_is_current, w2_is_current;
5152
5153 p1 = SAVED_WINDOW_N (sw1, i);
5154 p2 = SAVED_WINDOW_N (sw2, i);
5155
5156 /* Verify that the current windows in the two
5157 configurations correspond to each other. */
5158 w1_is_current = EQ (d1->current_window, p1->window);
5159 w2_is_current = EQ (d2->current_window, p2->window);
5160
5161 if (w1_is_current != w2_is_current)
5162 return 0;
5163
5164 /* Verify that the corresponding windows do match. */
5165 if (! EQ (p1->buffer, p2->buffer))
5166 return 0;
5167 if (! EQ (p1->left, p2->left))
5168 return 0;
5169 if (! EQ (p1->top, p2->top))
5170 return 0;
5171 if (! EQ (p1->width, p2->width))
5172 return 0;
5173 if (! EQ (p1->height, p2->height))
5174 return 0;
cbff28e8
RS
5175 if (! EQ (p1->display_table, p2->display_table))
5176 return 0;
5177 if (! EQ (p1->parent, p2->parent))
5178 return 0;
5179 if (! EQ (p1->prev, p2->prev))
5180 return 0;
2f8274be
RS
5181 if (! ignore_positions)
5182 {
5183 if (! EQ (p1->hscroll, p2->hscroll))
5184 return 0;
5185 if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
5186 return 0;
5187 if (NILP (Fequal (p1->start, p2->start)))
5188 return 0;
5189 if (NILP (Fequal (p1->pointm, p2->pointm)))
5190 return 0;
5191 if (NILP (Fequal (p1->mark, p2->mark)))
5192 return 0;
5193 }
cbff28e8
RS
5194 }
5195
5196 return 1;
5197}
2f8274be
RS
5198
5199DEFUN ("compare-window-configurations", Fcompare_window_configurations,
5200 Scompare_window_configurations, 2, 2, 0,
5201 "Compare two window configurations as regards the structure of windows.\n\
5202This function ignores details such as the values of point and mark\n\
5203and scrolling positions.")
5204 (x, y)
5205 Lisp_Object x, y;
5206{
5207 if (compare_window_configurations (x, y, 1))
5208 return Qt;
5209 return Qnil;
5210}
cbff28e8 5211\f
dfcf069d 5212void
7ab12479
JB
5213init_window_once ()
5214{
1ae1a37d
GM
5215 struct frame *f = make_terminal_frame ();
5216 XSETFRAME (selected_frame, f);
5217 Vterminal_frame = selected_frame;
5218 minibuf_window = f->minibuffer_window;
5219 selected_window = f->selected_window;
5220 last_nonminibuf_frame = f;
5b03d3c0
RS
5221
5222 window_initialized = 1;
7ab12479
JB
5223}
5224
dfcf069d 5225void
7ab12479
JB
5226syms_of_window ()
5227{
fbad6f9a
GM
5228 Qleft_bitmap_area = intern ("left-bitmap-area");
5229 staticpro (&Qleft_bitmap_area);
5230 Qright_bitmap_area = intern ("right-bitmap-area");
5231 staticpro (&Qright_bitmap_area);
5232
8a37516b
GM
5233 Qwindow_size_fixed = intern ("window-size-fixed");
5234 staticpro (&Qwindow_size_fixed);
233a4a2c 5235
543f5fb1
RS
5236 staticpro (&Qwindow_configuration_change_hook);
5237 Qwindow_configuration_change_hook
5238 = intern ("window-configuration-change-hook");
5239
7ab12479
JB
5240 Qwindowp = intern ("windowp");
5241 staticpro (&Qwindowp);
5242
3f8ab7bd
RS
5243 Qwindow_configuration_p = intern ("window-configuration-p");
5244 staticpro (&Qwindow_configuration_p);
5245
806b4d9b
JB
5246 Qwindow_live_p = intern ("window-live-p");
5247 staticpro (&Qwindow_live_p);
605be8af 5248
2cccc823 5249 Qtemp_buffer_show_hook = intern ("temp-buffer-show-hook");
a58ec57d
RS
5250 staticpro (&Qtemp_buffer_show_hook);
5251
7ab12479
JB
5252 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
5253 "Non-nil means call as function to display a help buffer.\n\
c3ef6b1d 5254The function is called with one argument, the buffer to be displayed.\n\
f52cca03
RS
5255Used by `with-output-to-temp-buffer'.\n\
5256If this function is used, then it must do the entire job of showing\n\
5257the buffer; `temp-buffer-show-hook' is not run unless this function runs it.");
7ab12479
JB
5258 Vtemp_buffer_show_function = Qnil;
5259
5260 DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
5261 "If non-nil, function to call to handle `display-buffer'.\n\
5262It will receive two args, the buffer and a flag which if non-nil means\n\
5263 that the currently selected window is not acceptable.\n\
5264Commands such as `switch-to-buffer-other-window' and `find-file-other-window'\n\
5265work using this function.");
5266 Vdisplay_buffer_function = Qnil;
5267
7ab12479
JB
5268 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
5269 "Non-nil means it is the window that C-M-v in minibuffer should scroll.");
5270 Vminibuf_scroll_window = Qnil;
5271
5272 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
5273 "If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.");
5274 Vother_window_scroll_buffer = Qnil;
5275
44fa5b1e 5276 DEFVAR_BOOL ("pop-up-frames", &pop_up_frames,
700f75a4 5277 "*Non-nil means `display-buffer' should make a separate frame.");
44fa5b1e 5278 pop_up_frames = 0;
7ab12479 5279
44fa5b1e 5280 DEFVAR_LISP ("pop-up-frame-function", &Vpop_up_frame_function,
a90712c2 5281 "Function to call to handle automatic new frame creation.\n\
44fa5b1e 5282It is called with no arguments and should return a newly created frame.\n\
7ab12479 5283\n\
44fa5b1e
JB
5284A typical value might be `(lambda () (new-frame pop-up-frame-alist))'\n\
5285where `pop-up-frame-alist' would hold the default frame parameters.");
5286 Vpop_up_frame_function = Qnil;
7ab12479 5287
a90712c2
RS
5288 DEFVAR_LISP ("special-display-buffer-names", &Vspecial_display_buffer_names,
5289 "*List of buffer names that should have their own special frames.\n\
5290Displaying a buffer whose name is in this list makes a special frame for it\n\
524580a4 5291using `special-display-function'. See also `special-display-regexps'.\n\
3548e138 5292\n\
524580a4
RS
5293An element of the list can be a list instead of just a string.\n\
5294There are two ways to use a list as an element:\n\
5295 (BUFFER FRAME-PARAMETERS...) (BUFFER FUNCTION OTHER-ARGS...)\n\
5296In the first case, FRAME-PARAMETERS are used to create the frame.\n\
5297In the latter case, FUNCTION is called with BUFFER as the first argument,\n\
5298followed by OTHER-ARGS--it can display BUFFER in any way it likes.\n\
4caa7448
RS
5299All this is done by the function found in `special-display-function'.\n\
5300\n\
5301If this variable appears \"not to work\", because you add a name to it\n\
5302but that buffer still appears in the selected window, look at the\n\
5303values of `same-window-buffer-names' and `same-window-regexps'.\n\
5304Those variables take precedence over this one.");
a90712c2
RS
5305 Vspecial_display_buffer_names = Qnil;
5306
5307 DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
5308 "*List of regexps saying which buffers should have their own special frames.\n\
5309If a buffer name matches one of these regexps, it gets its own frame.\n\
5310Displaying a buffer whose name is in this list makes a special frame for it\n\
0a952b57 5311using `special-display-function'.\n\
3548e138 5312\n\
524580a4
RS
5313An element of the list can be a list instead of just a string.\n\
5314There are two ways to use a list as an element:\n\
5315 (REGEXP FRAME-PARAMETERS...) (REGEXP FUNCTION OTHER-ARGS...)\n\
5316In the first case, FRAME-PARAMETERS are used to create the frame.\n\
5317In the latter case, FUNCTION is called with the buffer as first argument,\n\
5318followed by OTHER-ARGS--it can display the buffer in any way it likes.\n\
4caa7448
RS
5319All this is done by the function found in `special-display-function'.\n\
5320\n\
5321If this variable appears \"not to work\", because you add a regexp to it\n\
5322but the matching buffers still appear in the selected window, look at the\n\
5323values of `same-window-buffer-names' and `same-window-regexps'.\n\
5324Those variables take precedence over this one.");
a90712c2
RS
5325 Vspecial_display_regexps = Qnil;
5326
5327 DEFVAR_LISP ("special-display-function", &Vspecial_display_function,
5328 "Function to call to make a new frame for a special buffer.\n\
0a952b57
RS
5329It is called with two arguments, the buffer and optional buffer specific\n\
5330data, and should return a window displaying that buffer.\n\
a90712c2 5331The default value makes a separate frame for the buffer,\n\
bdd3a802 5332using `special-display-frame-alist' to specify the frame parameters.\n\
a90712c2
RS
5333\n\
5334A buffer is special if its is listed in `special-display-buffer-names'\n\
5335or matches a regexp in `special-display-regexps'.");
5336 Vspecial_display_function = Qnil;
5337
855d8627
RS
5338 DEFVAR_LISP ("same-window-buffer-names", &Vsame_window_buffer_names,
5339 "*List of buffer names that should appear in the selected window.\n\
5340Displaying one of these buffers using `display-buffer' or `pop-to-buffer'\n\
5341switches to it in the selected window, rather than making it appear\n\
2e5ce1a0 5342in some other window.\n\
855d8627
RS
5343\n\
5344An element of the list can be a cons cell instead of just a string.\n\
5345Then the car must be a string, which specifies the buffer name.\n\
5346This is for compatibility with `special-display-buffer-names';\n\
5347the cdr of the cons cell is ignored.\n\
5348\n\
5349See also `same-window-regexps'.");
5350 Vsame_window_buffer_names = Qnil;
5351
5352 DEFVAR_LISP ("same-window-regexps", &Vsame_window_regexps,
5353 "*List of regexps saying which buffers should appear in the selected window.\n\
5354If a buffer name matches one of these regexps, then displaying it\n\
5355using `display-buffer' or `pop-to-buffer' switches to it\n\
5356in the selected window, rather than making it appear in some other window.\n\
5357\n\
5358An element of the list can be a cons cell instead of just a string.\n\
5359Then the car must be a string, which specifies the buffer name.\n\
5360This is for compatibility with `special-display-buffer-names';\n\
5361the cdr of the cons cell is ignored.\n\
5362\n\
5363See also `same-window-buffer-names'.");
5364 Vsame_window_regexps = Qnil;
5365
7ab12479
JB
5366 DEFVAR_BOOL ("pop-up-windows", &pop_up_windows,
5367 "*Non-nil means display-buffer should make new windows.");
5368 pop_up_windows = 1;
5369
5370 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
5371 "*Number of lines of continuity when scrolling by screenfuls.");
5372 next_screen_context_lines = 2;
5373
5374 DEFVAR_INT ("split-height-threshold", &split_height_threshold,
5375 "*display-buffer would prefer to split the largest window if this large.\n\
5376If there is only one window, it is split regardless of this value.");
5377 split_height_threshold = 500;
5378
5379 DEFVAR_INT ("window-min-height", &window_min_height,
5380 "*Delete any window less than this tall (including its mode line).");
5381 window_min_height = 4;
5382
5383 DEFVAR_INT ("window-min-width", &window_min_width,
5384 "*Delete any window less than this wide.");
5385 window_min_width = 10;
5386
5500c422
GM
5387 DEFVAR_LISP ("scroll-preserve-screen-position",
5388 &Vscroll_preserve_screen_position,
9317a85d 5389 "*Nonzero means scroll commands move point to keep its screen line unchanged.");
5500c422 5390 Vscroll_preserve_screen_position = Qnil;
9317a85d 5391
543f5fb1
RS
5392 DEFVAR_LISP ("window-configuration-change-hook",
5393 &Vwindow_configuration_change_hook,
5394 "Functions to call when window configuration changes.\n\
e3e041eb 5395The selected frame is the one whose configuration has changed.");
543f5fb1
RS
5396 Vwindow_configuration_change_hook = Qnil;
5397
7ab12479
JB
5398 defsubr (&Sselected_window);
5399 defsubr (&Sminibuffer_window);
5400 defsubr (&Swindow_minibuffer_p);
5401 defsubr (&Swindowp);
806b4d9b 5402 defsubr (&Swindow_live_p);
7ab12479
JB
5403 defsubr (&Spos_visible_in_window_p);
5404 defsubr (&Swindow_buffer);
5405 defsubr (&Swindow_height);
5406 defsubr (&Swindow_width);
5407 defsubr (&Swindow_hscroll);
5408 defsubr (&Sset_window_hscroll);
190eb263
RS
5409 defsubr (&Swindow_redisplay_end_trigger);
5410 defsubr (&Sset_window_redisplay_end_trigger);
7ab12479 5411 defsubr (&Swindow_edges);
d5783c40
JB
5412 defsubr (&Scoordinates_in_window_p);
5413 defsubr (&Swindow_at);
7ab12479
JB
5414 defsubr (&Swindow_point);
5415 defsubr (&Swindow_start);
5416 defsubr (&Swindow_end);
5417 defsubr (&Sset_window_point);
5418 defsubr (&Sset_window_start);
5419 defsubr (&Swindow_dedicated_p);
d207b766 5420 defsubr (&Sset_window_dedicated_p);
7ab12479
JB
5421 defsubr (&Swindow_display_table);
5422 defsubr (&Sset_window_display_table);
5423 defsubr (&Snext_window);
5424 defsubr (&Sprevious_window);
5425 defsubr (&Sother_window);
5426 defsubr (&Sget_lru_window);
5427 defsubr (&Sget_largest_window);
5428 defsubr (&Sget_buffer_window);
5429 defsubr (&Sdelete_other_windows);
5430 defsubr (&Sdelete_windows_on);
5431 defsubr (&Sreplace_buffer_in_windows);
5432 defsubr (&Sdelete_window);
5433 defsubr (&Sset_window_buffer);
5434 defsubr (&Sselect_window);
4628f7a4
EN
5435 defsubr (&Sspecial_display_p);
5436 defsubr (&Ssame_window_p);
7ab12479
JB
5437 defsubr (&Sdisplay_buffer);
5438 defsubr (&Ssplit_window);
5439 defsubr (&Senlarge_window);
5440 defsubr (&Sshrink_window);
5441 defsubr (&Sscroll_up);
5442 defsubr (&Sscroll_down);
5443 defsubr (&Sscroll_left);
5444 defsubr (&Sscroll_right);
ccd0664b 5445 defsubr (&Sother_window_for_scrolling);
7ab12479
JB
5446 defsubr (&Sscroll_other_window);
5447 defsubr (&Srecenter);
5448 defsubr (&Smove_to_window_line);
5449 defsubr (&Swindow_configuration_p);
3f8ab7bd 5450 defsubr (&Swindow_configuration_frame);
7ab12479
JB
5451 defsubr (&Sset_window_configuration);
5452 defsubr (&Scurrent_window_configuration);
5453 defsubr (&Ssave_window_excursion);
5500c422
GM
5454 defsubr (&Sset_window_margins);
5455 defsubr (&Swindow_margins);
5456 defsubr (&Swindow_vscroll);
5457 defsubr (&Sset_window_vscroll);
2f8274be 5458 defsubr (&Scompare_window_configurations);
7ab12479
JB
5459}
5460
dfcf069d 5461void
7ab12479
JB
5462keys_of_window ()
5463{
5464 initial_define_key (control_x_map, '1', "delete-other-windows");
5465 initial_define_key (control_x_map, '2', "split-window");
5466 initial_define_key (control_x_map, '0', "delete-window");
5467 initial_define_key (control_x_map, 'o', "other-window");
5468 initial_define_key (control_x_map, '^', "enlarge-window");
5469 initial_define_key (control_x_map, '<', "scroll-left");
5470 initial_define_key (control_x_map, '>', "scroll-right");
5471
5472 initial_define_key (global_map, Ctl ('V'), "scroll-up");
5473 initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
5474 initial_define_key (meta_map, 'v', "scroll-down");
5475
5476 initial_define_key (global_map, Ctl('L'), "recenter");
5477 initial_define_key (meta_map, 'r', "move-to-window-line");
5478}