(buffer-menu): Undo previous change.
[bpt/emacs.git] / src / window.c
CommitLineData
7ab12479
JB
1/* Window creation, deletion and examination for GNU Emacs.
2 Does not include redisplay.
89bca612 3 Copyright (C) 1985, 1986, 1987, 1993, 1994 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
19the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
18160b98 21#include <config.h>
7ab12479
JB
22#include "lisp.h"
23#include "buffer.h"
44fa5b1e 24#include "frame.h"
7ab12479
JB
25#include "window.h"
26#include "commands.h"
27#include "indent.h"
28#include "termchar.h"
29#include "disptab.h"
f8026fd8 30#include "keyboard.h"
7ab12479 31
806b4d9b 32Lisp_Object Qwindowp, Qwindow_live_p;
7ab12479
JB
33
34Lisp_Object Fnext_window (), Fdelete_window (), Fselect_window ();
35Lisp_Object Fset_window_buffer (), Fsplit_window (), Frecenter ();
36
fd482be5 37void delete_all_subwindows ();
7ab12479
JB
38static struct window *decode_window();
39
40/* This is the window in which the terminal's cursor should
41 be left when nothing is being done with it. This must
42 always be a leaf window, and its buffer is selected by
43 the top level editing loop at the end of each command.
44
45 This value is always the same as
44fa5b1e 46 FRAME_SELECTED_WINDOW (selected_frame). */
7ab12479
JB
47
48Lisp_Object selected_window;
49
44fa5b1e 50/* The minibuffer window of the selected frame.
7ab12479
JB
51 Note that you cannot test for minibufferness of an arbitrary window
52 by comparing against this; but you can test for minibufferness of
53 the selected window. */
54Lisp_Object minibuf_window;
55
56/* Non-nil means it is the window for C-M-v to scroll
57 when the minibuffer is selected. */
58Lisp_Object Vminibuf_scroll_window;
59
60/* Non-nil means this is the buffer whose window C-M-v should scroll. */
61Lisp_Object Vother_window_scroll_buffer;
62
7ab12479
JB
63/* Non-nil means it's function to call to display temp buffers. */
64Lisp_Object Vtemp_buffer_show_function;
65
66/* If a window gets smaller than either of these, it is removed. */
67int window_min_height;
68int window_min_width;
69
70/* Nonzero implies Fdisplay_buffer should create windows. */
71int pop_up_windows;
72
44fa5b1e
JB
73/* Nonzero implies make new frames for Fdisplay_buffer. */
74int pop_up_frames;
7ab12479
JB
75
76/* Non-nil means use this function instead of default */
44fa5b1e 77Lisp_Object Vpop_up_frame_function;
7ab12479
JB
78
79/* Function to call to handle Fdisplay_buffer. */
80Lisp_Object Vdisplay_buffer_function;
81
a90712c2
RS
82/* List of buffer *names* for buffers that should have their own frames. */
83Lisp_Object Vspecial_display_buffer_names;
84
85/* List of regexps for buffer names that should have their own frames. */
86Lisp_Object Vspecial_display_regexps;
87
88/* Function to pop up a special frame. */
89Lisp_Object Vspecial_display_function;
90
7ab12479
JB
91/* Fdisplay_buffer always splits the largest window
92 if that window is more than this high. */
93int split_height_threshold;
94
95/* Number of lines of continuity in scrolling by screenfuls. */
96int next_screen_context_lines;
97
98/* Incremented for each window created. */
99static int sequence_number;
100
101#define min(a, b) ((a) < (b) ? (a) : (b))
102\f
103DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
104 "Returns t if OBJ is a window.")
105 (obj)
106 Lisp_Object obj;
107{
108 return XTYPE (obj) == Lisp_Window ? Qt : Qnil;
109}
110
806b4d9b 111DEFUN ("window-live-p", Fwindow_live_p, Swindow_live_p, 1, 1, 0,
605be8af
JB
112 "Returns t if OBJ is a window which is currently visible.")
113 (obj)
114 Lisp_Object obj;
115{
116 return ((XTYPE (obj) == Lisp_Window
117 && ! NILP (XWINDOW (obj)->buffer))
118 ? Qt : Qnil);
119}
120
7ab12479
JB
121Lisp_Object
122make_window ()
123{
124 register Lisp_Object val;
125 register struct window *p;
126
127 /* Add sizeof (Lisp_Object) here because sizeof (struct Lisp_Vector)
128 includes the first element. */
129 val = Fmake_vector (
130 make_number ((sizeof (struct window) - sizeof (struct Lisp_Vector)
131 + sizeof (Lisp_Object))
132 / sizeof (Lisp_Object)),
133 Qnil);
134 XSETTYPE (val, Lisp_Window);
135 p = XWINDOW (val);
136 XFASTINT (p->sequence_number) = ++sequence_number;
137 XFASTINT (p->left) = XFASTINT (p->top)
138 = XFASTINT (p->height) = XFASTINT (p->width)
139 = XFASTINT (p->hscroll) = 0;
140 XFASTINT (p->last_point_x) = XFASTINT (p->last_point_y) = 0;
141 p->start = Fmake_marker ();
142 p->pointm = Fmake_marker ();
143 XFASTINT (p->use_time) = 0;
44fa5b1e 144 p->frame = Qnil;
7ab12479
JB
145 p->display_table = Qnil;
146 p->dedicated = Qnil;
147 return val;
148}
149
150DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0,
151 "Return the window that the cursor now appears in and commands apply to.")
152 ()
153{
154 return selected_window;
155}
156
83762ba4
JB
157DEFUN ("minibuffer-window", Fminibuffer_window, Sminibuffer_window, 0, 1, 0,
158 "Return the window used now for minibuffers.\n\
159If the optional argument FRAME is specified, return the minibuffer window\n\
160used by that frame.")
161 (frame)
162 Lisp_Object frame;
7ab12479 163{
44fa5b1e 164#ifdef MULTI_FRAME
83762ba4
JB
165 if (NILP (frame))
166 XSET (frame, Lisp_Frame, selected_frame);
167 else
168 CHECK_LIVE_FRAME (frame, 0);
169#endif
170
171 return FRAME_MINIBUF_WINDOW (XFRAME (frame));
7ab12479
JB
172}
173
605be8af 174DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1, 0,
7ab12479
JB
175 "Returns non-nil if WINDOW is a minibuffer window.")
176 (window)
177 Lisp_Object window;
178{
179 struct window *w = decode_window (window);
180 return (MINI_WINDOW_P (w) ? Qt : Qnil);
181}
182
183DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
184 Spos_visible_in_window_p, 0, 2, 0,
44fa5b1e 185 "Return t if position POS is currently on the frame in WINDOW.\n\
7ab12479
JB
186Returns nil if that position is scrolled vertically out of view.\n\
187POS defaults to point; WINDOW, to the selected window.")
188 (pos, window)
189 Lisp_Object pos, window;
190{
191 register struct window *w;
192 register int top;
193 register int height;
194 register int posint;
195 register struct buffer *buf;
196 struct position posval;
afdb2485 197 int hscroll;
7ab12479 198
265a9e55 199 if (NILP (pos))
5ce7b543 200 posint = PT;
7ab12479
JB
201 else
202 {
203 CHECK_NUMBER_COERCE_MARKER (pos, 0);
204 posint = XINT (pos);
205 }
206
605be8af 207 w = decode_window (window);
7ab12479 208 top = marker_position (w->start);
afdb2485 209 hscroll = XINT (w->hscroll);
7ab12479
JB
210
211 if (posint < top)
212 return Qnil;
213
214 height = XFASTINT (w->height) - ! MINI_WINDOW_P (w);
215
216 buf = XBUFFER (w->buffer);
217 if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf))
218 {
44fa5b1e 219 /* If frame is up to date,
7ab12479
JB
220 use the info recorded about how much text fit on it. */
221 if (posint < BUF_Z (buf) - XFASTINT (w->window_end_pos)
222 || (XFASTINT (w->window_end_vpos) < height))
223 return Qt;
224 return Qnil;
225 }
226 else
227 {
33eb4ede 228 if (posint > BUF_ZV (buf))
7ab12479
JB
229 return Qnil;
230
231 /* If that info is not correct, calculate afresh */
afdb2485
KH
232 posval = *compute_motion (top, 0, (hscroll ? 1 - hscroll : 0),
233 posint, height, 0,
535e0b8e 234 window_internal_width (w) - 1,
e37f06d7 235 hscroll, 0, w);
7ab12479
JB
236
237 return posval.vpos < height ? Qt : Qnil;
238 }
239}
240\f
241static struct window *
242decode_window (window)
243 register Lisp_Object window;
244{
265a9e55 245 if (NILP (window))
7ab12479
JB
246 return XWINDOW (selected_window);
247
605be8af 248 CHECK_LIVE_WINDOW (window, 0);
7ab12479
JB
249 return XWINDOW (window);
250}
251
252DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
253 "Return the buffer that WINDOW is displaying.")
254 (window)
255 Lisp_Object window;
256{
257 return decode_window (window)->buffer;
258}
259
260DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0,
261 "Return the number of lines in WINDOW (including its mode line).")
262 (window)
263 Lisp_Object window;
264{
265 return decode_window (window)->height;
266}
267
268DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
3b5908ef
RS
269 "Return the number of display columns in WINDOW.\n\
270This is the width that is usable columns available for text in WINDOW.\n\
271If you want to find out how many columns WINDOW takes up,\n\
272use (let ((edges (window-edges))) (- (nth 2 edges) (nth 0 edges))).")
7ab12479
JB
273 (window)
274 Lisp_Object window;
275{
ee61d94e 276 return make_number (window_internal_width (decode_window (window)));
7ab12479
JB
277}
278
279DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
280 "Return the number of columns by which WINDOW is scrolled from left margin.")
281 (window)
282 Lisp_Object window;
283{
284 return decode_window (window)->hscroll;
285}
286
287DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
288 "Set number of columns WINDOW is scrolled from left margin to NCOL.\n\
289NCOL should be zero or positive.")
290 (window, ncol)
291 register Lisp_Object window, ncol;
292{
293 register struct window *w;
294
295 CHECK_NUMBER (ncol, 1);
296 if (XINT (ncol) < 0) XFASTINT (ncol) = 0;
297 if (XFASTINT (ncol) >= (1 << (SHORTBITS - 1)))
298 args_out_of_range (ncol, Qnil);
299 w = decode_window (window);
7f4161e0 300 if (XINT (w->hscroll) != XINT (ncol))
7ab12479
JB
301 clip_changed = 1; /* Prevent redisplay shortcuts */
302 w->hscroll = ncol;
303 return ncol;
304}
305
306DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0,
307 "Return a list of the edge coordinates of WINDOW.\n\
44fa5b1e 308\(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.\n\
7ab12479
JB
309RIGHT is one more than the rightmost column used by WINDOW,\n\
310and BOTTOM is one more than the bottommost row used by WINDOW\n\
311 and its mode-line.")
312 (window)
313 Lisp_Object window;
314{
315 register struct window *w = decode_window (window);
316
317 return Fcons (w->left, Fcons (w->top,
318 Fcons (make_number (XFASTINT (w->left) + XFASTINT (w->width)),
319 Fcons (make_number (XFASTINT (w->top)
320 + XFASTINT (w->height)),
321 Qnil))));
322}
323
d5783c40
JB
324/* Test if the character at column *x, row *y is within window *w.
325 If it is not, return 0;
326 if it is in the window's text area,
327 set *x and *y to its location relative to the upper left corner
328 of the window, and
329 return 1;
330 if it is on the window's modeline, return 2;
331 if it is on the border between the window and its right sibling,
332 return 3. */
333static int
334coordinates_in_window (w, x, y)
335 register struct window *w;
336 register int *x, *y;
337{
338 register int left = XINT (w->left);
339 register int width = XINT (w->width);
340 register int window_height = XINT (w->height);
341 register int top = XFASTINT (w->top);
342
343 if ( *x < left || *x >= left + width
344 || *y < top || *y >= top + window_height)
345 return 0;
346
347 /* Is the character is the mode line? */
348 if (*y == top + window_height - 1
05c2896a 349 && ! MINI_WINDOW_P (w))
d5783c40
JB
350 return 2;
351
352 /* Is the character in the right border? */
353 if (*x == left + width - 1
44fa5b1e 354 && left + width != FRAME_WIDTH (XFRAME (w->frame)))
d5783c40
JB
355 return 3;
356
357 *x -= left;
358 *y -= top;
359 return 1;
360}
361
362DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
363 Scoordinates_in_window_p, 2, 2, 0,
364 "Return non-nil if COORDINATES are in WINDOW.\n\
1113d9db 365COORDINATES is a cons of the form (X . Y), X and Y being distances\n\
44fa5b1e 366measured in characters from the upper-left corner of the frame.\n\
1113d9db 367(0 . 0) denotes the character in the upper left corner of the\n\
44fa5b1e 368frame.\n\
d5783c40
JB
369If COORDINATES are in the text portion of WINDOW,\n\
370 the coordinates relative to the window are returned.\n\
e5d77022 371If they are in the mode line of WINDOW, `mode-line' is returned.\n\
d5783c40 372If they are on the border between WINDOW and its right sibling,\n\
e5d77022 373 `vertical-line' is returned.")
d5783c40
JB
374 (coordinates, window)
375 register Lisp_Object coordinates, window;
376{
377 int x, y;
378
605be8af 379 CHECK_LIVE_WINDOW (window, 0);
d5783c40
JB
380 CHECK_CONS (coordinates, 1);
381 x = XINT (Fcar (coordinates));
382 y = XINT (Fcdr (coordinates));
383
384 switch (coordinates_in_window (XWINDOW (window), &x, &y))
385 {
386 case 0: /* NOT in window at all. */
387 return Qnil;
388
389 case 1: /* In text part of window. */
390 return Fcons (x, y);
391
392 case 2: /* In mode line of window. */
393 return Qmode_line;
394
395 case 3: /* On right border of window. */
e5d77022 396 return Qvertical_line;
d5783c40
JB
397
398 default:
399 abort ();
400 }
401}
402
7ab12479 403/* Find the window containing column x, row y, and return it as a
d5783c40
JB
404 Lisp_Object. If x, y is on the window's modeline, set *part
405 to 1; if it is on the separating line between the window and its
406 right sibling, set it to 2; otherwise set it to 0. If there is no
407 window under x, y return nil and leave *part unmodified. */
7ab12479 408Lisp_Object
44fa5b1e
JB
409window_from_coordinates (frame, x, y, part)
410 FRAME_PTR frame;
7ab12479 411 int x, y;
d5783c40 412 int *part;
7ab12479
JB
413{
414 register Lisp_Object tem, first;
415
44fa5b1e 416 tem = first = FRAME_SELECTED_WINDOW (frame);
7ab12479 417
d5783c40 418 do
7ab12479
JB
419 {
420 int found = coordinates_in_window (XWINDOW (tem), &x, &y);
421
422 if (found)
423 {
d5783c40 424 *part = found - 1;
7ab12479
JB
425 return tem;
426 }
427
d5783c40 428 tem = Fnext_window (tem, Qt, Qlambda);
7ab12479 429 }
d5783c40
JB
430 while (! EQ (tem, first));
431
432 return Qnil;
7ab12479
JB
433}
434
ab17c3f2 435DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
b0c33a94 436 "Return window containing coordinates X and Y on FRAME.\n\
44fa5b1e
JB
437If omitted, FRAME defaults to the currently selected frame.\n\
438The top left corner of the frame is considered to be row 0,\n\
95605e15 439column 0.")
b0c33a94
RS
440 (x, y, frame)
441 Lisp_Object x, y, frame;
7ab12479
JB
442{
443 int part;
444
4b206065 445#ifdef MULTI_FRAME
44fa5b1e
JB
446 if (NILP (frame))
447 XSET (frame, Lisp_Frame, selected_frame);
d5783c40 448 else
44fa5b1e 449 CHECK_LIVE_FRAME (frame, 2);
4b206065 450#endif
b0c33a94
RS
451 CHECK_NUMBER (x, 0);
452 CHECK_NUMBER (y, 1);
7ab12479 453
44fa5b1e 454 return window_from_coordinates (XFRAME (frame),
b0c33a94 455 XINT (x), XINT (y),
7ab12479
JB
456 &part);
457}
458
459DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
460 "Return current value of point in WINDOW.\n\
461For a nonselected window, this is the value point would have\n\
462if that window were selected.\n\
463\n\
464Note that, when WINDOW is the selected window and its buffer\n\
465is also currently selected, the value returned is the same as (point).\n\
466It would be more strictly correct to return the `top-level' value\n\
467of point, outside of any save-excursion forms.\n\
468But that is hard to define.")
469 (window)
470 Lisp_Object window;
471{
472 register struct window *w = decode_window (window);
473
474 if (w == XWINDOW (selected_window)
475 && current_buffer == XBUFFER (w->buffer))
476 return Fpoint ();
477 return Fmarker_position (w->pointm);
478}
479
480DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
481 "Return position at which display currently starts in WINDOW.")
482 (window)
483 Lisp_Object window;
484{
485 return Fmarker_position (decode_window (window)->start);
486}
487
488DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 1, 0,
489 "Return position at which display currently ends in WINDOW.")
490 (window)
491 Lisp_Object window;
492{
493 Lisp_Object value;
494 struct window *w = decode_window (window);
5a41ab94
RS
495 Lisp_Object buf;
496
497 buf = w->buffer;
498 CHECK_BUFFER (buf, 0);
499
7ab12479 500 XSET (value, Lisp_Int,
5a41ab94 501 BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
7ab12479
JB
502
503 return value;
504}
505
506DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
507 "Make point value in WINDOW be at position POS in WINDOW's buffer.")
508 (window, pos)
509 Lisp_Object window, pos;
510{
511 register struct window *w = decode_window (window);
512
513 CHECK_NUMBER_COERCE_MARKER (pos, 1);
514 if (w == XWINDOW (selected_window))
515 Fgoto_char (pos);
516 else
517 set_marker_restricted (w->pointm, pos, w->buffer);
518
519 return pos;
520}
521
522DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
523 "Make display in WINDOW start at position POS in WINDOW's buffer.\n\
524Optional third arg NOFORCE non-nil inhibits next redisplay\n\
525from overriding motion of point in order to display at this exact start.")
526 (window, pos, noforce)
527 Lisp_Object window, pos, noforce;
528{
529 register struct window *w = decode_window (window);
530
531 CHECK_NUMBER_COERCE_MARKER (pos, 1);
532 set_marker_restricted (w->start, pos, w->buffer);
533 /* this is not right, but much easier than doing what is right. */
534 w->start_at_line_beg = Qnil;
265a9e55 535 if (NILP (noforce))
7ab12479
JB
536 w->force_start = Qt;
537 w->update_mode_line = Qt;
538 XFASTINT (w->last_modified) = 0;
62c07cc7
JB
539 if (!EQ (window, selected_window))
540 windows_or_buffers_changed++;
7ab12479
JB
541 return pos;
542}
543
544DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
545 1, 1, 0,
546 "Return WINDOW's dedicated object, usually t or nil.\n\
1f18c48f 547See also `set-window-dedicated-p'.")
7ab12479
JB
548 (window)
549 Lisp_Object window;
550{
551 return decode_window (window)->dedicated;
552}
553
d207b766
RS
554DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p,
555 Sset_window_dedicated_p, 2, 2, 0,
556 "Control whether WINDOW is dedicated to the buffer it displays.\n\
557If it is dedicated, Emacs will not automatically change\n\
558which buffer appears in it.\n\
559The second argument is the new value for the dedication flag;\n\
560non-nil means yes.")
7ab12479
JB
561 (window, arg)
562 Lisp_Object window, arg;
563{
564 register struct window *w = decode_window (window);
565
265a9e55 566 if (NILP (arg))
7ab12479
JB
567 w->dedicated = Qnil;
568 else
d207b766 569 w->dedicated = Qt;
7ab12479
JB
570
571 return w->dedicated;
572}
573
574DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
575 0, 1, 0,
576 "Return the display-table that WINDOW is using.")
577 (window)
578 Lisp_Object window;
579{
580 return decode_window (window)->display_table;
581}
582
583/* Get the display table for use currently on window W.
584 This is either W's display table or W's buffer's display table.
585 Ignore the specified tables if they are not valid;
586 if no valid table is specified, return 0. */
587
588struct Lisp_Vector *
589window_display_table (w)
590 struct window *w;
591{
592 Lisp_Object tem;
593 tem = w->display_table;
594 if (XTYPE (tem) == Lisp_Vector && XVECTOR (tem)->size == DISP_TABLE_SIZE)
595 return XVECTOR (tem);
596 tem = XBUFFER (w->buffer)->display_table;
597 if (XTYPE (tem) == Lisp_Vector && XVECTOR (tem)->size == DISP_TABLE_SIZE)
598 return XVECTOR (tem);
599 tem = Vstandard_display_table;
600 if (XTYPE (tem) == Lisp_Vector && XVECTOR (tem)->size == DISP_TABLE_SIZE)
601 return XVECTOR (tem);
602 return 0;
603}
604
3a2712f9 605DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_display_table, 2, 2, 0,
7ab12479
JB
606 "Set WINDOW's display-table to TABLE.")
607 (window, table)
608 register Lisp_Object window, table;
609{
610 register struct window *w;
611 register Lisp_Object z; /* Return value. */
612
613 w = decode_window (window);
614 w->display_table = table;
615 return table;
616}
617\f
618/* Record info on buffer window w is displaying
619 when it is about to cease to display that buffer. */
620static
621unshow_buffer (w)
622 register struct window *w;
623{
12cae7c0 624 Lisp_Object buf;
7ab12479 625
12cae7c0 626 buf = w->buffer;
7ab12479
JB
627 if (XBUFFER (buf) != XMARKER (w->pointm)->buffer)
628 abort ();
629
573f41ab 630#if 0
7ab12479
JB
631 if (w == XWINDOW (selected_window)
632 || ! EQ (buf, XWINDOW (selected_window)->buffer))
633 /* Do this except when the selected window's buffer
634 is being removed from some other window. */
573f41ab
RS
635#endif
636 /* last_window_start records the start position that this buffer
637 had in the last window to be disconnected from it.
638 Now that this statement is unconditional,
639 it is possible for the buffer to be displayed in the
640 selected window, while last_window_start reflects another
641 window which was recently showing the same buffer.
642 Some people might say that might be a good thing. Let's see. */
7ab12479
JB
643 XBUFFER (buf)->last_window_start = marker_position (w->start);
644
645 /* Point in the selected window's buffer
646 is actually stored in that buffer, and the window's pointm isn't used.
647 So don't clobber point in that buffer. */
648 if (! EQ (buf, XWINDOW (selected_window)->buffer))
649 BUF_PT (XBUFFER (buf))
650 = clip_to_bounds (BUF_BEGV (XBUFFER (buf)),
651 marker_position (w->pointm),
652 BUF_ZV (XBUFFER (buf)));
653}
654
655/* Put replacement into the window structure in place of old. */
656static
657replace_window (old, replacement)
658 Lisp_Object old, replacement;
659{
660 register Lisp_Object tem;
661 register struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
662
44fa5b1e
JB
663 /* If OLD is its frame's root_window, then replacement is the new
664 root_window for that frame. */
7ab12479 665
7f4161e0 666 if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
44fa5b1e 667 FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
7ab12479
JB
668
669 p->left = o->left;
670 p->top = o->top;
671 p->width = o->width;
672 p->height = o->height;
673
674 p->next = tem = o->next;
265a9e55 675 if (!NILP (tem))
7ab12479
JB
676 XWINDOW (tem)->prev = replacement;
677
678 p->prev = tem = o->prev;
265a9e55 679 if (!NILP (tem))
7ab12479
JB
680 XWINDOW (tem)->next = replacement;
681
682 p->parent = tem = o->parent;
265a9e55 683 if (!NILP (tem))
7ab12479
JB
684 {
685 if (EQ (XWINDOW (tem)->vchild, old))
686 XWINDOW (tem)->vchild = replacement;
687 if (EQ (XWINDOW (tem)->hchild, old))
688 XWINDOW (tem)->hchild = replacement;
689 }
690
691/*** Here, if replacement is a vertical combination
692and so is its new parent, we should make replacement's
693children be children of that parent instead. ***/
694}
695
696DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
697 "Remove WINDOW from the display. Default is selected window.")
698 (window)
699 register Lisp_Object window;
700{
701 register Lisp_Object tem, parent, sib;
702 register struct window *p;
703 register struct window *par;
704
605be8af
JB
705 /* Because this function is called by other C code on non-leaf
706 windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
707 so we can't decode_window here. */
265a9e55 708 if (NILP (window))
7ab12479
JB
709 window = selected_window;
710 else
711 CHECK_WINDOW (window, 0);
7ab12479 712 p = XWINDOW (window);
605be8af
JB
713
714 /* It's okay to delete an already-deleted window. */
715 if (NILP (p->buffer)
716 && NILP (p->hchild)
717 && NILP (p->vchild))
718 return Qnil;
719
7ab12479 720 parent = p->parent;
265a9e55 721 if (NILP (parent))
7ab12479
JB
722 error ("Attempt to delete minibuffer or sole ordinary window");
723 par = XWINDOW (parent);
724
725 windows_or_buffers_changed++;
726
605be8af
JB
727 /* Are we trying to delete any frame's selected window? */
728 {
0def0403 729 Lisp_Object frame, pwindow;
605be8af 730
0def0403
RS
731 /* See if the frame's selected window is either WINDOW
732 or any subwindow of it, by finding all that window's parents
733 and comparing each one with WINDOW. */
734 frame = WINDOW_FRAME (XWINDOW (window));
735 pwindow = FRAME_SELECTED_WINDOW (XFRAME (frame));
736
737 while (!NILP (pwindow))
738 {
739 if (EQ (window, pwindow))
740 break;
741 pwindow = XWINDOW (pwindow)->parent;
742 }
743
744 if (EQ (window, pwindow))
605be8af 745 {
89bca612
RS
746 Lisp_Object alternative;
747 alternative = Fnext_window (window, Qlambda, Qnil);
605be8af
JB
748
749 /* If we're about to delete the selected window on the
750 selected frame, then we should use Fselect_window to select
751 the new window. On the other hand, if we're about to
752 delete the selected window on any other frame, we shouldn't do
753 anything but set the frame's selected_window slot. */
754 if (EQ (window, selected_window))
755 Fselect_window (alternative);
756 else
0def0403 757 FRAME_SELECTED_WINDOW (XFRAME (frame)) = alternative;
605be8af
JB
758 }
759 }
7ab12479
JB
760
761 tem = p->buffer;
762 /* tem is null for dummy parent windows
763 (which have inferiors but not any contents themselves) */
265a9e55 764 if (!NILP (tem))
7ab12479
JB
765 {
766 unshow_buffer (p);
767 unchain_marker (p->pointm);
768 unchain_marker (p->start);
7ab12479
JB
769 }
770
771 tem = p->next;
265a9e55 772 if (!NILP (tem))
7ab12479
JB
773 XWINDOW (tem)->prev = p->prev;
774
775 tem = p->prev;
265a9e55 776 if (!NILP (tem))
7ab12479
JB
777 XWINDOW (tem)->next = p->next;
778
779 if (EQ (window, par->hchild))
780 par->hchild = p->next;
781 if (EQ (window, par->vchild))
782 par->vchild = p->next;
783
784 /* Find one of our siblings to give our space to. */
785 sib = p->prev;
265a9e55 786 if (NILP (sib))
7ab12479
JB
787 {
788 /* If p gives its space to its next sibling, that sibling needs
789 to have its top/left side pulled back to where p's is.
790 set_window_{height,width} will re-position the sibling's
791 children. */
792 sib = p->next;
7f4161e0
JB
793 XWINDOW (sib)->top = p->top;
794 XWINDOW (sib)->left = p->left;
7ab12479
JB
795 }
796
797 /* Stretch that sibling. */
265a9e55 798 if (!NILP (par->vchild))
7ab12479
JB
799 set_window_height (sib,
800 XFASTINT (XWINDOW (sib)->height) + XFASTINT (p->height),
801 1);
265a9e55 802 if (!NILP (par->hchild))
7ab12479
JB
803 set_window_width (sib,
804 XFASTINT (XWINDOW (sib)->width) + XFASTINT (p->width),
805 1);
806
807 /* If parent now has only one child,
808 put the child into the parent's place. */
7ab12479 809 tem = par->hchild;
265a9e55 810 if (NILP (tem))
7ab12479 811 tem = par->vchild;
265a9e55 812 if (NILP (XWINDOW (tem)->next))
7ab12479 813 replace_window (parent, tem);
605be8af
JB
814
815 /* Since we may be deleting combination windows, we must make sure that
816 not only p but all its children have been marked as deleted. */
817 if (! NILP (p->hchild))
818 delete_all_subwindows (XWINDOW (p->hchild));
819 else if (! NILP (p->vchild))
820 delete_all_subwindows (XWINDOW (p->vchild));
821
822 /* Mark this window as deleted. */
823 p->buffer = p->hchild = p->vchild = Qnil;
824
7ab12479
JB
825 return Qnil;
826}
827\f
7ab12479 828
44fa5b1e 829extern Lisp_Object next_frame (), prev_frame ();
7ab12479 830
26f6279d
JB
831/* This comment supplies the doc string for `next-window',
832 for make-docfile to see. We cannot put this in the real DEFUN
833 due to limits in the Unix cpp.
834
835DEFUN ("next-window", Ffoo, Sfoo, 0, 3, 0,
7ab12479 836 "Return next window after WINDOW in canonical ordering of windows.\n\
d5783c40
JB
837If omitted, WINDOW defaults to the selected window.\n\
838\n\
839Optional second arg MINIBUF t means count the minibuffer window even\n\
840if not active. MINIBUF nil or omitted means count the minibuffer iff\n\
841it is active. MINIBUF neither t nor nil means not to count the\n\
842minibuffer even if it is active.\n\
843\n\
44fa5b1e
JB
844Several frames may share a single minibuffer; if the minibuffer\n\
845counts, all windows on all frames that share that minibuffer count\n\
ed160f1f 846too. Therefore, `next-window' can be used to iterate through the\n\
44fa5b1e
JB
847set of windows even when the minibuffer is on another frame. If the\n\
848minibuffer does not count, only windows from WINDOW's frame count.\n\
d5783c40 849\n\
44fa5b1e
JB
850Optional third arg ALL-FRAMES t means include windows on all frames.\n\
851ALL-FRAMES nil or omitted means cycle within the frames as specified\n\
89bca612 852above. ALL-FRAMES = `visible' means include windows on all visible frames.\n\
f812f9c6 853ALL-FRAMES = 0 means include windows on all visible and iconified frames.\n\
89bca612 854Anything else means restrict to WINDOW's frame.\n\
dbc4e1c1
JB
855\n\
856If you use consistent values for MINIBUF and ALL-FRAMES, you can use\n\
857`next-window' to iterate through the entire cycle of acceptable\n\
858windows, eventually ending up back at the window you started with.\n\
859`previous-window' traverses the same cycle, in the reverse order.")
26f6279d
JB
860 (window, minibuf, all_frames) */
861
862DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
863 0)
44fa5b1e
JB
864 (window, minibuf, all_frames)
865 register Lisp_Object window, minibuf, all_frames;
7ab12479
JB
866{
867 register Lisp_Object tem;
d5783c40 868 Lisp_Object start_window;
7ab12479 869
265a9e55 870 if (NILP (window))
7ab12479
JB
871 window = selected_window;
872 else
605be8af 873 CHECK_LIVE_WINDOW (window, 0);
7ab12479 874
d5783c40
JB
875 start_window = window;
876
877 /* minibuf == nil may or may not include minibuffers.
878 Decide if it does. */
265a9e55 879 if (NILP (minibuf))
d5783c40
JB
880 minibuf = (minibuf_level ? Qt : Qlambda);
881
c6e73093 882#ifdef MULTI_FRAME
1bb80f72 883 /* all_frames == nil doesn't specify which frames to include. */
44fa5b1e
JB
884 if (NILP (all_frames))
885 all_frames = (EQ (minibuf, Qt)
1bb80f72
RS
886 ? (FRAME_MINIBUF_WINDOW
887 (XFRAME
888 (WINDOW_FRAME
889 (XWINDOW (window)))))
890 : Qnil);
89bca612
RS
891 else if (EQ (all_frames, Qvisible))
892 ;
f812f9c6
RS
893 else if (XFASTINT (all_frames) == 0)
894 ;
44fa5b1e
JB
895 else if (! EQ (all_frames, Qt))
896 all_frames = Qnil;
644b477c
RS
897 /* Now all_frames is t meaning search all frames,
898 nil meaning search just current frame,
f812f9c6
RS
899 visible meaning search just visible frames,
900 0 meaning search visible and iconified frames,
644b477c 901 or a window, meaning search the frame that window belongs to. */
c6e73093 902#endif
7ab12479
JB
903
904 /* Do this loop at least once, to get the next window, and perhaps
905 again, if we hit the minibuffer and that is not acceptable. */
906 do
907 {
908 /* Find a window that actually has a next one. This loop
909 climbs up the tree. */
265a9e55
JB
910 while (tem = XWINDOW (window)->next, NILP (tem))
911 if (tem = XWINDOW (window)->parent, !NILP (tem))
7ab12479 912 window = tem;
d5783c40 913 else
7ab12479 914 {
44fa5b1e
JB
915 /* We've reached the end of this frame.
916 Which other frames are acceptable? */
917 tem = WINDOW_FRAME (XWINDOW (window));
918#ifdef MULTI_FRAME
919 if (! NILP (all_frames))
1bb80f72
RS
920 {
921 Lisp_Object tem1;
922
923 tem1 = tem;
924 tem = next_frame (tem, all_frames);
925 /* In the case where the minibuffer is active,
926 and we include its frame as well as the selected one,
927 next_frame may get stuck in that frame.
928 If that happens, go back to the selected frame
929 so we can complete the cycle. */
930 if (EQ (tem, tem1))
931 XSET (tem, Lisp_Frame, selected_frame);
932 }
7ab12479 933#endif
44fa5b1e 934 tem = FRAME_ROOT_WINDOW (XFRAME (tem));
d5783c40 935
7ab12479
JB
936 break;
937 }
938
939 window = tem;
d5783c40 940
7ab12479
JB
941 /* If we're in a combination window, find its first child and
942 recurse on that. Otherwise, we've found the window we want. */
943 while (1)
944 {
265a9e55 945 if (!NILP (XWINDOW (window)->hchild))
7ab12479 946 window = XWINDOW (window)->hchild;
265a9e55 947 else if (!NILP (XWINDOW (window)->vchild))
7ab12479
JB
948 window = XWINDOW (window)->vchild;
949 else break;
950 }
951 }
d5783c40
JB
952 /* Which windows are acceptible?
953 Exit the loop and accept this window if
7ab12479 954 this isn't a minibuffer window, or
d5783c40
JB
955 we're accepting minibuffer windows, or
956 we've come all the way around and we're back at the original window. */
7ab12479 957 while (MINI_WINDOW_P (XWINDOW (window))
d5783c40 958 && ! EQ (minibuf, Qt)
7f4161e0 959 && ! EQ (window, start_window));
7ab12479
JB
960
961 return window;
962}
963
26f6279d
JB
964/* This comment supplies the doc string for `previous-window',
965 for make-docfile to see. We cannot put this in the real DEFUN
966 due to limits in the Unix cpp.
967
968DEFUN ("previous-window", Ffoo, Sfoo, 0, 3, 0,
d5783c40
JB
969 "Return the window preceeding WINDOW in canonical ordering of windows.\n\
970If omitted, WINDOW defaults to the selected window.\n\
971\n\
972Optional second arg MINIBUF t means count the minibuffer window even\n\
973if not active. MINIBUF nil or omitted means count the minibuffer iff\n\
974it is active. MINIBUF neither t nor nil means not to count the\n\
975minibuffer even if it is active.\n\
976\n\
44fa5b1e
JB
977Several frames may share a single minibuffer; if the minibuffer\n\
978counts, all windows on all frames that share that minibuffer count\n\
ed160f1f 979too. Therefore, `previous-window' can be used to iterate through\n\
44fa5b1e 980the set of windows even when the minibuffer is on another frame. If\n\
ed160f1f 981the minibuffer does not count, only windows from WINDOW's frame count\n\
d5783c40 982\n\
44fa5b1e
JB
983Optional third arg ALL-FRAMES t means include windows on all frames.\n\
984ALL-FRAMES nil or omitted means cycle within the frames as specified\n\
89bca612 985above. ALL-FRAMES = `visible' means include windows on all visible frames.\n\
f812f9c6 986ALL-FRAMES = 0 means include windows on all visible and iconified frames.\n\
89bca612 987Anything else means restrict to WINDOW's frame.\n\
dbc4e1c1
JB
988\n\
989If you use consistent values for MINIBUF and ALL-FRAMES, you can use\n\
990`previous-window' to iterate through the entire cycle of acceptable\n\
991windows, eventually ending up back at the window you started with.\n\
992`next-window' traverses the same cycle, in the reverse order.")
26f6279d
JB
993 (window, minibuf, all_frames) */
994
995
996DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
997 0)
44fa5b1e
JB
998 (window, minibuf, all_frames)
999 register Lisp_Object window, minibuf, all_frames;
7ab12479
JB
1000{
1001 register Lisp_Object tem;
d5783c40 1002 Lisp_Object start_window;
7ab12479 1003
265a9e55 1004 if (NILP (window))
7ab12479
JB
1005 window = selected_window;
1006 else
605be8af 1007 CHECK_LIVE_WINDOW (window, 0);
7ab12479 1008
d5783c40
JB
1009 start_window = window;
1010
1011 /* minibuf == nil may or may not include minibuffers.
1012 Decide if it does. */
265a9e55 1013 if (NILP (minibuf))
d5783c40
JB
1014 minibuf = (minibuf_level ? Qt : Qlambda);
1015
c6e73093 1016#ifdef MULTI_FRAME
44fa5b1e
JB
1017 /* all_frames == nil doesn't specify which frames to include.
1018 Decide which frames it includes. */
1019 if (NILP (all_frames))
1020 all_frames = (EQ (minibuf, Qt)
1021 ? (FRAME_MINIBUF_WINDOW
1022 (XFRAME
1023 (WINDOW_FRAME
d5783c40
JB
1024 (XWINDOW (window)))))
1025 : Qnil);
89bca612
RS
1026 else if (EQ (all_frames, Qvisible))
1027 ;
f812f9c6
RS
1028 else if (XFASTINT (all_frames) == 0)
1029 ;
44fa5b1e
JB
1030 else if (! EQ (all_frames, Qt))
1031 all_frames = Qnil;
644b477c
RS
1032 /* Now all_frames is t meaning search all frames,
1033 nil meaning search just current frame,
f812f9c6
RS
1034 visible meaning search just visible frames,
1035 0 meaning search visible and iconified frames,
644b477c 1036 or a window, meaning search the frame that window belongs to. */
c6e73093 1037#endif
7ab12479
JB
1038
1039 /* Do this loop at least once, to get the previous window, and perhaps
1040 again, if we hit the minibuffer and that is not acceptable. */
1041 do
1042 {
1043 /* Find a window that actually has a previous one. This loop
1044 climbs up the tree. */
265a9e55
JB
1045 while (tem = XWINDOW (window)->prev, NILP (tem))
1046 if (tem = XWINDOW (window)->parent, !NILP (tem))
7ab12479 1047 window = tem;
d5783c40 1048 else
7ab12479 1049 {
44fa5b1e
JB
1050 /* We have found the top window on the frame.
1051 Which frames are acceptable? */
1052 tem = WINDOW_FRAME (XWINDOW (window));
1053#ifdef MULTI_FRAME
1054 if (! NILP (all_frames))
dbc4e1c1
JB
1055 /* It's actually important that we use prev_frame here,
1056 rather than next_frame. All the windows acceptable
1057 according to the given parameters should form a ring;
1058 Fnext_window and Fprevious_window should go back and
1059 forth around the ring. If we use next_frame here,
1060 then Fnext_window and Fprevious_window take different
1061 paths through the set of acceptable windows.
1062 window_loop assumes that these `ring' requirement are
1063 met. */
1bb80f72
RS
1064 {
1065 Lisp_Object tem1;
1066
1067 tem1 = tem;
1068 tem = prev_frame (tem, all_frames);
1069 /* In the case where the minibuffer is active,
1070 and we include its frame as well as the selected one,
1071 next_frame may get stuck in that frame.
1072 If that happens, go back to the selected frame
1073 so we can complete the cycle. */
1074 if (EQ (tem, tem1))
1075 XSET (tem, Lisp_Frame, selected_frame);
1076 }
7ab12479 1077#endif
644b477c
RS
1078 /* If this frame has a minibuffer, find that window first,
1079 because it is conceptually the last window in that frame. */
5e12e32f
JB
1080 if (FRAME_HAS_MINIBUF_P (XFRAME (tem)))
1081 tem = FRAME_MINIBUF_WINDOW (XFRAME (tem));
1082 else
644b477c 1083 tem = FRAME_ROOT_WINDOW (XFRAME (tem));
d5783c40 1084
7ab12479
JB
1085 break;
1086 }
1087
1088 window = tem;
1089 /* If we're in a combination window, find its last child and
1090 recurse on that. Otherwise, we've found the window we want. */
1091 while (1)
1092 {
265a9e55 1093 if (!NILP (XWINDOW (window)->hchild))
7ab12479 1094 window = XWINDOW (window)->hchild;
265a9e55 1095 else if (!NILP (XWINDOW (window)->vchild))
7ab12479
JB
1096 window = XWINDOW (window)->vchild;
1097 else break;
265a9e55 1098 while (tem = XWINDOW (window)->next, !NILP (tem))
7ab12479
JB
1099 window = tem;
1100 }
1101 }
d5783c40
JB
1102 /* Which windows are acceptable?
1103 Exit the loop and accept this window if
7ab12479 1104 this isn't a minibuffer window, or
d5783c40
JB
1105 we're accepting minibuffer windows, or
1106 we've come all the way around and we're back at the original window. */
7ab12479 1107 while (MINI_WINDOW_P (XWINDOW (window))
d5783c40 1108 && !EQ (minibuf, Qt)
7f4161e0 1109 && !EQ (window, start_window));
7ab12479
JB
1110
1111 return window;
1112}
1113
62c07cc7 1114DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
44fa5b1e
JB
1115 "Select the ARG'th different window on this frame.\n\
1116All windows on current frame are arranged in a cyclic order.\n\
7ab12479
JB
1117This command selects the window ARG steps away in that order.\n\
1118A negative ARG moves in the opposite order. If the optional second\n\
44fa5b1e
JB
1119argument ALL_FRAMES is non-nil, cycle through all frames.")
1120 (n, all_frames)
1121 register Lisp_Object n, all_frames;
7ab12479
JB
1122{
1123 register int i;
1124 register Lisp_Object w;
1125
1126 CHECK_NUMBER (n, 0);
1127 w = selected_window;
1128 i = XINT (n);
1129
1130 while (i > 0)
1131 {
44fa5b1e 1132 w = Fnext_window (w, Qnil, all_frames);
7ab12479
JB
1133 i--;
1134 }
1135 while (i < 0)
1136 {
44fa5b1e 1137 w = Fprevious_window (w, Qnil, all_frames);
7ab12479
JB
1138 i++;
1139 }
1140 Fselect_window (w);
1141 return Qnil;
1142}
1143\f
1144/* Look at all windows, performing an operation specified by TYPE
1145 with argument OBJ.
75d8f668 1146 If FRAMES is Qt, look at all frames;
75d8f668 1147 Qnil, look at just the selected frame;
89bca612 1148 Qvisible, look at visible frames;
75d8f668 1149 a frame, just look at windows on that frame.
7ab12479
JB
1150 If MINI is non-zero, perform the operation on minibuffer windows too.
1151*/
1152
1153enum window_loop
1154{
1155 WINDOW_LOOP_UNUSED,
1156 GET_BUFFER_WINDOW, /* Arg is buffer */
1157 GET_LRU_WINDOW, /* Arg is t for full-width windows only */
1158 DELETE_OTHER_WINDOWS, /* Arg is window not to delete */
1159 DELETE_BUFFER_WINDOWS, /* Arg is buffer */
1160 GET_LARGEST_WINDOW,
a68c0d3b 1161 UNSHOW_BUFFER /* Arg is buffer */
7ab12479
JB
1162};
1163
1164static Lisp_Object
44fa5b1e 1165window_loop (type, obj, mini, frames)
7ab12479 1166 enum window_loop type;
44fa5b1e 1167 register Lisp_Object obj, frames;
7ab12479
JB
1168 int mini;
1169{
1170 register Lisp_Object w;
1171 register Lisp_Object best_window;
1172 register Lisp_Object next_window;
4b206065 1173 register Lisp_Object last_window;
44fa5b1e 1174 FRAME_PTR frame;
89bca612
RS
1175 Lisp_Object frame_arg;
1176 frame_arg = Qt;
44fa5b1e 1177
4b206065 1178#ifdef MULTI_FRAME
44fa5b1e
JB
1179 /* If we're only looping through windows on a particular frame,
1180 frame points to that frame. If we're looping through windows
1181 on all frames, frame is 0. */
1182 if (FRAMEP (frames))
1183 frame = XFRAME (frames);
1184 else if (NILP (frames))
1185 frame = selected_frame;
7ab12479 1186 else
44fa5b1e 1187 frame = 0;
89bca612
RS
1188 if (frame)
1189 frame_arg = Qlambda;
f812f9c6
RS
1190 else if (XFASTINT (frames) == 0)
1191 frame_arg = frames;
89bca612
RS
1192 else if (EQ (frames, Qvisible))
1193 frame_arg = frames;
4b206065
JB
1194#else
1195 frame = 0;
1196#endif
7ab12479 1197
89bca612
RS
1198 /* frame_arg is Qlambda to stick to one frame,
1199 Qvisible to consider all visible frames,
1200 or Qt otherwise. */
1201
7ab12479
JB
1202 /* Pick a window to start with. */
1203 if (XTYPE (obj) == Lisp_Window)
4b206065 1204 w = obj;
44fa5b1e 1205 else if (frame)
4b206065 1206 w = FRAME_SELECTED_WINDOW (frame);
7ab12479 1207 else
4b206065
JB
1208 w = FRAME_SELECTED_WINDOW (selected_frame);
1209
1210 /* Figure out the last window we're going to mess with. Since
1211 Fnext_window, given the same options, is guaranteed to go in a
1212 ring, we can just use Fprevious_window to find the last one.
1213
1214 We can't just wait until we hit the first window again, because
1215 it might be deleted. */
1216
89bca612 1217 last_window = Fprevious_window (w, mini ? Qt : Qnil, frame_arg);
7ab12479 1218
7ab12479 1219 best_window = Qnil;
4b206065 1220 for (;;)
7ab12479 1221 {
75d8f668
JB
1222 FRAME_PTR w_frame = XFRAME (WINDOW_FRAME (XWINDOW (w)));
1223
7ab12479
JB
1224 /* Pick the next window now, since some operations will delete
1225 the current window. */
89bca612 1226 next_window = Fnext_window (w, mini ? Qt : Qnil, frame_arg);
7ab12479 1227
d29a5631
RS
1228 /* Note that we do not pay attention here to whether
1229 the frame is visible, since Fnext_window skips non-visible frames
1230 if that is desired, under the control of frame_arg. */
75d8f668 1231 if (! MINI_WINDOW_P (XWINDOW (w))
7ab12479
JB
1232 || (mini && minibuf_level > 0))
1233 switch (type)
1234 {
1235 case GET_BUFFER_WINDOW:
7ab12479
JB
1236 if (XBUFFER (XWINDOW (w)->buffer) == XBUFFER (obj))
1237 return w;
1238 break;
1239
1240 case GET_LRU_WINDOW:
1241 /* t as arg means consider only full-width windows */
e5d77022 1242 if (!NILP (obj) && XFASTINT (XWINDOW (w)->width)
a2db42d6 1243 != FRAME_WIDTH (XFRAME (WINDOW_FRAME (XWINDOW (w)))))
7ab12479 1244 break;
7ab12479
JB
1245 /* Ignore dedicated windows and minibuffers. */
1246 if (MINI_WINDOW_P (XWINDOW (w))
265a9e55 1247 || !NILP (XWINDOW (w)->dedicated))
7ab12479 1248 break;
265a9e55 1249 if (NILP (best_window)
7ab12479
JB
1250 || (XFASTINT (XWINDOW (best_window)->use_time)
1251 > XFASTINT (XWINDOW (w)->use_time)))
1252 best_window = w;
1253 break;
1254
1255 case DELETE_OTHER_WINDOWS:
1256 if (XWINDOW (w) != XWINDOW (obj))
1257 Fdelete_window (w);
1258 break;
1259
1260 case DELETE_BUFFER_WINDOWS:
1261 if (EQ (XWINDOW (w)->buffer, obj))
1262 {
1263 /* If we're deleting the buffer displayed in the only window
44fa5b1e 1264 on the frame, find a new buffer to display there. */
265a9e55 1265 if (NILP (XWINDOW (w)->parent))
7ab12479 1266 {
12cae7c0
KH
1267 Lisp_Object new_buffer;
1268 new_buffer = Fother_buffer (obj, Qnil);
265a9e55 1269 if (NILP (new_buffer))
7ab12479
JB
1270 new_buffer
1271 = Fget_buffer_create (build_string ("*scratch*"));
1272 Fset_window_buffer (w, new_buffer);
d895abb0
RS
1273 if (EQ (w, selected_window))
1274 Fset_buffer (XWINDOW (w)->buffer);
7ab12479
JB
1275 }
1276 else
1277 Fdelete_window (w);
1278 }
1279 break;
1280
1281 case GET_LARGEST_WINDOW:
7ab12479
JB
1282 /* Ignore dedicated windows and minibuffers. */
1283 if (MINI_WINDOW_P (XWINDOW (w))
265a9e55 1284 || !NILP (XWINDOW (w)->dedicated))
7ab12479
JB
1285 break;
1286 {
1287 struct window *best_window_ptr = XWINDOW (best_window);
1288 struct window *w_ptr = XWINDOW (w);
6b54027b
RS
1289 if (NILP (best_window)
1290 || (XFASTINT (w_ptr->height) * XFASTINT (w_ptr->width)
1291 > (XFASTINT (best_window_ptr->height)
1292 * XFASTINT (best_window_ptr->width))))
7ab12479
JB
1293 best_window = w;
1294 }
1295 break;
1296
1297 case UNSHOW_BUFFER:
1298 if (EQ (XWINDOW (w)->buffer, obj))
1299 {
1300 /* Find another buffer to show in this window. */
12cae7c0 1301 Lisp_Object another_buffer;
38ab08d1 1302 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
12cae7c0 1303 another_buffer = Fother_buffer (obj, Qnil);
265a9e55 1304 if (NILP (another_buffer))
7ab12479
JB
1305 another_buffer
1306 = Fget_buffer_create (build_string ("*scratch*"));
38ab08d1
RS
1307#ifdef MULTI_FRAME
1308 /* If this window is dedicated, and in a frame of its own,
1309 kill the frame. */
1310 if (EQ (w, FRAME_ROOT_WINDOW (f))
596122a7 1311 && !NILP (XWINDOW (w)->dedicated)
38ab08d1
RS
1312 && other_visible_frames (f))
1313 Fdelete_frame (WINDOW_FRAME (XWINDOW (w)), Qnil);
1314 else
1315#endif
1316 {
1317 /* Otherwise show a different buffer in the window. */
1318 XWINDOW (w)->dedicated = Qnil;
1319 Fset_window_buffer (w, another_buffer);
1320 if (EQ (w, selected_window))
1321 Fset_buffer (XWINDOW (w)->buffer);
1322 }
7ab12479
JB
1323 }
1324 break;
1325 }
4b206065
JB
1326
1327 if (EQ (w, last_window))
1328 break;
1329
7ab12479
JB
1330 w = next_window;
1331 }
7ab12479
JB
1332
1333 return best_window;
1334}
605be8af 1335
7ab12479
JB
1336DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
1337 "Return the window least recently selected or used for display.\n\
89bca612 1338If optional argument FRAME is `visible', search all visible frames.\n\
cee67da9 1339If FRAME is 0, search all visible and iconified frames.\n\
89bca612
RS
1340If FRAME is t, search all frames.\n\
1341If FRAME is nil, search only the selected frame.\n\
1342If FRAME is a frame, search only that frame.")
1343 (frame)
1344 Lisp_Object frame;
7ab12479
JB
1345{
1346 register Lisp_Object w;
1347 /* First try for a window that is full-width */
89bca612 1348 w = window_loop (GET_LRU_WINDOW, Qt, 0, frame);
265a9e55 1349 if (!NILP (w) && !EQ (w, selected_window))
7ab12479
JB
1350 return w;
1351 /* If none of them, try the rest */
89bca612 1352 return window_loop (GET_LRU_WINDOW, Qnil, 0, frame);
7ab12479
JB
1353}
1354
1355DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 1, 0,
1356 "Return the largest window in area.\n\
89bca612 1357If optional argument FRAME is `visible', search all visible frames.\n\
cee67da9 1358If FRAME is 0, search all visible and iconified frames.\n\
89bca612
RS
1359If FRAME is t, search all frames.\n\
1360If FRAME is nil, search only the selected frame.\n\
1361If FRAME is a frame, search only that frame.")
44fa5b1e
JB
1362 (frame)
1363 Lisp_Object frame;
7ab12479
JB
1364{
1365 return window_loop (GET_LARGEST_WINDOW, Qnil, 0,
44fa5b1e 1366 frame);
7ab12479
JB
1367}
1368
1369DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 1, 2, 0,
1370 "Return a window currently displaying BUFFER, or nil if none.\n\
89bca612 1371If optional argument FRAME is `visible', search all visible frames.\n\
f812f9c6 1372If optional argument FRAME is 0, search all visible and iconified frames.\n\
89bca612 1373If FRAME is t, search all frames.\n\
1bc981d2 1374If FRAME is nil, search only the selected frame.\n\
89bca612 1375If FRAME is a frame, search only that frame.")
44fa5b1e
JB
1376 (buffer, frame)
1377 Lisp_Object buffer, frame;
7ab12479
JB
1378{
1379 buffer = Fget_buffer (buffer);
1380 if (XTYPE (buffer) == Lisp_Buffer)
44fa5b1e 1381 return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame);
7ab12479
JB
1382 else
1383 return Qnil;
1384}
1385
1386DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
1387 0, 1, "",
44fa5b1e 1388 "Make WINDOW (or the selected window) fill its frame.\n\
f16a1ed3
RS
1389Only the frame WINDOW is on is affected.\n\
1390This function tries to reduce display jumps\n\
1391by keeping the text previously visible in WINDOW\n\
1392in the same place on the frame. Doing this depends on\n\
1393the value of (window-start WINDOW), so if calling this function\n\
1394in a program gives strange scrolling, make sure the window-start\n\
1395value is reasonable when this function is called.")
7ab12479
JB
1396 (window)
1397 Lisp_Object window;
1398{
1399 struct window *w;
00d3d838 1400 int startpos;
7ab12479
JB
1401 int top;
1402
265a9e55 1403 if (NILP (window))
7ab12479
JB
1404 window = selected_window;
1405 else
605be8af 1406 CHECK_LIVE_WINDOW (window, 0);
7ab12479
JB
1407
1408 w = XWINDOW (window);
00d3d838
KH
1409 startpos = marker_position (w->start);
1410 top = XFASTINT (w->top) - FRAME_MENU_BAR_LINES (XFRAME (WINDOW_FRAME (w)));
7ab12479 1411
70728a80 1412 window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_FRAME (w));
7ab12479 1413
00d3d838
KH
1414 /* Try to minimize scrolling, by setting the window start to the point
1415 will cause the text at the old window start to be at the same place
1416 on the frame. But don't try to do this if the window start is
1417 outside the visible portion (as might happen when the display is
1418 not current, due to typeahead). */
1419 if (startpos >= BUF_BEGV (XBUFFER (w->buffer))
1420 && startpos <= BUF_ZV (XBUFFER (w->buffer)))
1421 {
1422 struct position pos;
1423 struct buffer *obuf = current_buffer;
1424
1425 Fset_buffer (w->buffer);
1426 /* This computation used to temporarily move point, but that can
1427 have unwanted side effects due to text properties. */
1428 pos = *vmotion (startpos, -top, window_internal_width (w) - 1,
1429 XINT (w->hscroll), window);
1430 Fset_marker (w->start, make_number (pos.bufpos), w->buffer);
1431 w->start_at_line_beg = ((pos.bufpos == BEGV
1432 || FETCH_CHAR (pos.bufpos - 1) == '\n') ? Qt
1433 : Qnil);
1434
1435 set_buffer_internal (obuf);
1436 }
7ab12479
JB
1437 return Qnil;
1438}
1439
1440DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
3cbbb729 1441 1, 2, "bDelete windows on (buffer): ",
26f6279d
JB
1442 "Delete all windows showing BUFFER.\n\
1443Optional second argument FRAME controls which frames are affected.\n\
1444If nil or omitted, delete all windows showing BUFFER in any frame.\n\
1445If t, delete only windows showing BUFFER in the selected frame.\n\
89bca612 1446If `visible', delete all windows showing BUFFER in any visible frame.\n\
26f6279d
JB
1447If a frame, delete only windows showing BUFFER in that frame.")
1448 (buffer, frame)
1449 Lisp_Object buffer, frame;
7ab12479 1450{
26f6279d
JB
1451#ifdef MULTI_FRAME
1452 /* FRAME uses t and nil to mean the opposite of what window_loop
1453 expects. */
1454 if (! FRAMEP (frame))
1455 frame = NILP (frame) ? Qt : Qnil;
1456#else
1457 frame = Qt;
1458#endif
1459
265a9e55 1460 if (!NILP (buffer))
7ab12479
JB
1461 {
1462 buffer = Fget_buffer (buffer);
1463 CHECK_BUFFER (buffer, 0);
26f6279d 1464 window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
7ab12479
JB
1465 }
1466 return Qnil;
1467}
1468
1469DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
1470 Sreplace_buffer_in_windows,
1471 1, 1, "bReplace buffer in windows: ",
1472 "Replace BUFFER with some other buffer in all windows showing it.")
1473 (buffer)
1474 Lisp_Object buffer;
1475{
265a9e55 1476 if (!NILP (buffer))
7ab12479
JB
1477 {
1478 buffer = Fget_buffer (buffer);
1479 CHECK_BUFFER (buffer, 0);
1480 window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
1481 }
1482 return Qnil;
1483}
1484\f
1485/* Set the height of WINDOW and all its inferiors. */
a481b3ea
JB
1486
1487/* The smallest acceptable dimensions for a window. Anything smaller
1488 might crash Emacs. */
1489#define MIN_SAFE_WINDOW_WIDTH (2)
1490#define MIN_SAFE_WINDOW_HEIGHT (2)
1491
1492/* Make sure that window_min_height and window_min_width are
1493 not too small; if they are, set them to safe minima. */
1494
1495static void
1496check_min_window_sizes ()
1497{
1498 /* Smaller values might permit a crash. */
1499 if (window_min_width < MIN_SAFE_WINDOW_WIDTH)
1500 window_min_width = MIN_SAFE_WINDOW_WIDTH;
1501 if (window_min_height < MIN_SAFE_WINDOW_HEIGHT)
1502 window_min_height = MIN_SAFE_WINDOW_HEIGHT;
1503}
1504
1505/* If *ROWS or *COLS are too small a size for FRAME, set them to the
1506 minimum allowable size. */
605be8af 1507void
a481b3ea 1508check_frame_size (frame, rows, cols)
605be8af
JB
1509 FRAME_PTR frame;
1510 int *rows, *cols;
a481b3ea 1511{
628df3bf
JB
1512 /* For height, we have to see:
1513 whether the frame has a minibuffer,
1514 whether it wants a mode line, and
1515 whether it has a menu bar. */
a481b3ea 1516 int min_height =
79f92720
JB
1517 (FRAME_MINIBUF_ONLY_P (frame) ? MIN_SAFE_WINDOW_HEIGHT - 1
1518 : (! FRAME_HAS_MINIBUF_P (frame)) ? MIN_SAFE_WINDOW_HEIGHT
a481b3ea 1519 : 2 * MIN_SAFE_WINDOW_HEIGHT - 1);
628df3bf
JB
1520 if (FRAME_MENU_BAR_LINES (frame) > 0)
1521 min_height += FRAME_MENU_BAR_LINES (frame);
a481b3ea
JB
1522
1523 if (*rows < min_height)
1524 *rows = min_height;
1525 if (*cols < MIN_SAFE_WINDOW_WIDTH)
1526 *cols = MIN_SAFE_WINDOW_WIDTH;
1527}
1528
7ab12479
JB
1529/* Normally the window is deleted if it gets too small.
1530 nodelete nonzero means do not do this.
1531 (The caller should check later and do so if appropriate) */
1532
1533set_window_height (window, height, nodelete)
1534 Lisp_Object window;
1535 int height;
1536 int nodelete;
1537{
1538 register struct window *w = XWINDOW (window);
1539 register struct window *c;
1540 int oheight = XFASTINT (w->height);
1541 int top, pos, lastbot, opos, lastobot;
1542 Lisp_Object child;
1543
a481b3ea
JB
1544 check_min_window_sizes ();
1545
7ab12479 1546 if (!nodelete
265a9e55 1547 && ! NILP (w->parent)
7ab12479
JB
1548 && height < window_min_height)
1549 {
1550 Fdelete_window (window);
1551 return;
1552 }
1553
1554 XFASTINT (w->last_modified) = 0;
1555 windows_or_buffers_changed++;
1556 XFASTINT (w->height) = height;
265a9e55 1557 if (!NILP (w->hchild))
7ab12479 1558 {
265a9e55 1559 for (child = w->hchild; !NILP (child); child = XWINDOW (child)->next)
7ab12479
JB
1560 {
1561 XWINDOW (child)->top = w->top;
1562 set_window_height (child, height, nodelete);
1563 }
1564 }
265a9e55 1565 else if (!NILP (w->vchild))
7ab12479
JB
1566 {
1567 lastbot = top = XFASTINT (w->top);
1568 lastobot = 0;
265a9e55 1569 for (child = w->vchild; !NILP (child); child = c->next)
7ab12479
JB
1570 {
1571 c = XWINDOW (child);
1572
1573 opos = lastobot + XFASTINT (c->height);
1574
1575 XFASTINT (c->top) = lastbot;
1576
1577 pos = (((opos * height) << 1) + oheight) / (oheight << 1);
1578
1579 /* Avoid confusion: inhibit deletion of child if becomes too small */
1580 set_window_height (child, pos + top - lastbot, 1);
1581
1582 /* Now advance child to next window,
1583 and set lastbot if child was not just deleted. */
1584 lastbot = pos + top;
1585 lastobot = opos;
1586 }
1587 /* Now delete any children that became too small. */
1588 if (!nodelete)
265a9e55 1589 for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
7ab12479
JB
1590 {
1591 set_window_height (child, XINT (XWINDOW (child)->height), 0);
1592 }
1593 }
1594}
1595
1596/* Recursively set width of WINDOW and its inferiors. */
1597
1598set_window_width (window, width, nodelete)
1599 Lisp_Object window;
1600 int width;
1601 int nodelete;
1602{
1603 register struct window *w = XWINDOW (window);
1604 register struct window *c;
1605 int owidth = XFASTINT (w->width);
1606 int left, pos, lastright, opos, lastoright;
1607 Lisp_Object child;
1608
abdced83 1609 if (!nodelete && width < window_min_width && !NILP (w->parent))
7ab12479
JB
1610 {
1611 Fdelete_window (window);
1612 return;
1613 }
1614
1615 XFASTINT (w->last_modified) = 0;
1616 windows_or_buffers_changed++;
1617 XFASTINT (w->width) = width;
265a9e55 1618 if (!NILP (w->vchild))
7ab12479 1619 {
265a9e55 1620 for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
7ab12479
JB
1621 {
1622 XWINDOW (child)->left = w->left;
1623 set_window_width (child, width, nodelete);
1624 }
1625 }
265a9e55 1626 else if (!NILP (w->hchild))
7ab12479
JB
1627 {
1628 lastright = left = XFASTINT (w->left);
1629 lastoright = 0;
265a9e55 1630 for (child = w->hchild; !NILP (child); child = c->next)
7ab12479
JB
1631 {
1632 c = XWINDOW (child);
1633
1634 opos = lastoright + XFASTINT (c->width);
1635
1636 XFASTINT (c->left) = lastright;
1637
1638 pos = (((opos * width) << 1) + owidth) / (owidth << 1);
1639
1640 /* Inhibit deletion for becoming too small */
1641 set_window_width (child, pos + left - lastright, 1);
1642
1643 /* Now advance child to next window,
1644 and set lastright if child was not just deleted. */
1645 lastright = pos + left, lastoright = opos;
1646 }
1647 /* Delete children that became too small */
1648 if (!nodelete)
265a9e55 1649 for (child = w->hchild; !NILP (child); child = XWINDOW (child)->next)
7ab12479
JB
1650 {
1651 set_window_width (child, XINT (XWINDOW (child)->width), 0);
1652 }
1653 }
1654}
1655\f
1d8d96fa 1656int window_select_count;
7ab12479
JB
1657
1658DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 2, 0,
1659 "Make WINDOW display BUFFER as its contents.\n\
1660BUFFER can be a buffer or buffer name.")
1661 (window, buffer)
1662 register Lisp_Object window, buffer;
1663{
1664 register Lisp_Object tem;
1665 register struct window *w = decode_window (window);
1666
1667 buffer = Fget_buffer (buffer);
1668 CHECK_BUFFER (buffer, 1);
1669
265a9e55 1670 if (NILP (XBUFFER (buffer)->name))
7ab12479
JB
1671 error ("Attempt to display deleted buffer");
1672
1673 tem = w->buffer;
265a9e55 1674 if (NILP (tem))
7ab12479
JB
1675 error ("Window is deleted");
1676 else if (! EQ (tem, Qt)) /* w->buffer is t when the window
1677 is first being set up. */
1678 {
265a9e55 1679 if (!NILP (w->dedicated) && !EQ (tem, buffer))
3cf85532
RS
1680 error ("Window is dedicated to `%s'",
1681 XSTRING (XBUFFER (tem)->name)->data);
7ab12479
JB
1682
1683 unshow_buffer (w);
1684 }
1685
1686 w->buffer = buffer;
5a41ab94
RS
1687 w->window_end_pos = 0;
1688 w->window_end_valid = Qnil;
270967b2 1689 w->hscroll = 0;
7ab12479
JB
1690 Fset_marker (w->pointm,
1691 make_number (BUF_PT (XBUFFER (buffer))),
1692 buffer);
1693 set_marker_restricted (w->start,
1694 make_number (XBUFFER (buffer)->last_window_start),
1695 buffer);
1696 w->start_at_line_beg = Qnil;
e36ab06b 1697 w->force_start = Qnil;
7ab12479
JB
1698 XFASTINT (w->last_modified) = 0;
1699 windows_or_buffers_changed++;
1700 if (EQ (window, selected_window))
1701 Fset_buffer (buffer);
1702
1703 return Qnil;
1704}
1705
1706DEFUN ("select-window", Fselect_window, Sselect_window, 1, 1, 0,
1707 "Select WINDOW. Most editing will apply to WINDOW's buffer.\n\
1708The main editor command loop selects the buffer of the selected window\n\
1709before each command.")
1710 (window)
1711 register Lisp_Object window;
1712{
1713 register struct window *w;
1714 register struct window *ow = XWINDOW (selected_window);
1715
605be8af 1716 CHECK_LIVE_WINDOW (window, 0);
7ab12479
JB
1717
1718 w = XWINDOW (window);
1719
265a9e55 1720 if (NILP (w->buffer))
7ab12479
JB
1721 error ("Trying to select deleted window or non-leaf window");
1722
1723 XFASTINT (w->use_time) = ++window_select_count;
1724 if (EQ (window, selected_window))
1725 return window;
1726
1727 Fset_marker (ow->pointm, make_number (BUF_PT (XBUFFER (ow->buffer))),
1728 ow->buffer);
1729
1730 selected_window = window;
44fa5b1e
JB
1731#ifdef MULTI_FRAME
1732 if (XFRAME (WINDOW_FRAME (w)) != selected_frame)
7ab12479 1733 {
44fa5b1e 1734 XFRAME (WINDOW_FRAME (w))->selected_window = window;
147a6615
RS
1735 /* Use this rather than Fhandle_switch_frame
1736 so that FRAME_FOCUS_FRAME is moved appropriately as we
1737 move around in the state where a minibuffer in a separate
1738 frame is active. */
1739 Fselect_frame (WINDOW_FRAME (w), Qnil);
7ab12479
JB
1740 }
1741 else
44fa5b1e 1742 selected_frame->selected_window = window;
7ab12479
JB
1743#endif
1744
1745 record_buffer (w->buffer);
1746 Fset_buffer (w->buffer);
1747
1748 /* Go to the point recorded in the window.
1749 This is important when the buffer is in more
1750 than one window. It also matters when
1751 redisplay_window has altered point after scrolling,
1752 because it makes the change only in the window. */
1753 {
1754 register int new_point = marker_position (w->pointm);
1755 if (new_point < BEGV)
1756 SET_PT (BEGV);
a9c95e08 1757 else if (new_point > ZV)
7ab12479
JB
1758 SET_PT (ZV);
1759 else
1760 SET_PT (new_point);
1761 }
1762
1763 windows_or_buffers_changed++;
1764 return window;
1765}
1766
35aaf00c 1767DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 2,
6648f23a 1768 "BDisplay buffer: \nP",
7ab12479
JB
1769 "Make BUFFER appear in some window but don't select it.\n\
1770BUFFER can be a buffer or a buffer name.\n\
1771If BUFFER is shown already in some window, just use that one,\n\
1772unless the window is the selected window and the optional second\n\
46d3268a 1773argument NOT-THIS-WINDOW is non-nil (interactively, with prefix arg).\n\
5141b901 1774If `pop-up-frames' is non-nil, make a new frame if no window shows BUFFER.\n\
7ab12479
JB
1775Returns the window displaying BUFFER.")
1776 (buffer, not_this_window)
1777 register Lisp_Object buffer, not_this_window;
1778{
a90712c2 1779 register Lisp_Object window, tem;
7ab12479
JB
1780
1781 buffer = Fget_buffer (buffer);
1782 CHECK_BUFFER (buffer, 0);
1783
265a9e55 1784 if (!NILP (Vdisplay_buffer_function))
7ab12479
JB
1785 return call2 (Vdisplay_buffer_function, buffer, not_this_window);
1786
265a9e55 1787 if (NILP (not_this_window)
7ab12479
JB
1788 && XBUFFER (XWINDOW (selected_window)->buffer) == XBUFFER (buffer))
1789 return selected_window;
1790
c6e73093 1791#ifdef MULTI_FRAME
e8edb3ae 1792 /* If pop_up_frames,
f812f9c6
RS
1793 look for a window showing BUFFER on any visible or iconified frame. */
1794 window = Fget_buffer_window (buffer, pop_up_frames ? make_number (0) : Qnil);
c6e73093
KH
1795#else
1796 window = Fget_buffer_window (buffer, Qnil);
1797#endif
265a9e55
JB
1798 if (!NILP (window)
1799 && (NILP (not_this_window) || !EQ (window, selected_window)))
f812f9c6 1800 {
7cab5d2c 1801#ifdef MULTI_FRAME
f812f9c6
RS
1802 if (FRAME_ICONIFIED_P (XFRAME (WINDOW_FRAME (XWINDOW (window)))))
1803 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
7cab5d2c 1804#endif
f812f9c6
RS
1805 return window;
1806 }
7ab12479 1807
a90712c2
RS
1808 /* Certain buffer names get special handling. */
1809 if (! NILP (Vspecial_display_function))
1810 {
1811 tem = Fmember (XBUFFER (buffer)->name, Vspecial_display_buffer_names);
1812 if (!NILP (tem))
1813 return call1 (Vspecial_display_function, buffer);
1814
1815 for (tem = Vspecial_display_regexps; CONSP (tem); tem = XCONS (tem)->cdr)
1816 if (fast_string_match (XCONS (tem)->car, XBUFFER (buffer)->name) >= 0)
1817 return call1 (Vspecial_display_function, buffer);
1818 }
1819
44fa5b1e
JB
1820#ifdef MULTI_FRAME
1821 /* If there are no frames open that have more than a minibuffer,
1822 we need to create a new frame. */
1823 if (pop_up_frames || last_nonminibuf_frame == 0)
7ab12479 1824 {
a90712c2 1825 window = Fframe_selected_window (call0 (Vpop_up_frame_function));
7ab12479 1826 Fset_window_buffer (window, buffer);
7ab12479
JB
1827 return window;
1828 }
44fa5b1e 1829#endif /* MULTI_FRAME */
7ab12479 1830
43bad991 1831 if (pop_up_windows
44fa5b1e
JB
1832#ifdef MULTI_FRAME
1833 || FRAME_MINIBUF_ONLY_P (selected_frame)
cee67da9
RS
1834 /* If the current frame is a special display frame,
1835 don't try to reuse its windows. */
1836 || !NILP (XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->dedicated)
43bad991
JB
1837#endif
1838 )
7ab12479 1839 {
12cae7c0
KH
1840 Lisp_Object frames;
1841
1842 frames = Qnil;
44fa5b1e
JB
1843#ifdef MULTI_FRAME
1844 if (FRAME_MINIBUF_ONLY_P (selected_frame))
1845 XSET (frames, Lisp_Frame, last_nonminibuf_frame);
7ab12479
JB
1846#endif
1847 /* Don't try to create a window if would get an error */
1848 if (split_height_threshold < window_min_height << 1)
1849 split_height_threshold = window_min_height << 1;
1850
cee67da9
RS
1851 /* Note that both Fget_largest_window and Fget_lru_window
1852 ignore minibuffers and dedicated windows.
1853 This means they can return nil. */
7ab12479 1854
cee67da9
RS
1855 /* If the frame we would try to split cannot be split,
1856 try other frames. */
1857 if (FRAME_NO_SPLIT_P (NILP (frames) ? selected_frame
1858 : last_nonminibuf_frame))
1859 {
1860 /* Try visible frames first. */
1861 window = Fget_largest_window (Qvisible);
1862 /* If that didn't work, try iconified frames. */
1863 if (NILP (window))
1864 window = Fget_largest_window (make_number (0));
1865 if (NILP (window))
1866 window = Fget_largest_window (Qt);
1867 }
1868 else
1869 window = Fget_largest_window (frames);
1870
1871 /* If we got a tall enough full-width window, split it. */
265a9e55 1872 if (!NILP (window)
7ab12479 1873 && window_height (window) >= split_height_threshold
535e0b8e
JB
1874 && (XFASTINT (XWINDOW (window)->width)
1875 == FRAME_WIDTH (XFRAME (WINDOW_FRAME (XWINDOW (window))))))
7ab12479
JB
1876 window = Fsplit_window (window, Qnil, Qnil);
1877 else
1878 {
44fa5b1e 1879 window = Fget_lru_window (frames);
cee67da9
RS
1880 /* If the LRU window is selected, and big enough, split it. */
1881 if (!NILP (window)
1882 && (EQ (window, selected_window)
1883 || EQ (XWINDOW (window)->parent, Qnil))
7ab12479
JB
1884 && window_height (window) >= window_min_height << 1)
1885 window = Fsplit_window (window, Qnil, Qnil);
cee67da9
RS
1886#ifdef MULTI_FRAME
1887 /* If Fget_lru_window returned nil, try other approaches. */
1888 /* Try visible frames first. */
1889 if (NILP (window))
1890 window = Fget_largest_window (Qvisible);
1891 /* If that didn't work, try iconified frames. */
1892 if (NILP (window))
1893 window = Fget_largest_window (make_number (0));
1894 /* Try invisible frames. */
1895 if (NILP (window))
1896 window = Fget_largest_window (Qt);
1897 /* As a last resort, make a new frame. */
1898 if (NILP (window))
1899 window = Fframe_selected_window (call0 (Vpop_up_frame_function));
1900#else
1901 /* As a last resort, use a non minibuffer window. */
1902 if (NILP (window))
1903 window = Fframe_first_window (Fselected_frame ());
1904#endif
7ab12479
JB
1905 }
1906 }
1907 else
1908 window = Fget_lru_window (Qnil);
1909
1910 Fset_window_buffer (window, buffer);
1911 return window;
1912}
1913
1914void
1915temp_output_buffer_show (buf)
1916 register Lisp_Object buf;
1917{
1918 register struct buffer *old = current_buffer;
1919 register Lisp_Object window;
1920 register struct window *w;
1921
1922 Fset_buffer (buf);
1923 XBUFFER (buf)->save_modified = MODIFF;
1924 BEGV = BEG;
1925 ZV = Z;
1926 SET_PT (BEG);
1927 clip_changed = 1;
1928 set_buffer_internal (old);
1929
1930 if (!EQ (Vtemp_buffer_show_function, Qnil))
1931 call1 (Vtemp_buffer_show_function, buf);
1932 else
1933 {
1934 window = Fdisplay_buffer (buf, Qnil);
1935
44fa5b1e
JB
1936#ifdef MULTI_FRAME
1937 if (XFRAME (XWINDOW (window)->frame) != selected_frame)
1938 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
1939#endif /* MULTI_FRAME */
7ab12479
JB
1940 Vminibuf_scroll_window = window;
1941 w = XWINDOW (window);
1942 XFASTINT (w->hscroll) = 0;
1943 set_marker_restricted (w->start, make_number (1), buf);
1944 set_marker_restricted (w->pointm, make_number (1), buf);
1945 }
1946}
1947\f
1948static
1949make_dummy_parent (window)
1950 Lisp_Object window;
1951{
1952 register Lisp_Object old, new;
1953 register struct window *o, *p;
1954
1955 old = window;
1956 XSETTYPE (old, Lisp_Vector);
1957 new = Fcopy_sequence (old);
1958 XSETTYPE (new, Lisp_Window);
1959
1960 o = XWINDOW (old);
1961 p = XWINDOW (new);
1962 XFASTINT (p->sequence_number) = ++sequence_number;
1963
1964 /* Put new into window structure in place of window */
1965 replace_window (window, new);
1966
1967 o->next = Qnil;
1968 o->prev = Qnil;
1969 o->vchild = Qnil;
1970 o->hchild = Qnil;
1971 o->parent = new;
1972
1973 p->start = Qnil;
1974 p->pointm = Qnil;
1975 p->buffer = Qnil;
1976}
1977
1978DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
1979 "Split WINDOW, putting SIZE lines in the first of the pair.\n\
1980WINDOW defaults to selected one and SIZE to half its size.\n\
1981If optional third arg HOR-FLAG is non-nil, split side by side\n\
1982and put SIZE columns in the first of the pair.")
1983 (window, chsize, horflag)
1984 Lisp_Object window, chsize, horflag;
1985{
1986 register Lisp_Object new;
1987 register struct window *o, *p;
1988 register int size;
1989
265a9e55 1990 if (NILP (window))
7ab12479
JB
1991 window = selected_window;
1992 else
605be8af 1993 CHECK_LIVE_WINDOW (window, 0);
7ab12479
JB
1994
1995 o = XWINDOW (window);
1996
265a9e55 1997 if (NILP (chsize))
7ab12479 1998 {
265a9e55 1999 if (!NILP (horflag))
7ab12479
JB
2000 /* Round odd size up, since this is for the left-hand window,
2001 and it will lose a column for the separators. */
2002 size = ((XFASTINT (o->width) + 1) & -2) >> 1;
2003 else
2004 size = XFASTINT (o->height) >> 1;
2005 }
2006 else
2007 {
2008 CHECK_NUMBER (chsize, 1);
2009 size = XINT (chsize);
2010 }
2011
2012 if (MINI_WINDOW_P (o))
2013 error ("Attempt to split minibuffer window");
44fa5b1e
JB
2014 else if (FRAME_NO_SPLIT_P (XFRAME (WINDOW_FRAME (o))))
2015 error ("Attempt to split unsplittable frame");
7ab12479 2016
a481b3ea 2017 check_min_window_sizes ();
7ab12479 2018
265a9e55 2019 if (NILP (horflag))
7ab12479
JB
2020 {
2021 if (size < window_min_height
2022 || size + window_min_height > XFASTINT (o->height))
2023 args_out_of_range_3 (window, chsize, horflag);
265a9e55
JB
2024 if (NILP (o->parent)
2025 || NILP (XWINDOW (o->parent)->vchild))
7ab12479
JB
2026 {
2027 make_dummy_parent (window);
2028 new = o->parent;
2029 XWINDOW (new)->vchild = window;
2030 }
2031 }
2032 else
2033 {
2034 if (size < window_min_width
2035 || size + window_min_width > XFASTINT (o->width))
2036 args_out_of_range_3 (window, chsize, horflag);
265a9e55
JB
2037 if (NILP (o->parent)
2038 || NILP (XWINDOW (o->parent)->hchild))
7ab12479
JB
2039 {
2040 make_dummy_parent (window);
2041 new = o->parent;
2042 XWINDOW (new)->hchild = window;
2043 }
2044 }
2045
2046 /* Now we know that window's parent is a vertical combination
2047 if we are dividing vertically, or a horizontal combination
2048 if we are making side-by-side windows */
2049
2050 windows_or_buffers_changed++;
2051 new = make_window ();
2052 p = XWINDOW (new);
2053
44fa5b1e 2054 p->frame = o->frame;
7ab12479 2055 p->next = o->next;
265a9e55 2056 if (!NILP (p->next))
7ab12479
JB
2057 XWINDOW (p->next)->prev = new;
2058 p->prev = window;
2059 o->next = new;
2060 p->parent = o->parent;
2061 p->buffer = Qt;
2062
2063 Fset_window_buffer (new, o->buffer);
2064
44fa5b1e 2065 /* Apportion the available frame space among the two new windows */
7ab12479 2066
265a9e55 2067 if (!NILP (horflag))
7ab12479
JB
2068 {
2069 p->height = o->height;
2070 p->top = o->top;
2071 XFASTINT (p->width) = XFASTINT (o->width) - size;
2072 XFASTINT (o->width) = size;
2073 XFASTINT (p->left) = XFASTINT (o->left) + size;
2074 }
2075 else
2076 {
2077 p->left = o->left;
2078 p->width = o->width;
2079 XFASTINT (p->height) = XFASTINT (o->height) - size;
2080 XFASTINT (o->height) = size;
2081 XFASTINT (p->top) = XFASTINT (o->top) + size;
2082 }
2083
2084 return new;
2085}
2086\f
2087DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
2088 "Make current window ARG lines bigger.\n\
2089From program, optional second arg non-nil means grow sideways ARG columns.")
2090 (n, side)
2091 register Lisp_Object n, side;
2092{
2093 CHECK_NUMBER (n, 0);
265a9e55 2094 change_window_height (XINT (n), !NILP (side));
7ab12479
JB
2095 return Qnil;
2096}
2097
2098DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
2099 "Make current window ARG lines smaller.\n\
2100From program, optional second arg non-nil means shrink sideways ARG columns.")
2101 (n, side)
2102 register Lisp_Object n, side;
2103{
2104 CHECK_NUMBER (n, 0);
265a9e55 2105 change_window_height (-XINT (n), !NILP (side));
7ab12479
JB
2106 return Qnil;
2107}
2108
2109int
2110window_height (window)
2111 Lisp_Object window;
2112{
2113 register struct window *p = XWINDOW (window);
2114 return XFASTINT (p->height);
2115}
2116
2117int
2118window_width (window)
2119 Lisp_Object window;
2120{
2121 register struct window *p = XWINDOW (window);
2122 return XFASTINT (p->width);
2123}
2124
05c2896a
JB
2125#define MINSIZE(w) \
2126 (widthflag \
2127 ? window_min_width \
2128 : (MINI_WINDOW_P (XWINDOW (w)) ? 1 : window_min_height))
7ab12479
JB
2129
2130#define CURBEG(w) \
05c2896a 2131 *(widthflag ? (int *) &(XWINDOW (w)->left) : (int *) &(XWINDOW (w)->top))
7ab12479
JB
2132
2133#define CURSIZE(w) \
05c2896a 2134 *(widthflag ? (int *) &(XWINDOW (w)->width) : (int *) &(XWINDOW (w)->height))
7ab12479
JB
2135
2136/* Unlike set_window_height, this function
2137 also changes the heights of the siblings so as to
2138 keep everything consistent. */
2139
2140change_window_height (delta, widthflag)
2141 register int delta;
2142 int widthflag;
2143{
2144 register Lisp_Object parent;
2145 Lisp_Object window;
2146 register struct window *p;
2147 int *sizep;
2148 int (*sizefun) () = widthflag ? window_width : window_height;
2149 register int (*setsizefun) () = (widthflag
2150 ? set_window_width
2151 : set_window_height);
2152
a481b3ea 2153 check_min_window_sizes ();
7ab12479
JB
2154
2155 window = selected_window;
2156 while (1)
2157 {
2158 p = XWINDOW (window);
2159 parent = p->parent;
265a9e55 2160 if (NILP (parent))
7ab12479
JB
2161 {
2162 if (widthflag)
2163 error ("No other window to side of this one");
2164 break;
2165 }
265a9e55
JB
2166 if (widthflag ? !NILP (XWINDOW (parent)->hchild)
2167 : !NILP (XWINDOW (parent)->vchild))
7ab12479
JB
2168 break;
2169 window = parent;
2170 }
2171
05c2896a 2172 sizep = &CURSIZE (window);
7ab12479 2173
7ab12479
JB
2174 {
2175 register int maxdelta;
7ab12479 2176
265a9e55
JB
2177 maxdelta = (!NILP (parent) ? (*sizefun) (parent) - *sizep
2178 : !NILP (p->next) ? (*sizefun) (p->next) - MINSIZE (p->next)
2179 : !NILP (p->prev) ? (*sizefun) (p->prev) - MINSIZE (p->prev)
44fa5b1e
JB
2180 /* This is a frame with only one window, a minibuffer-only
2181 or a minibufferless frame. */
d5783c40 2182 : (delta = 0));
7ab12479
JB
2183
2184 if (delta > maxdelta)
2185 /* This case traps trying to make the minibuffer
44fa5b1e
JB
2186 the full frame, or make the only window aside from the
2187 minibuffer the full frame. */
7ab12479 2188 delta = maxdelta;
6b54027b 2189 }
d5783c40 2190
6b54027b
RS
2191 if (*sizep + delta < MINSIZE (window))
2192 {
2193 Fdelete_window (window);
d5783c40 2194 return;
6b54027b
RS
2195 }
2196
2197 if (delta == 0)
2198 return;
7ab12479 2199
6b54027b
RS
2200 if (!NILP (p->next)
2201 && (*sizefun) (p->next) - delta >= MINSIZE (p->next))
7ab12479
JB
2202 {
2203 (*setsizefun) (p->next, (*sizefun) (p->next) - delta, 0);
2204 (*setsizefun) (window, *sizep + delta, 0);
05c2896a 2205 CURBEG (p->next) += delta;
7ab12479
JB
2206 /* This does not change size of p->next,
2207 but it propagates the new top edge to its children */
2208 (*setsizefun) (p->next, (*sizefun) (p->next), 0);
2209 }
6b54027b
RS
2210 else if (!NILP (p->prev)
2211 && (*sizefun) (p->prev) - delta >= MINSIZE (p->prev))
7ab12479
JB
2212 {
2213 (*setsizefun) (p->prev, (*sizefun) (p->prev) - delta, 0);
05c2896a 2214 CURBEG (window) -= delta;
7ab12479
JB
2215 (*setsizefun) (window, *sizep + delta, 0);
2216 }
2217 else
2218 {
2219 register int delta1;
2220 register int opht = (*sizefun) (parent);
2221
2222 /* If trying to grow this window to or beyond size of the parent,
2223 make delta1 so big that, on shrinking back down,
2224 all the siblings end up with less than one line and are deleted. */
2225 if (opht <= *sizep + delta)
2226 delta1 = opht * opht * 2;
2227 /* Otherwise, make delta1 just right so that if we add delta1
2228 lines to this window and to the parent, and then shrink
2229 the parent back to its original size, the new proportional
2230 size of this window will increase by delta. */
2231 else
2232 delta1 = (delta * opht * 100) / ((opht - *sizep - delta) * 100);
2233
2234 /* Add delta1 lines or columns to this window, and to the parent,
2235 keeping things consistent while not affecting siblings. */
05c2896a 2236 CURSIZE (parent) = opht + delta1;
7ab12479
JB
2237 (*setsizefun) (window, *sizep + delta1, 0);
2238
2239 /* Squeeze out delta1 lines or columns from our parent,
2240 shriking this window and siblings proportionately.
2241 This brings parent back to correct size.
2242 Delta1 was calculated so this makes this window the desired size,
2243 taking it all out of the siblings. */
2244 (*setsizefun) (parent, opht, 0);
2245 }
2246
2247 XFASTINT (p->last_modified) = 0;
2248}
2249#undef MINSIZE
2250#undef CURBEG
2251#undef CURSIZE
2252
2253\f
2254/* Return number of lines of text (not counting mode line) in W. */
2255
2256int
2257window_internal_height (w)
2258 struct window *w;
2259{
2260 int ht = XFASTINT (w->height);
2261
2262 if (MINI_WINDOW_P (w))
2263 return ht;
2264
265a9e55
JB
2265 if (!NILP (w->parent) || !NILP (w->vchild) || !NILP (w->hchild)
2266 || !NILP (w->next) || !NILP (w->prev)
44fa5b1e 2267 || FRAME_WANTS_MODELINE_P (XFRAME (WINDOW_FRAME (w))))
7ab12479
JB
2268 return ht - 1;
2269
2270 return ht;
2271}
2272
535e0b8e
JB
2273
2274/* Return the number of columns in W.
a3c87d4e 2275 Don't count columns occupied by scroll bars or the vertical bar
535e0b8e
JB
2276 separating W from the sibling to its right. */
2277int
2278window_internal_width (w)
2279 struct window *w;
2280{
2281 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2282 int left = XINT (w->left);
2283 int width = XINT (w->width);
2284
2285 /* If this window is flush against the right edge of the frame, its
2286 internal width is its full width. */
2287 if (left + width >= FRAME_WIDTH (f))
2288 return width;
2289
2290 /* If we are not flush right, then our rightmost columns are
2291 occupied by some sort of separator. */
2292
a3c87d4e
JB
2293 /* Scroll bars occupy a few columns. */
2294 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2295 return width - VERTICAL_SCROLL_BAR_WIDTH;
535e0b8e
JB
2296
2297 /* The column of `|' characters separating side-by-side windows
2298 occupies one column only. */
2299 return width - 1;
2300}
2301
2302
7ab12479
JB
2303/* Scroll contents of window WINDOW up N lines. */
2304
2305void
f8026fd8 2306window_scroll (window, n, noerror)
7ab12479
JB
2307 Lisp_Object window;
2308 int n;
f8026fd8 2309 int noerror;
7ab12479
JB
2310{
2311 register struct window *w = XWINDOW (window);
5ce7b543 2312 register int opoint = PT;
7ab12479
JB
2313 register int pos;
2314 register int ht = window_internal_height (w);
2315 register Lisp_Object tem;
2316 int lose;
2317 Lisp_Object bolp, nmoved;
2318
5ce7b543 2319 XFASTINT (tem) = PT;
7ab12479
JB
2320 tem = Fpos_visible_in_window_p (tem, window);
2321
265a9e55 2322 if (NILP (tem))
7ab12479 2323 {
cd2be1dd 2324 Fvertical_motion (make_number (- (ht / 2)), window);
5ce7b543 2325 XFASTINT (tem) = PT;
7ab12479
JB
2326 Fset_marker (w->start, tem, w->buffer);
2327 w->force_start = Qt;
2328 }
2329
2330 SET_PT (marker_position (w->start));
5ce7b543 2331 lose = n < 0 && PT == BEGV;
540b6aa0 2332 Fvertical_motion (make_number (n), window);
5ce7b543 2333 pos = PT;
7ab12479
JB
2334 bolp = Fbolp ();
2335 SET_PT (opoint);
2336
2337 if (lose)
f8026fd8
JB
2338 {
2339 if (noerror)
2340 return;
2341 else
2342 Fsignal (Qbeginning_of_buffer, Qnil);
2343 }
7ab12479
JB
2344
2345 if (pos < ZV)
7ab12479
JB
2346 {
2347 set_marker_restricted (w->start, make_number (pos), w->buffer);
2348 w->start_at_line_beg = bolp;
2349 w->update_mode_line = Qt;
2350 XFASTINT (w->last_modified) = 0;
2351 if (pos > opoint)
2352 SET_PT (pos);
2353 if (n < 0)
2354 {
2355 SET_PT (pos);
540b6aa0 2356 tem = Fvertical_motion (make_number (ht), window);
5ce7b543 2357 if (PT > opoint || XFASTINT (tem) < ht)
7ab12479
JB
2358 SET_PT (opoint);
2359 else
540b6aa0 2360 Fvertical_motion (make_number (-1), window);
7ab12479
JB
2361 }
2362 }
2363 else
f8026fd8
JB
2364 {
2365 if (noerror)
2366 return;
2367 else
2368 Fsignal (Qend_of_buffer, Qnil);
2369 }
7ab12479
JB
2370}
2371\f
2372/* This is the guts of Fscroll_up and Fscroll_down. */
2373
2374static void
2375scroll_command (n, direction)
2376 register Lisp_Object n;
2377 int direction;
2378{
2379 register int defalt;
2380 int count = specpdl_ptr - specpdl;
2381
95605e15
JB
2382 /* If selected window's buffer isn't current, make it current for the moment.
2383 But don't screw up if window_scroll gets an error. */
7ab12479 2384 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
95605e15
JB
2385 {
2386 record_unwind_protect (save_excursion_restore, save_excursion_save ());
2387 Fset_buffer (XWINDOW (selected_window)->buffer);
2388 }
7ab12479
JB
2389
2390 defalt = (window_internal_height (XWINDOW (selected_window))
2391 - next_screen_context_lines);
2392 defalt = direction * (defalt < 1 ? 1 : defalt);
2393
265a9e55 2394 if (NILP (n))
f8026fd8 2395 window_scroll (selected_window, defalt, 0);
7ab12479 2396 else if (EQ (n, Qminus))
f8026fd8 2397 window_scroll (selected_window, - defalt, 0);
7ab12479
JB
2398 else
2399 {
2400 n = Fprefix_numeric_value (n);
f8026fd8 2401 window_scroll (selected_window, XINT (n) * direction, 0);
7ab12479 2402 }
95605e15
JB
2403
2404 unbind_to (count, Qnil);
7ab12479
JB
2405}
2406
2407DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
2408 "Scroll text of current window upward ARG lines; or near full screen if no ARG.\n\
2409A near full screen is `next-screen-context-lines' less than a full screen.\n\
279e0e0c 2410Negative ARG means scroll downward.\n\
7ab12479
JB
2411When calling from a program, supply a number as argument or nil.")
2412 (n)
2413 Lisp_Object n;
2414{
2415 scroll_command (n, 1);
2416 return Qnil;
2417}
2418
2419DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
2420 "Scroll text of current window downward ARG lines; or near full screen if no ARG.\n\
2421A near full screen is `next-screen-context-lines' less than a full screen.\n\
279e0e0c 2422Negative ARG means scroll upward.\n\
7ab12479
JB
2423When calling from a program, supply a number as argument or nil.")
2424 (n)
2425 Lisp_Object n;
2426{
2427 scroll_command (n, -1);
2428 return Qnil;
2429}
ccd0664b
RS
2430\f
2431DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0,
2432 "Return the other window for \"other window scroll\" commands.\n\
77b24de6 2433If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
ccd0664b
RS
2434specifies the window.\n\
2435If `other-window-scroll-buffer' is non-nil, a window\n\
2436showing that buffer is used.")
eb16ec06 2437 ()
7ab12479 2438{
ccd0664b 2439 Lisp_Object window;
7ab12479
JB
2440
2441 if (MINI_WINDOW_P (XWINDOW (selected_window))
265a9e55 2442 && !NILP (Vminibuf_scroll_window))
7ab12479
JB
2443 window = Vminibuf_scroll_window;
2444 /* If buffer is specified, scroll that buffer. */
265a9e55 2445 else if (!NILP (Vother_window_scroll_buffer))
7ab12479
JB
2446 {
2447 window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
265a9e55 2448 if (NILP (window))
7ab12479
JB
2449 window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt);
2450 }
2451 else
dbc4e1c1
JB
2452 {
2453 /* Nothing specified; look for a neighboring window on the same
2454 frame. */
2455 window = Fnext_window (selected_window, Qnil, Qnil);
2456
2457 if (EQ (window, selected_window))
2458 /* That didn't get us anywhere; look for a window on another
2459 visible frame. */
2460 do
2461 window = Fnext_window (window, Qnil, Qt);
2462 while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
2463 && ! EQ (window, selected_window));
2464 }
2465
605be8af 2466 CHECK_LIVE_WINDOW (window, 0);
7ab12479
JB
2467
2468 if (EQ (window, selected_window))
2469 error ("There is no other window");
2470
ccd0664b
RS
2471 return window;
2472}
2473
2474DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
2475 "Scroll next window upward ARG lines; or near full screen if no ARG.\n\
2476The next window is the one below the current one; or the one at the top\n\
2477if the current one is at the bottom. Negative ARG means scroll downward.\n\
2478When calling from a program, supply a number as argument or nil.\n\
2479\n\
2480If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
2481specifies the window to scroll.\n\
2482If `other-window-scroll-buffer' is non-nil, scroll the window\n\
2483showing that buffer, popping the buffer up if necessary.")
2484 (n)
2485 register Lisp_Object n;
2486{
2487 register Lisp_Object window;
2488 register int ht;
2489 register struct window *w;
2490 register int count = specpdl_ptr - specpdl;
2491
2492 window = Fother_window_for_scrolling ();
2493
7ab12479
JB
2494 w = XWINDOW (window);
2495 ht = window_internal_height (w);
2496
2497 /* Don't screw up if window_scroll gets an error. */
2498 record_unwind_protect (save_excursion_restore, save_excursion_save ());
2499
2500 Fset_buffer (w->buffer);
2501 SET_PT (marker_position (w->pointm));
2502
265a9e55 2503 if (NILP (n))
f8026fd8 2504 window_scroll (window, ht - next_screen_context_lines, 1);
7ab12479 2505 else if (EQ (n, Qminus))
f8026fd8 2506 window_scroll (window, next_screen_context_lines - ht, 1);
7ab12479
JB
2507 else
2508 {
2509 if (XTYPE (n) == Lisp_Cons)
2510 n = Fcar (n);
2511 CHECK_NUMBER (n, 0);
f8026fd8 2512 window_scroll (window, XINT (n), 1);
7ab12479
JB
2513 }
2514
5ce7b543 2515 Fset_marker (w->pointm, make_number (PT), Qnil);
f4e7b2c2 2516 unbind_to (count, Qnil);
7ab12479
JB
2517
2518 return Qnil;
2519}
2520\f
644b477c 2521DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 1, "P",
7ab12479
JB
2522 "Scroll selected window display ARG columns left.\n\
2523Default for ARG is window width minus 2.")
2524 (arg)
2525 register Lisp_Object arg;
2526{
2527
265a9e55 2528 if (NILP (arg))
b8baad40 2529 XFASTINT (arg) = window_internal_width (XWINDOW (selected_window)) - 2;
7ab12479
JB
2530 else
2531 arg = Fprefix_numeric_value (arg);
2532
2533 return
2534 Fset_window_hscroll (selected_window,
2535 make_number (XINT (XWINDOW (selected_window)->hscroll)
2536 + XINT (arg)));
2537}
2538
644b477c 2539DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 1, "P",
7ab12479
JB
2540 "Scroll selected window display ARG columns right.\n\
2541Default for ARG is window width minus 2.")
2542 (arg)
2543 register Lisp_Object arg;
2544{
265a9e55 2545 if (NILP (arg))
b8baad40 2546 XFASTINT (arg) = window_internal_width (XWINDOW (selected_window)) - 2;
7ab12479
JB
2547 else
2548 arg = Fprefix_numeric_value (arg);
2549
2550 return
2551 Fset_window_hscroll (selected_window,
2552 make_number (XINT (XWINDOW (selected_window)->hscroll)
2553 - XINT (arg)));
2554}
2555
2556DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
44fa5b1e 2557 "Center point in window and redisplay frame. With ARG, put point on line ARG.\n\
7ab12479 2558The desired position of point is always relative to the current window.\n\
44fa5b1e
JB
2559Just C-u as prefix means put point in the center of the window.\n\
2560No arg (i.e., it is nil) erases the entire frame and then\n\
2561redraws with point in the center of the current window.")
7ab12479
JB
2562 (n)
2563 register Lisp_Object n;
2564{
2565 register struct window *w = XWINDOW (selected_window);
2566 register int ht = window_internal_height (w);
5ce7b543 2567 register int opoint = PT;
540b6aa0 2568 Lisp_Object window;
7ab12479 2569
265a9e55 2570 if (NILP (n))
7ab12479 2571 {
44fa5b1e 2572 extern int frame_garbaged;
7ab12479 2573
44fa5b1e 2574 SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
7ab12479
JB
2575 XFASTINT (n) = ht / 2;
2576 }
2577 else if (XTYPE (n) == Lisp_Cons) /* Just C-u. */
2578 {
2579 XFASTINT (n) = ht / 2;
2580 }
2581 else
2582 {
2583 n = Fprefix_numeric_value (n);
2584 CHECK_NUMBER (n, 0);
2585 }
2586
2587 if (XINT (n) < 0)
2588 XSETINT (n, XINT (n) + ht);
2589
2590 XSETINT (n, - XINT (n));
2591
540b6aa0
RS
2592 XSET (window, Lisp_Window, w);
2593 Fvertical_motion (n, window);
5ce7b543 2594 Fset_marker (w->start, make_number (PT), w->buffer);
7ab12479
JB
2595 w->start_at_line_beg = Fbolp ();
2596
2597 SET_PT (opoint);
2598 w->force_start = Qt;
2599
2600 return Qnil;
2601}
2602\f
2603DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
2604 1, 1, "P",
2605 "Position point relative to window.\n\
2606With no argument, position text at center of window.\n\
44fa5b1e 2607An argument specifies frame line; zero means top of window,\n\
7ab12479
JB
2608negative means relative to bottom of window.")
2609 (arg)
2610 register Lisp_Object arg;
2611{
2612 register struct window *w = XWINDOW (selected_window);
2613 register int height = window_internal_height (w);
2614 register int start;
540b6aa0 2615 Lisp_Object window;
7ab12479 2616
265a9e55 2617 if (NILP (arg))
7ab12479
JB
2618 XFASTINT (arg) = height / 2;
2619 else
2620 {
2621 arg = Fprefix_numeric_value (arg);
2622 if (XINT (arg) < 0)
2623 XSETINT (arg, XINT (arg) + height);
2624 }
2625
2626 start = marker_position (w->start);
540b6aa0 2627 XSET (window, Lisp_Window, w);
7ab12479
JB
2628 if (start < BEGV || start > ZV)
2629 {
cd2be1dd 2630 Fvertical_motion (make_number (- (height / 2)), window);
5ce7b543 2631 Fset_marker (w->start, make_number (PT), w->buffer);
7ab12479
JB
2632 w->start_at_line_beg = Fbolp ();
2633 w->force_start = Qt;
2634 }
2635 else
2636 SET_PT (start);
2637
540b6aa0 2638 return Fvertical_motion (arg, window);
7ab12479
JB
2639}
2640\f
2641struct save_window_data
2642 {
2643 int size_from_Lisp_Vector_struct;
2644 struct Lisp_Vector *next_from_Lisp_Vector_struct;
8f6ea2e9 2645 Lisp_Object frame_width, frame_height, frame_menu_bar_lines;
bdc727bf 2646 Lisp_Object selected_frame;
7ab12479
JB
2647 Lisp_Object current_window;
2648 Lisp_Object current_buffer;
2649 Lisp_Object minibuf_scroll_window;
2650 Lisp_Object root_window;
bdc727bf 2651 Lisp_Object focus_frame;
7ab12479
JB
2652 /* A vector, interpreted as a struct saved_window */
2653 Lisp_Object saved_windows;
2654 };
ff06df24
JB
2655
2656/* Arg to Fmake_vector */
2657#define SAVE_WINDOW_DATA_SIZE \
2658 ((sizeof (struct save_window_data) \
2659 - (sizeof (struct Lisp_Vector) \
2660 /* Don't count the contents member of the struct Lisp_Vector */ \
2661 - sizeof (Lisp_Object))) \
2662 / sizeof (Lisp_Object))
7ab12479
JB
2663
2664/* This is saved as a Lisp_Vector */
2665struct saved_window
2666 {
2667 /* these first two must agree with struct Lisp_Vector in lisp.h */
2668 int size_from_Lisp_Vector_struct;
2669 struct Lisp_Vector *next_from_Lisp_Vector_struct;
2670
2671 Lisp_Object window;
2672 Lisp_Object buffer, start, pointm, mark;
2673 Lisp_Object left, top, width, height, hscroll;
2674 Lisp_Object parent, prev;
2675 Lisp_Object start_at_line_beg;
2676 Lisp_Object display_table;
2677 };
2678#define SAVED_WINDOW_VECTOR_SIZE 14 /* Arg to Fmake_vector */
2679
2680#define SAVED_WINDOW_N(swv,n) \
2681 ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
2682
2683DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
2684 "T if OBJECT is a window-configration object.")
2685 (obj)
2686 Lisp_Object obj;
2687{
2688 if (XTYPE (obj) == Lisp_Window_Configuration)
2689 return Qt;
2690 return Qnil;
2691}
2692
2693
d5b2799e
RS
2694DEFUN ("set-window-configuration", Fset_window_configuration,
2695 Sset_window_configuration, 1, 1, 0,
7ab12479
JB
2696 "Set the configuration of windows and buffers as specified by CONFIGURATION.\n\
2697CONFIGURATION must be a value previously returned\n\
2698by `current-window-configuration' (which see).")
2f83aebe
JB
2699 (configuration)
2700 Lisp_Object configuration;
7ab12479 2701{
7ab12479
JB
2702 register struct save_window_data *data;
2703 struct Lisp_Vector *saved_windows;
7ab12479 2704 Lisp_Object new_current_buffer;
fd482be5 2705 Lisp_Object frame;
44fa5b1e 2706 FRAME_PTR f;
7ab12479 2707
2f83aebe 2708 while (XTYPE (configuration) != Lisp_Window_Configuration)
7ab12479 2709 {
2f83aebe
JB
2710 configuration = wrong_type_argument (intern ("window-configuration-p"),
2711 configuration);
7ab12479
JB
2712 }
2713
2f83aebe 2714 data = (struct save_window_data *) XVECTOR (configuration);
7ab12479
JB
2715 saved_windows = XVECTOR (data->saved_windows);
2716
7ab12479 2717 new_current_buffer = data->current_buffer;
265a9e55 2718 if (NILP (XBUFFER (new_current_buffer)->name))
7ab12479
JB
2719 new_current_buffer = Qnil;
2720
fd482be5
JB
2721 frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
2722 f = XFRAME (frame);
9ace597f 2723
fd482be5
JB
2724 /* If f is a dead frame, don't bother rebuilding its window tree.
2725 However, there is other stuff we should still try to do below. */
2726 if (FRAME_LIVE_P (f))
7ab12479 2727 {
fd482be5
JB
2728 register struct window *w;
2729 register struct saved_window *p;
2730 int k;
2731
2732 /* If the frame has been resized since this window configuration was
2733 made, we change the frame to the size specified in the
2734 configuration, restore the configuration, and then resize it
2735 back. We keep track of the prevailing height in these variables. */
2736 int previous_frame_height = FRAME_HEIGHT (f);
2737 int previous_frame_width = FRAME_WIDTH (f);
8f6ea2e9 2738 int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
fd482be5
JB
2739
2740 if (XFASTINT (data->frame_height) != previous_frame_height
2741 || XFASTINT (data->frame_width) != previous_frame_width)
2742 change_frame_size (f, data->frame_height, data->frame_width, 0, 0);
217f2871 2743#ifdef HAVE_X_WINDOWS
8f6ea2e9
KH
2744 if (XFASTINT (data->frame_menu_bar_lines)
2745 != previous_frame_menu_bar_lines)
2746 x_set_menu_bar_lines (f, data->frame_menu_bar_lines, 0);
217f2871 2747#endif
fd482be5
JB
2748
2749 windows_or_buffers_changed++;
2750
2751 /* Kludge Alert!
2752 Mark all windows now on frame as "deleted".
2753 Restoring the new configuration "undeletes" any that are in it.
2754
2755 Save their current buffers in their height fields, since we may
2756 need it later, if a buffer saved in the configuration is now
2757 dead. */
2758 delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
2759
2760 for (k = 0; k < saved_windows->size; k++)
2761 {
2762 p = SAVED_WINDOW_N (saved_windows, k);
2763 w = XWINDOW (p->window);
2764 w->next = Qnil;
7ab12479 2765
fd482be5
JB
2766 if (!NILP (p->parent))
2767 w->parent = SAVED_WINDOW_N (saved_windows,
2768 XFASTINT (p->parent))->window;
2769 else
2770 w->parent = Qnil;
7ab12479 2771
fd482be5 2772 if (!NILP (p->prev))
7ab12479 2773 {
fd482be5
JB
2774 w->prev = SAVED_WINDOW_N (saved_windows,
2775 XFASTINT (p->prev))->window;
2776 XWINDOW (w->prev)->next = p->window;
2777 }
2778 else
2779 {
2780 w->prev = Qnil;
2781 if (!NILP (w->parent))
2782 {
2783 if (EQ (p->width, XWINDOW (w->parent)->width))
2784 {
2785 XWINDOW (w->parent)->vchild = p->window;
2786 XWINDOW (w->parent)->hchild = Qnil;
2787 }
2788 else
2789 {
2790 XWINDOW (w->parent)->hchild = p->window;
2791 XWINDOW (w->parent)->vchild = Qnil;
2792 }
2793 }
2794 }
2795
2796 /* If we squirreled away the buffer in the window's height,
2797 restore it now. */
2798 if (XTYPE (w->height) == Lisp_Buffer)
2799 w->buffer = w->height;
2800 w->left = p->left;
2801 w->top = p->top;
2802 w->width = p->width;
2803 w->height = p->height;
2804 w->hscroll = p->hscroll;
2805 w->display_table = p->display_table;
2806 XFASTINT (w->last_modified) = 0;
2807
2808 /* Reinstall the saved buffer and pointers into it. */
2809 if (NILP (p->buffer))
2810 w->buffer = p->buffer;
2811 else
2812 {
2813 if (!NILP (XBUFFER (p->buffer)->name))
2814 /* If saved buffer is alive, install it. */
2815 {
2816 w->buffer = p->buffer;
2817 w->start_at_line_beg = p->start_at_line_beg;
2818 set_marker_restricted (w->start,
2819 Fmarker_position (p->start),
2820 w->buffer);
2821 set_marker_restricted (w->pointm,
2822 Fmarker_position (p->pointm),
2823 w->buffer);
2824 Fset_marker (XBUFFER (w->buffer)->mark,
2825 Fmarker_position (p->mark), w->buffer);
2826
2827 /* As documented in Fcurrent_window_configuration, don't
2828 save the location of point in the buffer which was current
2829 when the window configuration was recorded. */
6b54027b
RS
2830 if (!EQ (p->buffer, new_current_buffer)
2831 && XBUFFER (p->buffer) == current_buffer)
fd482be5
JB
2832 Fgoto_char (w->pointm);
2833 }
52a68e98
RS
2834 else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
2835 /* Else unless window has a live buffer, get one. */
7ab12479 2836 {
fd482be5
JB
2837 w->buffer = Fcdr (Fcar (Vbuffer_alist));
2838 /* This will set the markers to beginning of visible
2839 range. */
2840 set_marker_restricted (w->start, make_number (0), w->buffer);
2841 set_marker_restricted (w->pointm, make_number (0),w->buffer);
2842 w->start_at_line_beg = Qt;
7ab12479
JB
2843 }
2844 else
fd482be5 2845 /* Keeping window's old buffer; make sure the markers
52a68e98 2846 are real. */
7ab12479 2847 {
fd482be5
JB
2848 /* Set window markers at start of visible range. */
2849 if (XMARKER (w->start)->buffer == 0)
2850 set_marker_restricted (w->start, make_number (0),
2851 w->buffer);
2852 if (XMARKER (w->pointm)->buffer == 0)
2853 set_marker_restricted (w->pointm,
2854 (make_number
2855 (BUF_PT (XBUFFER (w->buffer)))),
2856 w->buffer);
2857 w->start_at_line_beg = Qt;
7ab12479
JB
2858 }
2859 }
2860 }
9ace597f 2861
fd482be5
JB
2862 FRAME_ROOT_WINDOW (f) = data->root_window;
2863 Fselect_window (data->current_window);
7ab12479 2864
fd482be5 2865#ifdef MULTI_FRAME
db269683
JB
2866 if (NILP (data->focus_frame)
2867 || (XTYPE (data->focus_frame) == Lisp_Frame
2868 && FRAME_LIVE_P (XFRAME (data->focus_frame))))
2869 Fredirect_frame_focus (frame, data->focus_frame);
fd482be5 2870#endif
7ab12479 2871
fd482be5
JB
2872#if 0 /* I don't understand why this is needed, and it causes problems
2873 when the frame's old selected window has been deleted. */
2874#ifdef MULTI_FRAME
2875 if (f != selected_frame && ! FRAME_TERMCAP_P (f))
d5b2799e 2876 Fhandle_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)), Qnil);
fd482be5
JB
2877#endif
2878#endif
2879
2880 /* Set the screen height to the value it had before this function. */
2881 if (previous_frame_height != FRAME_HEIGHT (f)
2882 || previous_frame_width != FRAME_WIDTH (f))
2883 change_frame_size (f, previous_frame_height, previous_frame_width,
2884 0, 0);
217f2871 2885#ifdef HAVE_X_WINDOWS
8f6ea2e9
KH
2886 if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
2887 x_set_menu_bar_lines (f, previous_frame_menu_bar_lines, 0);
217f2871 2888#endif
fd482be5 2889 }
bdc727bf 2890
ad854249 2891#ifdef MULTI_FRAME
bdc727bf 2892 /* Fselect_window will have made f the selected frame, so we
d5b2799e 2893 reselect the proper frame here. Fhandle_switch_frame will change the
bdc727bf
JB
2894 selected window too, but that doesn't make the call to
2895 Fselect_window above totally superfluous; it still sets f's
2896 selected window. */
fd482be5 2897 if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
d5b2799e 2898 Fhandle_switch_frame (data->selected_frame, Qnil);
ad854249 2899#endif
bdc727bf
JB
2900
2901 if (!NILP (new_current_buffer))
2902 Fset_buffer (new_current_buffer);
2903
7ab12479
JB
2904 Vminibuf_scroll_window = data->minibuf_scroll_window;
2905 return (Qnil);
2906}
2907
44fa5b1e 2908/* Mark all windows now on frame as deleted
7ab12479
JB
2909 by setting their buffers to nil. */
2910
fd482be5 2911void
7ab12479
JB
2912delete_all_subwindows (w)
2913 register struct window *w;
2914{
265a9e55 2915 if (!NILP (w->next))
7ab12479 2916 delete_all_subwindows (XWINDOW (w->next));
265a9e55 2917 if (!NILP (w->vchild))
7ab12479 2918 delete_all_subwindows (XWINDOW (w->vchild));
265a9e55 2919 if (!NILP (w->hchild))
7ab12479 2920 delete_all_subwindows (XWINDOW (w->hchild));
605be8af
JB
2921
2922 w->height = w->buffer; /* See Fset_window_configuration for excuse. */
2923
2924 /* We set all three of these fields to nil, to make sure that we can
2925 distinguish this dead window from any live window. Live leaf
2926 windows will have buffer set, and combination windows will have
2927 vchild or hchild set. */
2928 w->buffer = Qnil;
2929 w->vchild = Qnil;
2930 w->hchild = Qnil;
7ab12479
JB
2931}
2932\f
2933static int
2934count_windows (window)
2935 register struct window *window;
2936{
2937 register int count = 1;
265a9e55 2938 if (!NILP (window->next))
7ab12479 2939 count += count_windows (XWINDOW (window->next));
265a9e55 2940 if (!NILP (window->vchild))
7ab12479 2941 count += count_windows (XWINDOW (window->vchild));
265a9e55 2942 if (!NILP (window->hchild))
7ab12479
JB
2943 count += count_windows (XWINDOW (window->hchild));
2944 return count;
2945}
2946
2947static int
2948save_window_save (window, vector, i)
2949 Lisp_Object window;
2950 struct Lisp_Vector *vector;
2951 int i;
2952{
2953 register struct saved_window *p;
2954 register struct window *w;
2955 register Lisp_Object tem;
2956
265a9e55 2957 for (;!NILP (window); window = w->next)
7ab12479
JB
2958 {
2959 p = SAVED_WINDOW_N (vector, i);
2960 w = XWINDOW (window);
2961
2962 XFASTINT (w->temslot) = i++;
2963 p->window = window;
2964 p->buffer = w->buffer;
2965 p->left = w->left;
2966 p->top = w->top;
2967 p->width = w->width;
2968 p->height = w->height;
2969 p->hscroll = w->hscroll;
2970 p->display_table = w->display_table;
265a9e55 2971 if (!NILP (w->buffer))
7ab12479
JB
2972 {
2973 /* Save w's value of point in the window configuration.
2974 If w is the selected window, then get the value of point
2975 from the buffer; pointm is garbage in the selected window. */
2976 if (EQ (window, selected_window))
2977 {
2978 p->pointm = Fmake_marker ();
2979 Fset_marker (p->pointm, BUF_PT (XBUFFER (w->buffer)),
2980 w->buffer);
2981 }
2982 else
2983 p->pointm = Fcopy_marker (w->pointm);
2984
2985 p->start = Fcopy_marker (w->start);
2986 p->start_at_line_beg = w->start_at_line_beg;
2987
2988 tem = XBUFFER (w->buffer)->mark;
2989 p->mark = Fcopy_marker (tem);
2990 }
2991 else
2992 {
2993 p->pointm = Qnil;
2994 p->start = Qnil;
2995 p->mark = Qnil;
2996 p->start_at_line_beg = Qnil;
2997 }
2998
265a9e55 2999 if (NILP (w->parent))
7ab12479
JB
3000 p->parent = Qnil;
3001 else
3002 p->parent = XWINDOW (w->parent)->temslot;
3003
265a9e55 3004 if (NILP (w->prev))
7ab12479
JB
3005 p->prev = Qnil;
3006 else
3007 p->prev = XWINDOW (w->prev)->temslot;
3008
265a9e55 3009 if (!NILP (w->vchild))
7ab12479 3010 i = save_window_save (w->vchild, vector, i);
265a9e55 3011 if (!NILP (w->hchild))
7ab12479
JB
3012 i = save_window_save (w->hchild, vector, i);
3013 }
3014
3015 return i;
3016}
3017
3018DEFUN ("current-window-configuration",
43bad991 3019 Fcurrent_window_configuration, Scurrent_window_configuration, 0, 1, 0,
44fa5b1e
JB
3020 "Return an object representing the current window configuration of FRAME.\n\
3021If FRAME is nil or omitted, use the selected frame.\n\
7ab12479
JB
3022This describes the number of windows, their sizes and current buffers,\n\
3023and for each displayed buffer, where display starts, and the positions of\n\
3024point and mark. An exception is made for point in the current buffer:\n\
bdc727bf
JB
3025its value is -not- saved.\n\
3026This also records the currently selected frame, and FRAME's focus\n\
3027redirection (see `redirect-frame-focus').")
44fa5b1e
JB
3028 (frame)
3029 Lisp_Object frame;
7ab12479
JB
3030{
3031 register Lisp_Object tem;
3032 register int n_windows;
3033 register struct save_window_data *data;
3034 register int i;
44fa5b1e 3035 FRAME_PTR f;
43bad991 3036
44fa5b1e
JB
3037 if (NILP (frame))
3038 f = selected_frame;
43bad991
JB
3039 else
3040 {
44fa5b1e
JB
3041 CHECK_LIVE_FRAME (frame, 0);
3042 f = XFRAME (frame);
43bad991 3043 }
7ab12479 3044
44fa5b1e 3045 n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
7ab12479
JB
3046 data = (struct save_window_data *)
3047 XVECTOR (Fmake_vector (make_number (SAVE_WINDOW_DATA_SIZE),
3048 Qnil));
44fa5b1e
JB
3049 XFASTINT (data->frame_width) = FRAME_WIDTH (f);
3050 XFASTINT (data->frame_height) = FRAME_HEIGHT (f);
8f6ea2e9 3051 XFASTINT (data->frame_menu_bar_lines) = FRAME_MENU_BAR_LINES (f);
ad854249 3052#ifdef MULTI_FRAME
bdc727bf 3053 XSET (data->selected_frame, Lisp_Frame, selected_frame);
ad854249 3054#endif
44fa5b1e 3055 data->current_window = FRAME_SELECTED_WINDOW (f);
7ab12479
JB
3056 XSET (data->current_buffer, Lisp_Buffer, current_buffer);
3057 data->minibuf_scroll_window = Vminibuf_scroll_window;
44fa5b1e 3058 data->root_window = FRAME_ROOT_WINDOW (f);
bdc727bf 3059 data->focus_frame = FRAME_FOCUS_FRAME (f);
7ab12479
JB
3060 tem = Fmake_vector (make_number (n_windows), Qnil);
3061 data->saved_windows = tem;
3062 for (i = 0; i < n_windows; i++)
3063 XVECTOR (tem)->contents[i]
3064 = Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil);
44fa5b1e 3065 save_window_save (FRAME_ROOT_WINDOW (f),
7ab12479
JB
3066 XVECTOR (tem), 0);
3067 XSET (tem, Lisp_Window_Configuration, data);
3068 return (tem);
3069}
3070
3071DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
3072 0, UNEVALLED, 0,
3073 "Execute body, preserving window sizes and contents.\n\
eb16ec06
RS
3074Restore which buffer appears in which window, where display starts,\n\
3075and the value of point and mark for each window.\n\
3076Also restore which buffer is current.\n\
3077But do not preserve point in the current buffer.\n\
7ab12479
JB
3078Does not restore the value of point in current buffer.")
3079 (args)
3080 Lisp_Object args;
3081{
3082 register Lisp_Object val;
3083 register int count = specpdl_ptr - specpdl;
3084
3085 record_unwind_protect (Fset_window_configuration,
43bad991 3086 Fcurrent_window_configuration (Qnil));
7ab12479
JB
3087 val = Fprogn (args);
3088 return unbind_to (count, val);
3089}
3090\f
3091init_window_once ()
3092{
44fa5b1e
JB
3093#ifdef MULTI_FRAME
3094 selected_frame = make_terminal_frame ();
3095 minibuf_window = selected_frame->minibuffer_window;
3096 selected_window = selected_frame->selected_window;
3097 last_nonminibuf_frame = selected_frame;
3098#else /* not MULTI_FRAME */
7ab12479
JB
3099 extern Lisp_Object get_minibuffer ();
3100
95605e15 3101 minibuf_window = make_window ();
4b206065 3102 FRAME_ROOT_WINDOW (selected_frame) = make_window ();
7ab12479 3103
44fa5b1e
JB
3104 XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->next = minibuf_window;
3105 XWINDOW (minibuf_window)->prev = FRAME_ROOT_WINDOW (selected_frame);
4b206065 3106 XWINDOW (minibuf_window)->mini_p = Qt;
7ab12479
JB
3107
3108 /* These values 9 and 10 are arbitrary,
3109 just so that there is "something there."
3110 Correct values are put in in init_xdisp */
3111
44fa5b1e 3112 XFASTINT (XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->width) = 10;
7ab12479
JB
3113 XFASTINT (XWINDOW (minibuf_window)->width) = 10;
3114
44fa5b1e 3115 XFASTINT (XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->height) = 9;
7ab12479
JB
3116 XFASTINT (XWINDOW (minibuf_window)->top) = 9;
3117 XFASTINT (XWINDOW (minibuf_window)->height) = 1;
3118
3119 /* Prevent error in Fset_window_buffer. */
44fa5b1e 3120 XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->buffer = Qt;
7ab12479
JB
3121 XWINDOW (minibuf_window)->buffer = Qt;
3122
3123 /* Now set them up for real. */
44fa5b1e 3124 Fset_window_buffer (FRAME_ROOT_WINDOW (selected_frame),
e5d77022 3125 Fcurrent_buffer ());
7ab12479
JB
3126 Fset_window_buffer (minibuf_window, get_minibuffer (0));
3127
44fa5b1e 3128 selected_window = FRAME_ROOT_WINDOW (selected_frame);
1d8d96fa
JB
3129 /* Make sure this window seems more recently used than
3130 a newly-created, never-selected window. Increment
3131 window_select_count so the first selection ever will get
3132 something newer than this. */
3133 XFASTINT (XWINDOW (selected_window)->use_time) = ++window_select_count;
44fa5b1e 3134#endif /* not MULTI_FRAME */
7ab12479
JB
3135}
3136
3137syms_of_window ()
3138{
3139 Qwindowp = intern ("windowp");
3140 staticpro (&Qwindowp);
3141
806b4d9b
JB
3142 Qwindow_live_p = intern ("window-live-p");
3143 staticpro (&Qwindow_live_p);
605be8af 3144
2f83aebe 3145#ifndef MULTI_FRAME
7ab12479
JB
3146 /* Make sure all windows get marked */
3147 staticpro (&minibuf_window);
2f83aebe 3148#endif
7ab12479
JB
3149
3150 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
3151 "Non-nil means call as function to display a help buffer.\n\
3152Used by `with-output-to-temp-buffer'.");
3153 Vtemp_buffer_show_function = Qnil;
3154
3155 DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
3156 "If non-nil, function to call to handle `display-buffer'.\n\
3157It will receive two args, the buffer and a flag which if non-nil means\n\
3158 that the currently selected window is not acceptable.\n\
3159Commands such as `switch-to-buffer-other-window' and `find-file-other-window'\n\
3160work using this function.");
3161 Vdisplay_buffer_function = Qnil;
3162
7ab12479
JB
3163 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
3164 "Non-nil means it is the window that C-M-v in minibuffer should scroll.");
3165 Vminibuf_scroll_window = Qnil;
3166
3167 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
3168 "If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.");
3169 Vother_window_scroll_buffer = Qnil;
3170
44fa5b1e 3171 DEFVAR_BOOL ("pop-up-frames", &pop_up_frames,
700f75a4 3172 "*Non-nil means `display-buffer' should make a separate frame.");
44fa5b1e 3173 pop_up_frames = 0;
7ab12479 3174
44fa5b1e 3175 DEFVAR_LISP ("pop-up-frame-function", &Vpop_up_frame_function,
a90712c2 3176 "Function to call to handle automatic new frame creation.\n\
44fa5b1e 3177It is called with no arguments and should return a newly created frame.\n\
7ab12479 3178\n\
44fa5b1e
JB
3179A typical value might be `(lambda () (new-frame pop-up-frame-alist))'\n\
3180where `pop-up-frame-alist' would hold the default frame parameters.");
3181 Vpop_up_frame_function = Qnil;
7ab12479 3182
a90712c2
RS
3183 DEFVAR_LISP ("special-display-buffer-names", &Vspecial_display_buffer_names,
3184 "*List of buffer names that should have their own special frames.\n\
3185Displaying a buffer whose name is in this list makes a special frame for it\n\
3186using `special-display-function'. See also `special-display-regexps'.");
3187 Vspecial_display_buffer_names = Qnil;
3188
3189 DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
3190 "*List of regexps saying which buffers should have their own special frames.\n\
3191If a buffer name matches one of these regexps, it gets its own frame.\n\
3192Displaying a buffer whose name is in this list makes a special frame for it\n\
3193using `special-display-function'. See also `special-display-buffer-names'.");
3194 Vspecial_display_regexps = Qnil;
3195
3196 DEFVAR_LISP ("special-display-function", &Vspecial_display_function,
3197 "Function to call to make a new frame for a special buffer.\n\
3198It is called with one argument, the buffer,\n\
3199and should return a window displaying that buffer.\n\
3200The default value makes a separate frame for the buffer,\n\
3201using `special-display-alist' to specify the frame parameters.\n\
3202\n\
3203A buffer is special if its is listed in `special-display-buffer-names'\n\
3204or matches a regexp in `special-display-regexps'.");
3205 Vspecial_display_function = Qnil;
3206
7ab12479
JB
3207 DEFVAR_BOOL ("pop-up-windows", &pop_up_windows,
3208 "*Non-nil means display-buffer should make new windows.");
3209 pop_up_windows = 1;
3210
3211 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
3212 "*Number of lines of continuity when scrolling by screenfuls.");
3213 next_screen_context_lines = 2;
3214
3215 DEFVAR_INT ("split-height-threshold", &split_height_threshold,
3216 "*display-buffer would prefer to split the largest window if this large.\n\
3217If there is only one window, it is split regardless of this value.");
3218 split_height_threshold = 500;
3219
3220 DEFVAR_INT ("window-min-height", &window_min_height,
3221 "*Delete any window less than this tall (including its mode line).");
3222 window_min_height = 4;
3223
3224 DEFVAR_INT ("window-min-width", &window_min_width,
3225 "*Delete any window less than this wide.");
3226 window_min_width = 10;
3227
3228 defsubr (&Sselected_window);
3229 defsubr (&Sminibuffer_window);
3230 defsubr (&Swindow_minibuffer_p);
3231 defsubr (&Swindowp);
806b4d9b 3232 defsubr (&Swindow_live_p);
7ab12479
JB
3233 defsubr (&Spos_visible_in_window_p);
3234 defsubr (&Swindow_buffer);
3235 defsubr (&Swindow_height);
3236 defsubr (&Swindow_width);
3237 defsubr (&Swindow_hscroll);
3238 defsubr (&Sset_window_hscroll);
3239 defsubr (&Swindow_edges);
d5783c40
JB
3240 defsubr (&Scoordinates_in_window_p);
3241 defsubr (&Swindow_at);
7ab12479
JB
3242 defsubr (&Swindow_point);
3243 defsubr (&Swindow_start);
3244 defsubr (&Swindow_end);
3245 defsubr (&Sset_window_point);
3246 defsubr (&Sset_window_start);
3247 defsubr (&Swindow_dedicated_p);
d207b766 3248 defsubr (&Sset_window_dedicated_p);
7ab12479
JB
3249 defsubr (&Swindow_display_table);
3250 defsubr (&Sset_window_display_table);
3251 defsubr (&Snext_window);
3252 defsubr (&Sprevious_window);
3253 defsubr (&Sother_window);
3254 defsubr (&Sget_lru_window);
3255 defsubr (&Sget_largest_window);
3256 defsubr (&Sget_buffer_window);
3257 defsubr (&Sdelete_other_windows);
3258 defsubr (&Sdelete_windows_on);
3259 defsubr (&Sreplace_buffer_in_windows);
3260 defsubr (&Sdelete_window);
3261 defsubr (&Sset_window_buffer);
3262 defsubr (&Sselect_window);
3263 defsubr (&Sdisplay_buffer);
3264 defsubr (&Ssplit_window);
3265 defsubr (&Senlarge_window);
3266 defsubr (&Sshrink_window);
3267 defsubr (&Sscroll_up);
3268 defsubr (&Sscroll_down);
3269 defsubr (&Sscroll_left);
3270 defsubr (&Sscroll_right);
ccd0664b 3271 defsubr (&Sother_window_for_scrolling);
7ab12479
JB
3272 defsubr (&Sscroll_other_window);
3273 defsubr (&Srecenter);
3274 defsubr (&Smove_to_window_line);
3275 defsubr (&Swindow_configuration_p);
3276 defsubr (&Sset_window_configuration);
3277 defsubr (&Scurrent_window_configuration);
3278 defsubr (&Ssave_window_excursion);
3279}
3280
3281keys_of_window ()
3282{
3283 initial_define_key (control_x_map, '1', "delete-other-windows");
3284 initial_define_key (control_x_map, '2', "split-window");
3285 initial_define_key (control_x_map, '0', "delete-window");
3286 initial_define_key (control_x_map, 'o', "other-window");
3287 initial_define_key (control_x_map, '^', "enlarge-window");
3288 initial_define_key (control_x_map, '<', "scroll-left");
3289 initial_define_key (control_x_map, '>', "scroll-right");
3290
3291 initial_define_key (global_map, Ctl ('V'), "scroll-up");
3292 initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
3293 initial_define_key (meta_map, 'v', "scroll-down");
3294
3295 initial_define_key (global_map, Ctl('L'), "recenter");
3296 initial_define_key (meta_map, 'r', "move-to-window-line");
3297}