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