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