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