frame-override-unsplittable/inhibit-frame-unsplittable name change.
[bpt/emacs.git] / src / window.c
1 /* Window creation, deletion and examination for GNU Emacs.
2 Does not include redisplay.
3 Copyright (C) 1985, 86, 87, 93, 94, 95, 96 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, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #include <config.h>
23 #include "lisp.h"
24 #include "buffer.h"
25 #include "frame.h"
26 #include "window.h"
27 #include "commands.h"
28 #include "indent.h"
29 #include "termchar.h"
30 #include "disptab.h"
31 #include "keyboard.h"
32
33 Lisp_Object Qwindowp, Qwindow_live_p;
34
35 Lisp_Object Fnext_window (), Fdelete_window (), Fselect_window ();
36 Lisp_Object Fset_window_buffer (), Fsplit_window (), Frecenter ();
37
38 void delete_all_subwindows ();
39 static struct window *decode_window();
40
41 /* This is the window in which the terminal's cursor should
42 be left when nothing is being done with it. This must
43 always be a leaf window, and its buffer is selected by
44 the top level editing loop at the end of each command.
45
46 This value is always the same as
47 FRAME_SELECTED_WINDOW (selected_frame). */
48
49 Lisp_Object selected_window;
50
51 /* The minibuffer window of the selected frame.
52 Note that you cannot test for minibufferness of an arbitrary window
53 by comparing against this; but you can test for minibufferness of
54 the selected window. */
55 Lisp_Object minibuf_window;
56
57 /* Non-nil means it is the window for C-M-v to scroll
58 when the minibuffer is selected. */
59 Lisp_Object Vminibuf_scroll_window;
60
61 /* Non-nil means this is the buffer whose window C-M-v should scroll. */
62 Lisp_Object Vother_window_scroll_buffer;
63
64 /* Non-nil means it's function to call to display temp buffers. */
65 Lisp_Object Vtemp_buffer_show_function;
66
67 /* If a window gets smaller than either of these, it is removed. */
68 int window_min_height;
69 int window_min_width;
70
71 /* Nonzero implies Fdisplay_buffer should create windows. */
72 int pop_up_windows;
73
74 /* Nonzero implies make new frames for Fdisplay_buffer. */
75 int pop_up_frames;
76
77 /* Non-nil means use this function instead of default */
78 Lisp_Object Vpop_up_frame_function;
79
80 /* Function to call to handle Fdisplay_buffer. */
81 Lisp_Object Vdisplay_buffer_function;
82
83 /* List of buffer *names* for buffers that should have their own frames. */
84 Lisp_Object Vspecial_display_buffer_names;
85
86 /* List of regexps for buffer names that should have their own frames. */
87 Lisp_Object Vspecial_display_regexps;
88
89 /* Function to pop up a special frame. */
90 Lisp_Object Vspecial_display_function;
91
92 /* List of buffer *names* for buffers to appear in selected window. */
93 Lisp_Object Vsame_window_buffer_names;
94
95 /* List of regexps for buffer names to appear in selected window. */
96 Lisp_Object Vsame_window_regexps;
97
98 /* Hook run at end of temp_output_buffer_show. */
99 Lisp_Object Qtemp_buffer_show_hook;
100
101 /* Fdisplay_buffer always splits the largest window
102 if that window is more than this high. */
103 int split_height_threshold;
104
105 /* Number of lines of continuity in scrolling by screenfuls. */
106 int next_screen_context_lines;
107
108 /* Incremented for each window created. */
109 static int sequence_number;
110
111 /* Nonzero after init_window_once has finished. */
112 static int window_initialized;
113
114 /* Hook to run when window config changes. */
115 Lisp_Object Qwindow_configuration_change_hook;
116 Lisp_Object Vwindow_configuration_change_hook;
117
118 /* Nonzero means scroll commands try to put point
119 at the same screen height as previously. */
120 static int scroll_preserve_screen_position;
121
122 /* Non-nil means we can split a frame even if it is "unsplittable". */
123 static int inhibit_frame_unsplittable;
124
125 #define min(a, b) ((a) < (b) ? (a) : (b))
126
127 extern int scroll_margin;
128
129 extern Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
130 \f
131 DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
132 "Returns t if OBJECT is a window.")
133 (object)
134 Lisp_Object object;
135 {
136 return WINDOWP (object) ? Qt : Qnil;
137 }
138
139 DEFUN ("window-live-p", Fwindow_live_p, Swindow_live_p, 1, 1, 0,
140 "Returns t if OBJECT is a window which is currently visible.")
141 (object)
142 Lisp_Object object;
143 {
144 return (WINDOWP (object) && ! NILP (XWINDOW (object)->buffer) ? Qt : Qnil);
145 }
146
147 Lisp_Object
148 make_window ()
149 {
150 Lisp_Object val;
151 register struct window *p;
152 register struct Lisp_Vector *vec;
153 int i;
154
155 vec = allocate_vectorlike ((EMACS_INT) VECSIZE (struct window));
156 for (i = 0; i < VECSIZE (struct window); i++)
157 vec->contents[i] = Qnil;
158 vec->size = VECSIZE (struct window);
159 p = (struct window *)vec;
160 XSETFASTINT (p->sequence_number, ++sequence_number);
161 XSETFASTINT (p->left, 0);
162 XSETFASTINT (p->top, 0);
163 XSETFASTINT (p->height, 0);
164 XSETFASTINT (p->width, 0);
165 XSETFASTINT (p->hscroll, 0);
166 XSETFASTINT (p->last_point_x, 0);
167 XSETFASTINT (p->last_point_y, 0);
168 p->start = Fmake_marker ();
169 p->pointm = Fmake_marker ();
170 XSETFASTINT (p->use_time, 0);
171 p->frame = Qnil;
172 p->display_table = Qnil;
173 p->dedicated = Qnil;
174 XSETWINDOW (val, p);
175 return val;
176 }
177
178 DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0,
179 "Return the window that the cursor now appears in and commands apply to.")
180 ()
181 {
182 return selected_window;
183 }
184
185 DEFUN ("minibuffer-window", Fminibuffer_window, Sminibuffer_window, 0, 1, 0,
186 "Return the window used now for minibuffers.\n\
187 If the optional argument FRAME is specified, return the minibuffer window\n\
188 used by that frame.")
189 (frame)
190 Lisp_Object frame;
191 {
192 if (NILP (frame))
193 XSETFRAME (frame, selected_frame);
194 else
195 CHECK_LIVE_FRAME (frame, 0);
196
197 return FRAME_MINIBUF_WINDOW (XFRAME (frame));
198 }
199
200 DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1, 0,
201 "Returns non-nil if WINDOW is a minibuffer window.")
202 (window)
203 Lisp_Object window;
204 {
205 struct window *w = decode_window (window);
206 return (MINI_WINDOW_P (w) ? Qt : Qnil);
207 }
208
209 DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
210 Spos_visible_in_window_p, 0, 2, 0,
211 "Return t if position POS is currently on the frame in WINDOW.\n\
212 Returns nil if that position is scrolled vertically out of view.\n\
213 POS defaults to point; WINDOW, to the selected window.")
214 (pos, window)
215 Lisp_Object pos, window;
216 {
217 register struct window *w;
218 register int top;
219 register int height;
220 register int posint;
221 register struct buffer *buf;
222 struct position posval;
223 int hscroll;
224
225 if (NILP (pos))
226 posint = PT;
227 else
228 {
229 CHECK_NUMBER_COERCE_MARKER (pos, 0);
230 posint = XINT (pos);
231 }
232
233 w = decode_window (window);
234 top = marker_position (w->start);
235 hscroll = XINT (w->hscroll);
236
237 if (posint < top)
238 return Qnil;
239
240 height = XFASTINT (w->height) - ! MINI_WINDOW_P (w);
241
242 buf = XBUFFER (w->buffer);
243 if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf)
244 && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (buf))
245 {
246 /* If frame is up to date,
247 use the info recorded about how much text fit on it. */
248 if (posint < BUF_Z (buf) - XFASTINT (w->window_end_pos)
249 || (XFASTINT (w->window_end_vpos) < height))
250 return Qt;
251 return Qnil;
252 }
253 else
254 {
255 if (posint > BUF_ZV (buf))
256 return Qnil;
257
258 /* w->start can be out of range. If it is, do something reasonable. */
259 if (top < BUF_BEGV (buf) || top > BUF_ZV (buf))
260 return Qnil;
261
262 /* If that info is not correct, calculate afresh */
263 /* BUG FIX for the 7th arg (TOHPOS).
264
265 '0' is harmless, however, ' - (1 << (BITS_PER_SHORT - 1))' is
266 more appropriate here. In case of HSCROLL > 0, this can avoid
267 needless calculation done until (HPOS == 0).
268
269 We want to determine if the position POSINT is in HEIGHT or
270 not. We don't have to do calculation until (HPOS == 0). We
271 can stop it when VPOS goes beyond HEIGHT. */
272 posval = *compute_motion (top, 0, (hscroll ? 1 - hscroll : 0), 0,
273 posint, height, - (1 << (BITS_PER_SHORT - 1)),
274 window_internal_width (w) - 1,
275 hscroll, 0, w);
276
277 return posval.vpos < height ? Qt : Qnil;
278 }
279 }
280 \f
281 static struct window *
282 decode_window (window)
283 register Lisp_Object window;
284 {
285 if (NILP (window))
286 return XWINDOW (selected_window);
287
288 CHECK_LIVE_WINDOW (window, 0);
289 return XWINDOW (window);
290 }
291
292 DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
293 "Return the buffer that WINDOW is displaying.")
294 (window)
295 Lisp_Object window;
296 {
297 return decode_window (window)->buffer;
298 }
299
300 DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0,
301 "Return the number of lines in WINDOW (including its mode line).")
302 (window)
303 Lisp_Object window;
304 {
305 return decode_window (window)->height;
306 }
307
308 DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
309 "Return the number of display columns in WINDOW.\n\
310 This is the width that is usable columns available for text in WINDOW.\n\
311 If you want to find out how many columns WINDOW takes up,\n\
312 use (let ((edges (window-edges))) (- (nth 2 edges) (nth 0 edges))).")
313 (window)
314 Lisp_Object window;
315 {
316 return make_number (window_internal_width (decode_window (window)));
317 }
318
319 DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
320 "Return the number of columns by which WINDOW is scrolled from left margin.")
321 (window)
322 Lisp_Object window;
323 {
324 return decode_window (window)->hscroll;
325 }
326
327 DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
328 "Set number of columns WINDOW is scrolled from left margin to NCOL.\n\
329 NCOL should be zero or positive.")
330 (window, ncol)
331 register Lisp_Object window, ncol;
332 {
333 register struct window *w;
334
335 CHECK_NUMBER (ncol, 1);
336 if (XINT (ncol) < 0) XSETFASTINT (ncol, 0);
337 w = decode_window (window);
338 if (XINT (w->hscroll) != XINT (ncol))
339 XBUFFER (w->buffer)->clip_changed = 1; /* Prevent redisplay shortcuts */
340 w->hscroll = ncol;
341 return ncol;
342 }
343
344 DEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger,
345 Swindow_redisplay_end_trigger, 0, 1, 0,
346 "Return WINDOW's redisplay end trigger value.\n\
347 See `set-window-redisplay-end-trigger' for more information.")
348 (window)
349 Lisp_Object window;
350 {
351 return decode_window (window)->redisplay_end_trigger;
352 }
353
354 DEFUN ("set-window-redisplay-end-trigger", Fset_window_redisplay_end_trigger,
355 Sset_window_redisplay_end_trigger, 2, 2, 0,
356 "Set WINDOW's redisplay end trigger value to VALUE.\n\
357 VALUE should be a buffer position (typically a marker) or nil.\n\
358 If it is a buffer position, then if redisplay in WINDOW reaches a position\n\
359 beyond VALUE, the functions in `redisplay-end-trigger-functions' are called\n\
360 with two arguments: WINDOW, and the end trigger value.\n\
361 Afterwards the end-trigger value is reset to nil.")
362 (window, value)
363 register Lisp_Object window, value;
364 {
365 register struct window *w;
366
367 w = decode_window (window);
368 w->redisplay_end_trigger = value;
369 return value;
370 }
371
372 DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0,
373 "Return a list of the edge coordinates of WINDOW.\n\
374 \(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.\n\
375 RIGHT is one more than the rightmost column used by WINDOW,\n\
376 and BOTTOM is one more than the bottommost row used by WINDOW\n\
377 and its mode-line.")
378 (window)
379 Lisp_Object window;
380 {
381 register struct window *w = decode_window (window);
382
383 return Fcons (w->left, Fcons (w->top,
384 Fcons (make_number (WINDOW_RIGHT_EDGE (w)),
385 Fcons (make_number (XFASTINT (w->top)
386 + XFASTINT (w->height)),
387 Qnil))));
388 }
389
390 /* Test if the character at column *x, row *y is within window *w.
391 If it is not, return 0;
392 if it is in the window's text area,
393 set *x and *y to its location relative to the upper left corner
394 of the window, and
395 return 1;
396 if it is on the window's modeline, return 2;
397 if it is on the border between the window and its right sibling,
398 return 3. */
399 static int
400 coordinates_in_window (w, x, y)
401 register struct window *w;
402 register int *x, *y;
403 {
404 register int left = XINT (w->left);
405 register int right_edge = WINDOW_RIGHT_EDGE (w);
406 register int left_margin = WINDOW_LEFT_MARGIN (w);
407 register int right_margin = WINDOW_RIGHT_MARGIN (w);
408 register int window_height = XINT (w->height);
409 register int top = XFASTINT (w->top);
410
411 if ( *x < left || *x >= right_edge
412 || *y < top || *y >= top + window_height)
413 return 0;
414
415 if (left_margin != left && *x < left_margin && *x >= left)
416 return 3;
417
418 if (right_margin != right_edge && *x >= right_margin && *x < right_edge)
419 return 3;
420
421 /* Is the character is the mode line? */
422 if (*y == top + window_height - 1
423 && ! MINI_WINDOW_P (w))
424 return 2;
425
426 *x -= WINDOW_LEFT_MARGIN (w);
427 *y -= top;
428 return 1;
429 }
430
431 DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
432 Scoordinates_in_window_p, 2, 2, 0,
433 "Return non-nil if COORDINATES are in WINDOW.\n\
434 COORDINATES is a cons of the form (X . Y), X and Y being distances\n\
435 measured in characters from the upper-left corner of the frame.\n\
436 (0 . 0) denotes the character in the upper left corner of the\n\
437 frame.\n\
438 If COORDINATES are in the text portion of WINDOW,\n\
439 the coordinates relative to the window are returned.\n\
440 If they are in the mode line of WINDOW, `mode-line' is returned.\n\
441 If they are on the border between WINDOW and its right sibling,\n\
442 `vertical-line' is returned.")
443 (coordinates, window)
444 register Lisp_Object coordinates, window;
445 {
446 int x, y;
447
448 CHECK_LIVE_WINDOW (window, 0);
449 CHECK_CONS (coordinates, 1);
450 x = XINT (Fcar (coordinates));
451 y = XINT (Fcdr (coordinates));
452
453 switch (coordinates_in_window (XWINDOW (window), &x, &y))
454 {
455 case 0: /* NOT in window at all. */
456 return Qnil;
457
458 case 1: /* In text part of window. */
459 return Fcons (x, y);
460
461 case 2: /* In mode line of window. */
462 return Qmode_line;
463
464 case 3: /* On right border of window. */
465 return Qvertical_line;
466
467 default:
468 abort ();
469 }
470 }
471
472 /* Find the window containing column x, row y, and return it as a
473 Lisp_Object. If x, y is on the window's modeline, set *part
474 to 1; if it is on the separating line between the window and its
475 right sibling, set it to 2; otherwise set it to 0. If there is no
476 window under x, y return nil and leave *part unmodified. */
477 Lisp_Object
478 window_from_coordinates (frame, x, y, part)
479 FRAME_PTR frame;
480 int x, y;
481 int *part;
482 {
483 register Lisp_Object tem, first;
484
485 tem = first = FRAME_SELECTED_WINDOW (frame);
486
487 do
488 {
489 int found = coordinates_in_window (XWINDOW (tem), &x, &y);
490
491 if (found)
492 {
493 *part = found - 1;
494 return tem;
495 }
496
497 tem = Fnext_window (tem, Qt, Qlambda);
498 }
499 while (! EQ (tem, first));
500
501 return Qnil;
502 }
503
504 DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
505 "Return window containing coordinates X and Y on FRAME.\n\
506 If omitted, FRAME defaults to the currently selected frame.\n\
507 The top left corner of the frame is considered to be row 0,\n\
508 column 0.")
509 (x, y, frame)
510 Lisp_Object x, y, frame;
511 {
512 int part;
513
514 if (NILP (frame))
515 XSETFRAME (frame, selected_frame);
516 else
517 CHECK_LIVE_FRAME (frame, 2);
518 CHECK_NUMBER (x, 0);
519 CHECK_NUMBER (y, 1);
520
521 return window_from_coordinates (XFRAME (frame),
522 XINT (x), XINT (y),
523 &part);
524 }
525
526 DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
527 "Return current value of point in WINDOW.\n\
528 For a nonselected window, this is the value point would have\n\
529 if that window were selected.\n\
530 \n\
531 Note that, when WINDOW is the selected window and its buffer\n\
532 is also currently selected, the value returned is the same as (point).\n\
533 It would be more strictly correct to return the `top-level' value\n\
534 of point, outside of any save-excursion forms.\n\
535 But that is hard to define.")
536 (window)
537 Lisp_Object window;
538 {
539 register struct window *w = decode_window (window);
540
541 if (w == XWINDOW (selected_window)
542 && current_buffer == XBUFFER (w->buffer))
543 return Fpoint ();
544 return Fmarker_position (w->pointm);
545 }
546
547 DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
548 "Return position at which display currently starts in WINDOW.\n\
549 This is updated by redisplay or by calling `set-window-start'.")
550 (window)
551 Lisp_Object window;
552 {
553 return Fmarker_position (decode_window (window)->start);
554 }
555
556 /* This is text temporarily removed from the doc string below.
557
558 This function returns nil if the position is not currently known.\n\
559 That happens when redisplay is preempted and doesn't finish.\n\
560 If in that case you want to compute where the end of the window would\n\
561 have been if redisplay had finished, do this:\n\
562 (save-excursion\n\
563 (goto-char (window-start window))\n\
564 (vertical-motion (1- (window-height window)) window)\n\
565 (point))") */
566
567 DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 1, 0,
568 "Return position at which display currently ends in WINDOW.\n\
569 This is updated by redisplay, when it runs to completion.\n\
570 Simply changing the buffer text or setting `window-start'\n\
571 does not update this value.")
572 (window)
573 Lisp_Object window;
574 {
575 Lisp_Object value;
576 struct window *w = decode_window (window);
577 Lisp_Object buf;
578
579 buf = w->buffer;
580 CHECK_BUFFER (buf, 0);
581
582 #if 0 /* This change broke some things. We should make it later. */
583 /* If we don't know the end position, return nil.
584 The user can compute it with vertical-motion if he wants to.
585 It would be nicer to do it automatically,
586 but that's so slow that it would probably bother people. */
587 if (NILP (w->window_end_valid))
588 return Qnil;
589 #endif
590
591 XSETINT (value,
592 BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
593
594 return value;
595 }
596
597 DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
598 "Make point value in WINDOW be at position POS in WINDOW's buffer.")
599 (window, pos)
600 Lisp_Object window, pos;
601 {
602 register struct window *w = decode_window (window);
603
604 CHECK_NUMBER_COERCE_MARKER (pos, 1);
605 if (w == XWINDOW (selected_window))
606 Fgoto_char (pos);
607 else
608 set_marker_restricted (w->pointm, pos, w->buffer);
609
610 return pos;
611 }
612
613 DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
614 "Make display in WINDOW start at position POS in WINDOW's buffer.\n\
615 Optional third arg NOFORCE non-nil inhibits next redisplay\n\
616 from overriding motion of point in order to display at this exact start.")
617 (window, pos, noforce)
618 Lisp_Object window, pos, noforce;
619 {
620 register struct window *w = decode_window (window);
621
622 CHECK_NUMBER_COERCE_MARKER (pos, 1);
623 set_marker_restricted (w->start, pos, w->buffer);
624 /* this is not right, but much easier than doing what is right. */
625 w->start_at_line_beg = Qnil;
626 if (NILP (noforce))
627 w->force_start = Qt;
628 w->update_mode_line = Qt;
629 XSETFASTINT (w->last_modified, 0);
630 XSETFASTINT (w->last_overlay_modified, 0);
631 if (!EQ (window, selected_window))
632 windows_or_buffers_changed++;
633 return pos;
634 }
635
636 DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
637 1, 1, 0,
638 "Return WINDOW's dedicated object, usually t or nil.\n\
639 See also `set-window-dedicated-p'.")
640 (window)
641 Lisp_Object window;
642 {
643 return decode_window (window)->dedicated;
644 }
645
646 DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p,
647 Sset_window_dedicated_p, 2, 2, 0,
648 "Control whether WINDOW is dedicated to the buffer it displays.\n\
649 If it is dedicated, Emacs will not automatically change\n\
650 which buffer appears in it.\n\
651 The second argument is the new value for the dedication flag;\n\
652 non-nil means yes.")
653 (window, arg)
654 Lisp_Object window, arg;
655 {
656 register struct window *w = decode_window (window);
657
658 if (NILP (arg))
659 w->dedicated = Qnil;
660 else
661 w->dedicated = Qt;
662
663 return w->dedicated;
664 }
665
666 DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
667 0, 1, 0,
668 "Return the display-table that WINDOW is using.")
669 (window)
670 Lisp_Object window;
671 {
672 return decode_window (window)->display_table;
673 }
674
675 /* Get the display table for use currently on window W.
676 This is either W's display table or W's buffer's display table.
677 Ignore the specified tables if they are not valid;
678 if no valid table is specified, return 0. */
679
680 struct Lisp_Char_Table *
681 window_display_table (w)
682 struct window *w;
683 {
684 Lisp_Object tem;
685 tem = w->display_table;
686 if (DISP_TABLE_P (tem))
687 return XCHAR_TABLE (tem);
688 tem = XBUFFER (w->buffer)->display_table;
689 if (DISP_TABLE_P (tem))
690 return XCHAR_TABLE (tem);
691 tem = Vstandard_display_table;
692 if (DISP_TABLE_P (tem))
693 return XCHAR_TABLE (tem);
694 return 0;
695 }
696
697 DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_display_table, 2, 2, 0,
698 "Set WINDOW's display-table to TABLE.")
699 (window, table)
700 register Lisp_Object window, table;
701 {
702 register struct window *w;
703 register Lisp_Object z; /* Return value. */
704
705 w = decode_window (window);
706 w->display_table = table;
707 return table;
708 }
709 \f
710 /* Record info on buffer window w is displaying
711 when it is about to cease to display that buffer. */
712 static
713 unshow_buffer (w)
714 register struct window *w;
715 {
716 Lisp_Object buf;
717
718 buf = w->buffer;
719 if (XBUFFER (buf) != XMARKER (w->pointm)->buffer)
720 abort ();
721
722 if (w == XWINDOW (XBUFFER (buf)->last_selected_window))
723 XBUFFER (buf)->last_selected_window = Qnil;
724
725 #if 0
726 if (w == XWINDOW (selected_window)
727 || ! EQ (buf, XWINDOW (selected_window)->buffer))
728 /* Do this except when the selected window's buffer
729 is being removed from some other window. */
730 #endif
731 /* last_window_start records the start position that this buffer
732 had in the last window to be disconnected from it.
733 Now that this statement is unconditional,
734 it is possible for the buffer to be displayed in the
735 selected window, while last_window_start reflects another
736 window which was recently showing the same buffer.
737 Some people might say that might be a good thing. Let's see. */
738 XBUFFER (buf)->last_window_start = marker_position (w->start);
739
740 /* Point in the selected window's buffer
741 is actually stored in that buffer, and the window's pointm isn't used.
742 So don't clobber point in that buffer. */
743 if (! EQ (buf, XWINDOW (selected_window)->buffer))
744 BUF_PT (XBUFFER (buf))
745 = clip_to_bounds (BUF_BEGV (XBUFFER (buf)),
746 marker_position (w->pointm),
747 BUF_ZV (XBUFFER (buf)));
748 }
749
750 /* Put replacement into the window structure in place of old. */
751 static
752 replace_window (old, replacement)
753 Lisp_Object old, replacement;
754 {
755 register Lisp_Object tem;
756 register struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
757
758 /* If OLD is its frame's root_window, then replacement is the new
759 root_window for that frame. */
760
761 if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
762 FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
763
764 p->left = o->left;
765 p->top = o->top;
766 p->width = o->width;
767 p->height = o->height;
768
769 p->next = tem = o->next;
770 if (!NILP (tem))
771 XWINDOW (tem)->prev = replacement;
772
773 p->prev = tem = o->prev;
774 if (!NILP (tem))
775 XWINDOW (tem)->next = replacement;
776
777 p->parent = tem = o->parent;
778 if (!NILP (tem))
779 {
780 if (EQ (XWINDOW (tem)->vchild, old))
781 XWINDOW (tem)->vchild = replacement;
782 if (EQ (XWINDOW (tem)->hchild, old))
783 XWINDOW (tem)->hchild = replacement;
784 }
785
786 /*** Here, if replacement is a vertical combination
787 and so is its new parent, we should make replacement's
788 children be children of that parent instead. ***/
789 }
790
791 DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
792 "Remove WINDOW from the display. Default is selected window.")
793 (window)
794 register Lisp_Object window;
795 {
796 delete_window (window);
797
798 if (! NILP (Vwindow_configuration_change_hook)
799 && ! NILP (Vrun_hooks))
800 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
801
802 return Qnil;
803 }
804
805 delete_window (window)
806 register Lisp_Object window;
807 {
808 register Lisp_Object tem, parent, sib;
809 register struct window *p;
810 register struct window *par;
811
812 /* Because this function is called by other C code on non-leaf
813 windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
814 so we can't decode_window here. */
815 if (NILP (window))
816 window = selected_window;
817 else
818 CHECK_WINDOW (window, 0);
819 p = XWINDOW (window);
820
821 /* It's okay to delete an already-deleted window. */
822 if (NILP (p->buffer)
823 && NILP (p->hchild)
824 && NILP (p->vchild))
825 return;
826
827 parent = p->parent;
828 if (NILP (parent))
829 error ("Attempt to delete minibuffer or sole ordinary window");
830 par = XWINDOW (parent);
831
832 windows_or_buffers_changed++;
833 FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (p))) = 1;
834
835 /* Are we trying to delete any frame's selected window? */
836 {
837 Lisp_Object frame, pwindow;
838
839 /* See if the frame's selected window is either WINDOW
840 or any subwindow of it, by finding all that window's parents
841 and comparing each one with WINDOW. */
842 frame = WINDOW_FRAME (XWINDOW (window));
843 pwindow = FRAME_SELECTED_WINDOW (XFRAME (frame));
844
845 while (!NILP (pwindow))
846 {
847 if (EQ (window, pwindow))
848 break;
849 pwindow = XWINDOW (pwindow)->parent;
850 }
851
852 if (EQ (window, pwindow))
853 {
854 Lisp_Object alternative;
855 alternative = Fnext_window (window, Qlambda, Qnil);
856
857 /* If we're about to delete the selected window on the
858 selected frame, then we should use Fselect_window to select
859 the new window. On the other hand, if we're about to
860 delete the selected window on any other frame, we shouldn't do
861 anything but set the frame's selected_window slot. */
862 if (EQ (window, selected_window))
863 Fselect_window (alternative);
864 else
865 FRAME_SELECTED_WINDOW (XFRAME (frame)) = alternative;
866 }
867 }
868
869 tem = p->buffer;
870 /* tem is null for dummy parent windows
871 (which have inferiors but not any contents themselves) */
872 if (!NILP (tem))
873 {
874 unshow_buffer (p);
875 unchain_marker (p->pointm);
876 unchain_marker (p->start);
877 }
878
879 tem = p->next;
880 if (!NILP (tem))
881 XWINDOW (tem)->prev = p->prev;
882
883 tem = p->prev;
884 if (!NILP (tem))
885 XWINDOW (tem)->next = p->next;
886
887 if (EQ (window, par->hchild))
888 par->hchild = p->next;
889 if (EQ (window, par->vchild))
890 par->vchild = p->next;
891
892 /* Find one of our siblings to give our space to. */
893 sib = p->prev;
894 if (NILP (sib))
895 {
896 /* If p gives its space to its next sibling, that sibling needs
897 to have its top/left side pulled back to where p's is.
898 set_window_{height,width} will re-position the sibling's
899 children. */
900 sib = p->next;
901 XWINDOW (sib)->top = p->top;
902 XWINDOW (sib)->left = p->left;
903 }
904
905 /* Stretch that sibling. */
906 if (!NILP (par->vchild))
907 set_window_height (sib,
908 XFASTINT (XWINDOW (sib)->height) + XFASTINT (p->height),
909 1);
910 if (!NILP (par->hchild))
911 set_window_width (sib,
912 XFASTINT (XWINDOW (sib)->width) + XFASTINT (p->width),
913 1);
914
915 /* If parent now has only one child,
916 put the child into the parent's place. */
917 tem = par->hchild;
918 if (NILP (tem))
919 tem = par->vchild;
920 if (NILP (XWINDOW (tem)->next))
921 replace_window (parent, tem);
922
923 /* Since we may be deleting combination windows, we must make sure that
924 not only p but all its children have been marked as deleted. */
925 if (! NILP (p->hchild))
926 delete_all_subwindows (XWINDOW (p->hchild));
927 else if (! NILP (p->vchild))
928 delete_all_subwindows (XWINDOW (p->vchild));
929
930 /* Mark this window as deleted. */
931 p->buffer = p->hchild = p->vchild = Qnil;
932 }
933 \f
934
935 extern Lisp_Object next_frame (), prev_frame ();
936
937 /* This comment supplies the doc string for `next-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 ("next-window", Ffoo, Sfoo, 0, 3, 0,
942 "Return next window after 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. Therefore, `next-window' can be used to iterate through the\n\
953 set of windows even when the minibuffer is on another frame. If the\n\
954 minibuffer does not count, only windows from WINDOW's frame count.\n\
955 \n\
956 Optional third arg ALL-FRAMES t means include windows on all frames.\n\
957 ALL-FRAMES nil or omitted means cycle within the frames as specified\n\
958 above. ALL-FRAMES = `visible' means include windows on all visible frames.\n\
959 ALL-FRAMES = 0 means include windows on all visible and iconified frames.\n\
960 If ALL-FRAMES is a frame, restrict search to windows on that frame.\n\
961 Anything else means restrict to WINDOW's frame.\n\
962 \n\
963 If you use consistent values for MINIBUF and ALL-FRAMES, you can use\n\
964 `next-window' to iterate through the entire cycle of acceptable\n\
965 windows, eventually ending up back at the window you started with.\n\
966 `previous-window' traverses the same cycle, in the reverse order.")
967 (window, minibuf, all_frames) */
968
969 DEFUN ("next-window", Fnext_window, Snext_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 ? minibuf_window : Qlambda);
988 else if (! EQ (minibuf, Qt))
989 minibuf = Qlambda;
990 /* Now minibuf can be t => count all minibuffer windows,
991 lambda => count none of them,
992 or a specific minibuffer window (the active one) to count. */
993
994 /* all_frames == nil doesn't specify which frames to include. */
995 if (NILP (all_frames))
996 all_frames = (! EQ (minibuf, Qlambda)
997 ? (FRAME_MINIBUF_WINDOW
998 (XFRAME
999 (WINDOW_FRAME
1000 (XWINDOW (window)))))
1001 : Qnil);
1002 else if (EQ (all_frames, Qvisible))
1003 ;
1004 else if (XFASTINT (all_frames) == 0)
1005 ;
1006 else if (FRAMEP (all_frames) && ! EQ (all_frames, Fwindow_frame (window)))
1007 /* If all_frames is a frame and window arg isn't on that frame, just
1008 return the first window on the frame. */
1009 return Fframe_first_window (all_frames);
1010 else if (! EQ (all_frames, Qt))
1011 all_frames = Qnil;
1012 /* Now all_frames is t meaning search all frames,
1013 nil meaning search just current frame,
1014 visible meaning search just visible frames,
1015 0 meaning search visible and iconified frames,
1016 or a window, meaning search the frame that window belongs to. */
1017
1018 /* Do this loop at least once, to get the next window, and perhaps
1019 again, if we hit the minibuffer and that is not acceptable. */
1020 do
1021 {
1022 /* Find a window that actually has a next one. This loop
1023 climbs up the tree. */
1024 while (tem = XWINDOW (window)->next, NILP (tem))
1025 if (tem = XWINDOW (window)->parent, !NILP (tem))
1026 window = tem;
1027 else
1028 {
1029 /* We've reached the end of this frame.
1030 Which other frames are acceptable? */
1031 tem = WINDOW_FRAME (XWINDOW (window));
1032 if (! NILP (all_frames))
1033 {
1034 Lisp_Object tem1;
1035
1036 tem1 = tem;
1037 tem = next_frame (tem, all_frames);
1038 /* In the case where the minibuffer is active,
1039 and we include its frame as well as the selected one,
1040 next_frame may get stuck in that frame.
1041 If that happens, go back to the selected frame
1042 so we can complete the cycle. */
1043 if (EQ (tem, tem1))
1044 XSETFRAME (tem, selected_frame);
1045 }
1046 tem = FRAME_ROOT_WINDOW (XFRAME (tem));
1047
1048 break;
1049 }
1050
1051 window = tem;
1052
1053 /* If we're in a combination window, find its first child and
1054 recurse on that. Otherwise, we've found the window we want. */
1055 while (1)
1056 {
1057 if (!NILP (XWINDOW (window)->hchild))
1058 window = XWINDOW (window)->hchild;
1059 else if (!NILP (XWINDOW (window)->vchild))
1060 window = XWINDOW (window)->vchild;
1061 else break;
1062 }
1063 }
1064 /* Which windows are acceptable?
1065 Exit the loop and accept this window if
1066 this isn't a minibuffer window,
1067 or we're accepting all minibuffer windows,
1068 or this is the active minibuffer and we are accepting that one, or
1069 we've come all the way around and we're back at the original window. */
1070 while (MINI_WINDOW_P (XWINDOW (window))
1071 && ! EQ (minibuf, Qt)
1072 && ! EQ (minibuf, window)
1073 && ! EQ (window, start_window));
1074
1075 return window;
1076 }
1077
1078 /* This comment supplies the doc string for `previous-window',
1079 for make-docfile to see. We cannot put this in the real DEFUN
1080 due to limits in the Unix cpp.
1081
1082 DEFUN ("previous-window", Ffoo, Sfoo, 0, 3, 0,
1083 "Return the window preceding WINDOW in canonical ordering of windows.\n\
1084 If omitted, WINDOW defaults to the selected window.\n\
1085 \n\
1086 Optional second arg MINIBUF t means count the minibuffer window even\n\
1087 if not active. MINIBUF nil or omitted means count the minibuffer iff\n\
1088 it is active. MINIBUF neither t nor nil means not to count the\n\
1089 minibuffer even if it is active.\n\
1090 \n\
1091 Several frames may share a single minibuffer; if the minibuffer\n\
1092 counts, all windows on all frames that share that minibuffer count\n\
1093 too. Therefore, `previous-window' can be used to iterate through\n\
1094 the set of windows even when the minibuffer is on another frame. If\n\
1095 the minibuffer does not count, only windows from WINDOW's frame count\n\
1096 \n\
1097 Optional third arg ALL-FRAMES t means include windows on all frames.\n\
1098 ALL-FRAMES nil or omitted means cycle within the frames as specified\n\
1099 above. ALL-FRAMES = `visible' means include windows on all visible frames.\n\
1100 ALL-FRAMES = 0 means include windows on all visible and iconified frames.\n\
1101 If ALL-FRAMES is a frame, restrict search to windows on that frame.\n\
1102 Anything else means restrict to WINDOW's frame.\n\
1103 \n\
1104 If you use consistent values for MINIBUF and ALL-FRAMES, you can use\n\
1105 `previous-window' to iterate through the entire cycle of acceptable\n\
1106 windows, eventually ending up back at the window you started with.\n\
1107 `next-window' traverses the same cycle, in the reverse order.")
1108 (window, minibuf, all_frames) */
1109
1110
1111 DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
1112 0)
1113 (window, minibuf, all_frames)
1114 register Lisp_Object window, minibuf, all_frames;
1115 {
1116 register Lisp_Object tem;
1117 Lisp_Object start_window;
1118
1119 if (NILP (window))
1120 window = selected_window;
1121 else
1122 CHECK_LIVE_WINDOW (window, 0);
1123
1124 start_window = window;
1125
1126 /* minibuf == nil may or may not include minibuffers.
1127 Decide if it does. */
1128 if (NILP (minibuf))
1129 minibuf = (minibuf_level ? minibuf_window : Qlambda);
1130 else if (! EQ (minibuf, Qt))
1131 minibuf = Qlambda;
1132 /* Now minibuf can be t => count all minibuffer windows,
1133 lambda => count none of them,
1134 or a specific minibuffer window (the active one) to count. */
1135
1136 /* all_frames == nil doesn't specify which frames to include.
1137 Decide which frames it includes. */
1138 if (NILP (all_frames))
1139 all_frames = (! EQ (minibuf, Qlambda)
1140 ? (FRAME_MINIBUF_WINDOW
1141 (XFRAME
1142 (WINDOW_FRAME
1143 (XWINDOW (window)))))
1144 : Qnil);
1145 else if (EQ (all_frames, Qvisible))
1146 ;
1147 else if (XFASTINT (all_frames) == 0)
1148 ;
1149 else if (FRAMEP (all_frames) && ! EQ (all_frames, Fwindow_frame (window)))
1150 /* If all_frames is a frame and window arg isn't on that frame, just
1151 return the first window on the frame. */
1152 return Fframe_first_window (all_frames);
1153 else if (! EQ (all_frames, Qt))
1154 all_frames = Qnil;
1155 /* Now all_frames is t meaning search all frames,
1156 nil meaning search just current frame,
1157 visible meaning search just visible frames,
1158 0 meaning search visible and iconified frames,
1159 or a window, meaning search the frame that window belongs to. */
1160
1161 /* Do this loop at least once, to get the previous window, and perhaps
1162 again, if we hit the minibuffer and that is not acceptable. */
1163 do
1164 {
1165 /* Find a window that actually has a previous one. This loop
1166 climbs up the tree. */
1167 while (tem = XWINDOW (window)->prev, NILP (tem))
1168 if (tem = XWINDOW (window)->parent, !NILP (tem))
1169 window = tem;
1170 else
1171 {
1172 /* We have found the top window on the frame.
1173 Which frames are acceptable? */
1174 tem = WINDOW_FRAME (XWINDOW (window));
1175 if (! NILP (all_frames))
1176 /* It's actually important that we use prev_frame here,
1177 rather than next_frame. All the windows acceptable
1178 according to the given parameters should form a ring;
1179 Fnext_window and Fprevious_window should go back and
1180 forth around the ring. If we use next_frame here,
1181 then Fnext_window and Fprevious_window take different
1182 paths through the set of acceptable windows.
1183 window_loop assumes that these `ring' requirement are
1184 met. */
1185 {
1186 Lisp_Object tem1;
1187
1188 tem1 = tem;
1189 tem = prev_frame (tem, all_frames);
1190 /* In the case where the minibuffer is active,
1191 and we include its frame as well as the selected one,
1192 next_frame may get stuck in that frame.
1193 If that happens, go back to the selected frame
1194 so we can complete the cycle. */
1195 if (EQ (tem, tem1))
1196 XSETFRAME (tem, selected_frame);
1197 }
1198 /* If this frame has a minibuffer, find that window first,
1199 because it is conceptually the last window in that frame. */
1200 if (FRAME_HAS_MINIBUF_P (XFRAME (tem)))
1201 tem = FRAME_MINIBUF_WINDOW (XFRAME (tem));
1202 else
1203 tem = FRAME_ROOT_WINDOW (XFRAME (tem));
1204
1205 break;
1206 }
1207
1208 window = tem;
1209 /* If we're in a combination window, find its last child and
1210 recurse on that. Otherwise, we've found the window we want. */
1211 while (1)
1212 {
1213 if (!NILP (XWINDOW (window)->hchild))
1214 window = XWINDOW (window)->hchild;
1215 else if (!NILP (XWINDOW (window)->vchild))
1216 window = XWINDOW (window)->vchild;
1217 else break;
1218 while (tem = XWINDOW (window)->next, !NILP (tem))
1219 window = tem;
1220 }
1221 }
1222 /* Which windows are acceptable?
1223 Exit the loop and accept this window if
1224 this isn't a minibuffer window,
1225 or we're accepting all minibuffer windows,
1226 or this is the active minibuffer and we are accepting that one, or
1227 we've come all the way around and we're back at the original window. */
1228 while (MINI_WINDOW_P (XWINDOW (window))
1229 && ! EQ (minibuf, Qt)
1230 && ! EQ (minibuf, window)
1231 && ! EQ (window, start_window));
1232
1233 return window;
1234 }
1235
1236 DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
1237 "Select the ARG'th different window on this frame.\n\
1238 All windows on current frame are arranged in a cyclic order.\n\
1239 This command selects the window ARG steps away in that order.\n\
1240 A negative ARG moves in the opposite order. If the optional second\n\
1241 argument ALL_FRAMES is non-nil, cycle through all frames.")
1242 (arg, all_frames)
1243 register Lisp_Object arg, all_frames;
1244 {
1245 register int i;
1246 register Lisp_Object w;
1247
1248 CHECK_NUMBER (arg, 0);
1249 w = selected_window;
1250 i = XINT (arg);
1251
1252 while (i > 0)
1253 {
1254 w = Fnext_window (w, Qnil, all_frames);
1255 i--;
1256 }
1257 while (i < 0)
1258 {
1259 w = Fprevious_window (w, Qnil, all_frames);
1260 i++;
1261 }
1262 Fselect_window (w);
1263 return Qnil;
1264 }
1265 \f
1266 /* Look at all windows, performing an operation specified by TYPE
1267 with argument OBJ.
1268 If FRAMES is Qt, look at all frames;
1269 Qnil, look at just the selected frame;
1270 Qvisible, look at visible frames;
1271 a frame, just look at windows on that frame.
1272 If MINI is non-zero, perform the operation on minibuffer windows too.
1273 */
1274
1275 enum window_loop
1276 {
1277 WINDOW_LOOP_UNUSED,
1278 GET_BUFFER_WINDOW, /* Arg is buffer */
1279 GET_LRU_WINDOW, /* Arg is t for full-width windows only */
1280 DELETE_OTHER_WINDOWS, /* Arg is window not to delete */
1281 DELETE_BUFFER_WINDOWS, /* Arg is buffer */
1282 GET_LARGEST_WINDOW,
1283 UNSHOW_BUFFER /* Arg is buffer */
1284 };
1285
1286 static Lisp_Object
1287 window_loop (type, obj, mini, frames)
1288 enum window_loop type;
1289 register Lisp_Object obj, frames;
1290 int mini;
1291 {
1292 register Lisp_Object w;
1293 register Lisp_Object best_window;
1294 register Lisp_Object next_window;
1295 register Lisp_Object last_window;
1296 FRAME_PTR frame;
1297 Lisp_Object frame_arg;
1298 frame_arg = Qt;
1299
1300 /* If we're only looping through windows on a particular frame,
1301 frame points to that frame. If we're looping through windows
1302 on all frames, frame is 0. */
1303 if (FRAMEP (frames))
1304 frame = XFRAME (frames);
1305 else if (NILP (frames))
1306 frame = selected_frame;
1307 else
1308 frame = 0;
1309 if (frame)
1310 frame_arg = Qlambda;
1311 else if (XFASTINT (frames) == 0)
1312 frame_arg = frames;
1313 else if (EQ (frames, Qvisible))
1314 frame_arg = frames;
1315
1316 /* frame_arg is Qlambda to stick to one frame,
1317 Qvisible to consider all visible frames,
1318 or Qt otherwise. */
1319
1320 /* Pick a window to start with. */
1321 if (WINDOWP (obj))
1322 w = obj;
1323 else if (frame)
1324 w = FRAME_SELECTED_WINDOW (frame);
1325 else
1326 w = FRAME_SELECTED_WINDOW (selected_frame);
1327
1328 /* Figure out the last window we're going to mess with. Since
1329 Fnext_window, given the same options, is guaranteed to go in a
1330 ring, we can just use Fprevious_window to find the last one.
1331
1332 We can't just wait until we hit the first window again, because
1333 it might be deleted. */
1334
1335 last_window = Fprevious_window (w, mini ? Qt : Qnil, frame_arg);
1336
1337 best_window = Qnil;
1338 for (;;)
1339 {
1340 FRAME_PTR w_frame = XFRAME (WINDOW_FRAME (XWINDOW (w)));
1341
1342 /* Pick the next window now, since some operations will delete
1343 the current window. */
1344 next_window = Fnext_window (w, mini ? Qt : Qnil, frame_arg);
1345
1346 /* Note that we do not pay attention here to whether
1347 the frame is visible, since Fnext_window skips non-visible frames
1348 if that is desired, under the control of frame_arg. */
1349 if (! MINI_WINDOW_P (XWINDOW (w))
1350 || (mini && minibuf_level > 0))
1351 switch (type)
1352 {
1353 case GET_BUFFER_WINDOW:
1354 if (XBUFFER (XWINDOW (w)->buffer) == XBUFFER (obj)
1355 /* Don't find any minibuffer window
1356 except the one that is currently in use. */
1357 && (MINI_WINDOW_P (XWINDOW (w))
1358 ? EQ (w, minibuf_window) : 1))
1359 return w;
1360 break;
1361
1362 case GET_LRU_WINDOW:
1363 /* t as arg means consider only full-width windows */
1364 if (!NILP (obj) && !WINDOW_FULL_WIDTH_P (XWINDOW (w)))
1365 break;
1366 /* Ignore dedicated windows and minibuffers. */
1367 if (MINI_WINDOW_P (XWINDOW (w))
1368 || !NILP (XWINDOW (w)->dedicated))
1369 break;
1370 if (NILP (best_window)
1371 || (XFASTINT (XWINDOW (best_window)->use_time)
1372 > XFASTINT (XWINDOW (w)->use_time)))
1373 best_window = w;
1374 break;
1375
1376 case DELETE_OTHER_WINDOWS:
1377 if (XWINDOW (w) != XWINDOW (obj))
1378 Fdelete_window (w);
1379 break;
1380
1381 case DELETE_BUFFER_WINDOWS:
1382 if (EQ (XWINDOW (w)->buffer, obj))
1383 {
1384 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
1385
1386 /* If this window is dedicated, and in a frame of its own,
1387 kill the frame. */
1388 if (EQ (w, FRAME_ROOT_WINDOW (f))
1389 && !NILP (XWINDOW (w)->dedicated)
1390 && other_visible_frames (f))
1391 {
1392 /* Skip the other windows on this frame.
1393 There might be one, the minibuffer! */
1394 if (! EQ (w, last_window))
1395 while (f == XFRAME (WINDOW_FRAME (XWINDOW (next_window))))
1396 {
1397 /* As we go, check for the end of the loop.
1398 We mustn't start going around a second time. */
1399 if (EQ (next_window, last_window))
1400 {
1401 last_window = w;
1402 break;
1403 }
1404 next_window = Fnext_window (next_window,
1405 mini ? Qt : Qnil,
1406 frame_arg);
1407 }
1408 /* Now we can safely delete the frame. */
1409 Fdelete_frame (WINDOW_FRAME (XWINDOW (w)), Qnil);
1410 }
1411 else
1412 /* If we're deleting the buffer displayed in the only window
1413 on the frame, find a new buffer to display there. */
1414 if (NILP (XWINDOW (w)->parent))
1415 {
1416 Lisp_Object new_buffer;
1417 new_buffer = Fother_buffer (obj, Qnil);
1418 if (NILP (new_buffer))
1419 new_buffer
1420 = Fget_buffer_create (build_string ("*scratch*"));
1421 Fset_window_buffer (w, new_buffer);
1422 if (EQ (w, selected_window))
1423 Fset_buffer (XWINDOW (w)->buffer);
1424 }
1425 else
1426 Fdelete_window (w);
1427 }
1428 break;
1429
1430 case GET_LARGEST_WINDOW:
1431 /* Ignore dedicated windows and minibuffers. */
1432 if (MINI_WINDOW_P (XWINDOW (w))
1433 || !NILP (XWINDOW (w)->dedicated))
1434 break;
1435 {
1436 struct window *best_window_ptr = XWINDOW (best_window);
1437 struct window *w_ptr = XWINDOW (w);
1438 if (NILP (best_window)
1439 || (XFASTINT (w_ptr->height) * XFASTINT (w_ptr->width)
1440 > (XFASTINT (best_window_ptr->height)
1441 * XFASTINT (best_window_ptr->width))))
1442 best_window = w;
1443 }
1444 break;
1445
1446 case UNSHOW_BUFFER:
1447 if (EQ (XWINDOW (w)->buffer, obj))
1448 {
1449 /* Find another buffer to show in this window. */
1450 Lisp_Object another_buffer;
1451 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
1452 another_buffer = Fother_buffer (obj, Qnil);
1453 if (NILP (another_buffer))
1454 another_buffer
1455 = Fget_buffer_create (build_string ("*scratch*"));
1456 /* If this window is dedicated, and in a frame of its own,
1457 kill the frame. */
1458 if (EQ (w, FRAME_ROOT_WINDOW (f))
1459 && !NILP (XWINDOW (w)->dedicated)
1460 && other_visible_frames (f))
1461 {
1462 /* Skip the other windows on this frame.
1463 There might be one, the minibuffer! */
1464 if (! EQ (w, last_window))
1465 while (f == XFRAME (WINDOW_FRAME (XWINDOW (next_window))))
1466 {
1467 /* As we go, check for the end of the loop.
1468 We mustn't start going around a second time. */
1469 if (EQ (next_window, last_window))
1470 {
1471 last_window = w;
1472 break;
1473 }
1474 next_window = Fnext_window (next_window,
1475 mini ? Qt : Qnil,
1476 frame_arg);
1477 }
1478 /* Now we can safely delete the frame. */
1479 Fdelete_frame (WINDOW_FRAME (XWINDOW (w)), Qnil);
1480 }
1481 else
1482 {
1483 /* Otherwise show a different buffer in the window. */
1484 XWINDOW (w)->dedicated = Qnil;
1485 Fset_window_buffer (w, another_buffer);
1486 if (EQ (w, selected_window))
1487 Fset_buffer (XWINDOW (w)->buffer);
1488 }
1489 }
1490 break;
1491 }
1492
1493 if (EQ (w, last_window))
1494 break;
1495
1496 w = next_window;
1497 }
1498
1499 return best_window;
1500 }
1501
1502 DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
1503 "Return the window least recently selected or used for display.\n\
1504 If optional argument FRAME is `visible', search all visible frames.\n\
1505 If FRAME is 0, search all visible and iconified frames.\n\
1506 If FRAME is t, search all frames.\n\
1507 If FRAME is nil, search only the selected frame.\n\
1508 If FRAME is a frame, search only that frame.")
1509 (frame)
1510 Lisp_Object frame;
1511 {
1512 register Lisp_Object w;
1513 /* First try for a window that is full-width */
1514 w = window_loop (GET_LRU_WINDOW, Qt, 0, frame);
1515 if (!NILP (w) && !EQ (w, selected_window))
1516 return w;
1517 /* If none of them, try the rest */
1518 return window_loop (GET_LRU_WINDOW, Qnil, 0, frame);
1519 }
1520
1521 DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 1, 0,
1522 "Return the largest window in area.\n\
1523 If optional argument FRAME is `visible', search all visible frames.\n\
1524 If FRAME is 0, search all visible and iconified frames.\n\
1525 If FRAME is t, search all frames.\n\
1526 If FRAME is nil, search only the selected frame.\n\
1527 If FRAME is a frame, search only that frame.")
1528 (frame)
1529 Lisp_Object frame;
1530 {
1531 return window_loop (GET_LARGEST_WINDOW, Qnil, 0,
1532 frame);
1533 }
1534
1535 DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 1, 2, 0,
1536 "Return a window currently displaying BUFFER, or nil if none.\n\
1537 If optional argument FRAME is `visible', search all visible frames.\n\
1538 If optional argument FRAME is 0, search all visible and iconified frames.\n\
1539 If FRAME is t, search all frames.\n\
1540 If FRAME is nil, search only the selected frame.\n\
1541 If FRAME is a frame, search only that frame.")
1542 (buffer, frame)
1543 Lisp_Object buffer, frame;
1544 {
1545 buffer = Fget_buffer (buffer);
1546 if (BUFFERP (buffer))
1547 return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame);
1548 else
1549 return Qnil;
1550 }
1551
1552 DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
1553 0, 1, "",
1554 "Make WINDOW (or the selected window) fill its frame.\n\
1555 Only the frame WINDOW is on is affected.\n\
1556 This function tries to reduce display jumps\n\
1557 by keeping the text previously visible in WINDOW\n\
1558 in the same place on the frame. Doing this depends on\n\
1559 the value of (window-start WINDOW), so if calling this function\n\
1560 in a program gives strange scrolling, make sure the window-start\n\
1561 value is reasonable when this function is called.")
1562 (window)
1563 Lisp_Object window;
1564 {
1565 struct window *w;
1566 int startpos;
1567 int top;
1568
1569 if (NILP (window))
1570 window = selected_window;
1571 else
1572 CHECK_LIVE_WINDOW (window, 0);
1573
1574 w = XWINDOW (window);
1575
1576 startpos = marker_position (w->start);
1577 top = XFASTINT (w->top) - FRAME_MENU_BAR_LINES (XFRAME (WINDOW_FRAME (w)));
1578
1579 if (MINI_WINDOW_P (w) && top > 0)
1580 error ("Can't expand minibuffer to full frame");
1581
1582 window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_FRAME (w));
1583
1584 /* Try to minimize scrolling, by setting the window start to the point
1585 will cause the text at the old window start to be at the same place
1586 on the frame. But don't try to do this if the window start is
1587 outside the visible portion (as might happen when the display is
1588 not current, due to typeahead). */
1589 if (startpos >= BUF_BEGV (XBUFFER (w->buffer))
1590 && startpos <= BUF_ZV (XBUFFER (w->buffer)))
1591 {
1592 struct position pos;
1593 struct buffer *obuf = current_buffer;
1594
1595 Fset_buffer (w->buffer);
1596 /* This computation used to temporarily move point, but that can
1597 have unwanted side effects due to text properties. */
1598 pos = *vmotion (startpos, -top, w);
1599
1600 Fset_marker (w->start, make_number (pos.bufpos), w->buffer);
1601 w->start_at_line_beg = ((pos.bufpos == BEGV
1602 || FETCH_BYTE (pos.bufpos - 1) == '\n') ? Qt
1603 : Qnil);
1604 /* We need to do this, so that the window-scroll-functions
1605 get called. */
1606 w->optional_new_start = Qt;
1607
1608 set_buffer_internal (obuf);
1609 }
1610 return Qnil;
1611 }
1612
1613 DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
1614 1, 2, "bDelete windows on (buffer): ",
1615 "Delete all windows showing BUFFER.\n\
1616 Optional second argument FRAME controls which frames are affected.\n\
1617 If nil or omitted, delete all windows showing BUFFER in any frame.\n\
1618 If t, delete only windows showing BUFFER in the selected frame.\n\
1619 If `visible', delete all windows showing BUFFER in any visible frame.\n\
1620 If a frame, delete only windows showing BUFFER in that frame.")
1621 (buffer, frame)
1622 Lisp_Object buffer, frame;
1623 {
1624 /* FRAME uses t and nil to mean the opposite of what window_loop
1625 expects. */
1626 if (! FRAMEP (frame))
1627 frame = NILP (frame) ? Qt : Qnil;
1628
1629 if (!NILP (buffer))
1630 {
1631 buffer = Fget_buffer (buffer);
1632 CHECK_BUFFER (buffer, 0);
1633 window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
1634 }
1635 return Qnil;
1636 }
1637
1638 DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
1639 Sreplace_buffer_in_windows,
1640 1, 1, "bReplace buffer in windows: ",
1641 "Replace BUFFER with some other buffer in all windows showing it.")
1642 (buffer)
1643 Lisp_Object buffer;
1644 {
1645 if (!NILP (buffer))
1646 {
1647 buffer = Fget_buffer (buffer);
1648 CHECK_BUFFER (buffer, 0);
1649 window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
1650 }
1651 return Qnil;
1652 }
1653
1654 /* Replace BUFFER with some other buffer in all windows
1655 of all frames, even those on other keyboards. */
1656
1657 void
1658 replace_buffer_in_all_windows (buffer)
1659 Lisp_Object buffer;
1660 {
1661 #ifdef MULTI_KBOARD
1662 Lisp_Object tail, frame;
1663
1664 /* A single call to window_loop won't do the job
1665 because it only considers frames on the current keyboard.
1666 So loop manually over frames, and handle each one. */
1667 FOR_EACH_FRAME (tail, frame)
1668 window_loop (UNSHOW_BUFFER, buffer, 0, frame);
1669 #else
1670 window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
1671 #endif
1672 }
1673 \f
1674 /* Set the height of WINDOW and all its inferiors. */
1675
1676 /* The smallest acceptable dimensions for a window. Anything smaller
1677 might crash Emacs. */
1678 #define MIN_SAFE_WINDOW_WIDTH (2)
1679 #define MIN_SAFE_WINDOW_HEIGHT (2)
1680
1681 /* Make sure that window_min_height and window_min_width are
1682 not too small; if they are, set them to safe minima. */
1683
1684 static void
1685 check_min_window_sizes ()
1686 {
1687 /* Smaller values might permit a crash. */
1688 if (window_min_width < MIN_SAFE_WINDOW_WIDTH)
1689 window_min_width = MIN_SAFE_WINDOW_WIDTH;
1690 if (window_min_height < MIN_SAFE_WINDOW_HEIGHT)
1691 window_min_height = MIN_SAFE_WINDOW_HEIGHT;
1692 }
1693
1694 /* If *ROWS or *COLS are too small a size for FRAME, set them to the
1695 minimum allowable size. */
1696 void
1697 check_frame_size (frame, rows, cols)
1698 FRAME_PTR frame;
1699 int *rows, *cols;
1700 {
1701 /* For height, we have to see:
1702 whether the frame has a minibuffer,
1703 whether it wants a mode line, and
1704 whether it has a menu bar. */
1705 int min_height =
1706 (FRAME_MINIBUF_ONLY_P (frame) ? MIN_SAFE_WINDOW_HEIGHT - 1
1707 : (! FRAME_HAS_MINIBUF_P (frame)) ? MIN_SAFE_WINDOW_HEIGHT
1708 : 2 * MIN_SAFE_WINDOW_HEIGHT - 1);
1709 if (FRAME_MENU_BAR_LINES (frame) > 0)
1710 min_height += FRAME_MENU_BAR_LINES (frame);
1711
1712 if (*rows < min_height)
1713 *rows = min_height;
1714 if (*cols < MIN_SAFE_WINDOW_WIDTH)
1715 *cols = MIN_SAFE_WINDOW_WIDTH;
1716 }
1717
1718 /* Normally the window is deleted if it gets too small.
1719 nodelete nonzero means do not do this.
1720 (The caller should check later and do so if appropriate) */
1721
1722 set_window_height (window, height, nodelete)
1723 Lisp_Object window;
1724 int height;
1725 int nodelete;
1726 {
1727 register struct window *w = XWINDOW (window);
1728 register struct window *c;
1729 int oheight = XFASTINT (w->height);
1730 int top, pos, lastbot, opos, lastobot;
1731 Lisp_Object child;
1732
1733 check_min_window_sizes ();
1734
1735 if (!nodelete
1736 && ! NILP (w->parent)
1737 && height < window_min_height)
1738 {
1739 delete_window (window);
1740 return;
1741 }
1742
1743 XSETFASTINT (w->last_modified, 0);
1744 XSETFASTINT (w->last_overlay_modified, 0);
1745 windows_or_buffers_changed++;
1746 FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
1747
1748 XSETFASTINT (w->height, height);
1749 if (!NILP (w->hchild))
1750 {
1751 for (child = w->hchild; !NILP (child); child = XWINDOW (child)->next)
1752 {
1753 XWINDOW (child)->top = w->top;
1754 set_window_height (child, height, nodelete);
1755 }
1756 }
1757 else if (!NILP (w->vchild))
1758 {
1759 lastbot = top = XFASTINT (w->top);
1760 lastobot = 0;
1761 for (child = w->vchild; !NILP (child); child = c->next)
1762 {
1763 c = XWINDOW (child);
1764
1765 opos = lastobot + XFASTINT (c->height);
1766
1767 XSETFASTINT (c->top, lastbot);
1768
1769 pos = (((opos * height) << 1) + oheight) / (oheight << 1);
1770
1771 /* Avoid confusion: inhibit deletion of child if becomes too small */
1772 set_window_height (child, pos + top - lastbot, 1);
1773
1774 /* Now advance child to next window,
1775 and set lastbot if child was not just deleted. */
1776 lastbot = pos + top;
1777 lastobot = opos;
1778 }
1779 /* Now delete any children that became too small. */
1780 if (!nodelete)
1781 for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
1782 {
1783 set_window_height (child, XINT (XWINDOW (child)->height), 0);
1784 }
1785 }
1786 }
1787
1788 /* Recursively set width of WINDOW and its inferiors. */
1789
1790 set_window_width (window, width, nodelete)
1791 Lisp_Object window;
1792 int width;
1793 int nodelete;
1794 {
1795 register struct window *w = XWINDOW (window);
1796 register struct window *c;
1797 int owidth = XFASTINT (w->width);
1798 int left, pos, lastright, opos, lastoright;
1799 Lisp_Object child;
1800
1801 if (!nodelete && width < window_min_width && !NILP (w->parent))
1802 {
1803 delete_window (window);
1804 return;
1805 }
1806
1807 XSETFASTINT (w->last_modified, 0);
1808 XSETFASTINT (w->last_overlay_modified, 0);
1809 windows_or_buffers_changed++;
1810 FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
1811
1812 XSETFASTINT (w->width, width);
1813 if (!NILP (w->vchild))
1814 {
1815 for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
1816 {
1817 XWINDOW (child)->left = w->left;
1818 set_window_width (child, width, nodelete);
1819 }
1820 }
1821 else if (!NILP (w->hchild))
1822 {
1823 lastright = left = XFASTINT (w->left);
1824 lastoright = 0;
1825 for (child = w->hchild; !NILP (child); child = c->next)
1826 {
1827 c = XWINDOW (child);
1828
1829 opos = lastoright + XFASTINT (c->width);
1830
1831 XSETFASTINT (c->left, lastright);
1832
1833 pos = (((opos * width) << 1) + owidth) / (owidth << 1);
1834
1835 /* Inhibit deletion for becoming too small */
1836 set_window_width (child, pos + left - lastright, 1);
1837
1838 /* Now advance child to next window,
1839 and set lastright if child was not just deleted. */
1840 lastright = pos + left, lastoright = opos;
1841 }
1842 /* Delete children that became too small */
1843 if (!nodelete)
1844 for (child = w->hchild; !NILP (child); child = XWINDOW (child)->next)
1845 {
1846 set_window_width (child, XINT (XWINDOW (child)->width), 0);
1847 }
1848 }
1849 }
1850 \f
1851 int window_select_count;
1852
1853 Lisp_Object
1854 Fset_window_buffer_unwind (obuf)
1855 Lisp_Object obuf;
1856 {
1857 Fset_buffer (obuf);
1858 return Qnil;
1859 }
1860
1861 DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 2, 0,
1862 "Make WINDOW display BUFFER as its contents.\n\
1863 BUFFER can be a buffer or buffer name.")
1864 (window, buffer)
1865 register Lisp_Object window, buffer;
1866 {
1867 register Lisp_Object tem;
1868 register struct window *w = decode_window (window);
1869 int count = specpdl_ptr - specpdl;
1870
1871 buffer = Fget_buffer (buffer);
1872 CHECK_BUFFER (buffer, 1);
1873
1874 if (NILP (XBUFFER (buffer)->name))
1875 error ("Attempt to display deleted buffer");
1876
1877 tem = w->buffer;
1878 if (NILP (tem))
1879 error ("Window is deleted");
1880 else if (! EQ (tem, Qt)) /* w->buffer is t when the window
1881 is first being set up. */
1882 {
1883 if (!NILP (w->dedicated) && !EQ (tem, buffer))
1884 error ("Window is dedicated to `%s'",
1885 XSTRING (XBUFFER (tem)->name)->data);
1886
1887 unshow_buffer (w);
1888 }
1889
1890 w->buffer = buffer;
1891
1892 if (EQ (window, selected_window))
1893 XBUFFER (w->buffer)->last_selected_window = window;
1894 if (INTEGERP (XBUFFER (buffer)->display_count))
1895 XSETINT (XBUFFER (buffer)->display_count,
1896 XINT (XBUFFER (buffer)->display_count) + 1);
1897
1898 XSETFASTINT (w->window_end_pos, 0);
1899 w->window_end_valid = Qnil;
1900 XSETFASTINT (w->hscroll, 0);
1901 Fset_marker (w->pointm,
1902 make_number (BUF_PT (XBUFFER (buffer))),
1903 buffer);
1904 set_marker_restricted (w->start,
1905 make_number (XBUFFER (buffer)->last_window_start),
1906 buffer);
1907 w->start_at_line_beg = Qnil;
1908 w->force_start = Qnil;
1909 XSETFASTINT (w->last_modified, 0);
1910 XSETFASTINT (w->last_overlay_modified, 0);
1911 windows_or_buffers_changed++;
1912
1913 /* We must select BUFFER for running the window-scroll-functions.
1914 If WINDOW is selected, switch permanently.
1915 Otherwise, switch but go back to the ambient buffer afterward. */
1916 if (EQ (window, selected_window))
1917 Fset_buffer (buffer);
1918 /* We can't check ! NILP (Vwindow_scroll_functions) here
1919 because that might itself be a local variable. */
1920 else if (window_initialized)
1921 {
1922 record_unwind_protect (Fset_window_buffer_unwind, Fcurrent_buffer ());
1923 Fset_buffer (buffer);
1924 }
1925
1926 if (! NILP (Vwindow_scroll_functions))
1927 run_hook_with_args_2 (Qwindow_scroll_functions, window,
1928 Fmarker_position (w->start));
1929
1930 if (! NILP (Vwindow_configuration_change_hook)
1931 && ! NILP (Vrun_hooks))
1932 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
1933
1934 unbind_to (count, Qnil);
1935
1936 return Qnil;
1937 }
1938
1939 DEFUN ("select-window", Fselect_window, Sselect_window, 1, 1, 0,
1940 "Select WINDOW. Most editing will apply to WINDOW's buffer.\n\
1941 The main editor command loop selects the buffer of the selected window\n\
1942 before each command.")
1943 (window)
1944 register Lisp_Object window;
1945 {
1946 register struct window *w;
1947 register struct window *ow = XWINDOW (selected_window);
1948
1949 CHECK_LIVE_WINDOW (window, 0);
1950
1951 w = XWINDOW (window);
1952
1953 if (NILP (w->buffer))
1954 error ("Trying to select deleted window or non-leaf window");
1955
1956 XSETFASTINT (w->use_time, ++window_select_count);
1957 if (EQ (window, selected_window))
1958 return window;
1959
1960 Fset_marker (ow->pointm, make_number (BUF_PT (XBUFFER (ow->buffer))),
1961 ow->buffer);
1962
1963 selected_window = window;
1964 if (XFRAME (WINDOW_FRAME (w)) != selected_frame)
1965 {
1966 XFRAME (WINDOW_FRAME (w))->selected_window = window;
1967 /* Use this rather than Fhandle_switch_frame
1968 so that FRAME_FOCUS_FRAME is moved appropriately as we
1969 move around in the state where a minibuffer in a separate
1970 frame is active. */
1971 Fselect_frame (WINDOW_FRAME (w), Qnil);
1972 }
1973 else
1974 selected_frame->selected_window = window;
1975
1976 record_buffer (w->buffer);
1977 Fset_buffer (w->buffer);
1978
1979 XBUFFER (w->buffer)->last_selected_window = window;
1980
1981 /* Go to the point recorded in the window.
1982 This is important when the buffer is in more
1983 than one window. It also matters when
1984 redisplay_window has altered point after scrolling,
1985 because it makes the change only in the window. */
1986 {
1987 register int new_point = marker_position (w->pointm);
1988 if (new_point < BEGV)
1989 SET_PT (BEGV);
1990 else if (new_point > ZV)
1991 SET_PT (ZV);
1992 else
1993 SET_PT (new_point);
1994 }
1995
1996 windows_or_buffers_changed++;
1997 return window;
1998 }
1999
2000 /* Deiconify the frame containing the window WINDOW,
2001 unless it is the selected frame;
2002 then return WINDOW.
2003
2004 The reason for the exception for the selected frame
2005 is that it seems better not to change the selected frames visibility
2006 merely because of displaying a different buffer in it.
2007 The deiconification is useful when a buffer gets shown in
2008 another frame that you were not using lately. */
2009
2010 static Lisp_Object
2011 display_buffer_1 (window)
2012 Lisp_Object window;
2013 {
2014 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
2015 FRAME_SAMPLE_VISIBILITY (f);
2016 if (f != selected_frame)
2017 {
2018 if (FRAME_ICONIFIED_P (f))
2019 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
2020 else if (FRAME_VISIBLE_P (f))
2021 Fraise_frame (WINDOW_FRAME (XWINDOW (window)));
2022 }
2023 return window;
2024 }
2025
2026 DEFUN ("special-display-p", Fspecial_display_p, Sspecial_display_p, 1, 1, 0,
2027 "Returns non-nil if a buffer named BUFFER-NAME would be created specially.\n\
2028 The value is actually t if the frame should be called with default frame\n\
2029 parameters, and a list of frame parameters if they were specified.\n\
2030 See `special-display-buffer-names', and `special-display-regexps'.")
2031 (buffer_name)
2032 Lisp_Object buffer_name;
2033 {
2034 Lisp_Object tem;
2035
2036 CHECK_STRING (buffer_name, 1);
2037
2038 tem = Fmember (buffer_name, Vspecial_display_buffer_names);
2039 if (!NILP (tem))
2040 return Qt;
2041
2042 tem = Fassoc (buffer_name, Vspecial_display_buffer_names);
2043 if (!NILP (tem))
2044 return XCDR (tem);
2045
2046 for (tem = Vspecial_display_regexps; CONSP (tem); tem = XCDR (tem))
2047 {
2048 Lisp_Object car = XCAR (tem);
2049 if (STRINGP (car)
2050 && fast_string_match (car, buffer_name) >= 0)
2051 return Qt;
2052 else if (CONSP (car)
2053 && STRINGP (XCAR (car))
2054 && fast_string_match (XCAR (car), buffer_name) >= 0)
2055 return XCDR (tem);
2056 }
2057 return Qnil;
2058 }
2059
2060 DEFUN ("same-window-p", Fsame_window_p, Ssame_window_p, 1, 1, 0,
2061 "Returns non-nil if a new buffer named BUFFER-NAME would use the same window.\n\
2062 See `same-window-buffer-names' and `same-window-regexps'.")
2063 (buffer_name)
2064 Lisp_Object buffer_name;
2065 {
2066 Lisp_Object tem;
2067
2068 CHECK_STRING (buffer_name, 1);
2069
2070 tem = Fmember (buffer_name, Vsame_window_buffer_names);
2071 if (!NILP (tem))
2072 return Qt;
2073
2074 tem = Fassoc (buffer_name, Vsame_window_buffer_names);
2075 if (!NILP (tem))
2076 return Qt;
2077
2078 for (tem = Vsame_window_regexps; CONSP (tem); tem = XCDR (tem))
2079 {
2080 Lisp_Object car = XCAR (tem);
2081 if (STRINGP (car)
2082 && fast_string_match (car, buffer_name) >= 0)
2083 return Qt;
2084 else if (CONSP (car)
2085 && STRINGP (XCAR (car))
2086 && fast_string_match (XCAR (car), buffer_name) >= 0)
2087 return Qt;
2088 }
2089 return Qnil;
2090 }
2091
2092 DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 2,
2093 "BDisplay buffer: \nP", /* Use B so the default is (other-buffer). */
2094 "Make BUFFER appear in some window but don't select it.\n\
2095 BUFFER can be a buffer or a buffer name.\n\
2096 If BUFFER is shown already in some window, just use that one,\n\
2097 unless the window is the selected window and the optional second\n\
2098 argument NOT-THIS-WINDOW is non-nil (interactively, with prefix arg).\n\
2099 If `pop-up-frames' is non-nil, make a new frame if no window shows BUFFER.\n\
2100 Returns the window displaying BUFFER.\n\
2101 \n\
2102 The variables `special-display-buffer-names', `special-display-regexps',\n\
2103 `same-window-buffer-names', and `same-window-regexps' customize how certain\n\
2104 buffer names are handled.")
2105 (buffer, not_this_window)
2106 register Lisp_Object buffer, not_this_window;
2107 {
2108 register Lisp_Object window, tem;
2109
2110 buffer = Fget_buffer (buffer);
2111 CHECK_BUFFER (buffer, 0);
2112
2113 if (!NILP (Vdisplay_buffer_function))
2114 return call2 (Vdisplay_buffer_function, buffer, not_this_window);
2115
2116 if (NILP (not_this_window)
2117 && XBUFFER (XWINDOW (selected_window)->buffer) == XBUFFER (buffer))
2118 return display_buffer_1 (selected_window);
2119
2120 /* See if the user has specified this buffer should appear
2121 in the selected window. */
2122 if (NILP (not_this_window))
2123 {
2124 tem = Fsame_window_p (XBUFFER (buffer)->name);
2125 if (!NILP (tem))
2126 {
2127 Fswitch_to_buffer (buffer, Qnil);
2128 return display_buffer_1 (selected_window);
2129 }
2130 }
2131
2132 /* If pop_up_frames,
2133 look for a window showing BUFFER on any visible or iconified frame.
2134 Otherwise search only the current frame. */
2135 if (pop_up_frames || last_nonminibuf_frame == 0)
2136 XSETFASTINT (tem, 0);
2137 else
2138 XSETFRAME (tem, last_nonminibuf_frame);
2139 window = Fget_buffer_window (buffer, tem);
2140 if (!NILP (window)
2141 && (NILP (not_this_window) || !EQ (window, selected_window)))
2142 {
2143 return display_buffer_1 (window);
2144 }
2145
2146 /* Certain buffer names get special handling. */
2147 if (!NILP (Vspecial_display_function))
2148 {
2149 tem = Fspecial_display_p (XBUFFER (buffer)->name);
2150 if (EQ (tem, Qt))
2151 return call1 (Vspecial_display_function, buffer);
2152 if (CONSP (tem))
2153 return call2 (Vspecial_display_function, buffer, tem);
2154 }
2155
2156 /* If there are no frames open that have more than a minibuffer,
2157 we need to create a new frame. */
2158 if (pop_up_frames || last_nonminibuf_frame == 0)
2159 {
2160 window = Fframe_selected_window (call0 (Vpop_up_frame_function));
2161 Fset_window_buffer (window, buffer);
2162 return display_buffer_1 (window);
2163 }
2164
2165 if (pop_up_windows
2166 || FRAME_MINIBUF_ONLY_P (selected_frame)
2167 /* If the current frame is a special display frame,
2168 don't try to reuse its windows. */
2169 || !NILP (XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->dedicated)
2170 )
2171 {
2172 Lisp_Object frames;
2173
2174 frames = Qnil;
2175 if (FRAME_MINIBUF_ONLY_P (selected_frame))
2176 XSETFRAME (frames, last_nonminibuf_frame);
2177 /* Don't try to create a window if would get an error */
2178 if (split_height_threshold < window_min_height << 1)
2179 split_height_threshold = window_min_height << 1;
2180
2181 /* Note that both Fget_largest_window and Fget_lru_window
2182 ignore minibuffers and dedicated windows.
2183 This means they can return nil. */
2184
2185 /* If the frame we would try to split cannot be split,
2186 try other frames. */
2187 if (FRAME_NO_SPLIT_P (NILP (frames) ? selected_frame
2188 : last_nonminibuf_frame))
2189 {
2190 /* Try visible frames first. */
2191 window = Fget_largest_window (Qvisible);
2192 /* If that didn't work, try iconified frames. */
2193 if (NILP (window))
2194 window = Fget_largest_window (make_number (0));
2195 if (NILP (window))
2196 window = Fget_largest_window (Qt);
2197 }
2198 else
2199 window = Fget_largest_window (frames);
2200
2201 /* If we got a tall enough full-width window that can be split,
2202 split it. */
2203 if (!NILP (window)
2204 && ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
2205 && window_height (window) >= split_height_threshold
2206 && WINDOW_FULL_WIDTH_P (XWINDOW (window)))
2207 window = Fsplit_window (window, Qnil, Qnil);
2208 else
2209 {
2210 Lisp_Object upper, lower, other;
2211
2212 window = Fget_lru_window (frames);
2213 /* If the LRU window is selected, and big enough,
2214 and can be split, split it. */
2215 if (!NILP (window)
2216 && ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
2217 && (EQ (window, selected_window)
2218 || EQ (XWINDOW (window)->parent, Qnil))
2219 && window_height (window) >= window_min_height << 1)
2220 window = Fsplit_window (window, Qnil, Qnil);
2221 /* If Fget_lru_window returned nil, try other approaches. */
2222
2223 /* Try visible frames first. */
2224 if (NILP (window))
2225 window = Fget_buffer_window (buffer, Qvisible);
2226 if (NILP (window))
2227 window = Fget_largest_window (Qvisible);
2228 /* If that didn't work, try iconified frames. */
2229 if (NILP (window))
2230 window = Fget_buffer_window (buffer, make_number (0));
2231 if (NILP (window))
2232 window = Fget_largest_window (make_number (0));
2233 /* Try invisible frames. */
2234 if (NILP (window))
2235 window = Fget_buffer_window (buffer, Qt);
2236 if (NILP (window))
2237 window = Fget_largest_window (Qt);
2238 /* As a last resort, make a new frame. */
2239 if (NILP (window))
2240 window = Fframe_selected_window (call0 (Vpop_up_frame_function));
2241 /* If window appears above or below another,
2242 even out their heights. */
2243 other = upper = lower = Qnil;
2244 if (!NILP (XWINDOW (window)->prev))
2245 other = upper = XWINDOW (window)->prev, lower = window;
2246 if (!NILP (XWINDOW (window)->next))
2247 other = lower = XWINDOW (window)->next, upper = window;
2248 if (!NILP (other)
2249 /* Check that OTHER and WINDOW are vertically arrayed. */
2250 && !EQ (XWINDOW (other)->top, XWINDOW (window)->top)
2251 && (XFASTINT (XWINDOW (other)->height)
2252 > XFASTINT (XWINDOW (window)->height)))
2253 {
2254 int total = (XFASTINT (XWINDOW (other)->height)
2255 + XFASTINT (XWINDOW (window)->height));
2256 Lisp_Object old_selected_window;
2257 old_selected_window = selected_window;
2258
2259 selected_window = upper;
2260 change_window_height ((total / 2
2261 - XFASTINT (XWINDOW (upper)->height)),
2262 0);
2263 selected_window = old_selected_window;
2264 }
2265 }
2266 }
2267 else
2268 window = Fget_lru_window (Qnil);
2269
2270 Fset_window_buffer (window, buffer);
2271 return display_buffer_1 (window);
2272 }
2273
2274 void
2275 temp_output_buffer_show (buf)
2276 register Lisp_Object buf;
2277 {
2278 register struct buffer *old = current_buffer;
2279 register Lisp_Object window;
2280 register struct window *w;
2281
2282 Fset_buffer (buf);
2283 BUF_SAVE_MODIFF (XBUFFER (buf)) = MODIFF;
2284 BEGV = BEG;
2285 ZV = Z;
2286 SET_PT (BEG);
2287 XBUFFER (buf)->clip_changed = 1;
2288 set_buffer_internal (old);
2289
2290 if (!EQ (Vtemp_buffer_show_function, Qnil))
2291 call1 (Vtemp_buffer_show_function, buf);
2292 else
2293 {
2294 window = Fdisplay_buffer (buf, Qnil);
2295
2296 if (XFRAME (XWINDOW (window)->frame) != selected_frame)
2297 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
2298 Vminibuf_scroll_window = window;
2299 w = XWINDOW (window);
2300 XSETFASTINT (w->hscroll, 0);
2301 set_marker_restricted (w->start, make_number (1), buf);
2302 set_marker_restricted (w->pointm, make_number (1), buf);
2303
2304 /* Run temp-buffer-show-hook, with the chosen window selected. */
2305 if (!NILP (Vrun_hooks))
2306 {
2307 Lisp_Object tem;
2308 tem = Fboundp (Qtemp_buffer_show_hook);
2309 if (!NILP (tem))
2310 {
2311 tem = Fsymbol_value (Qtemp_buffer_show_hook);
2312 if (!NILP (tem))
2313 {
2314 int count = specpdl_ptr - specpdl;
2315
2316 /* Select the window that was chosen, for running the hook. */
2317 record_unwind_protect (Fset_window_configuration,
2318 Fcurrent_window_configuration (Qnil));
2319
2320 Fselect_window (window);
2321 call1 (Vrun_hooks, Qtemp_buffer_show_hook);
2322 unbind_to (count, Qnil);
2323 }
2324 }
2325 }
2326 }
2327 }
2328 \f
2329 static
2330 make_dummy_parent (window)
2331 Lisp_Object window;
2332 {
2333 Lisp_Object new;
2334 register struct window *o, *p;
2335 register struct Lisp_Vector *vec;
2336 int i;
2337
2338 o = XWINDOW (window);
2339 vec = allocate_vectorlike ((EMACS_INT)VECSIZE (struct window));
2340 for (i = 0; i < VECSIZE (struct window); ++i)
2341 vec->contents[i] = ((struct Lisp_Vector *)o)->contents[i];
2342 vec->size = VECSIZE (struct window);
2343 p = (struct window *)vec;
2344 XSETWINDOW (new, p);
2345
2346 XSETFASTINT (p->sequence_number, ++sequence_number);
2347
2348 /* Put new into window structure in place of window */
2349 replace_window (window, new);
2350
2351 o->next = Qnil;
2352 o->prev = Qnil;
2353 o->vchild = Qnil;
2354 o->hchild = Qnil;
2355 o->parent = new;
2356
2357 p->start = Qnil;
2358 p->pointm = Qnil;
2359 p->buffer = Qnil;
2360 }
2361
2362 DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
2363 "Split WINDOW, putting SIZE lines in the first of the pair.\n\
2364 WINDOW defaults to selected one and SIZE to half its size.\n\
2365 If optional third arg HORFLAG is non-nil, split side by side\n\
2366 and put SIZE columns in the first of the pair.")
2367 (window, size, horflag)
2368 Lisp_Object window, size, horflag;
2369 {
2370 register Lisp_Object new;
2371 register struct window *o, *p;
2372 FRAME_PTR fo;
2373 register int size_int;
2374
2375 if (NILP (window))
2376 window = selected_window;
2377 else
2378 CHECK_LIVE_WINDOW (window, 0);
2379
2380 o = XWINDOW (window);
2381 fo = XFRAME (WINDOW_FRAME (o));
2382
2383 if (NILP (size))
2384 {
2385 if (!NILP (horflag))
2386 /* Calculate the size of the left-hand window, by dividing
2387 the usable space in columns by two. */
2388 size_int = XFASTINT (o->width) >> 1;
2389 else
2390 size_int = XFASTINT (o->height) >> 1;
2391 }
2392 else
2393 {
2394 CHECK_NUMBER (size, 1);
2395 size_int = XINT (size);
2396 }
2397
2398 if (MINI_WINDOW_P (o))
2399 error ("Attempt to split minibuffer window");
2400 else if (FRAME_NO_SPLIT_P (fo) && ! inhibit_frame_unsplittable)
2401 error ("Attempt to split unsplittable frame");
2402
2403 check_min_window_sizes ();
2404
2405 if (NILP (horflag))
2406 {
2407 if (size_int < window_min_height)
2408 error ("Window height %d too small (after splitting)", size_int);
2409 if (size_int + window_min_height > XFASTINT (o->height))
2410 error ("Window height %d too small (after splitting)",
2411 XFASTINT (o->height) - size_int);
2412 if (NILP (o->parent)
2413 || NILP (XWINDOW (o->parent)->vchild))
2414 {
2415 make_dummy_parent (window);
2416 new = o->parent;
2417 XWINDOW (new)->vchild = window;
2418 }
2419 }
2420 else
2421 {
2422 if (size_int < window_min_width)
2423 error ("Window width %d too small (after splitting)", size_int);
2424
2425 if (size_int + window_min_width > XFASTINT (o->width))
2426 error ("Window width %d too small (after splitting)",
2427 XFASTINT (o->width) - size_int);
2428 if (NILP (o->parent)
2429 || NILP (XWINDOW (o->parent)->hchild))
2430 {
2431 make_dummy_parent (window);
2432 new = o->parent;
2433 XWINDOW (new)->hchild = window;
2434 }
2435 }
2436
2437 /* Now we know that window's parent is a vertical combination
2438 if we are dividing vertically, or a horizontal combination
2439 if we are making side-by-side windows */
2440
2441 windows_or_buffers_changed++;
2442 FRAME_WINDOW_SIZES_CHANGED (fo) = 1;
2443 new = make_window ();
2444 p = XWINDOW (new);
2445
2446 p->frame = o->frame;
2447 p->next = o->next;
2448 if (!NILP (p->next))
2449 XWINDOW (p->next)->prev = new;
2450 p->prev = window;
2451 o->next = new;
2452 p->parent = o->parent;
2453 p->buffer = Qt;
2454
2455 /* Apportion the available frame space among the two new windows */
2456
2457 if (!NILP (horflag))
2458 {
2459 p->height = o->height;
2460 p->top = o->top;
2461 XSETFASTINT (p->width, XFASTINT (o->width) - size_int);
2462 XSETFASTINT (o->width, size_int);
2463 XSETFASTINT (p->left, XFASTINT (o->left) + size_int);
2464 }
2465 else
2466 {
2467 p->left = o->left;
2468 p->width = o->width;
2469 XSETFASTINT (p->height, XFASTINT (o->height) - size_int);
2470 XSETFASTINT (o->height, size_int);
2471 XSETFASTINT (p->top, XFASTINT (o->top) + size_int);
2472 }
2473
2474 Fset_window_buffer (new, o->buffer);
2475
2476 return new;
2477 }
2478 \f
2479 DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
2480 "Make current window ARG lines bigger.\n\
2481 From program, optional second arg non-nil means grow sideways ARG columns.")
2482 (arg, side)
2483 register Lisp_Object arg, side;
2484 {
2485 CHECK_NUMBER (arg, 0);
2486 change_window_height (XINT (arg), !NILP (side));
2487
2488 if (! NILP (Vwindow_configuration_change_hook))
2489 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
2490
2491 return Qnil;
2492 }
2493
2494 DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
2495 "Make current window ARG lines smaller.\n\
2496 From program, optional second arg non-nil means shrink sideways arg columns.")
2497 (arg, side)
2498 register Lisp_Object arg, side;
2499 {
2500 CHECK_NUMBER (arg, 0);
2501 change_window_height (-XINT (arg), !NILP (side));
2502
2503 if (! NILP (Vwindow_configuration_change_hook))
2504 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
2505
2506 return Qnil;
2507 }
2508
2509 int
2510 window_height (window)
2511 Lisp_Object window;
2512 {
2513 register struct window *p = XWINDOW (window);
2514 return XFASTINT (p->height);
2515 }
2516
2517 int
2518 window_width (window)
2519 Lisp_Object window;
2520 {
2521 register struct window *p = XWINDOW (window);
2522 return XFASTINT (p->width);
2523 }
2524
2525 #define MINSIZE(w) \
2526 (widthflag \
2527 ? window_min_width \
2528 : (MINI_WINDOW_P (XWINDOW (w)) ? 1 : window_min_height))
2529
2530 #define CURBEG(w) \
2531 *(widthflag ? (int *) &(XWINDOW (w)->left) : (int *) &(XWINDOW (w)->top))
2532
2533 #define CURSIZE(w) \
2534 *(widthflag ? (int *) &(XWINDOW (w)->width) : (int *) &(XWINDOW (w)->height))
2535
2536 /* Unlike set_window_height, this function
2537 also changes the heights of the siblings so as to
2538 keep everything consistent. */
2539
2540 change_window_height (delta, widthflag)
2541 register int delta;
2542 int widthflag;
2543 {
2544 register Lisp_Object parent;
2545 Lisp_Object window;
2546 register struct window *p;
2547 int *sizep;
2548 int (*sizefun) () = widthflag ? window_width : window_height;
2549 register int (*setsizefun) () = (widthflag
2550 ? set_window_width
2551 : set_window_height);
2552 int maximum;
2553 Lisp_Object next, prev;
2554
2555 check_min_window_sizes ();
2556
2557 window = selected_window;
2558 while (1)
2559 {
2560 p = XWINDOW (window);
2561 parent = p->parent;
2562 if (NILP (parent))
2563 {
2564 if (widthflag)
2565 error ("No other window to side of this one");
2566 break;
2567 }
2568 if (widthflag ? !NILP (XWINDOW (parent)->hchild)
2569 : !NILP (XWINDOW (parent)->vchild))
2570 break;
2571 window = parent;
2572 }
2573
2574 sizep = &CURSIZE (window);
2575
2576 {
2577 register int maxdelta;
2578
2579 maxdelta = (!NILP (parent) ? (*sizefun) (parent) - *sizep
2580 : !NILP (p->next) ? (*sizefun) (p->next) - MINSIZE (p->next)
2581 : !NILP (p->prev) ? (*sizefun) (p->prev) - MINSIZE (p->prev)
2582 /* This is a frame with only one window, a minibuffer-only
2583 or a minibufferless frame. */
2584 : (delta = 0));
2585
2586 if (delta > maxdelta)
2587 /* This case traps trying to make the minibuffer
2588 the full frame, or make the only window aside from the
2589 minibuffer the full frame. */
2590 delta = maxdelta;
2591 }
2592
2593 if (*sizep + delta < MINSIZE (window))
2594 {
2595 delete_window (window);
2596 return;
2597 }
2598
2599 if (delta == 0)
2600 return;
2601
2602 /* Find the total we can get from other siblings. */
2603 maximum = 0;
2604 for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
2605 maximum += (*sizefun) (next) - MINSIZE (next);
2606 for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
2607 maximum += (*sizefun) (prev) - MINSIZE (prev);
2608
2609 /* If we can get it all from them, do so. */
2610 if (delta < maximum)
2611 {
2612 Lisp_Object first_unaffected;
2613 Lisp_Object first_affected;
2614
2615 next = p->next;
2616 prev = p->prev;
2617 first_affected = window;
2618 /* Look at one sibling at a time,
2619 moving away from this window in both directions alternately,
2620 and take as much as we can get without deleting that sibling. */
2621 while (delta != 0)
2622 {
2623 if (delta == 0)
2624 break;
2625 if (! NILP (next))
2626 {
2627 int this_one = (*sizefun) (next) - MINSIZE (next);
2628 if (this_one > delta)
2629 this_one = delta;
2630
2631 (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
2632 (*setsizefun) (window, *sizep + this_one, 0);
2633
2634 delta -= this_one;
2635 next = XWINDOW (next)->next;
2636 }
2637 if (delta == 0)
2638 break;
2639 if (! NILP (prev))
2640 {
2641 int this_one = (*sizefun) (prev) - MINSIZE (prev);
2642 if (this_one > delta)
2643 this_one = delta;
2644
2645 first_affected = prev;
2646
2647 (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
2648 (*setsizefun) (window, *sizep + this_one, 0);
2649
2650 delta -= this_one;
2651 prev = XWINDOW (prev)->prev;
2652 }
2653 }
2654
2655 /* Now recalculate the edge positions of all the windows affected,
2656 based on the new sizes. */
2657 first_unaffected = next;
2658 prev = first_affected;
2659 for (next = XWINDOW (prev)->next; ! EQ (next, first_unaffected);
2660 prev = next, next = XWINDOW (next)->next)
2661 {
2662 CURBEG (next) = CURBEG (prev) + (*sizefun) (prev);
2663 /* This does not change size of NEXT,
2664 but it propagates the new top edge to its children */
2665 (*setsizefun) (next, (*sizefun) (next), 0);
2666 }
2667 }
2668 else
2669 {
2670 register int delta1;
2671 register int opht = (*sizefun) (parent);
2672
2673 /* If trying to grow this window to or beyond size of the parent,
2674 make delta1 so big that, on shrinking back down,
2675 all the siblings end up with less than one line and are deleted. */
2676 if (opht <= *sizep + delta)
2677 delta1 = opht * opht * 2;
2678 /* Otherwise, make delta1 just right so that if we add delta1
2679 lines to this window and to the parent, and then shrink
2680 the parent back to its original size, the new proportional
2681 size of this window will increase by delta. */
2682 else
2683 delta1 = (delta * opht * 100) / ((opht - *sizep - delta) * 100);
2684
2685 /* Add delta1 lines or columns to this window, and to the parent,
2686 keeping things consistent while not affecting siblings. */
2687 CURSIZE (parent) = opht + delta1;
2688 (*setsizefun) (window, *sizep + delta1, 0);
2689
2690 /* Squeeze out delta1 lines or columns from our parent,
2691 shriking this window and siblings proportionately.
2692 This brings parent back to correct size.
2693 Delta1 was calculated so this makes this window the desired size,
2694 taking it all out of the siblings. */
2695 (*setsizefun) (parent, opht, 0);
2696 }
2697
2698 XSETFASTINT (p->last_modified, 0);
2699 XSETFASTINT (p->last_overlay_modified, 0);
2700 }
2701 #undef MINSIZE
2702 #undef CURBEG
2703 #undef CURSIZE
2704
2705 \f
2706 /* Return number of lines of text (not counting mode line) in W. */
2707
2708 int
2709 window_internal_height (w)
2710 struct window *w;
2711 {
2712 int ht = XFASTINT (w->height);
2713
2714 if (MINI_WINDOW_P (w))
2715 return ht;
2716
2717 if (!NILP (w->parent) || !NILP (w->vchild) || !NILP (w->hchild)
2718 || !NILP (w->next) || !NILP (w->prev)
2719 || FRAME_WANTS_MODELINE_P (XFRAME (WINDOW_FRAME (w))))
2720 return ht - 1;
2721
2722 return ht;
2723 }
2724
2725
2726 /* Return the number of columns in W.
2727 Don't count columns occupied by scroll bars or the vertical bar
2728 separating W from the sibling to its right. */
2729 int
2730 window_internal_width (w)
2731 struct window *w;
2732 {
2733 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2734 int width = XINT (w->width);
2735
2736 /* Scroll bars occupy a few columns. */
2737 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2738 return width - FRAME_SCROLL_BAR_COLS (f);
2739
2740 /* The column of `|' characters separating side-by-side windows
2741 occupies one column only. */
2742 if (!WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
2743 return width - 1;
2744
2745 return width;
2746 }
2747
2748
2749 /* Scroll contents of window WINDOW up N lines.
2750 If WHOLE is nonzero, it means scroll N screenfuls instead. */
2751
2752 static void
2753 window_scroll (window, n, whole, noerror)
2754 Lisp_Object window;
2755 int n;
2756 int whole;
2757 int noerror;
2758 {
2759 register struct window *w = XWINDOW (window);
2760 register int opoint = PT;
2761 register int pos;
2762 register int ht = window_internal_height (w);
2763 register Lisp_Object tem;
2764 int lose;
2765 Lisp_Object bolp, nmoved;
2766 int startpos;
2767 struct position posit;
2768 int original_vpos;
2769
2770 startpos = marker_position (w->start);
2771
2772 posit = *compute_motion (startpos, 0, 0, 0,
2773 PT, ht, 0,
2774 window_internal_width (w), XINT (w->hscroll),
2775 0, w);
2776 original_vpos = posit.vpos;
2777
2778 XSETFASTINT (tem, PT);
2779 tem = Fpos_visible_in_window_p (tem, window);
2780
2781 if (NILP (tem))
2782 {
2783 Fvertical_motion (make_number (- (ht / 2)), window);
2784 startpos = PT;
2785 }
2786
2787 SET_PT (startpos);
2788 lose = n < 0 && PT == BEGV;
2789 Fvertical_motion (make_number (n), window);
2790 pos = PT;
2791 bolp = Fbolp ();
2792 SET_PT (opoint);
2793
2794 if (lose)
2795 {
2796 if (noerror)
2797 return;
2798 else
2799 Fsignal (Qbeginning_of_buffer, Qnil);
2800 }
2801
2802 if (pos < ZV)
2803 {
2804 int this_scroll_margin = scroll_margin;
2805
2806 /* Don't use a scroll margin that is negative or too large. */
2807 if (this_scroll_margin < 0)
2808 this_scroll_margin = 0;
2809
2810 if (XINT (w->height) < 4 * scroll_margin)
2811 this_scroll_margin = XINT (w->height) / 4;
2812
2813 set_marker_restricted (w->start, make_number (pos), w->buffer);
2814 w->start_at_line_beg = bolp;
2815 w->update_mode_line = Qt;
2816 XSETFASTINT (w->last_modified, 0);
2817 XSETFASTINT (w->last_overlay_modified, 0);
2818 /* Set force_start so that redisplay_window will run
2819 the window-scroll-functions. */
2820 w->force_start = Qt;
2821
2822 if (whole && scroll_preserve_screen_position)
2823 {
2824 SET_PT (pos);
2825 Fvertical_motion (make_number (original_vpos), window);
2826 }
2827 /* If we scrolled forward, put point enough lines down
2828 that it is outside the scroll margin. */
2829 else if (n > 0)
2830 {
2831 int top_margin;
2832
2833 if (this_scroll_margin > 0)
2834 {
2835 SET_PT (pos);
2836 Fvertical_motion (make_number (this_scroll_margin), window);
2837 top_margin = PT;
2838 }
2839 else
2840 top_margin = pos;
2841
2842 if (top_margin <= opoint)
2843 SET_PT (opoint);
2844 else if (scroll_preserve_screen_position)
2845 {
2846 SET_PT (pos);
2847 Fvertical_motion (make_number (original_vpos), window);
2848 }
2849 else
2850 SET_PT (pos);
2851 }
2852 else if (n < 0)
2853 {
2854 int bottom_margin;
2855
2856 /* If we scrolled backward, put point near the end of the window
2857 but not within the scroll margin. */
2858 SET_PT (pos);
2859 tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
2860 if (XFASTINT (tem) == ht - this_scroll_margin)
2861 bottom_margin = PT;
2862 else
2863 bottom_margin = PT + 1;
2864
2865 if (bottom_margin > opoint)
2866 SET_PT (opoint);
2867 else
2868 {
2869 if (scroll_preserve_screen_position)
2870 {
2871 SET_PT (pos);
2872 Fvertical_motion (make_number (original_vpos), window);
2873 }
2874 else
2875 Fvertical_motion (make_number (-1), window);
2876 }
2877 }
2878 }
2879 else
2880 {
2881 if (noerror)
2882 return;
2883 else
2884 Fsignal (Qend_of_buffer, Qnil);
2885 }
2886 }
2887 \f
2888 /* This is the guts of Fscroll_up and Fscroll_down. */
2889
2890 static void
2891 scroll_command (n, direction)
2892 register Lisp_Object n;
2893 int direction;
2894 {
2895 register int defalt;
2896 int count = specpdl_ptr - specpdl;
2897
2898 /* If selected window's buffer isn't current, make it current for the moment.
2899 But don't screw up if window_scroll gets an error. */
2900 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
2901 {
2902 record_unwind_protect (save_excursion_restore, save_excursion_save ());
2903 Fset_buffer (XWINDOW (selected_window)->buffer);
2904 }
2905
2906 defalt = (window_internal_height (XWINDOW (selected_window))
2907 - next_screen_context_lines);
2908 defalt = direction * (defalt < 1 ? 1 : defalt);
2909
2910 if (NILP (n))
2911 window_scroll (selected_window, defalt, 1, 0);
2912 else if (EQ (n, Qminus))
2913 window_scroll (selected_window, - defalt, 1, 0);
2914 else
2915 {
2916 n = Fprefix_numeric_value (n);
2917 window_scroll (selected_window, XINT (n) * direction, 0, 0);
2918 }
2919
2920 unbind_to (count, Qnil);
2921 }
2922
2923 DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
2924 "Scroll text of current window upward ARG lines; or near full screen if no ARG.\n\
2925 A near full screen is `next-screen-context-lines' less than a full screen.\n\
2926 Negative ARG means scroll downward.\n\
2927 When calling from a program, supply a number as argument or nil.")
2928 (arg)
2929 Lisp_Object arg;
2930 {
2931 scroll_command (arg, 1);
2932 return Qnil;
2933 }
2934
2935 DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
2936 "Scroll text of current window downward ARG lines; or near full screen if no ARG.\n\
2937 A near full screen is `next-screen-context-lines' less than a full screen.\n\
2938 Negative ARG means scroll upward.\n\
2939 When calling from a program, supply a number as argument or nil.")
2940 (arg)
2941 Lisp_Object arg;
2942 {
2943 scroll_command (arg, -1);
2944 return Qnil;
2945 }
2946 \f
2947 DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0,
2948 "Return the other window for \"other window scroll\" commands.\n\
2949 If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
2950 specifies the window.\n\
2951 If `other-window-scroll-buffer' is non-nil, a window\n\
2952 showing that buffer is used.")
2953 ()
2954 {
2955 Lisp_Object window;
2956
2957 if (MINI_WINDOW_P (XWINDOW (selected_window))
2958 && !NILP (Vminibuf_scroll_window))
2959 window = Vminibuf_scroll_window;
2960 /* If buffer is specified, scroll that buffer. */
2961 else if (!NILP (Vother_window_scroll_buffer))
2962 {
2963 window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
2964 if (NILP (window))
2965 window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt);
2966 }
2967 else
2968 {
2969 /* Nothing specified; look for a neighboring window on the same
2970 frame. */
2971 window = Fnext_window (selected_window, Qnil, Qnil);
2972
2973 if (EQ (window, selected_window))
2974 /* That didn't get us anywhere; look for a window on another
2975 visible frame. */
2976 do
2977 window = Fnext_window (window, Qnil, Qt);
2978 while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
2979 && ! EQ (window, selected_window));
2980 }
2981
2982 CHECK_LIVE_WINDOW (window, 0);
2983
2984 if (EQ (window, selected_window))
2985 error ("There is no other window");
2986
2987 return window;
2988 }
2989
2990 DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
2991 "Scroll next window upward ARG lines; or near full screen if no ARG.\n\
2992 The next window is the one below the current one; or the one at the top\n\
2993 if the current one is at the bottom. Negative ARG means scroll downward.\n\
2994 When calling from a program, supply a number as argument or nil.\n\
2995 \n\
2996 If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
2997 specifies the window to scroll.\n\
2998 If `other-window-scroll-buffer' is non-nil, scroll the window\n\
2999 showing that buffer, popping the buffer up if necessary.")
3000 (arg)
3001 register Lisp_Object arg;
3002 {
3003 register Lisp_Object window;
3004 register int defalt;
3005 register struct window *w;
3006 register int count = specpdl_ptr - specpdl;
3007
3008 window = Fother_window_for_scrolling ();
3009
3010 w = XWINDOW (window);
3011 defalt = window_internal_height (w) - next_screen_context_lines;
3012 if (defalt < 1) defalt = 1;
3013
3014 /* Don't screw up if window_scroll gets an error. */
3015 record_unwind_protect (save_excursion_restore, save_excursion_save ());
3016
3017 Fset_buffer (w->buffer);
3018 SET_PT (marker_position (w->pointm));
3019
3020 if (NILP (arg))
3021 window_scroll (window, defalt, 1, 1);
3022 else if (EQ (arg, Qminus))
3023 window_scroll (window, -defalt, 1, 1);
3024 else
3025 {
3026 if (CONSP (arg))
3027 arg = Fcar (arg);
3028 CHECK_NUMBER (arg, 0);
3029 window_scroll (window, XINT (arg), 0, 1);
3030 }
3031
3032 Fset_marker (w->pointm, make_number (PT), Qnil);
3033 unbind_to (count, Qnil);
3034
3035 return Qnil;
3036 }
3037 \f
3038 DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 1, "P",
3039 "Scroll selected window display ARG columns left.\n\
3040 Default for ARG is window width minus 2.")
3041 (arg)
3042 register Lisp_Object arg;
3043 {
3044
3045 if (NILP (arg))
3046 XSETFASTINT (arg, window_internal_width (XWINDOW (selected_window)) - 2);
3047 else
3048 arg = Fprefix_numeric_value (arg);
3049
3050 return
3051 Fset_window_hscroll (selected_window,
3052 make_number (XINT (XWINDOW (selected_window)->hscroll)
3053 + XINT (arg)));
3054 }
3055
3056 DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 1, "P",
3057 "Scroll selected window display ARG columns right.\n\
3058 Default for ARG is window width minus 2.")
3059 (arg)
3060 register Lisp_Object arg;
3061 {
3062 if (NILP (arg))
3063 XSETFASTINT (arg, window_internal_width (XWINDOW (selected_window)) - 2);
3064 else
3065 arg = Fprefix_numeric_value (arg);
3066
3067 return
3068 Fset_window_hscroll (selected_window,
3069 make_number (XINT (XWINDOW (selected_window)->hscroll)
3070 - XINT (arg)));
3071 }
3072
3073 DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
3074 "Center point in window and redisplay frame. With ARG, put point on line ARG.\n\
3075 The desired position of point is always relative to the current window.\n\
3076 Just C-u as prefix means put point in the center of the window.\n\
3077 If ARG is omitted or nil, erases the entire frame and then\n\
3078 redraws with point in the center of the current window.")
3079 (arg)
3080 register Lisp_Object arg;
3081 {
3082 register struct window *w = XWINDOW (selected_window);
3083 register int ht = window_internal_height (w);
3084 struct position pos;
3085
3086 if (NILP (arg))
3087 {
3088 extern int frame_garbaged;
3089
3090 SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
3091 XSETFASTINT (arg, ht / 2);
3092 }
3093 else if (CONSP (arg)) /* Just C-u. */
3094 {
3095 XSETFASTINT (arg, ht / 2);
3096 }
3097 else
3098 {
3099 arg = Fprefix_numeric_value (arg);
3100 CHECK_NUMBER (arg, 0);
3101 }
3102
3103 if (XINT (arg) < 0)
3104 XSETINT (arg, XINT (arg) + ht);
3105
3106 pos = *vmotion (PT, - XINT (arg), w);
3107
3108 Fset_marker (w->start, make_number (pos.bufpos), w->buffer);
3109 w->start_at_line_beg = ((pos.bufpos == BEGV
3110 || FETCH_BYTE (pos.bufpos - 1) == '\n')
3111 ? Qt : Qnil);
3112 w->force_start = Qt;
3113
3114 return Qnil;
3115 }
3116 \f
3117 DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
3118 1, 1, "P",
3119 "Position point relative to window.\n\
3120 With no argument, position point at center of window.\n\
3121 An argument specifies frame line; zero means top of window,\n\
3122 negative means relative to bottom of window.")
3123 (arg)
3124 register Lisp_Object arg;
3125 {
3126 register struct window *w = XWINDOW (selected_window);
3127 register int height = window_internal_height (w);
3128 register int start;
3129 Lisp_Object window;
3130
3131 if (NILP (arg))
3132 XSETFASTINT (arg, height / 2);
3133 else
3134 {
3135 arg = Fprefix_numeric_value (arg);
3136 if (XINT (arg) < 0)
3137 XSETINT (arg, XINT (arg) + height);
3138 }
3139
3140 start = marker_position (w->start);
3141 XSETWINDOW (window, w);
3142 if (start < BEGV || start > ZV)
3143 {
3144 Fvertical_motion (make_number (- (height / 2)), window);
3145 Fset_marker (w->start, make_number (PT), w->buffer);
3146 w->start_at_line_beg = Fbolp ();
3147 w->force_start = Qt;
3148 }
3149 else
3150 SET_PT (start);
3151
3152 return Fvertical_motion (arg, window);
3153 }
3154 \f
3155 struct save_window_data
3156 {
3157 EMACS_INT size_from_Lisp_Vector_struct;
3158 struct Lisp_Vector *next_from_Lisp_Vector_struct;
3159 Lisp_Object frame_width, frame_height, frame_menu_bar_lines;
3160 Lisp_Object selected_frame;
3161 Lisp_Object current_window;
3162 Lisp_Object current_buffer;
3163 Lisp_Object minibuf_scroll_window;
3164 Lisp_Object root_window;
3165 Lisp_Object focus_frame;
3166 /* Record the values of window-min-width and window-min-height
3167 so that window sizes remain consistent with them. */
3168 Lisp_Object min_width, min_height;
3169 /* A vector, interpreted as a struct saved_window */
3170 Lisp_Object saved_windows;
3171 };
3172
3173 /* This is saved as a Lisp_Vector */
3174 struct saved_window
3175 {
3176 /* these first two must agree with struct Lisp_Vector in lisp.h */
3177 EMACS_INT size_from_Lisp_Vector_struct;
3178 struct Lisp_Vector *next_from_Lisp_Vector_struct;
3179
3180 Lisp_Object window;
3181 Lisp_Object buffer, start, pointm, mark;
3182 Lisp_Object left, top, width, height, hscroll;
3183 Lisp_Object parent, prev;
3184 Lisp_Object start_at_line_beg;
3185 Lisp_Object display_table;
3186 };
3187 #define SAVED_WINDOW_VECTOR_SIZE 14 /* Arg to Fmake_vector */
3188
3189 #define SAVED_WINDOW_N(swv,n) \
3190 ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
3191
3192 DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
3193 "T if OBJECT is a window-configuration object.")
3194 (object)
3195 Lisp_Object object;
3196 {
3197 if (WINDOW_CONFIGURATIONP (object))
3198 return Qt;
3199 return Qnil;
3200 }
3201
3202
3203 DEFUN ("set-window-configuration", Fset_window_configuration,
3204 Sset_window_configuration, 1, 1, 0,
3205 "Set the configuration of windows and buffers as specified by CONFIGURATION.\n\
3206 CONFIGURATION must be a value previously returned\n\
3207 by `current-window-configuration' (which see).")
3208 (configuration)
3209 Lisp_Object configuration;
3210 {
3211 register struct save_window_data *data;
3212 struct Lisp_Vector *saved_windows;
3213 Lisp_Object new_current_buffer;
3214 Lisp_Object frame;
3215 FRAME_PTR f;
3216
3217 while (!WINDOW_CONFIGURATIONP (configuration))
3218 {
3219 configuration = wrong_type_argument (intern ("window-configuration-p"),
3220 configuration);
3221 }
3222
3223 data = (struct save_window_data *) XVECTOR (configuration);
3224 saved_windows = XVECTOR (data->saved_windows);
3225
3226 new_current_buffer = data->current_buffer;
3227 if (NILP (XBUFFER (new_current_buffer)->name))
3228 new_current_buffer = Qnil;
3229
3230 frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
3231 f = XFRAME (frame);
3232
3233 /* If f is a dead frame, don't bother rebuilding its window tree.
3234 However, there is other stuff we should still try to do below. */
3235 if (FRAME_LIVE_P (f))
3236 {
3237 register struct window *w;
3238 register struct saved_window *p;
3239 int k;
3240
3241 /* If the frame has been resized since this window configuration was
3242 made, we change the frame to the size specified in the
3243 configuration, restore the configuration, and then resize it
3244 back. We keep track of the prevailing height in these variables. */
3245 int previous_frame_height = FRAME_HEIGHT (f);
3246 int previous_frame_width = FRAME_WIDTH (f);
3247 int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
3248
3249 if (XFASTINT (data->frame_height) != previous_frame_height
3250 || XFASTINT (data->frame_width) != previous_frame_width)
3251 change_frame_size (f, data->frame_height, data->frame_width, 0, 0);
3252 #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
3253 if (XFASTINT (data->frame_menu_bar_lines)
3254 != previous_frame_menu_bar_lines)
3255 x_set_menu_bar_lines (f, data->frame_menu_bar_lines, 0);
3256 #endif
3257
3258 windows_or_buffers_changed++;
3259 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
3260
3261 /* Temporarily avoid any problems with windows that are smaller
3262 than they are supposed to be. */
3263 window_min_height = 1;
3264 window_min_width = 1;
3265
3266 /* Kludge Alert!
3267 Mark all windows now on frame as "deleted".
3268 Restoring the new configuration "undeletes" any that are in it.
3269
3270 Save their current buffers in their height fields, since we may
3271 need it later, if a buffer saved in the configuration is now
3272 dead. */
3273 delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
3274
3275 for (k = 0; k < saved_windows->size; k++)
3276 {
3277 p = SAVED_WINDOW_N (saved_windows, k);
3278 w = XWINDOW (p->window);
3279 w->next = Qnil;
3280
3281 if (!NILP (p->parent))
3282 w->parent = SAVED_WINDOW_N (saved_windows,
3283 XFASTINT (p->parent))->window;
3284 else
3285 w->parent = Qnil;
3286
3287 if (!NILP (p->prev))
3288 {
3289 w->prev = SAVED_WINDOW_N (saved_windows,
3290 XFASTINT (p->prev))->window;
3291 XWINDOW (w->prev)->next = p->window;
3292 }
3293 else
3294 {
3295 w->prev = Qnil;
3296 if (!NILP (w->parent))
3297 {
3298 if (EQ (p->width, XWINDOW (w->parent)->width))
3299 {
3300 XWINDOW (w->parent)->vchild = p->window;
3301 XWINDOW (w->parent)->hchild = Qnil;
3302 }
3303 else
3304 {
3305 XWINDOW (w->parent)->hchild = p->window;
3306 XWINDOW (w->parent)->vchild = Qnil;
3307 }
3308 }
3309 }
3310
3311 /* If we squirreled away the buffer in the window's height,
3312 restore it now. */
3313 if (BUFFERP (w->height))
3314 w->buffer = w->height;
3315 w->left = p->left;
3316 w->top = p->top;
3317 w->width = p->width;
3318 w->height = p->height;
3319 w->hscroll = p->hscroll;
3320 w->display_table = p->display_table;
3321 XSETFASTINT (w->last_modified, 0);
3322 XSETFASTINT (w->last_overlay_modified, 0);
3323
3324 /* Reinstall the saved buffer and pointers into it. */
3325 if (NILP (p->buffer))
3326 w->buffer = p->buffer;
3327 else
3328 {
3329 if (!NILP (XBUFFER (p->buffer)->name))
3330 /* If saved buffer is alive, install it. */
3331 {
3332 w->buffer = p->buffer;
3333 w->start_at_line_beg = p->start_at_line_beg;
3334 set_marker_restricted (w->start,
3335 Fmarker_position (p->start),
3336 w->buffer);
3337 set_marker_restricted (w->pointm,
3338 Fmarker_position (p->pointm),
3339 w->buffer);
3340 Fset_marker (XBUFFER (w->buffer)->mark,
3341 Fmarker_position (p->mark), w->buffer);
3342
3343 /* As documented in Fcurrent_window_configuration, don't
3344 save the location of point in the buffer which was current
3345 when the window configuration was recorded. */
3346 if (!EQ (p->buffer, new_current_buffer)
3347 && XBUFFER (p->buffer) == current_buffer)
3348 Fgoto_char (w->pointm);
3349 }
3350 else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
3351 /* Else unless window has a live buffer, get one. */
3352 {
3353 w->buffer = Fcdr (Fcar (Vbuffer_alist));
3354 /* This will set the markers to beginning of visible
3355 range. */
3356 set_marker_restricted (w->start, make_number (0), w->buffer);
3357 set_marker_restricted (w->pointm, make_number (0),w->buffer);
3358 w->start_at_line_beg = Qt;
3359 }
3360 else
3361 /* Keeping window's old buffer; make sure the markers
3362 are real. */
3363 {
3364 /* Set window markers at start of visible range. */
3365 if (XMARKER (w->start)->buffer == 0)
3366 set_marker_restricted (w->start, make_number (0),
3367 w->buffer);
3368 if (XMARKER (w->pointm)->buffer == 0)
3369 set_marker_restricted (w->pointm,
3370 (make_number
3371 (BUF_PT (XBUFFER (w->buffer)))),
3372 w->buffer);
3373 w->start_at_line_beg = Qt;
3374 }
3375 }
3376 }
3377
3378 FRAME_ROOT_WINDOW (f) = data->root_window;
3379 Fselect_window (data->current_window);
3380 XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
3381 = selected_window;
3382
3383 if (NILP (data->focus_frame)
3384 || (FRAMEP (data->focus_frame)
3385 && FRAME_LIVE_P (XFRAME (data->focus_frame))))
3386 Fredirect_frame_focus (frame, data->focus_frame);
3387
3388 #if 0 /* I don't understand why this is needed, and it causes problems
3389 when the frame's old selected window has been deleted. */
3390 if (f != selected_frame && FRAME_WINDOW_P (f))
3391 do_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)),
3392 Qnil, 0);
3393 #endif
3394
3395 /* Set the screen height to the value it had before this function. */
3396 if (previous_frame_height != FRAME_HEIGHT (f)
3397 || previous_frame_width != FRAME_WIDTH (f))
3398 change_frame_size (f, previous_frame_height, previous_frame_width,
3399 0, 0);
3400 #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
3401 if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
3402 x_set_menu_bar_lines (f, previous_frame_menu_bar_lines, 0);
3403 #endif
3404 }
3405
3406 /* Restore the minimum heights recorded in the configuration. */
3407 window_min_height = XINT (data->min_height);
3408 window_min_width = XINT (data->min_width);
3409
3410 /* Fselect_window will have made f the selected frame, so we
3411 reselect the proper frame here. Fhandle_switch_frame will change the
3412 selected window too, but that doesn't make the call to
3413 Fselect_window above totally superfluous; it still sets f's
3414 selected window. */
3415 if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
3416 do_switch_frame (data->selected_frame, Qnil, 0);
3417
3418 if (!NILP (new_current_buffer))
3419 Fset_buffer (new_current_buffer);
3420
3421 Vminibuf_scroll_window = data->minibuf_scroll_window;
3422
3423 if (! NILP (Vwindow_configuration_change_hook)
3424 && ! NILP (Vrun_hooks))
3425 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
3426
3427 return (Qnil);
3428 }
3429
3430 /* Mark all windows now on frame as deleted
3431 by setting their buffers to nil. */
3432
3433 void
3434 delete_all_subwindows (w)
3435 register struct window *w;
3436 {
3437 if (!NILP (w->next))
3438 delete_all_subwindows (XWINDOW (w->next));
3439 if (!NILP (w->vchild))
3440 delete_all_subwindows (XWINDOW (w->vchild));
3441 if (!NILP (w->hchild))
3442 delete_all_subwindows (XWINDOW (w->hchild));
3443
3444 w->height = w->buffer; /* See Fset_window_configuration for excuse. */
3445
3446 if (!NILP (w->buffer))
3447 unshow_buffer (w);
3448
3449 /* We set all three of these fields to nil, to make sure that we can
3450 distinguish this dead window from any live window. Live leaf
3451 windows will have buffer set, and combination windows will have
3452 vchild or hchild set. */
3453 w->buffer = Qnil;
3454 w->vchild = Qnil;
3455 w->hchild = Qnil;
3456 }
3457 \f
3458 static int
3459 count_windows (window)
3460 register struct window *window;
3461 {
3462 register int count = 1;
3463 if (!NILP (window->next))
3464 count += count_windows (XWINDOW (window->next));
3465 if (!NILP (window->vchild))
3466 count += count_windows (XWINDOW (window->vchild));
3467 if (!NILP (window->hchild))
3468 count += count_windows (XWINDOW (window->hchild));
3469 return count;
3470 }
3471
3472 static int
3473 save_window_save (window, vector, i)
3474 Lisp_Object window;
3475 struct Lisp_Vector *vector;
3476 int i;
3477 {
3478 register struct saved_window *p;
3479 register struct window *w;
3480 register Lisp_Object tem;
3481
3482 for (;!NILP (window); window = w->next)
3483 {
3484 p = SAVED_WINDOW_N (vector, i);
3485 w = XWINDOW (window);
3486
3487 XSETFASTINT (w->temslot, i++);
3488 p->window = window;
3489 p->buffer = w->buffer;
3490 p->left = w->left;
3491 p->top = w->top;
3492 p->width = w->width;
3493 p->height = w->height;
3494 p->hscroll = w->hscroll;
3495 p->display_table = w->display_table;
3496 if (!NILP (w->buffer))
3497 {
3498 /* Save w's value of point in the window configuration.
3499 If w is the selected window, then get the value of point
3500 from the buffer; pointm is garbage in the selected window. */
3501 if (EQ (window, selected_window))
3502 {
3503 p->pointm = Fmake_marker ();
3504 Fset_marker (p->pointm, BUF_PT (XBUFFER (w->buffer)),
3505 w->buffer);
3506 }
3507 else
3508 p->pointm = Fcopy_marker (w->pointm, Qnil);
3509
3510 p->start = Fcopy_marker (w->start, Qnil);
3511 p->start_at_line_beg = w->start_at_line_beg;
3512
3513 tem = XBUFFER (w->buffer)->mark;
3514 p->mark = Fcopy_marker (tem, Qnil);
3515 }
3516 else
3517 {
3518 p->pointm = Qnil;
3519 p->start = Qnil;
3520 p->mark = Qnil;
3521 p->start_at_line_beg = Qnil;
3522 }
3523
3524 if (NILP (w->parent))
3525 p->parent = Qnil;
3526 else
3527 p->parent = XWINDOW (w->parent)->temslot;
3528
3529 if (NILP (w->prev))
3530 p->prev = Qnil;
3531 else
3532 p->prev = XWINDOW (w->prev)->temslot;
3533
3534 if (!NILP (w->vchild))
3535 i = save_window_save (w->vchild, vector, i);
3536 if (!NILP (w->hchild))
3537 i = save_window_save (w->hchild, vector, i);
3538 }
3539
3540 return i;
3541 }
3542
3543 DEFUN ("current-window-configuration", Fcurrent_window_configuration,
3544 Scurrent_window_configuration, 0, 1, 0,
3545 "Return an object representing the current window configuration of FRAME.\n\
3546 If FRAME is nil or omitted, use the selected frame.\n\
3547 This describes the number of windows, their sizes and current buffers,\n\
3548 and for each displayed buffer, where display starts, and the positions of\n\
3549 point and mark. An exception is made for point in the current buffer:\n\
3550 its value is -not- saved.\n\
3551 This also records the currently selected frame, and FRAME's focus\n\
3552 redirection (see `redirect-frame-focus').")
3553 (frame)
3554 Lisp_Object frame;
3555 {
3556 register Lisp_Object tem;
3557 register int n_windows;
3558 register struct save_window_data *data;
3559 register struct Lisp_Vector *vec;
3560 register int i;
3561 FRAME_PTR f;
3562
3563 if (NILP (frame))
3564 f = selected_frame;
3565 else
3566 {
3567 CHECK_LIVE_FRAME (frame, 0);
3568 f = XFRAME (frame);
3569 }
3570
3571 n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
3572 vec = allocate_vectorlike (VECSIZE (struct save_window_data));
3573 for (i = 0; i < VECSIZE (struct save_window_data); i++)
3574 vec->contents[i] = Qnil;
3575 vec->size = VECSIZE (struct save_window_data);
3576 data = (struct save_window_data *)vec;
3577
3578 XSETFASTINT (data->frame_width, FRAME_WIDTH (f));
3579 XSETFASTINT (data->frame_height, FRAME_HEIGHT (f));
3580 XSETFASTINT (data->frame_menu_bar_lines, FRAME_MENU_BAR_LINES (f));
3581 XSETFRAME (data->selected_frame, selected_frame);
3582 data->current_window = FRAME_SELECTED_WINDOW (f);
3583 XSETBUFFER (data->current_buffer, current_buffer);
3584 data->minibuf_scroll_window = Vminibuf_scroll_window;
3585 data->root_window = FRAME_ROOT_WINDOW (f);
3586 data->focus_frame = FRAME_FOCUS_FRAME (f);
3587 XSETINT (data->min_height, window_min_height);
3588 XSETINT (data->min_width, window_min_width);
3589 tem = Fmake_vector (make_number (n_windows), Qnil);
3590 data->saved_windows = tem;
3591 for (i = 0; i < n_windows; i++)
3592 XVECTOR (tem)->contents[i]
3593 = Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil);
3594 save_window_save (FRAME_ROOT_WINDOW (f),
3595 XVECTOR (tem), 0);
3596 XSETWINDOW_CONFIGURATION (tem, data);
3597 return (tem);
3598 }
3599
3600 DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
3601 0, UNEVALLED, 0,
3602 "Execute body, preserving window sizes and contents.\n\
3603 Restore which buffer appears in which window, where display starts,\n\
3604 and the value of point and mark for each window.\n\
3605 Also restore which buffer is current.\n\
3606 But do not preserve point in the current buffer.\n\
3607 Does not restore the value of point in current buffer.")
3608 (args)
3609 Lisp_Object args;
3610 {
3611 register Lisp_Object val;
3612 register int count = specpdl_ptr - specpdl;
3613
3614 record_unwind_protect (Fset_window_configuration,
3615 Fcurrent_window_configuration (Qnil));
3616 val = Fprogn (args);
3617 return unbind_to (count, val);
3618 }
3619 \f
3620 init_window_once ()
3621 {
3622 selected_frame = make_terminal_frame ();
3623 XSETFRAME (Vterminal_frame, selected_frame);
3624 minibuf_window = selected_frame->minibuffer_window;
3625 selected_window = selected_frame->selected_window;
3626 last_nonminibuf_frame = selected_frame;
3627
3628 window_initialized = 1;
3629 }
3630
3631 syms_of_window ()
3632 {
3633 staticpro (&Qwindow_configuration_change_hook);
3634 Qwindow_configuration_change_hook
3635 = intern ("window-configuration-change-hook");
3636
3637 Qwindowp = intern ("windowp");
3638 staticpro (&Qwindowp);
3639
3640 Qwindow_live_p = intern ("window-live-p");
3641 staticpro (&Qwindow_live_p);
3642
3643 Qtemp_buffer_show_hook = intern ("temp-buffer-show-hook");
3644 staticpro (&Qtemp_buffer_show_hook);
3645
3646 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
3647 "Non-nil means call as function to display a help buffer.\n\
3648 The function is called with one argument, the buffer to be displayed.\n\
3649 Used by `with-output-to-temp-buffer'.\n\
3650 If this function is used, then it must do the entire job of showing\n\
3651 the buffer; `temp-buffer-show-hook' is not run unless this function runs it.");
3652 Vtemp_buffer_show_function = Qnil;
3653
3654 DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
3655 "If non-nil, function to call to handle `display-buffer'.\n\
3656 It will receive two args, the buffer and a flag which if non-nil means\n\
3657 that the currently selected window is not acceptable.\n\
3658 Commands such as `switch-to-buffer-other-window' and `find-file-other-window'\n\
3659 work using this function.");
3660 Vdisplay_buffer_function = Qnil;
3661
3662 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
3663 "Non-nil means it is the window that C-M-v in minibuffer should scroll.");
3664 Vminibuf_scroll_window = Qnil;
3665
3666 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
3667 "If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.");
3668 Vother_window_scroll_buffer = Qnil;
3669
3670 DEFVAR_BOOL ("pop-up-frames", &pop_up_frames,
3671 "*Non-nil means `display-buffer' should make a separate frame.");
3672 pop_up_frames = 0;
3673
3674 DEFVAR_LISP ("pop-up-frame-function", &Vpop_up_frame_function,
3675 "Function to call to handle automatic new frame creation.\n\
3676 It is called with no arguments and should return a newly created frame.\n\
3677 \n\
3678 A typical value might be `(lambda () (new-frame pop-up-frame-alist))'\n\
3679 where `pop-up-frame-alist' would hold the default frame parameters.");
3680 Vpop_up_frame_function = Qnil;
3681
3682 DEFVAR_LISP ("special-display-buffer-names", &Vspecial_display_buffer_names,
3683 "*List of buffer names that should have their own special frames.\n\
3684 Displaying a buffer whose name is in this list makes a special frame for it\n\
3685 using `special-display-function'. See also `special-display-regexps'.\n\
3686 \n\
3687 An element of the list can be a list instead of just a string.\n\
3688 There are two ways to use a list as an element:\n\
3689 (BUFFER FRAME-PARAMETERS...) (BUFFER FUNCTION OTHER-ARGS...)\n\
3690 In the first case, FRAME-PARAMETERS are used to create the frame.\n\
3691 In the latter case, FUNCTION is called with BUFFER as the first argument,\n\
3692 followed by OTHER-ARGS--it can display BUFFER in any way it likes.\n\
3693 All this is done by the function found in `special-display-function'.");
3694 Vspecial_display_buffer_names = Qnil;
3695
3696 DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
3697 "*List of regexps saying which buffers should have their own special frames.\n\
3698 If a buffer name matches one of these regexps, it gets its own frame.\n\
3699 Displaying a buffer whose name is in this list makes a special frame for it\n\
3700 using `special-display-function'.\n\
3701 \n\
3702 An element of the list can be a list instead of just a string.\n\
3703 There are two ways to use a list as an element:\n\
3704 (REGEXP FRAME-PARAMETERS...) (REGEXP FUNCTION OTHER-ARGS...)\n\
3705 In the first case, FRAME-PARAMETERS are used to create the frame.\n\
3706 In the latter case, FUNCTION is called with the buffer as first argument,\n\
3707 followed by OTHER-ARGS--it can display the buffer in any way it likes.\n\
3708 All this is done by the function found in `special-display-function'.");
3709 Vspecial_display_regexps = Qnil;
3710
3711 DEFVAR_LISP ("special-display-function", &Vspecial_display_function,
3712 "Function to call to make a new frame for a special buffer.\n\
3713 It is called with two arguments, the buffer and optional buffer specific\n\
3714 data, and should return a window displaying that buffer.\n\
3715 The default value makes a separate frame for the buffer,\n\
3716 using `special-display-frame-alist' to specify the frame parameters.\n\
3717 \n\
3718 A buffer is special if its is listed in `special-display-buffer-names'\n\
3719 or matches a regexp in `special-display-regexps'.");
3720 Vspecial_display_function = Qnil;
3721
3722 DEFVAR_LISP ("same-window-buffer-names", &Vsame_window_buffer_names,
3723 "*List of buffer names that should appear in the selected window.\n\
3724 Displaying one of these buffers using `display-buffer' or `pop-to-buffer'\n\
3725 switches to it in the selected window, rather than making it appear\n\
3726 in some other window.\n\
3727 \n\
3728 An element of the list can be a cons cell instead of just a string.\n\
3729 Then the car must be a string, which specifies the buffer name.\n\
3730 This is for compatibility with `special-display-buffer-names';\n\
3731 the cdr of the cons cell is ignored.\n\
3732 \n\
3733 See also `same-window-regexps'.");
3734 Vsame_window_buffer_names = Qnil;
3735
3736 DEFVAR_LISP ("same-window-regexps", &Vsame_window_regexps,
3737 "*List of regexps saying which buffers should appear in the selected window.\n\
3738 If a buffer name matches one of these regexps, then displaying it\n\
3739 using `display-buffer' or `pop-to-buffer' switches to it\n\
3740 in the selected window, rather than making it appear in some other window.\n\
3741 \n\
3742 An element of the list can be a cons cell instead of just a string.\n\
3743 Then the car must be a string, which specifies the buffer name.\n\
3744 This is for compatibility with `special-display-buffer-names';\n\
3745 the cdr of the cons cell is ignored.\n\
3746 \n\
3747 See also `same-window-buffer-names'.");
3748 Vsame_window_regexps = Qnil;
3749
3750 DEFVAR_BOOL ("pop-up-windows", &pop_up_windows,
3751 "*Non-nil means display-buffer should make new windows.");
3752 pop_up_windows = 1;
3753
3754 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
3755 "*Number of lines of continuity when scrolling by screenfuls.");
3756 next_screen_context_lines = 2;
3757
3758 DEFVAR_INT ("split-height-threshold", &split_height_threshold,
3759 "*display-buffer would prefer to split the largest window if this large.\n\
3760 If there is only one window, it is split regardless of this value.");
3761 split_height_threshold = 500;
3762
3763 DEFVAR_INT ("window-min-height", &window_min_height,
3764 "*Delete any window less than this tall (including its mode line).");
3765 window_min_height = 4;
3766
3767 DEFVAR_INT ("window-min-width", &window_min_width,
3768 "*Delete any window less than this wide.");
3769 window_min_width = 10;
3770
3771 DEFVAR_BOOL ("scroll-preserve-screen-position",
3772 &scroll_preserve_screen_position,
3773 "*Nonzero means scroll commands move point to keep its screen line unchanged.");
3774 scroll_preserve_screen_position = 0;
3775
3776 DEFVAR_LISP ("window-configuration-change-hook",
3777 &Vwindow_configuration_change_hook,
3778 "Functions to call when window configuration changes.\n\
3779 The selected frae is the one whose configuration has changed.");
3780 Vwindow_configuration_change_hook = Qnil;
3781
3782 DEFVAR_BOOL ("inhibit-frame-unsplittable", &inhibit_frame_unsplittable,
3783 "Non-nil means allow splitting an `unsplittable' frame.\n\
3784 \(That means, a frame whise `unsplittable' parameter is non-nil.)\n\
3785 Packages such as Ispell that work by splitting the selected frame\n\
3786 can bind this, so that they will work when used in an unsplittable frame.");
3787
3788 defsubr (&Sselected_window);
3789 defsubr (&Sminibuffer_window);
3790 defsubr (&Swindow_minibuffer_p);
3791 defsubr (&Swindowp);
3792 defsubr (&Swindow_live_p);
3793 defsubr (&Spos_visible_in_window_p);
3794 defsubr (&Swindow_buffer);
3795 defsubr (&Swindow_height);
3796 defsubr (&Swindow_width);
3797 defsubr (&Swindow_hscroll);
3798 defsubr (&Sset_window_hscroll);
3799 defsubr (&Swindow_redisplay_end_trigger);
3800 defsubr (&Sset_window_redisplay_end_trigger);
3801 defsubr (&Swindow_edges);
3802 defsubr (&Scoordinates_in_window_p);
3803 defsubr (&Swindow_at);
3804 defsubr (&Swindow_point);
3805 defsubr (&Swindow_start);
3806 defsubr (&Swindow_end);
3807 defsubr (&Sset_window_point);
3808 defsubr (&Sset_window_start);
3809 defsubr (&Swindow_dedicated_p);
3810 defsubr (&Sset_window_dedicated_p);
3811 defsubr (&Swindow_display_table);
3812 defsubr (&Sset_window_display_table);
3813 defsubr (&Snext_window);
3814 defsubr (&Sprevious_window);
3815 defsubr (&Sother_window);
3816 defsubr (&Sget_lru_window);
3817 defsubr (&Sget_largest_window);
3818 defsubr (&Sget_buffer_window);
3819 defsubr (&Sdelete_other_windows);
3820 defsubr (&Sdelete_windows_on);
3821 defsubr (&Sreplace_buffer_in_windows);
3822 defsubr (&Sdelete_window);
3823 defsubr (&Sset_window_buffer);
3824 defsubr (&Sselect_window);
3825 defsubr (&Sspecial_display_p);
3826 defsubr (&Ssame_window_p);
3827 defsubr (&Sdisplay_buffer);
3828 defsubr (&Ssplit_window);
3829 defsubr (&Senlarge_window);
3830 defsubr (&Sshrink_window);
3831 defsubr (&Sscroll_up);
3832 defsubr (&Sscroll_down);
3833 defsubr (&Sscroll_left);
3834 defsubr (&Sscroll_right);
3835 defsubr (&Sother_window_for_scrolling);
3836 defsubr (&Sscroll_other_window);
3837 defsubr (&Srecenter);
3838 defsubr (&Smove_to_window_line);
3839 defsubr (&Swindow_configuration_p);
3840 defsubr (&Sset_window_configuration);
3841 defsubr (&Scurrent_window_configuration);
3842 defsubr (&Ssave_window_excursion);
3843 }
3844
3845 keys_of_window ()
3846 {
3847 initial_define_key (control_x_map, '1', "delete-other-windows");
3848 initial_define_key (control_x_map, '2', "split-window");
3849 initial_define_key (control_x_map, '0', "delete-window");
3850 initial_define_key (control_x_map, 'o', "other-window");
3851 initial_define_key (control_x_map, '^', "enlarge-window");
3852 initial_define_key (control_x_map, '<', "scroll-left");
3853 initial_define_key (control_x_map, '>', "scroll-right");
3854
3855 initial_define_key (global_map, Ctl ('V'), "scroll-up");
3856 initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
3857 initial_define_key (meta_map, 'v', "scroll-down");
3858
3859 initial_define_key (global_map, Ctl('L'), "recenter");
3860 initial_define_key (meta_map, 'r', "move-to-window-line");
3861 }