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