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