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