(frames_bury_buffer): Don't add a buffer to the frame's
[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}
4219\f
4220DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
4221 1, 1, "P",
4222 "Position point relative to window.\n\
19e3bf0a 4223With no argument, position point at center of window.\n\
d81724c7
RS
4224An argument specifies vertical position within the window;\n\
4225zero means top of window, negative means relative to bottom of window.")
7ab12479
JB
4226 (arg)
4227 register Lisp_Object arg;
4228{
4229 register struct window *w = XWINDOW (selected_window);
4230 register int height = window_internal_height (w);
4231 register int start;
540b6aa0 4232 Lisp_Object window;
7ab12479 4233
265a9e55 4234 if (NILP (arg))
d834a2e9 4235 XSETFASTINT (arg, height / 2);
7ab12479
JB
4236 else
4237 {
4238 arg = Fprefix_numeric_value (arg);
4239 if (XINT (arg) < 0)
4240 XSETINT (arg, XINT (arg) + height);
4241 }
4242
4243 start = marker_position (w->start);
74112613 4244 XSETWINDOW (window, w);
7ab12479
JB
4245 if (start < BEGV || start > ZV)
4246 {
cd2be1dd 4247 Fvertical_motion (make_number (- (height / 2)), window);
b73ea88e 4248 set_marker_both (w->start, w->buffer, PT, PT_BYTE);
7ab12479
JB
4249 w->start_at_line_beg = Fbolp ();
4250 w->force_start = Qt;
4251 }
4252 else
b73ea88e 4253 Fgoto_char (w->start);
7ab12479 4254
540b6aa0 4255 return Fvertical_motion (arg, window);
7ab12479 4256}
5500c422
GM
4257
4258
7ab12479 4259\f
5500c422
GM
4260/***********************************************************************
4261 Window Configuration
4262 ***********************************************************************/
4263
7ab12479
JB
4264struct save_window_data
4265 {
f5ccc0cc 4266 EMACS_INT size_from_Lisp_Vector_struct;
7ab12479 4267 struct Lisp_Vector *next_from_Lisp_Vector_struct;
8f6ea2e9 4268 Lisp_Object frame_width, frame_height, frame_menu_bar_lines;
9ea173e8 4269 Lisp_Object frame_tool_bar_lines;
bdc727bf 4270 Lisp_Object selected_frame;
7ab12479
JB
4271 Lisp_Object current_window;
4272 Lisp_Object current_buffer;
4273 Lisp_Object minibuf_scroll_window;
4274 Lisp_Object root_window;
bdc727bf 4275 Lisp_Object focus_frame;
756b6edc
RS
4276 /* Record the values of window-min-width and window-min-height
4277 so that window sizes remain consistent with them. */
4278 Lisp_Object min_width, min_height;
cbff28e8
RS
4279 /* A vector, each of whose elements is a struct saved_window
4280 for one window. */
7ab12479
JB
4281 Lisp_Object saved_windows;
4282 };
ff06df24 4283
cbff28e8 4284/* This is saved as a Lisp_Vector */
7ab12479
JB
4285struct saved_window
4286 {
4287 /* these first two must agree with struct Lisp_Vector in lisp.h */
f5ccc0cc 4288 EMACS_INT size_from_Lisp_Vector_struct;
7ab12479
JB
4289 struct Lisp_Vector *next_from_Lisp_Vector_struct;
4290
4291 Lisp_Object window;
4292 Lisp_Object buffer, start, pointm, mark;
4293 Lisp_Object left, top, width, height, hscroll;
4294 Lisp_Object parent, prev;
4295 Lisp_Object start_at_line_beg;
4296 Lisp_Object display_table;
4297 };
4298#define SAVED_WINDOW_VECTOR_SIZE 14 /* Arg to Fmake_vector */
4299
4300#define SAVED_WINDOW_N(swv,n) \
4301 ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
4302
4303DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
cbff28e8 4304 "Return t if OBJECT is a window-configuration object.")
413430c5
EN
4305 (object)
4306 Lisp_Object object;
7ab12479 4307{
413430c5 4308 if (WINDOW_CONFIGURATIONP (object))
7ab12479
JB
4309 return Qt;
4310 return Qnil;
4311}
4312
3f8ab7bd
RS
4313DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
4314 "Return the frame that CONFIG, a window-configuration object, is about.")
4315 (config)
4316 Lisp_Object config;
4317{
4318 register struct save_window_data *data;
4319 struct Lisp_Vector *saved_windows;
4320
4321 if (! WINDOW_CONFIGURATIONP (config))
4322 wrong_type_argument (Qwindow_configuration_p, config);
4323
4324 data = (struct save_window_data *) XVECTOR (config);
4325 saved_windows = XVECTOR (data->saved_windows);
4326 return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
4327}
4328
d5b2799e
RS
4329DEFUN ("set-window-configuration", Fset_window_configuration,
4330 Sset_window_configuration, 1, 1, 0,
7ab12479
JB
4331 "Set the configuration of windows and buffers as specified by CONFIGURATION.\n\
4332CONFIGURATION must be a value previously returned\n\
3f8ab7bd
RS
4333by `current-window-configuration' (which see).\n\
4334If CONFIGURATION was made from a frame that is now deleted,\n\
4335only frame-independent values can be restored. In this case,\n\
4336the return value is nil. Otherwise the value is t.")
4337 (configuration)
2f83aebe 4338 Lisp_Object configuration;
7ab12479 4339{
7ab12479
JB
4340 register struct save_window_data *data;
4341 struct Lisp_Vector *saved_windows;
7ab12479 4342 Lisp_Object new_current_buffer;
fd482be5 4343 Lisp_Object frame;
44fa5b1e 4344 FRAME_PTR f;
d2b35234 4345 int old_point = -1;
7ab12479 4346
017b2bad 4347 while (!WINDOW_CONFIGURATIONP (configuration))
3f8ab7bd 4348 wrong_type_argument (Qwindow_configuration_p, configuration);
7ab12479 4349
2f83aebe 4350 data = (struct save_window_data *) XVECTOR (configuration);
7ab12479
JB
4351 saved_windows = XVECTOR (data->saved_windows);
4352
7ab12479 4353 new_current_buffer = data->current_buffer;
265a9e55 4354 if (NILP (XBUFFER (new_current_buffer)->name))
7ab12479 4355 new_current_buffer = Qnil;
d2b35234
RS
4356 else
4357 {
4358 if (XBUFFER (new_current_buffer) == current_buffer)
4359 old_point = PT;
cbff28e8 4360
d2b35234 4361 }
7ab12479 4362
fd482be5
JB
4363 frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
4364 f = XFRAME (frame);
9ace597f 4365
fd482be5
JB
4366 /* If f is a dead frame, don't bother rebuilding its window tree.
4367 However, there is other stuff we should still try to do below. */
4368 if (FRAME_LIVE_P (f))
7ab12479 4369 {
fd482be5
JB
4370 register struct window *w;
4371 register struct saved_window *p;
5500c422
GM
4372 struct window *root_window;
4373 struct window **leaf_windows;
4374 int n_leaf_windows;
4375 int k, i;
fd482be5
JB
4376
4377 /* If the frame has been resized since this window configuration was
4378 made, we change the frame to the size specified in the
4379 configuration, restore the configuration, and then resize it
4380 back. We keep track of the prevailing height in these variables. */
4381 int previous_frame_height = FRAME_HEIGHT (f);
4382 int previous_frame_width = FRAME_WIDTH (f);
8f6ea2e9 4383 int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
9ea173e8 4384 int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
fd482be5 4385
d2b35234
RS
4386 /* The mouse highlighting code could get screwed up
4387 if it runs during this. */
4388 BLOCK_INPUT;
4389
fd482be5
JB
4390 if (XFASTINT (data->frame_height) != previous_frame_height
4391 || XFASTINT (data->frame_width) != previous_frame_width)
f8ad443a 4392 change_frame_size (f, XFASTINT (data->frame_height),
2b653806 4393 XFASTINT (data->frame_width), 0, 0, 0);
e3678b64 4394#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
8f6ea2e9
KH
4395 if (XFASTINT (data->frame_menu_bar_lines)
4396 != previous_frame_menu_bar_lines)
f8ad443a 4397 x_set_menu_bar_lines (f, data->frame_menu_bar_lines, make_number (0));
4314246f 4398#ifdef HAVE_WINDOW_SYSTEM
9ea173e8
GM
4399 if (XFASTINT (data->frame_tool_bar_lines)
4400 != previous_frame_tool_bar_lines)
4401 x_set_tool_bar_lines (f, data->frame_tool_bar_lines, make_number (0));
4314246f 4402#endif
217f2871 4403#endif
fd482be5 4404
719eaeb1
GM
4405 /* "Swap out" point from the selected window
4406 into its buffer. We do this now, before
4407 restoring the window contents, and prevent it from
4408 being done later on when we select a new window. */
596ae0cf
RS
4409 if (! NILP (XWINDOW (selected_window)->buffer))
4410 {
4411 w = XWINDOW (selected_window);
4412 set_marker_both (w->pointm,
4413 w->buffer,
4414 BUF_PT (XBUFFER (w->buffer)),
4415 BUF_PT_BYTE (XBUFFER (w->buffer)));
4416 }
4417
fd482be5 4418 windows_or_buffers_changed++;
29aeee73 4419 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
fd482be5 4420
5500c422
GM
4421 /* Problem: Freeing all matrices and later allocating them again
4422 is a serious redisplay flickering problem. What we would
4423 really like to do is to free only those matrices not reused
4424 below. */
4425 root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
4426 leaf_windows
4427 = (struct window **) alloca (count_windows (root_window)
4428 * sizeof (struct window *));
4429 n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
4430
756b6edc
RS
4431 /* Temporarily avoid any problems with windows that are smaller
4432 than they are supposed to be. */
4433 window_min_height = 1;
4434 window_min_width = 1;
4435
fd482be5
JB
4436 /* Kludge Alert!
4437 Mark all windows now on frame as "deleted".
4438 Restoring the new configuration "undeletes" any that are in it.
37962e60 4439
fd482be5
JB
4440 Save their current buffers in their height fields, since we may
4441 need it later, if a buffer saved in the configuration is now
4442 dead. */
4443 delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
4444
4445 for (k = 0; k < saved_windows->size; k++)
4446 {
4447 p = SAVED_WINDOW_N (saved_windows, k);
4448 w = XWINDOW (p->window);
4449 w->next = Qnil;
7ab12479 4450
fd482be5
JB
4451 if (!NILP (p->parent))
4452 w->parent = SAVED_WINDOW_N (saved_windows,
4453 XFASTINT (p->parent))->window;
4454 else
4455 w->parent = Qnil;
7ab12479 4456
fd482be5 4457 if (!NILP (p->prev))
7ab12479 4458 {
fd482be5
JB
4459 w->prev = SAVED_WINDOW_N (saved_windows,
4460 XFASTINT (p->prev))->window;
4461 XWINDOW (w->prev)->next = p->window;
4462 }
4463 else
4464 {
4465 w->prev = Qnil;
4466 if (!NILP (w->parent))
4467 {
4468 if (EQ (p->width, XWINDOW (w->parent)->width))
4469 {
4470 XWINDOW (w->parent)->vchild = p->window;
4471 XWINDOW (w->parent)->hchild = Qnil;
4472 }
4473 else
4474 {
4475 XWINDOW (w->parent)->hchild = p->window;
4476 XWINDOW (w->parent)->vchild = Qnil;
4477 }
4478 }
4479 }
4480
4481 /* If we squirreled away the buffer in the window's height,
4482 restore it now. */
017b2bad 4483 if (BUFFERP (w->height))
fd482be5
JB
4484 w->buffer = w->height;
4485 w->left = p->left;
4486 w->top = p->top;
4487 w->width = p->width;
4488 w->height = p->height;
4489 w->hscroll = p->hscroll;
4490 w->display_table = p->display_table;
d834a2e9 4491 XSETFASTINT (w->last_modified, 0);
3cd21523 4492 XSETFASTINT (w->last_overlay_modified, 0);
fd482be5
JB
4493
4494 /* Reinstall the saved buffer and pointers into it. */
4495 if (NILP (p->buffer))
4496 w->buffer = p->buffer;
4497 else
4498 {
4499 if (!NILP (XBUFFER (p->buffer)->name))
4500 /* If saved buffer is alive, install it. */
4501 {
4502 w->buffer = p->buffer;
4503 w->start_at_line_beg = p->start_at_line_beg;
b73ea88e
RS
4504 set_marker_restricted (w->start, p->start, w->buffer);
4505 set_marker_restricted (w->pointm, p->pointm, w->buffer);
fd482be5 4506 Fset_marker (XBUFFER (w->buffer)->mark,
b73ea88e 4507 p->mark, w->buffer);
fd482be5
JB
4508
4509 /* As documented in Fcurrent_window_configuration, don't
4510 save the location of point in the buffer which was current
4511 when the window configuration was recorded. */
6b54027b
RS
4512 if (!EQ (p->buffer, new_current_buffer)
4513 && XBUFFER (p->buffer) == current_buffer)
fd482be5
JB
4514 Fgoto_char (w->pointm);
4515 }
52a68e98
RS
4516 else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
4517 /* Else unless window has a live buffer, get one. */
7ab12479 4518 {
fd482be5
JB
4519 w->buffer = Fcdr (Fcar (Vbuffer_alist));
4520 /* This will set the markers to beginning of visible
4521 range. */
4522 set_marker_restricted (w->start, make_number (0), w->buffer);
4523 set_marker_restricted (w->pointm, make_number (0),w->buffer);
4524 w->start_at_line_beg = Qt;
7ab12479
JB
4525 }
4526 else
fd482be5 4527 /* Keeping window's old buffer; make sure the markers
52a68e98 4528 are real. */
7ab12479 4529 {
fd482be5
JB
4530 /* Set window markers at start of visible range. */
4531 if (XMARKER (w->start)->buffer == 0)
4532 set_marker_restricted (w->start, make_number (0),
4533 w->buffer);
4534 if (XMARKER (w->pointm)->buffer == 0)
b73ea88e
RS
4535 set_marker_restricted_both (w->pointm, w->buffer,
4536 BUF_PT (XBUFFER (w->buffer)),
4537 BUF_PT_BYTE (XBUFFER (w->buffer)));
fd482be5 4538 w->start_at_line_beg = Qt;
7ab12479
JB
4539 }
4540 }
4541 }
9ace597f 4542
fd482be5 4543 FRAME_ROOT_WINDOW (f) = data->root_window;
719eaeb1
GM
4544 /* Prevent "swapping out point" in the old selected window
4545 using the buffer that has been restored into it.
4546 That swapping out has already been done,
4547 near the beginning of this function. */
4548 selected_window = Qnil;
fd482be5 4549 Fselect_window (data->current_window);
396a830c
RS
4550 XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
4551 = selected_window;
7ab12479 4552
db269683 4553 if (NILP (data->focus_frame)
017b2bad 4554 || (FRAMEP (data->focus_frame)
db269683
JB
4555 && FRAME_LIVE_P (XFRAME (data->focus_frame))))
4556 Fredirect_frame_focus (frame, data->focus_frame);
7ab12479 4557
fd482be5
JB
4558#if 0 /* I don't understand why this is needed, and it causes problems
4559 when the frame's old selected window has been deleted. */
e4e59717 4560 if (f != selected_frame && FRAME_WINDOW_P (f))
9a7c6fc3
RS
4561 do_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)),
4562 Qnil, 0);
fd482be5
JB
4563#endif
4564
4565 /* Set the screen height to the value it had before this function. */
4566 if (previous_frame_height != FRAME_HEIGHT (f)
4567 || previous_frame_width != FRAME_WIDTH (f))
4568 change_frame_size (f, previous_frame_height, previous_frame_width,
2b653806 4569 0, 0, 0);
e3678b64 4570#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
8f6ea2e9 4571 if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
f8ad443a
AS
4572 x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
4573 make_number (0));
4314246f 4574#ifdef HAVE_WINDOW_SYSTEM
9ea173e8
GM
4575 if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
4576 x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
4577 make_number (0));
4314246f 4578#endif
217f2871 4579#endif
d2b35234 4580
5500c422
GM
4581 /* Now, free glyph matrices in windows that were not reused. */
4582 for (i = 0; i < n_leaf_windows; ++i)
4583 if (NILP (leaf_windows[i]->buffer))
4584 {
4585 /* Assert it's not reused as a combination. */
4586 xassert (NILP (leaf_windows[i]->hchild)
4587 && NILP (leaf_windows[i]->vchild));
4588 free_window_matrices (leaf_windows[i]);
4589 SET_FRAME_GARBAGED (f);
4590 }
4591
4592 adjust_glyphs (f);
4593
d2b35234 4594 UNBLOCK_INPUT;
756b6edc 4595
478292ed
RS
4596 /* Fselect_window will have made f the selected frame, so we
4597 reselect the proper frame here. Fhandle_switch_frame will change the
4598 selected window too, but that doesn't make the call to
4599 Fselect_window above totally superfluous; it still sets f's
4600 selected window. */
4601 if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
4602 do_switch_frame (data->selected_frame, Qnil, 0);
4603
4604 if (! NILP (Vwindow_configuration_change_hook)
4605 && ! NILP (Vrun_hooks))
4606 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
4607 }
bdc727bf
JB
4608
4609 if (!NILP (new_current_buffer))
d2b35234
RS
4610 {
4611 Fset_buffer (new_current_buffer);
4612
4613 /* If the buffer that is current now is the same
4614 that was current before setting the window configuration,
4615 don't alter its PT. */
4616 if (old_point >= 0)
4617 SET_PT (old_point);
4618 }
bdc727bf 4619
478292ed
RS
4620 /* Restore the minimum heights recorded in the configuration. */
4621 window_min_height = XINT (data->min_height);
4622 window_min_width = XINT (data->min_width);
543f5fb1 4623
478292ed 4624 Vminibuf_scroll_window = data->minibuf_scroll_window;
543f5fb1 4625
3f8ab7bd 4626 return (FRAME_LIVE_P (f) ? Qt : Qnil);
7ab12479
JB
4627}
4628
44fa5b1e 4629/* Mark all windows now on frame as deleted
7ab12479
JB
4630 by setting their buffers to nil. */
4631
fd482be5 4632void
7ab12479
JB
4633delete_all_subwindows (w)
4634 register struct window *w;
4635{
265a9e55 4636 if (!NILP (w->next))
7ab12479 4637 delete_all_subwindows (XWINDOW (w->next));
265a9e55 4638 if (!NILP (w->vchild))
7ab12479 4639 delete_all_subwindows (XWINDOW (w->vchild));
265a9e55 4640 if (!NILP (w->hchild))
7ab12479 4641 delete_all_subwindows (XWINDOW (w->hchild));
605be8af
JB
4642
4643 w->height = w->buffer; /* See Fset_window_configuration for excuse. */
4644
86e48436
RS
4645 if (!NILP (w->buffer))
4646 unshow_buffer (w);
4647
605be8af
JB
4648 /* We set all three of these fields to nil, to make sure that we can
4649 distinguish this dead window from any live window. Live leaf
4650 windows will have buffer set, and combination windows will have
4651 vchild or hchild set. */
4652 w->buffer = Qnil;
4653 w->vchild = Qnil;
4654 w->hchild = Qnil;
7ab12479
JB
4655}
4656\f
4657static int
4658count_windows (window)
4659 register struct window *window;
4660{
4661 register int count = 1;
265a9e55 4662 if (!NILP (window->next))
7ab12479 4663 count += count_windows (XWINDOW (window->next));
265a9e55 4664 if (!NILP (window->vchild))
7ab12479 4665 count += count_windows (XWINDOW (window->vchild));
265a9e55 4666 if (!NILP (window->hchild))
7ab12479
JB
4667 count += count_windows (XWINDOW (window->hchild));
4668 return count;
4669}
4670
5500c422
GM
4671
4672/* Fill vector FLAT with leaf windows under W, starting at index I.
4673 Value is last index + 1. */
4674
4675static int
4676get_leaf_windows (w, flat, i)
4677 struct window *w;
4678 struct window **flat;
4679 int i;
4680{
4681 while (w)
4682 {
4683 if (!NILP (w->hchild))
4684 i = get_leaf_windows (XWINDOW (w->hchild), flat, i);
4685 else if (!NILP (w->vchild))
4686 i = get_leaf_windows (XWINDOW (w->vchild), flat, i);
4687 else
4688 flat[i++] = w;
4689
4690 w = NILP (w->next) ? 0 : XWINDOW (w->next);
4691 }
4692
4693 return i;
4694}
4695
4696
4697/* Return a pointer to the glyph W's physical cursor is on. Value is
4698 null if W's current matrix is invalid, so that no meaningfull glyph
4699 can be returned. */
4700
4701struct glyph *
4702get_phys_cursor_glyph (w)
4703 struct window *w;
4704{
4705 struct glyph_row *row;
4706 struct glyph *glyph;
4707
4708 if (w->phys_cursor.vpos >= 0
4709 && w->phys_cursor.vpos < w->current_matrix->nrows
4710 && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
4711 row->enabled_p)
4712 && row->used[TEXT_AREA] > w->phys_cursor.hpos)
4713 glyph = row->glyphs[TEXT_AREA] + w->phys_cursor.hpos;
4714 else
4715 glyph = NULL;
4716
4717 return glyph;
4718}
4719
4720
7ab12479
JB
4721static int
4722save_window_save (window, vector, i)
4723 Lisp_Object window;
4724 struct Lisp_Vector *vector;
4725 int i;
4726{
4727 register struct saved_window *p;
4728 register struct window *w;
4729 register Lisp_Object tem;
4730
265a9e55 4731 for (;!NILP (window); window = w->next)
7ab12479
JB
4732 {
4733 p = SAVED_WINDOW_N (vector, i);
4734 w = XWINDOW (window);
4735
d834a2e9 4736 XSETFASTINT (w->temslot, i++);
7ab12479
JB
4737 p->window = window;
4738 p->buffer = w->buffer;
4739 p->left = w->left;
4740 p->top = w->top;
4741 p->width = w->width;
4742 p->height = w->height;
4743 p->hscroll = w->hscroll;
4744 p->display_table = w->display_table;
265a9e55 4745 if (!NILP (w->buffer))
7ab12479
JB
4746 {
4747 /* Save w's value of point in the window configuration.
4748 If w is the selected window, then get the value of point
4749 from the buffer; pointm is garbage in the selected window. */
4750 if (EQ (window, selected_window))
4751 {
4752 p->pointm = Fmake_marker ();
b73ea88e
RS
4753 set_marker_both (p->pointm, w->buffer,
4754 BUF_PT (XBUFFER (w->buffer)),
4755 BUF_PT_BYTE (XBUFFER (w->buffer)));
7ab12479
JB
4756 }
4757 else
eeb82665 4758 p->pointm = Fcopy_marker (w->pointm, Qnil);
7ab12479 4759
eeb82665 4760 p->start = Fcopy_marker (w->start, Qnil);
7ab12479
JB
4761 p->start_at_line_beg = w->start_at_line_beg;
4762
4763 tem = XBUFFER (w->buffer)->mark;
eeb82665 4764 p->mark = Fcopy_marker (tem, Qnil);
7ab12479
JB
4765 }
4766 else
4767 {
4768 p->pointm = Qnil;
4769 p->start = Qnil;
4770 p->mark = Qnil;
4771 p->start_at_line_beg = Qnil;
4772 }
4773
265a9e55 4774 if (NILP (w->parent))
7ab12479
JB
4775 p->parent = Qnil;
4776 else
4777 p->parent = XWINDOW (w->parent)->temslot;
4778
265a9e55 4779 if (NILP (w->prev))
7ab12479
JB
4780 p->prev = Qnil;
4781 else
4782 p->prev = XWINDOW (w->prev)->temslot;
4783
265a9e55 4784 if (!NILP (w->vchild))
7ab12479 4785 i = save_window_save (w->vchild, vector, i);
265a9e55 4786 if (!NILP (w->hchild))
7ab12479
JB
4787 i = save_window_save (w->hchild, vector, i);
4788 }
4789
4790 return i;
4791}
4792
a0d76c27
EN
4793DEFUN ("current-window-configuration", Fcurrent_window_configuration,
4794 Scurrent_window_configuration, 0, 1, 0,
44fa5b1e
JB
4795 "Return an object representing the current window configuration of FRAME.\n\
4796If FRAME is nil or omitted, use the selected frame.\n\
7ab12479
JB
4797This describes the number of windows, their sizes and current buffers,\n\
4798and for each displayed buffer, where display starts, and the positions of\n\
4799point and mark. An exception is made for point in the current buffer:\n\
bdc727bf
JB
4800its value is -not- saved.\n\
4801This also records the currently selected frame, and FRAME's focus\n\
4802redirection (see `redirect-frame-focus').")
44fa5b1e
JB
4803 (frame)
4804 Lisp_Object frame;
7ab12479
JB
4805{
4806 register Lisp_Object tem;
4807 register int n_windows;
4808 register struct save_window_data *data;
da2792e0 4809 register struct Lisp_Vector *vec;
7ab12479 4810 register int i;
44fa5b1e 4811 FRAME_PTR f;
43bad991 4812
44fa5b1e 4813 if (NILP (frame))
1ae1a37d
GM
4814 frame = selected_frame;
4815 CHECK_LIVE_FRAME (frame, 0);
4816 f = XFRAME (frame);
7ab12479 4817
44fa5b1e 4818 n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
da2792e0
KH
4819 vec = allocate_vectorlike (VECSIZE (struct save_window_data));
4820 for (i = 0; i < VECSIZE (struct save_window_data); i++)
4821 vec->contents[i] = Qnil;
4822 vec->size = VECSIZE (struct save_window_data);
4823 data = (struct save_window_data *)vec;
4824
d834a2e9
KH
4825 XSETFASTINT (data->frame_width, FRAME_WIDTH (f));
4826 XSETFASTINT (data->frame_height, FRAME_HEIGHT (f));
4827 XSETFASTINT (data->frame_menu_bar_lines, FRAME_MENU_BAR_LINES (f));
9ea173e8 4828 XSETFASTINT (data->frame_tool_bar_lines, FRAME_TOOL_BAR_LINES (f));
1ae1a37d 4829 data->selected_frame = selected_frame;
44fa5b1e 4830 data->current_window = FRAME_SELECTED_WINDOW (f);
74112613 4831 XSETBUFFER (data->current_buffer, current_buffer);
7ab12479 4832 data->minibuf_scroll_window = Vminibuf_scroll_window;
44fa5b1e 4833 data->root_window = FRAME_ROOT_WINDOW (f);
bdc727bf 4834 data->focus_frame = FRAME_FOCUS_FRAME (f);
74112613
KH
4835 XSETINT (data->min_height, window_min_height);
4836 XSETINT (data->min_width, window_min_width);
7ab12479
JB
4837 tem = Fmake_vector (make_number (n_windows), Qnil);
4838 data->saved_windows = tem;
4839 for (i = 0; i < n_windows; i++)
4840 XVECTOR (tem)->contents[i]
4841 = Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil);
44fa5b1e 4842 save_window_save (FRAME_ROOT_WINDOW (f),
7ab12479 4843 XVECTOR (tem), 0);
74112613 4844 XSETWINDOW_CONFIGURATION (tem, data);
7ab12479
JB
4845 return (tem);
4846}
4847
4848DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
4849 0, UNEVALLED, 0,
4850 "Execute body, preserving window sizes and contents.\n\
eb16ec06
RS
4851Restore which buffer appears in which window, where display starts,\n\
4852and the value of point and mark for each window.\n\
8ed92cf0 4853Also restore the choice of selected window.\n\
eb16ec06 4854Also restore which buffer is current.\n\
7ab12479
JB
4855Does not restore the value of point in current buffer.")
4856 (args)
4857 Lisp_Object args;
4858{
4859 register Lisp_Object val;
4860 register int count = specpdl_ptr - specpdl;
4861
4862 record_unwind_protect (Fset_window_configuration,
43bad991 4863 Fcurrent_window_configuration (Qnil));
7ab12479
JB
4864 val = Fprogn (args);
4865 return unbind_to (count, val);
4866}
5500c422
GM
4867
4868\f
4869/***********************************************************************
4870 Marginal Areas
4871 ***********************************************************************/
4872
4873DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
a7bdfc08 4874 2, 3, 0,
5500c422 4875 "Set width of marginal areas of window WINDOW.\n\
a7bdfc08 4876If window is nil, set margins of the currently selected window.\n\
5500c422
GM
4877First parameter LEFT-WIDTH specifies the number of character\n\
4878cells to reserve for the left marginal area. Second parameter\n\
4879RIGHT-WIDTH does the same for the right marginal area.\n\
4880A nil width parameter means no margin.")
cfa22082 4881 (window, left, right)
5500c422
GM
4882 Lisp_Object window, left, right;
4883{
4884 struct window *w = decode_window (window);
5500c422
GM
4885
4886 if (!NILP (left))
cfa22082 4887 CHECK_NUMBER_OR_FLOAT (left, 1);
5500c422 4888 if (!NILP (right))
cfa22082 4889 CHECK_NUMBER_OR_FLOAT (right, 2);
5500c422
GM
4890
4891 /* Check widths < 0 and translate a zero width to nil.
4892 Margins that are too wide have to be checked elsewhere. */
4893 if ((INTEGERP (left) && XINT (left) < 0)
7539e11f 4894 || (FLOATP (left) && XFLOAT_DATA (left) <= 0))
5500c422
GM
4895 XSETFASTINT (left, 0);
4896 if (INTEGERP (left) && XFASTINT (left) == 0)
4897 left = Qnil;
4898
4899 if ((INTEGERP (right) && XINT (right) < 0)
7539e11f 4900 || (FLOATP (right) && XFLOAT_DATA (right) <= 0))
5500c422
GM
4901 XSETFASTINT (right, 0);
4902 if (INTEGERP (right) && XFASTINT (right) == 0)
4903 right = Qnil;
4904
4905 w->left_margin_width = left;
4906 w->right_margin_width = right;
4907
4908 ++windows_or_buffers_changed;
4909 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
4910 return Qnil;
4911}
4912
4913
4914DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
4915 0, 1, 0,
4916 "Get width of marginal areas of window WINDOW.\n\
4917If WINDOW is omitted or nil, use the currently selected window.\n\
4918Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).\n\
4919If a marginal area does not exist, its width will be returned\n\
4920as nil.")
4921 (window)
4922 Lisp_Object window;
4923{
4924 struct window *w = decode_window (window);
4925 return Fcons (w->left_margin_width, w->right_margin_width);
4926}
4927
4928
7ab12479 4929\f
5500c422
GM
4930/***********************************************************************
4931 Smooth scrolling
4932 ***********************************************************************/
4933
4934DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 1, 0,
4935 "Return the amount by which WINDOW is scrolled vertically.\n\
4936Use the selected window if WINDOW is nil or omitted.\n\
4937Value is a multiple of the canonical character height of WINDOW.")
4938 (window)
4939 Lisp_Object window;
4940{
47004952 4941 Lisp_Object result;
5500c422
GM
4942 struct frame *f;
4943 struct window *w;
4944
4945 if (NILP (window))
4946 window = selected_window;
47004952
GM
4947 else
4948 CHECK_WINDOW (window, 0);
5500c422
GM
4949 w = XWINDOW (window);
4950 f = XFRAME (w->frame);
4951
4952 if (FRAME_WINDOW_P (f))
47004952 4953 result = CANON_Y_FROM_PIXEL_Y (f, -w->vscroll);
5500c422 4954 else
47004952
GM
4955 result = make_number (0);
4956 return result;
5500c422
GM
4957}
4958
4959
4960DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
47004952
GM
4961 2, 2, 0,
4962 "Set amount by which WINDOW should be scrolled vertically to VSCROLL.\n\
5500c422 4963WINDOW nil or omitted means use the selected window. VSCROLL is a\n\
47004952
GM
4964non-negative multiple of the canonical character height of WINDOW.")
4965 (window, vscroll)
4966 Lisp_Object window, vscroll;
5500c422
GM
4967{
4968 struct window *w;
4969 struct frame *f;
4970
5500c422
GM
4971 if (NILP (window))
4972 window = selected_window;
47004952
GM
4973 else
4974 CHECK_WINDOW (window, 0);
4975 CHECK_NUMBER_OR_FLOAT (vscroll, 1);
4976
5500c422
GM
4977 w = XWINDOW (window);
4978 f = XFRAME (w->frame);
4979
4980 if (FRAME_WINDOW_P (f))
4981 {
4982 int old_dy = w->vscroll;
47004952
GM
4983
4984 w->vscroll = - CANON_Y_UNIT (f) * XFLOATINT (vscroll);
4985 w->vscroll = min (w->vscroll, 0);
5500c422
GM
4986
4987 /* Adjust glyph matrix of the frame if the virtual display
4988 area becomes larger than before. */
4989 if (w->vscroll < 0 && w->vscroll < old_dy)
4990 adjust_glyphs (f);
4991
4992 /* Prevent redisplay shortcuts. */
b1599b4c 4993 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
5500c422
GM
4994 }
4995
47004952 4996 return Fwindow_vscroll (window);
5500c422
GM
4997}
4998
7bbb5782
GM
4999\f
5000/* Call FN for all leaf windows on frame F. FN is called with the
5001 first argument being a pointer to the leaf window, and with
5002 additional arguments A1..A4. */
5003
5004void
5005foreach_window (f, fn, a1, a2, a3, a4)
5006 struct frame *f;
5007 void (* fn) ();
5008 int a1, a2, a3, a4;
5009{
5010 foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, a1, a2, a3, a4);
5011}
5012
5013
5014/* Helper function for foreach_window. Call FN for all leaf windows
5015 reachable from W. FN is called with the first argument being a
5016 pointer to the leaf window, and with additional arguments A1..A4. */
5017
5018static void
5019foreach_window_1 (w, fn, a1, a2, a3, a4)
5020 struct window *w;
5021 void (* fn) ();
5022 int a1, a2, a3, a4;
5023{
5024 while (w)
5025 {
5026 if (!NILP (w->hchild))
5027 foreach_window_1 (XWINDOW (w->hchild), fn, a1, a2, a3, a4);
5028 else if (!NILP (w->vchild))
5029 foreach_window_1 (XWINDOW (w->vchild), fn, a1, a2, a3, a4);
5030 else
5031 fn (w, a1, a2, a3, a4);
5032
5033 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5034 }
5035}
5036
5037
5038/* Freeze or unfreeze the window start of W if unless it is a
5039 mini-window or the selected window. FREEZE_P non-zero means freeze
5040 the window start. */
5041
5042static void
5043freeze_window_start (w, freeze_p)
5044 struct window *w;
5045 int freeze_p;
5046{
5047 if (w == XWINDOW (selected_window)
5048 || MINI_WINDOW_P (w)
5049 || (MINI_WINDOW_P (XWINDOW (selected_window))
24d744ac 5050 && ! NILP (Vminibuf_scroll_window)
7bbb5782
GM
5051 && w == XWINDOW (Vminibuf_scroll_window)))
5052 freeze_p = 0;
5053
5054 w->frozen_window_start_p = freeze_p;
5055}
5056
5057
5058/* Freeze or unfreeze the window starts of all leaf windows on frame
5059 F, except the selected window and a mini-window. FREEZE_P non-zero
5060 means freeze the window start. */
5061
5062void
5063freeze_window_starts (f, freeze_p)
5064 struct frame *f;
5065 int freeze_p;
5066{
5067 foreach_window (f, freeze_window_start, freeze_p);
5068}
5500c422
GM
5069
5070\f
5071/***********************************************************************
5072 Initialization
5073 ***********************************************************************/
5074
cbff28e8
RS
5075/* Return 1 if window configurations C1 and C2
5076 describe the same state of affairs. This is used by Fequal. */
5077
5078int
2f8274be 5079compare_window_configurations (c1, c2, ignore_positions)
cbff28e8 5080 Lisp_Object c1, c2;
2f8274be 5081 int ignore_positions;
cbff28e8
RS
5082{
5083 register struct save_window_data *d1, *d2;
5084 struct Lisp_Vector *sw1, *sw2;
5085 int i;
5086
4d3edcb4
GM
5087 if (!WINDOW_CONFIGURATIONP (c1))
5088 wrong_type_argument (Qwindow_configuration_p, c1);
5089 if (!WINDOW_CONFIGURATIONP (c2))
5090 wrong_type_argument (Qwindow_configuration_p, c2);
5091
cbff28e8
RS
5092 d1 = (struct save_window_data *) XVECTOR (c1);
5093 d2 = (struct save_window_data *) XVECTOR (c2);
5094 sw1 = XVECTOR (d1->saved_windows);
5095 sw2 = XVECTOR (d2->saved_windows);
5096
5097 if (! EQ (d1->frame_width, d2->frame_width))
5098 return 0;
5099 if (! EQ (d1->frame_height, d2->frame_height))
5100 return 0;
5101 if (! EQ (d1->frame_menu_bar_lines, d2->frame_menu_bar_lines))
5102 return 0;
5103 if (! EQ (d1->selected_frame, d2->selected_frame))
5104 return 0;
5105 /* Don't compare the current_window field directly.
5106 Instead see w1_is_current and w2_is_current, below. */
5107 if (! EQ (d1->current_buffer, d2->current_buffer))
5108 return 0;
2f8274be
RS
5109 if (! ignore_positions)
5110 if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
5111 return 0;
cbff28e8
RS
5112 /* Don't compare the root_window field.
5113 We don't require the two configurations
5114 to use the same window object,
5115 and the two root windows must be equivalent
5116 if everything else compares equal. */
5117 if (! EQ (d1->focus_frame, d2->focus_frame))
5118 return 0;
5119 if (! EQ (d1->min_width, d2->min_width))
5120 return 0;
5121 if (! EQ (d1->min_height, d2->min_height))
5122 return 0;
5123
5124 /* Verify that the two confis have the same number of windows. */
5125 if (sw1->size != sw2->size)
5126 return 0;
5127
5128 for (i = 0; i < sw1->size; i++)
5129 {
5130 struct saved_window *p1, *p2;
5131 int w1_is_current, w2_is_current;
5132
5133 p1 = SAVED_WINDOW_N (sw1, i);
5134 p2 = SAVED_WINDOW_N (sw2, i);
5135
5136 /* Verify that the current windows in the two
5137 configurations correspond to each other. */
5138 w1_is_current = EQ (d1->current_window, p1->window);
5139 w2_is_current = EQ (d2->current_window, p2->window);
5140
5141 if (w1_is_current != w2_is_current)
5142 return 0;
5143
5144 /* Verify that the corresponding windows do match. */
5145 if (! EQ (p1->buffer, p2->buffer))
5146 return 0;
5147 if (! EQ (p1->left, p2->left))
5148 return 0;
5149 if (! EQ (p1->top, p2->top))
5150 return 0;
5151 if (! EQ (p1->width, p2->width))
5152 return 0;
5153 if (! EQ (p1->height, p2->height))
5154 return 0;
cbff28e8
RS
5155 if (! EQ (p1->display_table, p2->display_table))
5156 return 0;
5157 if (! EQ (p1->parent, p2->parent))
5158 return 0;
5159 if (! EQ (p1->prev, p2->prev))
5160 return 0;
2f8274be
RS
5161 if (! ignore_positions)
5162 {
5163 if (! EQ (p1->hscroll, p2->hscroll))
5164 return 0;
5165 if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
5166 return 0;
5167 if (NILP (Fequal (p1->start, p2->start)))
5168 return 0;
5169 if (NILP (Fequal (p1->pointm, p2->pointm)))
5170 return 0;
5171 if (NILP (Fequal (p1->mark, p2->mark)))
5172 return 0;
5173 }
cbff28e8
RS
5174 }
5175
5176 return 1;
5177}
2f8274be
RS
5178
5179DEFUN ("compare-window-configurations", Fcompare_window_configurations,
5180 Scompare_window_configurations, 2, 2, 0,
5181 "Compare two window configurations as regards the structure of windows.\n\
5182This function ignores details such as the values of point and mark\n\
5183and scrolling positions.")
5184 (x, y)
5185 Lisp_Object x, y;
5186{
5187 if (compare_window_configurations (x, y, 1))
5188 return Qt;
5189 return Qnil;
5190}
cbff28e8 5191\f
dfcf069d 5192void
7ab12479
JB
5193init_window_once ()
5194{
1ae1a37d
GM
5195 struct frame *f = make_terminal_frame ();
5196 XSETFRAME (selected_frame, f);
5197 Vterminal_frame = selected_frame;
5198 minibuf_window = f->minibuffer_window;
5199 selected_window = f->selected_window;
5200 last_nonminibuf_frame = f;
5b03d3c0
RS
5201
5202 window_initialized = 1;
7ab12479
JB
5203}
5204
dfcf069d 5205void
7ab12479
JB
5206syms_of_window ()
5207{
fbad6f9a
GM
5208 Qleft_bitmap_area = intern ("left-bitmap-area");
5209 staticpro (&Qleft_bitmap_area);
5210 Qright_bitmap_area = intern ("right-bitmap-area");
5211 staticpro (&Qright_bitmap_area);
5212
8a37516b
GM
5213 Qwindow_size_fixed = intern ("window-size-fixed");
5214 staticpro (&Qwindow_size_fixed);
233a4a2c 5215
543f5fb1
RS
5216 staticpro (&Qwindow_configuration_change_hook);
5217 Qwindow_configuration_change_hook
5218 = intern ("window-configuration-change-hook");
5219
7ab12479
JB
5220 Qwindowp = intern ("windowp");
5221 staticpro (&Qwindowp);
5222
3f8ab7bd
RS
5223 Qwindow_configuration_p = intern ("window-configuration-p");
5224 staticpro (&Qwindow_configuration_p);
5225
806b4d9b
JB
5226 Qwindow_live_p = intern ("window-live-p");
5227 staticpro (&Qwindow_live_p);
605be8af 5228
2cccc823 5229 Qtemp_buffer_show_hook = intern ("temp-buffer-show-hook");
a58ec57d
RS
5230 staticpro (&Qtemp_buffer_show_hook);
5231
7ab12479
JB
5232 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
5233 "Non-nil means call as function to display a help buffer.\n\
c3ef6b1d 5234The function is called with one argument, the buffer to be displayed.\n\
f52cca03
RS
5235Used by `with-output-to-temp-buffer'.\n\
5236If this function is used, then it must do the entire job of showing\n\
5237the buffer; `temp-buffer-show-hook' is not run unless this function runs it.");
7ab12479
JB
5238 Vtemp_buffer_show_function = Qnil;
5239
5240 DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
5241 "If non-nil, function to call to handle `display-buffer'.\n\
5242It will receive two args, the buffer and a flag which if non-nil means\n\
5243 that the currently selected window is not acceptable.\n\
5244Commands such as `switch-to-buffer-other-window' and `find-file-other-window'\n\
5245work using this function.");
5246 Vdisplay_buffer_function = Qnil;
5247
7ab12479
JB
5248 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
5249 "Non-nil means it is the window that C-M-v in minibuffer should scroll.");
5250 Vminibuf_scroll_window = Qnil;
5251
5252 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
5253 "If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.");
5254 Vother_window_scroll_buffer = Qnil;
5255
44fa5b1e 5256 DEFVAR_BOOL ("pop-up-frames", &pop_up_frames,
700f75a4 5257 "*Non-nil means `display-buffer' should make a separate frame.");
44fa5b1e 5258 pop_up_frames = 0;
7ab12479 5259
44fa5b1e 5260 DEFVAR_LISP ("pop-up-frame-function", &Vpop_up_frame_function,
a90712c2 5261 "Function to call to handle automatic new frame creation.\n\
44fa5b1e 5262It is called with no arguments and should return a newly created frame.\n\
7ab12479 5263\n\
44fa5b1e
JB
5264A typical value might be `(lambda () (new-frame pop-up-frame-alist))'\n\
5265where `pop-up-frame-alist' would hold the default frame parameters.");
5266 Vpop_up_frame_function = Qnil;
7ab12479 5267
a90712c2
RS
5268 DEFVAR_LISP ("special-display-buffer-names", &Vspecial_display_buffer_names,
5269 "*List of buffer names that should have their own special frames.\n\
5270Displaying a buffer whose name is in this list makes a special frame for it\n\
524580a4 5271using `special-display-function'. See also `special-display-regexps'.\n\
3548e138 5272\n\
524580a4
RS
5273An element of the list can be a list instead of just a string.\n\
5274There are two ways to use a list as an element:\n\
5275 (BUFFER FRAME-PARAMETERS...) (BUFFER FUNCTION OTHER-ARGS...)\n\
5276In the first case, FRAME-PARAMETERS are used to create the frame.\n\
5277In the latter case, FUNCTION is called with BUFFER as the first argument,\n\
5278followed by OTHER-ARGS--it can display BUFFER in any way it likes.\n\
4caa7448
RS
5279All this is done by the function found in `special-display-function'.\n\
5280\n\
5281If this variable appears \"not to work\", because you add a name to it\n\
5282but that buffer still appears in the selected window, look at the\n\
5283values of `same-window-buffer-names' and `same-window-regexps'.\n\
5284Those variables take precedence over this one.");
a90712c2
RS
5285 Vspecial_display_buffer_names = Qnil;
5286
5287 DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
5288 "*List of regexps saying which buffers should have their own special frames.\n\
5289If a buffer name matches one of these regexps, it gets its own frame.\n\
5290Displaying a buffer whose name is in this list makes a special frame for it\n\
0a952b57 5291using `special-display-function'.\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 (REGEXP FRAME-PARAMETERS...) (REGEXP 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 the buffer as first argument,\n\
5298followed by OTHER-ARGS--it can display the 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 regexp to it\n\
5302but the matching buffers still appear 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_regexps = Qnil;
5306
5307 DEFVAR_LISP ("special-display-function", &Vspecial_display_function,
5308 "Function to call to make a new frame for a special buffer.\n\
0a952b57
RS
5309It is called with two arguments, the buffer and optional buffer specific\n\
5310data, and should return a window displaying that buffer.\n\
a90712c2 5311The default value makes a separate frame for the buffer,\n\
bdd3a802 5312using `special-display-frame-alist' to specify the frame parameters.\n\
a90712c2
RS
5313\n\
5314A buffer is special if its is listed in `special-display-buffer-names'\n\
5315or matches a regexp in `special-display-regexps'.");
5316 Vspecial_display_function = Qnil;
5317
855d8627
RS
5318 DEFVAR_LISP ("same-window-buffer-names", &Vsame_window_buffer_names,
5319 "*List of buffer names that should appear in the selected window.\n\
5320Displaying one of these buffers using `display-buffer' or `pop-to-buffer'\n\
5321switches to it in the selected window, rather than making it appear\n\
2e5ce1a0 5322in some other window.\n\
855d8627
RS
5323\n\
5324An element of the list can be a cons cell instead of just a string.\n\
5325Then the car must be a string, which specifies the buffer name.\n\
5326This is for compatibility with `special-display-buffer-names';\n\
5327the cdr of the cons cell is ignored.\n\
5328\n\
5329See also `same-window-regexps'.");
5330 Vsame_window_buffer_names = Qnil;
5331
5332 DEFVAR_LISP ("same-window-regexps", &Vsame_window_regexps,
5333 "*List of regexps saying which buffers should appear in the selected window.\n\
5334If a buffer name matches one of these regexps, then displaying it\n\
5335using `display-buffer' or `pop-to-buffer' switches to it\n\
5336in the selected window, rather than making it appear in some other window.\n\
5337\n\
5338An element of the list can be a cons cell instead of just a string.\n\
5339Then the car must be a string, which specifies the buffer name.\n\
5340This is for compatibility with `special-display-buffer-names';\n\
5341the cdr of the cons cell is ignored.\n\
5342\n\
5343See also `same-window-buffer-names'.");
5344 Vsame_window_regexps = Qnil;
5345
7ab12479
JB
5346 DEFVAR_BOOL ("pop-up-windows", &pop_up_windows,
5347 "*Non-nil means display-buffer should make new windows.");
5348 pop_up_windows = 1;
5349
5350 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
5351 "*Number of lines of continuity when scrolling by screenfuls.");
5352 next_screen_context_lines = 2;
5353
5354 DEFVAR_INT ("split-height-threshold", &split_height_threshold,
5355 "*display-buffer would prefer to split the largest window if this large.\n\
5356If there is only one window, it is split regardless of this value.");
5357 split_height_threshold = 500;
5358
5359 DEFVAR_INT ("window-min-height", &window_min_height,
5360 "*Delete any window less than this tall (including its mode line).");
5361 window_min_height = 4;
5362
5363 DEFVAR_INT ("window-min-width", &window_min_width,
5364 "*Delete any window less than this wide.");
5365 window_min_width = 10;
5366
5500c422
GM
5367 DEFVAR_LISP ("scroll-preserve-screen-position",
5368 &Vscroll_preserve_screen_position,
9317a85d 5369 "*Nonzero means scroll commands move point to keep its screen line unchanged.");
5500c422 5370 Vscroll_preserve_screen_position = Qnil;
9317a85d 5371
543f5fb1
RS
5372 DEFVAR_LISP ("window-configuration-change-hook",
5373 &Vwindow_configuration_change_hook,
5374 "Functions to call when window configuration changes.\n\
e3e041eb 5375The selected frame is the one whose configuration has changed.");
543f5fb1
RS
5376 Vwindow_configuration_change_hook = Qnil;
5377
7ab12479
JB
5378 defsubr (&Sselected_window);
5379 defsubr (&Sminibuffer_window);
5380 defsubr (&Swindow_minibuffer_p);
5381 defsubr (&Swindowp);
806b4d9b 5382 defsubr (&Swindow_live_p);
7ab12479
JB
5383 defsubr (&Spos_visible_in_window_p);
5384 defsubr (&Swindow_buffer);
5385 defsubr (&Swindow_height);
5386 defsubr (&Swindow_width);
5387 defsubr (&Swindow_hscroll);
5388 defsubr (&Sset_window_hscroll);
190eb263
RS
5389 defsubr (&Swindow_redisplay_end_trigger);
5390 defsubr (&Sset_window_redisplay_end_trigger);
7ab12479 5391 defsubr (&Swindow_edges);
d5783c40
JB
5392 defsubr (&Scoordinates_in_window_p);
5393 defsubr (&Swindow_at);
7ab12479
JB
5394 defsubr (&Swindow_point);
5395 defsubr (&Swindow_start);
5396 defsubr (&Swindow_end);
5397 defsubr (&Sset_window_point);
5398 defsubr (&Sset_window_start);
5399 defsubr (&Swindow_dedicated_p);
d207b766 5400 defsubr (&Sset_window_dedicated_p);
7ab12479
JB
5401 defsubr (&Swindow_display_table);
5402 defsubr (&Sset_window_display_table);
5403 defsubr (&Snext_window);
5404 defsubr (&Sprevious_window);
5405 defsubr (&Sother_window);
5406 defsubr (&Sget_lru_window);
5407 defsubr (&Sget_largest_window);
5408 defsubr (&Sget_buffer_window);
5409 defsubr (&Sdelete_other_windows);
5410 defsubr (&Sdelete_windows_on);
5411 defsubr (&Sreplace_buffer_in_windows);
5412 defsubr (&Sdelete_window);
5413 defsubr (&Sset_window_buffer);
5414 defsubr (&Sselect_window);
4628f7a4
EN
5415 defsubr (&Sspecial_display_p);
5416 defsubr (&Ssame_window_p);
7ab12479
JB
5417 defsubr (&Sdisplay_buffer);
5418 defsubr (&Ssplit_window);
5419 defsubr (&Senlarge_window);
5420 defsubr (&Sshrink_window);
5421 defsubr (&Sscroll_up);
5422 defsubr (&Sscroll_down);
5423 defsubr (&Sscroll_left);
5424 defsubr (&Sscroll_right);
ccd0664b 5425 defsubr (&Sother_window_for_scrolling);
7ab12479
JB
5426 defsubr (&Sscroll_other_window);
5427 defsubr (&Srecenter);
5428 defsubr (&Smove_to_window_line);
5429 defsubr (&Swindow_configuration_p);
3f8ab7bd 5430 defsubr (&Swindow_configuration_frame);
7ab12479
JB
5431 defsubr (&Sset_window_configuration);
5432 defsubr (&Scurrent_window_configuration);
5433 defsubr (&Ssave_window_excursion);
5500c422
GM
5434 defsubr (&Sset_window_margins);
5435 defsubr (&Swindow_margins);
5436 defsubr (&Swindow_vscroll);
5437 defsubr (&Sset_window_vscroll);
2f8274be 5438 defsubr (&Scompare_window_configurations);
7ab12479
JB
5439}
5440
dfcf069d 5441void
7ab12479
JB
5442keys_of_window ()
5443{
5444 initial_define_key (control_x_map, '1', "delete-other-windows");
5445 initial_define_key (control_x_map, '2', "split-window");
5446 initial_define_key (control_x_map, '0', "delete-window");
5447 initial_define_key (control_x_map, 'o', "other-window");
5448 initial_define_key (control_x_map, '^', "enlarge-window");
5449 initial_define_key (control_x_map, '<', "scroll-left");
5450 initial_define_key (control_x_map, '>', "scroll-right");
5451
5452 initial_define_key (global_map, Ctl ('V'), "scroll-up");
5453 initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
5454 initial_define_key (meta_map, 'v', "scroll-down");
5455
5456 initial_define_key (global_map, Ctl('L'), "recenter");
5457 initial_define_key (meta_map, 'r', "move-to-window-line");
5458}