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