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