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