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