(unshow_buffer): Unconditionally set last_window_start.
[bpt/emacs.git] / src / window.c
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
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the 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
32 Lisp_Object Qwindowp, Qwindow_live_p;
33
34 Lisp_Object Fnext_window (), Fdelete_window (), Fselect_window ();
35 Lisp_Object Fset_window_buffer (), Fsplit_window (), Frecenter ();
36
37 void delete_all_subwindows ();
38 static 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
48 Lisp_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. */
54 Lisp_Object minibuf_window;
55
56 /* Non-nil means it is the window for C-M-v to scroll
57 when the minibuffer is selected. */
58 Lisp_Object Vminibuf_scroll_window;
59
60 /* Non-nil means this is the buffer whose window C-M-v should scroll. */
61 Lisp_Object Vother_window_scroll_buffer;
62
63 /* Non-nil means it's function to call to display temp buffers. */
64 Lisp_Object Vtemp_buffer_show_function;
65
66 /* If a window gets smaller than either of these, it is removed. */
67 int window_min_height;
68 int window_min_width;
69
70 /* Nonzero implies Fdisplay_buffer should create windows. */
71 int pop_up_windows;
72
73 /* Nonzero implies make new frames for Fdisplay_buffer. */
74 int pop_up_frames;
75
76 /* Non-nil means use this function instead of default */
77 Lisp_Object Vpop_up_frame_function;
78
79 /* Function to call to handle Fdisplay_buffer. */
80 Lisp_Object Vdisplay_buffer_function;
81
82 /* Fdisplay_buffer always splits the largest window
83 if that window is more than this high. */
84 int split_height_threshold;
85
86 /* Number of lines of continuity in scrolling by screenfuls. */
87 int next_screen_context_lines;
88
89 /* Incremented for each window created. */
90 static int sequence_number;
91
92 #define min(a, b) ((a) < (b) ? (a) : (b))
93 \f
94 DEFUN ("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
102 DEFUN ("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
112 Lisp_Object
113 make_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
141 DEFUN ("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
148 DEFUN ("minibuffer-window", Fminibuffer_window, Sminibuffer_window, 0, 1, 0,
149 "Return the window used now for minibuffers.\n\
150 If the optional argument FRAME is specified, return the minibuffer window\n\
151 used 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
165 DEFUN ("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
174 DEFUN ("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\
177 Returns nil if that position is scrolled vertically out of view.\n\
178 POS 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
232 static struct window *
233 decode_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
243 DEFUN ("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
251 DEFUN ("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
259 DEFUN ("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
270 DEFUN ("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
278 DEFUN ("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\
280 NCOL 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
297 DEFUN ("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\
300 RIGHT is one more than the rightmost column used by WINDOW,\n\
301 and 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. */
324 static int
325 coordinates_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
353 DEFUN ("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\
356 COORDINATES is a cons of the form (X . Y), X and Y being distances\n\
357 measured 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\
359 frame.\n\
360 If COORDINATES are in the text portion of WINDOW,\n\
361 the coordinates relative to the window are returned.\n\
362 If they are in the mode line of WINDOW, `mode-line' is returned.\n\
363 If 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. */
399 Lisp_Object
400 window_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
426 DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
427 "Return window containing coordinates X and Y on FRAME.\n\
428 If omitted, FRAME defaults to the currently selected frame.\n\
429 The top left corner of the frame is considered to be row 0,\n\
430 column 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
450 DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
451 "Return current value of point in WINDOW.\n\
452 For a nonselected window, this is the value point would have\n\
453 if that window were selected.\n\
454 \n\
455 Note that, when WINDOW is the selected window and its buffer\n\
456 is also currently selected, the value returned is the same as (point).\n\
457 It would be more strictly correct to return the `top-level' value\n\
458 of point, outside of any save-excursion forms.\n\
459 But 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
471 DEFUN ("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
479 DEFUN ("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
497 DEFUN ("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
513 DEFUN ("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\
515 Optional third arg NOFORCE non-nil inhibits next redisplay\n\
516 from 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
535 DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
536 1, 1, 0,
537 "Return WINDOW's dedicated object, usually t or nil.\n\
538 See also `set-window-dedicated-p'.")
539 (window)
540 Lisp_Object window;
541 {
542 return decode_window (window)->dedicated;
543 }
544
545 DEFUN ("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\
548 If it is dedicated, Emacs will not automatically change\n\
549 which buffer appears in it.\n\
550 The second argument is the new value for the dedication flag;\n\
551 non-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
565 DEFUN ("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
579 struct Lisp_Vector *
580 window_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
596 DEFUN ("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. */
611 static
612 unshow_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. */
646 static
647 replace_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
682 and so is its new parent, we should make replacement's
683 children be children of that parent instead. ***/
684 }
685
686 DEFUN ("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
818 extern 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
824 DEFUN ("next-window", Ffoo, Sfoo, 0, 3, 0,
825 "Return next window after WINDOW in canonical ordering of windows.\n\
826 If omitted, WINDOW defaults to the selected window.\n\
827 \n\
828 Optional second arg MINIBUF t means count the minibuffer window even\n\
829 if not active. MINIBUF nil or omitted means count the minibuffer iff\n\
830 it is active. MINIBUF neither t nor nil means not to count the\n\
831 minibuffer even if it is active.\n\
832 \n\
833 Several frames may share a single minibuffer; if the minibuffer\n\
834 counts, all windows on all frames that share that minibuffer count\n\
835 too. This means that next-window may be used to iterate through the\n\
836 set of windows even when the minibuffer is on another frame. If the\n\
837 minibuffer does not count, only windows from WINDOW's frame count.\n\
838 \n\
839 Optional third arg ALL-FRAMES t means include windows on all frames.\n\
840 ALL-FRAMES nil or omitted means cycle within the frames as specified\n\
841 above. If neither nil nor t, restrict to WINDOW's frame.\n\
842 \n\
843 If 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\
845 windows, 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
849 DEFUN ("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
936 DEFUN ("previous-window", Ffoo, Sfoo, 0, 3, 0,
937 "Return the window preceeding WINDOW in canonical ordering of windows.\n\
938 If omitted, WINDOW defaults to the selected window.\n\
939 \n\
940 Optional second arg MINIBUF t means count the minibuffer window even\n\
941 if not active. MINIBUF nil or omitted means count the minibuffer iff\n\
942 it is active. MINIBUF neither t nor nil means not to count the\n\
943 minibuffer even if it is active.\n\
944 \n\
945 Several frames may share a single minibuffer; if the minibuffer\n\
946 counts, all windows on all frames that share that minibuffer count\n\
947 too. This means that previous-window may be used to iterate through\n\
948 the set of windows even when the minibuffer is on another frame. If\n\
949 the minibuffer does not count, only windows from WINDOW's frame\n\
950 count.\n\
951 \n\
952 Optional third arg ALL-FRAMES t means include windows on all frames.\n\
953 ALL-FRAMES nil or omitted means cycle within the frames as specified\n\
954 above. If neither nil nor t, restrict to WINDOW's frame.\n\
955 \n\
956 If 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\
958 windows, 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
963 DEFUN ("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
1061 DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
1062 "Select the ARG'th different window on this frame.\n\
1063 All windows on current frame are arranged in a cyclic order.\n\
1064 This command selects the window ARG steps away in that order.\n\
1065 A negative ARG moves in the opposite order. If the optional second\n\
1066 argument 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
1099 enum 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
1110 static Lisp_Object
1111 window_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
1281 DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
1282 "Return the window least recently selected or used for display.\n\
1283 If optional argument FRAMES is t, search all frames. If FRAME is a\n\
1284 frame, 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
1297 DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 1, 0,
1298 "Return the largest window in area.\n\
1299 If optional argument FRAMES is t, search all frames. If FRAME is a\n\
1300 frame, 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
1308 DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 1, 2, 0,
1309 "Return a window currently displaying BUFFER, or nil if none.\n\
1310 If optional argument FRAME is t, search all visible frames.\n\
1311 If FRAME is nil, search only the selected frame.\n\
1312 If 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
1323 DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
1324 0, 1, "",
1325 "Make WINDOW (or the selected window) fill its frame.\n\
1326 Only the frame WINDOW is on is affected.\n\
1327 This function tries to reduce display jumps\n\
1328 by keeping the text previously visible in WINDOW\n\
1329 in the same place on the frame. Doing this depends on\n\
1330 the value of (window-start WINDOW), so if calling this function\n\
1331 in a program gives strange scrolling, make sure the window-start\n\
1332 value 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
1364 DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
1365 1, 2, "bDelete windows on (buffer): ",
1366 "Delete all windows showing BUFFER.\n\
1367 Optional second argument FRAME controls which frames are affected.\n\
1368 If nil or omitted, delete all windows showing BUFFER in any frame.\n\
1369 If t, delete only windows showing BUFFER in the selected frame.\n\
1370 If 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
1392 DEFUN ("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
1418 static void
1419 check_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. */
1430 void
1431 check_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
1456 set_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
1521 set_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
1579 int window_select_count;
1580
1581 DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 2, 0,
1582 "Make WINDOW display BUFFER as its contents.\n\
1583 BUFFER 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
1628 DEFUN ("select-window", Fselect_window, Sselect_window, 1, 1, 0,
1629 "Select WINDOW. Most editing will apply to WINDOW's buffer.\n\
1630 The main editor command loop selects the buffer of the selected window\n\
1631 before 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
1685 DEFUN ("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\
1688 BUFFER can be a buffer or a buffer name.\n\
1689 If BUFFER is shown already in some window, just use that one,\n\
1690 unless the window is the selected window and the optional second\n\
1691 argument NOT-THIS-WINDOW is non-nil (interactively, with prefix arg).\n\
1692 If `pop-up-frames' is non-nil, make a new frame if no window shows BUFFER.\n\
1693 Returns 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
1769 void
1770 temp_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
1803 static
1804 make_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
1833 DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
1834 "Split WINDOW, putting SIZE lines in the first of the pair.\n\
1835 WINDOW defaults to selected one and SIZE to half its size.\n\
1836 If optional third arg HOR-FLAG is non-nil, split side by side\n\
1837 and 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
1942 DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
1943 "Make current window ARG lines bigger.\n\
1944 From 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
1953 DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
1954 "Make current window ARG lines smaller.\n\
1955 From 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
1964 int
1965 window_height (window)
1966 Lisp_Object window;
1967 {
1968 register struct window *p = XWINDOW (window);
1969 return XFASTINT (p->height);
1970 }
1971
1972 int
1973 window_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
1995 change_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
2111 int
2112 window_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. */
2132 int
2133 window_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
2160 void
2161 window_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
2229 static void
2230 scroll_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
2262 DEFUN ("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\
2264 A near full screen is `next-screen-context-lines' less than a full screen.\n\
2265 When 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
2273 DEFUN ("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\
2275 A near full screen is `next-screen-context-lines' less than a full screen.\n\
2276 When 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
2284 DEFUN ("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\
2286 The next window is the one below the current one; or the one at the top\n\
2287 if the current one is at the bottom.\n\
2288 When calling from a program, supply a number as argument or nil.\n\
2289 \n\
2290 If in the minibuffer, `minibuf-scroll-window' if non-nil\n\
2291 specifies the window to scroll.\n\
2292 If `other-window-scroll-buffer' is non-nil, scroll the window\n\
2293 showing 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
2359 DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 1, "P",
2360 "Scroll selected window display ARG columns left.\n\
2361 Default 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
2377 DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 1, "P",
2378 "Scroll selected window display ARG columns right.\n\
2379 Default 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
2394 DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
2395 "Center point in window and redisplay frame. With ARG, put point on line ARG.\n\
2396 The desired position of point is always relative to the current window.\n\
2397 Just C-u as prefix means put point in the center of the window.\n\
2398 No arg (i.e., it is nil) erases the entire frame and then\n\
2399 redraws 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
2439 DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
2440 1, 1, "P",
2441 "Position point relative to window.\n\
2442 With no argument, position text at center of window.\n\
2443 An argument specifies frame line; zero means top of window,\n\
2444 negative 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
2475 struct 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;
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 */
2499 struct 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
2517 DEFUN ("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
2528 DEFUN ("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\
2531 CONFIGURATION must be a value previously returned\n\
2532 by `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
2573 if (XFASTINT (data->frame_height) != previous_frame_height
2574 || XFASTINT (data->frame_width) != previous_frame_width)
2575 change_frame_size (f, data->frame_height, data->frame_width, 0, 0);
2576
2577 windows_or_buffers_changed++;
2578
2579 /* Kludge Alert!
2580 Mark all windows now on frame as "deleted".
2581 Restoring the new configuration "undeletes" any that are in it.
2582
2583 Save their current buffers in their height fields, since we may
2584 need it later, if a buffer saved in the configuration is now
2585 dead. */
2586 delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
2587
2588 for (k = 0; k < saved_windows->size; k++)
2589 {
2590 p = SAVED_WINDOW_N (saved_windows, k);
2591 w = XWINDOW (p->window);
2592 w->next = Qnil;
2593
2594 if (!NILP (p->parent))
2595 w->parent = SAVED_WINDOW_N (saved_windows,
2596 XFASTINT (p->parent))->window;
2597 else
2598 w->parent = Qnil;
2599
2600 if (!NILP (p->prev))
2601 {
2602 w->prev = SAVED_WINDOW_N (saved_windows,
2603 XFASTINT (p->prev))->window;
2604 XWINDOW (w->prev)->next = p->window;
2605 }
2606 else
2607 {
2608 w->prev = Qnil;
2609 if (!NILP (w->parent))
2610 {
2611 if (EQ (p->width, XWINDOW (w->parent)->width))
2612 {
2613 XWINDOW (w->parent)->vchild = p->window;
2614 XWINDOW (w->parent)->hchild = Qnil;
2615 }
2616 else
2617 {
2618 XWINDOW (w->parent)->hchild = p->window;
2619 XWINDOW (w->parent)->vchild = Qnil;
2620 }
2621 }
2622 }
2623
2624 /* If we squirreled away the buffer in the window's height,
2625 restore it now. */
2626 if (XTYPE (w->height) == Lisp_Buffer)
2627 w->buffer = w->height;
2628 w->left = p->left;
2629 w->top = p->top;
2630 w->width = p->width;
2631 w->height = p->height;
2632 w->hscroll = p->hscroll;
2633 w->display_table = p->display_table;
2634 XFASTINT (w->last_modified) = 0;
2635
2636 /* Reinstall the saved buffer and pointers into it. */
2637 if (NILP (p->buffer))
2638 w->buffer = p->buffer;
2639 else
2640 {
2641 if (!NILP (XBUFFER (p->buffer)->name))
2642 /* If saved buffer is alive, install it. */
2643 {
2644 w->buffer = p->buffer;
2645 w->start_at_line_beg = p->start_at_line_beg;
2646 set_marker_restricted (w->start,
2647 Fmarker_position (p->start),
2648 w->buffer);
2649 set_marker_restricted (w->pointm,
2650 Fmarker_position (p->pointm),
2651 w->buffer);
2652 Fset_marker (XBUFFER (w->buffer)->mark,
2653 Fmarker_position (p->mark), w->buffer);
2654
2655 /* As documented in Fcurrent_window_configuration, don't
2656 save the location of point in the buffer which was current
2657 when the window configuration was recorded. */
2658 if (!EQ (p->buffer, new_current_buffer) &&
2659 XBUFFER (p->buffer) == current_buffer)
2660 Fgoto_char (w->pointm);
2661 }
2662 else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
2663 /* Else unless window has a live buffer, get one. */
2664 {
2665 w->buffer = Fcdr (Fcar (Vbuffer_alist));
2666 /* This will set the markers to beginning of visible
2667 range. */
2668 set_marker_restricted (w->start, make_number (0), w->buffer);
2669 set_marker_restricted (w->pointm, make_number (0),w->buffer);
2670 w->start_at_line_beg = Qt;
2671 }
2672 else
2673 /* Keeping window's old buffer; make sure the markers
2674 are real. */
2675 {
2676 /* Set window markers at start of visible range. */
2677 if (XMARKER (w->start)->buffer == 0)
2678 set_marker_restricted (w->start, make_number (0),
2679 w->buffer);
2680 if (XMARKER (w->pointm)->buffer == 0)
2681 set_marker_restricted (w->pointm,
2682 (make_number
2683 (BUF_PT (XBUFFER (w->buffer)))),
2684 w->buffer);
2685 w->start_at_line_beg = Qt;
2686 }
2687 }
2688 }
2689
2690 FRAME_ROOT_WINDOW (f) = data->root_window;
2691 Fselect_window (data->current_window);
2692
2693 #ifdef MULTI_FRAME
2694 if (NILP (data->focus_frame)
2695 || (XTYPE (data->focus_frame) == Lisp_Frame
2696 && FRAME_LIVE_P (XFRAME (data->focus_frame))))
2697 Fredirect_frame_focus (frame, data->focus_frame);
2698 #endif
2699
2700 #if 0 /* I don't understand why this is needed, and it causes problems
2701 when the frame's old selected window has been deleted. */
2702 #ifdef MULTI_FRAME
2703 if (f != selected_frame && ! FRAME_TERMCAP_P (f))
2704 Fhandle_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)), Qnil);
2705 #endif
2706 #endif
2707
2708 /* Set the screen height to the value it had before this function. */
2709 if (previous_frame_height != FRAME_HEIGHT (f)
2710 || previous_frame_width != FRAME_WIDTH (f))
2711 change_frame_size (f, previous_frame_height, previous_frame_width,
2712 0, 0);
2713 }
2714
2715 #ifdef MULTI_FRAME
2716 /* Fselect_window will have made f the selected frame, so we
2717 reselect the proper frame here. Fhandle_switch_frame will change the
2718 selected window too, but that doesn't make the call to
2719 Fselect_window above totally superfluous; it still sets f's
2720 selected window. */
2721 if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
2722 Fhandle_switch_frame (data->selected_frame, Qnil);
2723 #endif
2724
2725 if (!NILP (new_current_buffer))
2726 Fset_buffer (new_current_buffer);
2727
2728 Vminibuf_scroll_window = data->minibuf_scroll_window;
2729 return (Qnil);
2730 }
2731
2732 /* Mark all windows now on frame as deleted
2733 by setting their buffers to nil. */
2734
2735 void
2736 delete_all_subwindows (w)
2737 register struct window *w;
2738 {
2739 if (!NILP (w->next))
2740 delete_all_subwindows (XWINDOW (w->next));
2741 if (!NILP (w->vchild))
2742 delete_all_subwindows (XWINDOW (w->vchild));
2743 if (!NILP (w->hchild))
2744 delete_all_subwindows (XWINDOW (w->hchild));
2745
2746 w->height = w->buffer; /* See Fset_window_configuration for excuse. */
2747
2748 /* We set all three of these fields to nil, to make sure that we can
2749 distinguish this dead window from any live window. Live leaf
2750 windows will have buffer set, and combination windows will have
2751 vchild or hchild set. */
2752 w->buffer = Qnil;
2753 w->vchild = Qnil;
2754 w->hchild = Qnil;
2755 }
2756 \f
2757 static int
2758 count_windows (window)
2759 register struct window *window;
2760 {
2761 register int count = 1;
2762 if (!NILP (window->next))
2763 count += count_windows (XWINDOW (window->next));
2764 if (!NILP (window->vchild))
2765 count += count_windows (XWINDOW (window->vchild));
2766 if (!NILP (window->hchild))
2767 count += count_windows (XWINDOW (window->hchild));
2768 return count;
2769 }
2770
2771 static int
2772 save_window_save (window, vector, i)
2773 Lisp_Object window;
2774 struct Lisp_Vector *vector;
2775 int i;
2776 {
2777 register struct saved_window *p;
2778 register struct window *w;
2779 register Lisp_Object tem;
2780
2781 for (;!NILP (window); window = w->next)
2782 {
2783 p = SAVED_WINDOW_N (vector, i);
2784 w = XWINDOW (window);
2785
2786 XFASTINT (w->temslot) = i++;
2787 p->window = window;
2788 p->buffer = w->buffer;
2789 p->left = w->left;
2790 p->top = w->top;
2791 p->width = w->width;
2792 p->height = w->height;
2793 p->hscroll = w->hscroll;
2794 p->display_table = w->display_table;
2795 if (!NILP (w->buffer))
2796 {
2797 /* Save w's value of point in the window configuration.
2798 If w is the selected window, then get the value of point
2799 from the buffer; pointm is garbage in the selected window. */
2800 if (EQ (window, selected_window))
2801 {
2802 p->pointm = Fmake_marker ();
2803 Fset_marker (p->pointm, BUF_PT (XBUFFER (w->buffer)),
2804 w->buffer);
2805 }
2806 else
2807 p->pointm = Fcopy_marker (w->pointm);
2808
2809 p->start = Fcopy_marker (w->start);
2810 p->start_at_line_beg = w->start_at_line_beg;
2811
2812 tem = XBUFFER (w->buffer)->mark;
2813 p->mark = Fcopy_marker (tem);
2814 }
2815 else
2816 {
2817 p->pointm = Qnil;
2818 p->start = Qnil;
2819 p->mark = Qnil;
2820 p->start_at_line_beg = Qnil;
2821 }
2822
2823 if (NILP (w->parent))
2824 p->parent = Qnil;
2825 else
2826 p->parent = XWINDOW (w->parent)->temslot;
2827
2828 if (NILP (w->prev))
2829 p->prev = Qnil;
2830 else
2831 p->prev = XWINDOW (w->prev)->temslot;
2832
2833 if (!NILP (w->vchild))
2834 i = save_window_save (w->vchild, vector, i);
2835 if (!NILP (w->hchild))
2836 i = save_window_save (w->hchild, vector, i);
2837 }
2838
2839 return i;
2840 }
2841
2842 DEFUN ("current-window-configuration",
2843 Fcurrent_window_configuration, Scurrent_window_configuration, 0, 1, 0,
2844 "Return an object representing the current window configuration of FRAME.\n\
2845 If FRAME is nil or omitted, use the selected frame.\n\
2846 This describes the number of windows, their sizes and current buffers,\n\
2847 and for each displayed buffer, where display starts, and the positions of\n\
2848 point and mark. An exception is made for point in the current buffer:\n\
2849 its value is -not- saved.\n\
2850 This also records the currently selected frame, and FRAME's focus\n\
2851 redirection (see `redirect-frame-focus').")
2852 (frame)
2853 Lisp_Object frame;
2854 {
2855 register Lisp_Object tem;
2856 register int n_windows;
2857 register struct save_window_data *data;
2858 register int i;
2859 FRAME_PTR f;
2860
2861 if (NILP (frame))
2862 f = selected_frame;
2863 else
2864 {
2865 CHECK_LIVE_FRAME (frame, 0);
2866 f = XFRAME (frame);
2867 }
2868
2869 n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
2870 data = (struct save_window_data *)
2871 XVECTOR (Fmake_vector (make_number (SAVE_WINDOW_DATA_SIZE),
2872 Qnil));
2873 XFASTINT (data->frame_width) = FRAME_WIDTH (f);
2874 XFASTINT (data->frame_height) = FRAME_HEIGHT (f);
2875 #ifdef MULTI_FRAME
2876 XSET (data->selected_frame, Lisp_Frame, selected_frame);
2877 #endif
2878 data->current_window = FRAME_SELECTED_WINDOW (f);
2879 XSET (data->current_buffer, Lisp_Buffer, current_buffer);
2880 data->minibuf_scroll_window = Vminibuf_scroll_window;
2881 data->root_window = FRAME_ROOT_WINDOW (f);
2882 data->focus_frame = FRAME_FOCUS_FRAME (f);
2883 tem = Fmake_vector (make_number (n_windows), Qnil);
2884 data->saved_windows = tem;
2885 for (i = 0; i < n_windows; i++)
2886 XVECTOR (tem)->contents[i]
2887 = Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil);
2888 save_window_save (FRAME_ROOT_WINDOW (f),
2889 XVECTOR (tem), 0);
2890 XSET (tem, Lisp_Window_Configuration, data);
2891 return (tem);
2892 }
2893
2894 DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
2895 0, UNEVALLED, 0,
2896 "Execute body, preserving window sizes and contents.\n\
2897 Restores which buffer appears in which window, where display starts,\n\
2898 as well as the current buffer.\n\
2899 Does not restore the value of point in current buffer.")
2900 (args)
2901 Lisp_Object args;
2902 {
2903 register Lisp_Object val;
2904 register int count = specpdl_ptr - specpdl;
2905
2906 record_unwind_protect (Fset_window_configuration,
2907 Fcurrent_window_configuration (Qnil));
2908 val = Fprogn (args);
2909 return unbind_to (count, val);
2910 }
2911 \f
2912 init_window_once ()
2913 {
2914 #ifdef MULTI_FRAME
2915 selected_frame = make_terminal_frame ();
2916 minibuf_window = selected_frame->minibuffer_window;
2917 selected_window = selected_frame->selected_window;
2918 last_nonminibuf_frame = selected_frame;
2919 #else /* not MULTI_FRAME */
2920 extern Lisp_Object get_minibuffer ();
2921
2922 minibuf_window = make_window ();
2923 FRAME_ROOT_WINDOW (selected_frame) = make_window ();
2924
2925 XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->next = minibuf_window;
2926 XWINDOW (minibuf_window)->prev = FRAME_ROOT_WINDOW (selected_frame);
2927 XWINDOW (minibuf_window)->mini_p = Qt;
2928
2929 /* These values 9 and 10 are arbitrary,
2930 just so that there is "something there."
2931 Correct values are put in in init_xdisp */
2932
2933 XFASTINT (XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->width) = 10;
2934 XFASTINT (XWINDOW (minibuf_window)->width) = 10;
2935
2936 XFASTINT (XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->height) = 9;
2937 XFASTINT (XWINDOW (minibuf_window)->top) = 9;
2938 XFASTINT (XWINDOW (minibuf_window)->height) = 1;
2939
2940 /* Prevent error in Fset_window_buffer. */
2941 XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->buffer = Qt;
2942 XWINDOW (minibuf_window)->buffer = Qt;
2943
2944 /* Now set them up for real. */
2945 Fset_window_buffer (FRAME_ROOT_WINDOW (selected_frame),
2946 Fcurrent_buffer ());
2947 Fset_window_buffer (minibuf_window, get_minibuffer (0));
2948
2949 selected_window = FRAME_ROOT_WINDOW (selected_frame);
2950 /* Make sure this window seems more recently used than
2951 a newly-created, never-selected window. Increment
2952 window_select_count so the first selection ever will get
2953 something newer than this. */
2954 XFASTINT (XWINDOW (selected_window)->use_time) = ++window_select_count;
2955 #endif /* not MULTI_FRAME */
2956 }
2957
2958 syms_of_window ()
2959 {
2960 Qwindowp = intern ("windowp");
2961 staticpro (&Qwindowp);
2962
2963 Qwindow_live_p = intern ("window-live-p");
2964 staticpro (&Qwindow_live_p);
2965
2966 #ifndef MULTI_FRAME
2967 /* Make sure all windows get marked */
2968 staticpro (&minibuf_window);
2969 #endif
2970
2971 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
2972 "Non-nil means call as function to display a help buffer.\n\
2973 Used by `with-output-to-temp-buffer'.");
2974 Vtemp_buffer_show_function = Qnil;
2975
2976 DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
2977 "If non-nil, function to call to handle `display-buffer'.\n\
2978 It will receive two args, the buffer and a flag which if non-nil means\n\
2979 that the currently selected window is not acceptable.\n\
2980 Commands such as `switch-to-buffer-other-window' and `find-file-other-window'\n\
2981 work using this function.");
2982 Vdisplay_buffer_function = Qnil;
2983
2984 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
2985 "Non-nil means it is the window that C-M-v in minibuffer should scroll.");
2986 Vminibuf_scroll_window = Qnil;
2987
2988 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
2989 "If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.");
2990 Vother_window_scroll_buffer = Qnil;
2991
2992 DEFVAR_BOOL ("pop-up-frames", &pop_up_frames,
2993 "*Non-nil means `display-buffer' should make a separate frame.");
2994 pop_up_frames = 0;
2995
2996 DEFVAR_LISP ("pop-up-frame-function", &Vpop_up_frame_function,
2997 "*If non-nil, function to call to handle automatic new frame creation.\n\
2998 It is called with no arguments and should return a newly created frame.\n\
2999 \n\
3000 A typical value might be `(lambda () (new-frame pop-up-frame-alist))'\n\
3001 where `pop-up-frame-alist' would hold the default frame parameters.");
3002 Vpop_up_frame_function = Qnil;
3003
3004 DEFVAR_BOOL ("pop-up-windows", &pop_up_windows,
3005 "*Non-nil means display-buffer should make new windows.");
3006 pop_up_windows = 1;
3007
3008 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
3009 "*Number of lines of continuity when scrolling by screenfuls.");
3010 next_screen_context_lines = 2;
3011
3012 DEFVAR_INT ("split-height-threshold", &split_height_threshold,
3013 "*display-buffer would prefer to split the largest window if this large.\n\
3014 If there is only one window, it is split regardless of this value.");
3015 split_height_threshold = 500;
3016
3017 DEFVAR_INT ("window-min-height", &window_min_height,
3018 "*Delete any window less than this tall (including its mode line).");
3019 window_min_height = 4;
3020
3021 DEFVAR_INT ("window-min-width", &window_min_width,
3022 "*Delete any window less than this wide.");
3023 window_min_width = 10;
3024
3025 defsubr (&Sselected_window);
3026 defsubr (&Sminibuffer_window);
3027 defsubr (&Swindow_minibuffer_p);
3028 defsubr (&Swindowp);
3029 defsubr (&Swindow_live_p);
3030 defsubr (&Spos_visible_in_window_p);
3031 defsubr (&Swindow_buffer);
3032 defsubr (&Swindow_height);
3033 defsubr (&Swindow_width);
3034 defsubr (&Swindow_hscroll);
3035 defsubr (&Sset_window_hscroll);
3036 defsubr (&Swindow_edges);
3037 defsubr (&Scoordinates_in_window_p);
3038 defsubr (&Swindow_at);
3039 defsubr (&Swindow_point);
3040 defsubr (&Swindow_start);
3041 defsubr (&Swindow_end);
3042 defsubr (&Sset_window_point);
3043 defsubr (&Sset_window_start);
3044 defsubr (&Swindow_dedicated_p);
3045 defsubr (&Sset_window_dedicated_p);
3046 defsubr (&Swindow_display_table);
3047 defsubr (&Sset_window_display_table);
3048 defsubr (&Snext_window);
3049 defsubr (&Sprevious_window);
3050 defsubr (&Sother_window);
3051 defsubr (&Sget_lru_window);
3052 defsubr (&Sget_largest_window);
3053 defsubr (&Sget_buffer_window);
3054 defsubr (&Sdelete_other_windows);
3055 defsubr (&Sdelete_windows_on);
3056 defsubr (&Sreplace_buffer_in_windows);
3057 defsubr (&Sdelete_window);
3058 defsubr (&Sset_window_buffer);
3059 defsubr (&Sselect_window);
3060 defsubr (&Sdisplay_buffer);
3061 defsubr (&Ssplit_window);
3062 defsubr (&Senlarge_window);
3063 defsubr (&Sshrink_window);
3064 defsubr (&Sscroll_up);
3065 defsubr (&Sscroll_down);
3066 defsubr (&Sscroll_left);
3067 defsubr (&Sscroll_right);
3068 defsubr (&Sscroll_other_window);
3069 defsubr (&Srecenter);
3070 defsubr (&Smove_to_window_line);
3071 defsubr (&Swindow_configuration_p);
3072 defsubr (&Sset_window_configuration);
3073 defsubr (&Scurrent_window_configuration);
3074 defsubr (&Ssave_window_excursion);
3075 }
3076
3077 keys_of_window ()
3078 {
3079 initial_define_key (control_x_map, '1', "delete-other-windows");
3080 initial_define_key (control_x_map, '2', "split-window");
3081 initial_define_key (control_x_map, '0', "delete-window");
3082 initial_define_key (control_x_map, 'o', "other-window");
3083 initial_define_key (control_x_map, '^', "enlarge-window");
3084 initial_define_key (control_x_map, '<', "scroll-left");
3085 initial_define_key (control_x_map, '>', "scroll-right");
3086
3087 initial_define_key (global_map, Ctl ('V'), "scroll-up");
3088 initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
3089 initial_define_key (meta_map, 'v', "scroll-down");
3090
3091 initial_define_key (global_map, Ctl('L'), "recenter");
3092 initial_define_key (meta_map, 'r', "move-to-window-line");
3093 }