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