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