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