(init_environment): Change argv[0] to contain the full path to Emacs.
[bpt/emacs.git] / src / window.c
1 /* Window creation, deletion and examination for GNU Emacs.
2 Does not include redisplay.
3 Copyright (C) 1985,86,87,93,94,95,96,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, Qwindow_configuration_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 CHECK_ALL_WINDOWS
1312 };
1313
1314 static Lisp_Object
1315 window_loop (type, obj, mini, frames)
1316 enum window_loop type;
1317 register Lisp_Object obj, frames;
1318 int mini;
1319 {
1320 register Lisp_Object w;
1321 register Lisp_Object best_window;
1322 register Lisp_Object next_window;
1323 register Lisp_Object last_window;
1324 FRAME_PTR frame;
1325 Lisp_Object frame_arg;
1326 frame_arg = Qt;
1327
1328 /* If we're only looping through windows on a particular frame,
1329 frame points to that frame. If we're looping through windows
1330 on all frames, frame is 0. */
1331 if (FRAMEP (frames))
1332 frame = XFRAME (frames);
1333 else if (NILP (frames))
1334 frame = selected_frame;
1335 else
1336 frame = 0;
1337 if (frame)
1338 frame_arg = Qlambda;
1339 else if (XFASTINT (frames) == 0)
1340 frame_arg = frames;
1341 else if (EQ (frames, Qvisible))
1342 frame_arg = frames;
1343
1344 /* frame_arg is Qlambda to stick to one frame,
1345 Qvisible to consider all visible frames,
1346 or Qt otherwise. */
1347
1348 /* Pick a window to start with. */
1349 if (WINDOWP (obj))
1350 w = obj;
1351 else if (frame)
1352 w = FRAME_SELECTED_WINDOW (frame);
1353 else
1354 w = FRAME_SELECTED_WINDOW (selected_frame);
1355
1356 /* Figure out the last window we're going to mess with. Since
1357 Fnext_window, given the same options, is guaranteed to go in a
1358 ring, we can just use Fprevious_window to find the last one.
1359
1360 We can't just wait until we hit the first window again, because
1361 it might be deleted. */
1362
1363 last_window = Fprevious_window (w, mini ? Qt : Qnil, frame_arg);
1364
1365 best_window = Qnil;
1366 for (;;)
1367 {
1368 FRAME_PTR w_frame = XFRAME (WINDOW_FRAME (XWINDOW (w)));
1369
1370 /* Pick the next window now, since some operations will delete
1371 the current window. */
1372 next_window = Fnext_window (w, mini ? Qt : Qnil, frame_arg);
1373
1374 /* Note that we do not pay attention here to whether
1375 the frame is visible, since Fnext_window skips non-visible frames
1376 if that is desired, under the control of frame_arg. */
1377 if (! MINI_WINDOW_P (XWINDOW (w))
1378 /* For UNSHOW_BUFFER, we must always consider all windows. */
1379 || type == UNSHOW_BUFFER
1380 || (mini && minibuf_level > 0))
1381 switch (type)
1382 {
1383 case GET_BUFFER_WINDOW:
1384 if (XBUFFER (XWINDOW (w)->buffer) == XBUFFER (obj)
1385 /* Don't find any minibuffer window
1386 except the one that is currently in use. */
1387 && (MINI_WINDOW_P (XWINDOW (w))
1388 ? EQ (w, minibuf_window) : 1))
1389 return w;
1390 break;
1391
1392 case GET_LRU_WINDOW:
1393 /* t as arg means consider only full-width windows */
1394 if (!NILP (obj) && !WINDOW_FULL_WIDTH_P (XWINDOW (w)))
1395 break;
1396 /* Ignore dedicated windows and minibuffers. */
1397 if (MINI_WINDOW_P (XWINDOW (w))
1398 || !NILP (XWINDOW (w)->dedicated))
1399 break;
1400 if (NILP (best_window)
1401 || (XFASTINT (XWINDOW (best_window)->use_time)
1402 > XFASTINT (XWINDOW (w)->use_time)))
1403 best_window = w;
1404 break;
1405
1406 case DELETE_OTHER_WINDOWS:
1407 if (XWINDOW (w) != XWINDOW (obj))
1408 Fdelete_window (w);
1409 break;
1410
1411 case DELETE_BUFFER_WINDOWS:
1412 if (EQ (XWINDOW (w)->buffer, obj))
1413 {
1414 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
1415
1416 /* If this window is dedicated, and in a frame of its own,
1417 kill the frame. */
1418 if (EQ (w, FRAME_ROOT_WINDOW (f))
1419 && !NILP (XWINDOW (w)->dedicated)
1420 && other_visible_frames (f))
1421 {
1422 /* Skip the other windows on this frame.
1423 There might be one, the minibuffer! */
1424 if (! EQ (w, last_window))
1425 while (f == XFRAME (WINDOW_FRAME (XWINDOW (next_window))))
1426 {
1427 /* As we go, check for the end of the loop.
1428 We mustn't start going around a second time. */
1429 if (EQ (next_window, last_window))
1430 {
1431 last_window = w;
1432 break;
1433 }
1434 next_window = Fnext_window (next_window,
1435 mini ? Qt : Qnil,
1436 frame_arg);
1437 }
1438 /* Now we can safely delete the frame. */
1439 Fdelete_frame (WINDOW_FRAME (XWINDOW (w)), Qnil);
1440 }
1441 else
1442 /* If we're deleting the buffer displayed in the only window
1443 on the frame, find a new buffer to display there. */
1444 if (NILP (XWINDOW (w)->parent))
1445 {
1446 Lisp_Object new_buffer;
1447 new_buffer = Fother_buffer (obj, Qnil,
1448 XWINDOW (w)->frame);
1449 if (NILP (new_buffer))
1450 new_buffer
1451 = Fget_buffer_create (build_string ("*scratch*"));
1452 Fset_window_buffer (w, new_buffer);
1453 if (EQ (w, selected_window))
1454 Fset_buffer (XWINDOW (w)->buffer);
1455 }
1456 else
1457 Fdelete_window (w);
1458 }
1459 break;
1460
1461 case GET_LARGEST_WINDOW:
1462 /* Ignore dedicated windows and minibuffers. */
1463 if (MINI_WINDOW_P (XWINDOW (w))
1464 || !NILP (XWINDOW (w)->dedicated))
1465 break;
1466 {
1467 struct window *best_window_ptr = XWINDOW (best_window);
1468 struct window *w_ptr = XWINDOW (w);
1469 if (NILP (best_window)
1470 || (XFASTINT (w_ptr->height) * XFASTINT (w_ptr->width)
1471 > (XFASTINT (best_window_ptr->height)
1472 * XFASTINT (best_window_ptr->width))))
1473 best_window = w;
1474 }
1475 break;
1476
1477 case UNSHOW_BUFFER:
1478 if (EQ (XWINDOW (w)->buffer, obj))
1479 {
1480 /* Find another buffer to show in this window. */
1481 Lisp_Object another_buffer;
1482 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
1483 another_buffer = Fother_buffer (obj, Qnil, XWINDOW (w)->frame);
1484 if (NILP (another_buffer))
1485 another_buffer
1486 = Fget_buffer_create (build_string ("*scratch*"));
1487 /* If this window is dedicated, and in a frame of its own,
1488 kill the frame. */
1489 if (EQ (w, FRAME_ROOT_WINDOW (f))
1490 && !NILP (XWINDOW (w)->dedicated)
1491 && other_visible_frames (f))
1492 {
1493 /* Skip the other windows on this frame.
1494 There might be one, the minibuffer! */
1495 if (! EQ (w, last_window))
1496 while (f == XFRAME (WINDOW_FRAME (XWINDOW (next_window))))
1497 {
1498 /* As we go, check for the end of the loop.
1499 We mustn't start going around a second time. */
1500 if (EQ (next_window, last_window))
1501 {
1502 last_window = w;
1503 break;
1504 }
1505 next_window = Fnext_window (next_window,
1506 mini ? Qt : Qnil,
1507 frame_arg);
1508 }
1509 /* Now we can safely delete the frame. */
1510 Fdelete_frame (WINDOW_FRAME (XWINDOW (w)), Qnil);
1511 }
1512 else
1513 {
1514 /* Otherwise show a different buffer in the window. */
1515 XWINDOW (w)->dedicated = Qnil;
1516 Fset_window_buffer (w, another_buffer);
1517 if (EQ (w, selected_window))
1518 Fset_buffer (XWINDOW (w)->buffer);
1519 }
1520 }
1521 break;
1522
1523 /* Check for a window that has a killed buffer. */
1524 case CHECK_ALL_WINDOWS:
1525 if (! NILP (XWINDOW (w)->buffer)
1526 && NILP (XBUFFER (XWINDOW (w)->buffer)->name))
1527 abort ();
1528 }
1529
1530 if (EQ (w, last_window))
1531 break;
1532
1533 w = next_window;
1534 }
1535
1536 return best_window;
1537 }
1538
1539 /* Used for debugging. Abort if any window has a dead buffer. */
1540
1541 check_all_windows ()
1542 {
1543 window_loop (CHECK_ALL_WINDOWS, Qnil, 1, Qt);
1544 }
1545
1546 DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
1547 "Return the window least recently selected or used for display.\n\
1548 If optional argument FRAME is `visible', search all visible frames.\n\
1549 If FRAME is 0, search all visible and iconified frames.\n\
1550 If FRAME is t, search all frames.\n\
1551 If FRAME is nil, search only the selected frame.\n\
1552 If FRAME is a frame, search only that frame.")
1553 (frame)
1554 Lisp_Object frame;
1555 {
1556 register Lisp_Object w;
1557 /* First try for a window that is full-width */
1558 w = window_loop (GET_LRU_WINDOW, Qt, 0, frame);
1559 if (!NILP (w) && !EQ (w, selected_window))
1560 return w;
1561 /* If none of them, try the rest */
1562 return window_loop (GET_LRU_WINDOW, Qnil, 0, frame);
1563 }
1564
1565 DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 1, 0,
1566 "Return the largest window in area.\n\
1567 If optional argument FRAME is `visible', search all visible frames.\n\
1568 If FRAME is 0, search all visible and iconified frames.\n\
1569 If FRAME is t, search all frames.\n\
1570 If FRAME is nil, search only the selected frame.\n\
1571 If FRAME is a frame, search only that frame.")
1572 (frame)
1573 Lisp_Object frame;
1574 {
1575 return window_loop (GET_LARGEST_WINDOW, Qnil, 0,
1576 frame);
1577 }
1578
1579 DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 1, 2, 0,
1580 "Return a window currently displaying BUFFER, or nil if none.\n\
1581 If optional argument FRAME is `visible', search all visible frames.\n\
1582 If optional argument FRAME is 0, search all visible and iconified frames.\n\
1583 If FRAME is t, search all frames.\n\
1584 If FRAME is nil, search only the selected frame.\n\
1585 If FRAME is a frame, search only that frame.")
1586 (buffer, frame)
1587 Lisp_Object buffer, frame;
1588 {
1589 buffer = Fget_buffer (buffer);
1590 if (BUFFERP (buffer))
1591 return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame);
1592 else
1593 return Qnil;
1594 }
1595
1596 DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
1597 0, 1, "",
1598 "Make WINDOW (or the selected window) fill its frame.\n\
1599 Only the frame WINDOW is on is affected.\n\
1600 This function tries to reduce display jumps\n\
1601 by keeping the text previously visible in WINDOW\n\
1602 in the same place on the frame. Doing this depends on\n\
1603 the value of (window-start WINDOW), so if calling this function\n\
1604 in a program gives strange scrolling, make sure the window-start\n\
1605 value is reasonable when this function is called.")
1606 (window)
1607 Lisp_Object window;
1608 {
1609 struct window *w;
1610 int startpos;
1611 int top;
1612
1613 if (NILP (window))
1614 window = selected_window;
1615 else
1616 CHECK_LIVE_WINDOW (window, 0);
1617
1618 w = XWINDOW (window);
1619
1620 startpos = marker_position (w->start);
1621 top = XFASTINT (w->top) - FRAME_MENU_BAR_LINES (XFRAME (WINDOW_FRAME (w)));
1622
1623 if (MINI_WINDOW_P (w) && top > 0)
1624 error ("Can't expand minibuffer to full frame");
1625
1626 window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_FRAME (w));
1627
1628 /* Try to minimize scrolling, by setting the window start to the point
1629 will cause the text at the old window start to be at the same place
1630 on the frame. But don't try to do this if the window start is
1631 outside the visible portion (as might happen when the display is
1632 not current, due to typeahead). */
1633 if (startpos >= BUF_BEGV (XBUFFER (w->buffer))
1634 && startpos <= BUF_ZV (XBUFFER (w->buffer)))
1635 {
1636 struct position pos;
1637 struct buffer *obuf = current_buffer;
1638
1639 Fset_buffer (w->buffer);
1640 /* This computation used to temporarily move point, but that can
1641 have unwanted side effects due to text properties. */
1642 pos = *vmotion (startpos, -top, w);
1643
1644 set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
1645 w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
1646 || FETCH_BYTE (pos.bytepos - 1) == '\n') ? Qt
1647 : Qnil);
1648 /* We need to do this, so that the window-scroll-functions
1649 get called. */
1650 w->optional_new_start = Qt;
1651
1652 set_buffer_internal (obuf);
1653 }
1654 return Qnil;
1655 }
1656
1657 DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
1658 1, 2, "bDelete windows on (buffer): ",
1659 "Delete all windows showing BUFFER.\n\
1660 Optional second argument FRAME controls which frames are affected.\n\
1661 If optional argument FRAME is `visible', search all visible frames.\n\
1662 If FRAME is 0, search all visible and iconified frames.\n\
1663 If FRAME is nil, search all frames.\n\
1664 If FRAME is t, search only the selected frame.\n\
1665 If FRAME is a frame, search only that frame.")
1666 (buffer, frame)
1667 Lisp_Object buffer, frame;
1668 {
1669 /* FRAME uses t and nil to mean the opposite of what window_loop
1670 expects. */
1671 if (NILP (frame))
1672 frame = Qt;
1673 else if (EQ (frame, Qt))
1674 frame = Qnil;
1675
1676 if (!NILP (buffer))
1677 {
1678 buffer = Fget_buffer (buffer);
1679 CHECK_BUFFER (buffer, 0);
1680 window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
1681 }
1682 return Qnil;
1683 }
1684
1685 DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
1686 Sreplace_buffer_in_windows,
1687 1, 1, "bReplace buffer in windows: ",
1688 "Replace BUFFER with some other buffer in all windows showing it.")
1689 (buffer)
1690 Lisp_Object buffer;
1691 {
1692 if (!NILP (buffer))
1693 {
1694 buffer = Fget_buffer (buffer);
1695 CHECK_BUFFER (buffer, 0);
1696 window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
1697 }
1698 return Qnil;
1699 }
1700
1701 /* Replace BUFFER with some other buffer in all windows
1702 of all frames, even those on other keyboards. */
1703
1704 void
1705 replace_buffer_in_all_windows (buffer)
1706 Lisp_Object buffer;
1707 {
1708 #ifdef MULTI_KBOARD
1709 Lisp_Object tail, frame;
1710
1711 /* A single call to window_loop won't do the job
1712 because it only considers frames on the current keyboard.
1713 So loop manually over frames, and handle each one. */
1714 FOR_EACH_FRAME (tail, frame)
1715 window_loop (UNSHOW_BUFFER, buffer, 1, frame);
1716 #else
1717 window_loop (UNSHOW_BUFFER, buffer, 1, Qt);
1718 #endif
1719 }
1720 \f
1721 /* Set the height of WINDOW and all its inferiors. */
1722
1723 /* The smallest acceptable dimensions for a window. Anything smaller
1724 might crash Emacs. */
1725 #define MIN_SAFE_WINDOW_WIDTH (2)
1726 #define MIN_SAFE_WINDOW_HEIGHT (2)
1727
1728 /* Make sure that window_min_height and window_min_width are
1729 not too small; if they are, set them to safe minima. */
1730
1731 static void
1732 check_min_window_sizes ()
1733 {
1734 /* Smaller values might permit a crash. */
1735 if (window_min_width < MIN_SAFE_WINDOW_WIDTH)
1736 window_min_width = MIN_SAFE_WINDOW_WIDTH;
1737 if (window_min_height < MIN_SAFE_WINDOW_HEIGHT)
1738 window_min_height = MIN_SAFE_WINDOW_HEIGHT;
1739 }
1740
1741 /* If *ROWS or *COLS are too small a size for FRAME, set them to the
1742 minimum allowable size. */
1743 void
1744 check_frame_size (frame, rows, cols)
1745 FRAME_PTR frame;
1746 int *rows, *cols;
1747 {
1748 /* For height, we have to see:
1749 whether the frame has a minibuffer,
1750 whether it wants a mode line, and
1751 whether it has a menu bar. */
1752 int min_height =
1753 (FRAME_MINIBUF_ONLY_P (frame) ? MIN_SAFE_WINDOW_HEIGHT - 1
1754 : (! FRAME_HAS_MINIBUF_P (frame)) ? MIN_SAFE_WINDOW_HEIGHT
1755 : 2 * MIN_SAFE_WINDOW_HEIGHT - 1);
1756 if (FRAME_MENU_BAR_LINES (frame) > 0)
1757 min_height += FRAME_MENU_BAR_LINES (frame);
1758
1759 if (*rows < min_height)
1760 *rows = min_height;
1761 if (*cols < MIN_SAFE_WINDOW_WIDTH)
1762 *cols = MIN_SAFE_WINDOW_WIDTH;
1763 }
1764
1765 /* Normally the window is deleted if it gets too small.
1766 nodelete nonzero means do not do this.
1767 (The caller should check later and do so if appropriate) */
1768
1769 void
1770 set_window_height (window, height, nodelete)
1771 Lisp_Object window;
1772 int height;
1773 int nodelete;
1774 {
1775 register struct window *w = XWINDOW (window);
1776 register struct window *c;
1777 int oheight = XFASTINT (w->height);
1778 int top, pos, lastbot, opos, lastobot;
1779 Lisp_Object child;
1780
1781 check_min_window_sizes ();
1782
1783 if (!nodelete
1784 && ! NILP (w->parent)
1785 && (MINI_WINDOW_P (w)
1786 ? height < 1
1787 : height < window_min_height))
1788 {
1789 delete_window (window);
1790 return;
1791 }
1792
1793 XSETFASTINT (w->last_modified, 0);
1794 XSETFASTINT (w->last_overlay_modified, 0);
1795 windows_or_buffers_changed++;
1796 FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
1797
1798 XSETFASTINT (w->height, height);
1799 if (!NILP (w->hchild))
1800 {
1801 for (child = w->hchild; !NILP (child); child = XWINDOW (child)->next)
1802 {
1803 XWINDOW (child)->top = w->top;
1804 set_window_height (child, height, nodelete);
1805 }
1806 }
1807 else if (!NILP (w->vchild))
1808 {
1809 lastbot = top = XFASTINT (w->top);
1810 lastobot = 0;
1811 for (child = w->vchild; !NILP (child); child = c->next)
1812 {
1813 c = XWINDOW (child);
1814
1815 opos = lastobot + XFASTINT (c->height);
1816
1817 XSETFASTINT (c->top, lastbot);
1818
1819 pos = (((opos * height) << 1) + oheight) / (oheight << 1);
1820
1821 /* Avoid confusion: inhibit deletion of child if becomes too small */
1822 set_window_height (child, pos + top - lastbot, 1);
1823
1824 /* Now advance child to next window,
1825 and set lastbot if child was not just deleted. */
1826 lastbot = pos + top;
1827 lastobot = opos;
1828 }
1829 /* Now delete any children that became too small. */
1830 if (!nodelete)
1831 for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
1832 {
1833 set_window_height (child, XINT (XWINDOW (child)->height), 0);
1834 }
1835 }
1836 }
1837
1838 /* Recursively set width of WINDOW and its inferiors. */
1839
1840 void
1841 set_window_width (window, width, nodelete)
1842 Lisp_Object window;
1843 int width;
1844 int nodelete;
1845 {
1846 register struct window *w = XWINDOW (window);
1847 register struct window *c;
1848 int owidth = XFASTINT (w->width);
1849 int left, pos, lastright, opos, lastoright;
1850 Lisp_Object child;
1851
1852 if (!nodelete && width < window_min_width && !NILP (w->parent))
1853 {
1854 delete_window (window);
1855 return;
1856 }
1857
1858 XSETFASTINT (w->last_modified, 0);
1859 XSETFASTINT (w->last_overlay_modified, 0);
1860 windows_or_buffers_changed++;
1861 FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
1862
1863 XSETFASTINT (w->width, width);
1864 if (!NILP (w->vchild))
1865 {
1866 for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
1867 {
1868 XWINDOW (child)->left = w->left;
1869 set_window_width (child, width, nodelete);
1870 }
1871 }
1872 else if (!NILP (w->hchild))
1873 {
1874 lastright = left = XFASTINT (w->left);
1875 lastoright = 0;
1876 for (child = w->hchild; !NILP (child); child = c->next)
1877 {
1878 c = XWINDOW (child);
1879
1880 opos = lastoright + XFASTINT (c->width);
1881
1882 XSETFASTINT (c->left, lastright);
1883
1884 pos = (((opos * width) << 1) + owidth) / (owidth << 1);
1885
1886 /* Inhibit deletion for becoming too small */
1887 set_window_width (child, pos + left - lastright, 1);
1888
1889 /* Now advance child to next window,
1890 and set lastright if child was not just deleted. */
1891 lastright = pos + left, lastoright = opos;
1892 }
1893 /* Delete children that became too small */
1894 if (!nodelete)
1895 for (child = w->hchild; !NILP (child); child = XWINDOW (child)->next)
1896 {
1897 set_window_width (child, XINT (XWINDOW (child)->width), 0);
1898 }
1899 }
1900 }
1901 \f
1902 int window_select_count;
1903
1904 Lisp_Object
1905 Fset_window_buffer_unwind (obuf)
1906 Lisp_Object obuf;
1907 {
1908 Fset_buffer (obuf);
1909 return Qnil;
1910 }
1911
1912 DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 2, 0,
1913 "Make WINDOW display BUFFER as its contents.\n\
1914 BUFFER can be a buffer or buffer name.")
1915 (window, buffer)
1916 register Lisp_Object window, buffer;
1917 {
1918 register Lisp_Object tem;
1919 register struct window *w = decode_window (window);
1920 int count = specpdl_ptr - specpdl;
1921
1922 buffer = Fget_buffer (buffer);
1923 CHECK_BUFFER (buffer, 1);
1924
1925 if (NILP (XBUFFER (buffer)->name))
1926 error ("Attempt to display deleted buffer");
1927
1928 tem = w->buffer;
1929 if (NILP (tem))
1930 error ("Window is deleted");
1931 else if (! EQ (tem, Qt)) /* w->buffer is t when the window
1932 is first being set up. */
1933 {
1934 if (!NILP (w->dedicated) && !EQ (tem, buffer))
1935 error ("Window is dedicated to `%s'",
1936 XSTRING (XBUFFER (tem)->name)->data);
1937
1938 unshow_buffer (w);
1939 }
1940
1941 w->buffer = buffer;
1942
1943 if (EQ (window, selected_window))
1944 XBUFFER (w->buffer)->last_selected_window = window;
1945
1946 /* Update time stamps of buffer display. */
1947 if (INTEGERP (XBUFFER (buffer)->display_count))
1948 XSETINT (XBUFFER (buffer)->display_count,
1949 XINT (XBUFFER (buffer)->display_count) + 1);
1950 XBUFFER (buffer)->display_time = Fcurrent_time ();
1951
1952 XSETFASTINT (w->window_end_pos, 0);
1953 w->window_end_valid = Qnil;
1954 XSETFASTINT (w->hscroll, 0);
1955 set_marker_both (w->pointm, buffer,
1956 BUF_PT (XBUFFER (buffer)), BUF_PT_BYTE (XBUFFER (buffer)));
1957 set_marker_restricted (w->start,
1958 make_number (XBUFFER (buffer)->last_window_start),
1959 buffer);
1960 w->start_at_line_beg = Qnil;
1961 w->force_start = Qnil;
1962 XSETFASTINT (w->last_modified, 0);
1963 XSETFASTINT (w->last_overlay_modified, 0);
1964 windows_or_buffers_changed++;
1965
1966 /* We must select BUFFER for running the window-scroll-functions.
1967 If WINDOW is selected, switch permanently.
1968 Otherwise, switch but go back to the ambient buffer afterward. */
1969 if (EQ (window, selected_window))
1970 Fset_buffer (buffer);
1971 /* We can't check ! NILP (Vwindow_scroll_functions) here
1972 because that might itself be a local variable. */
1973 else if (window_initialized)
1974 {
1975 record_unwind_protect (Fset_window_buffer_unwind, Fcurrent_buffer ());
1976 Fset_buffer (buffer);
1977 }
1978
1979 if (! NILP (Vwindow_scroll_functions))
1980 run_hook_with_args_2 (Qwindow_scroll_functions, window,
1981 Fmarker_position (w->start));
1982
1983 if (! NILP (Vwindow_configuration_change_hook)
1984 && ! NILP (Vrun_hooks))
1985 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
1986
1987 unbind_to (count, Qnil);
1988
1989 return Qnil;
1990 }
1991
1992 DEFUN ("select-window", Fselect_window, Sselect_window, 1, 1, 0,
1993 "Select WINDOW. Most editing will apply to WINDOW's buffer.\n\
1994 If WINDOW is not already selected, also make WINDOW's buffer current.\n\
1995 Note that the main editor command loop\n\
1996 selects the buffer of the selected window before each command.")
1997 (window)
1998 register Lisp_Object window;
1999 {
2000 return select_window_1 (window, 1);
2001 }
2002 \f
2003 static Lisp_Object
2004 select_window_1 (window, recordflag)
2005 register Lisp_Object window;
2006 int recordflag;
2007 {
2008 register struct window *w;
2009 register struct window *ow = XWINDOW (selected_window);
2010
2011 CHECK_LIVE_WINDOW (window, 0);
2012
2013 w = XWINDOW (window);
2014
2015 if (NILP (w->buffer))
2016 error ("Trying to select deleted window or non-leaf window");
2017
2018 XSETFASTINT (w->use_time, ++window_select_count);
2019 if (EQ (window, selected_window))
2020 return window;
2021
2022 if (! NILP (ow->buffer))
2023 set_marker_both (ow->pointm, ow->buffer,
2024 BUF_PT (XBUFFER (ow->buffer)),
2025 BUF_PT_BYTE (XBUFFER (ow->buffer)));
2026
2027 selected_window = window;
2028 if (XFRAME (WINDOW_FRAME (w)) != selected_frame)
2029 {
2030 XFRAME (WINDOW_FRAME (w))->selected_window = window;
2031 /* Use this rather than Fhandle_switch_frame
2032 so that FRAME_FOCUS_FRAME is moved appropriately as we
2033 move around in the state where a minibuffer in a separate
2034 frame is active. */
2035 Fselect_frame (WINDOW_FRAME (w), Qnil);
2036 }
2037 else
2038 selected_frame->selected_window = window;
2039
2040 if (recordflag)
2041 record_buffer (w->buffer);
2042 Fset_buffer (w->buffer);
2043
2044 XBUFFER (w->buffer)->last_selected_window = window;
2045
2046 /* Go to the point recorded in the window.
2047 This is important when the buffer is in more
2048 than one window. It also matters when
2049 redisplay_window has altered point after scrolling,
2050 because it makes the change only in the window. */
2051 {
2052 register int new_point = marker_position (w->pointm);
2053 if (new_point < BEGV)
2054 SET_PT (BEGV);
2055 else if (new_point > ZV)
2056 SET_PT (ZV);
2057 else
2058 SET_PT (new_point);
2059 }
2060
2061 windows_or_buffers_changed++;
2062 return window;
2063 }
2064 \f
2065 /* Deiconify the frame containing the window WINDOW,
2066 unless it is the selected frame;
2067 then return WINDOW.
2068
2069 The reason for the exception for the selected frame
2070 is that it seems better not to change the selected frames visibility
2071 merely because of displaying a different buffer in it.
2072 The deiconification is useful when a buffer gets shown in
2073 another frame that you were not using lately. */
2074
2075 static Lisp_Object
2076 display_buffer_1 (window)
2077 Lisp_Object window;
2078 {
2079 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
2080 FRAME_SAMPLE_VISIBILITY (f);
2081 if (f != selected_frame)
2082 {
2083 if (FRAME_ICONIFIED_P (f))
2084 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
2085 else if (FRAME_VISIBLE_P (f))
2086 Fraise_frame (WINDOW_FRAME (XWINDOW (window)));
2087 }
2088 return window;
2089 }
2090
2091 DEFUN ("special-display-p", Fspecial_display_p, Sspecial_display_p, 1, 1, 0,
2092 "Returns non-nil if a buffer named BUFFER-NAME would be created specially.\n\
2093 The value is actually t if the frame should be called with default frame\n\
2094 parameters, and a list of frame parameters if they were specified.\n\
2095 See `special-display-buffer-names', and `special-display-regexps'.")
2096 (buffer_name)
2097 Lisp_Object buffer_name;
2098 {
2099 Lisp_Object tem;
2100
2101 CHECK_STRING (buffer_name, 1);
2102
2103 tem = Fmember (buffer_name, Vspecial_display_buffer_names);
2104 if (!NILP (tem))
2105 return Qt;
2106
2107 tem = Fassoc (buffer_name, Vspecial_display_buffer_names);
2108 if (!NILP (tem))
2109 return XCDR (tem);
2110
2111 for (tem = Vspecial_display_regexps; CONSP (tem); tem = XCDR (tem))
2112 {
2113 Lisp_Object car = XCAR (tem);
2114 if (STRINGP (car)
2115 && fast_string_match (car, buffer_name) >= 0)
2116 return Qt;
2117 else if (CONSP (car)
2118 && STRINGP (XCAR (car))
2119 && fast_string_match (XCAR (car), buffer_name) >= 0)
2120 return XCDR (car);
2121 }
2122 return Qnil;
2123 }
2124
2125 DEFUN ("same-window-p", Fsame_window_p, Ssame_window_p, 1, 1, 0,
2126 "Returns non-nil if a new buffer named BUFFER-NAME would use the same window.\n\
2127 See `same-window-buffer-names' and `same-window-regexps'.")
2128 (buffer_name)
2129 Lisp_Object buffer_name;
2130 {
2131 Lisp_Object tem;
2132
2133 CHECK_STRING (buffer_name, 1);
2134
2135 tem = Fmember (buffer_name, Vsame_window_buffer_names);
2136 if (!NILP (tem))
2137 return Qt;
2138
2139 tem = Fassoc (buffer_name, Vsame_window_buffer_names);
2140 if (!NILP (tem))
2141 return Qt;
2142
2143 for (tem = Vsame_window_regexps; CONSP (tem); tem = XCDR (tem))
2144 {
2145 Lisp_Object car = XCAR (tem);
2146 if (STRINGP (car)
2147 && fast_string_match (car, buffer_name) >= 0)
2148 return Qt;
2149 else if (CONSP (car)
2150 && STRINGP (XCAR (car))
2151 && fast_string_match (XCAR (car), buffer_name) >= 0)
2152 return Qt;
2153 }
2154 return Qnil;
2155 }
2156
2157 /* Use B so the default is (other-buffer). */
2158 DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 3,
2159 "BDisplay buffer: \nP",
2160 "Make BUFFER appear in some window but don't select it.\n\
2161 BUFFER can be a buffer or a buffer name.\n\
2162 If BUFFER is shown already in some window, just use that one,\n\
2163 unless the window is the selected window and the optional second\n\
2164 argument NOT-THIS-WINDOW is non-nil (interactively, with prefix arg).\n\
2165 If `pop-up-frames' is non-nil, make a new frame if no window shows BUFFER.\n\
2166 Returns the window displaying BUFFER.\n\
2167 \n\
2168 The variables `special-display-buffer-names', `special-display-regexps',\n\
2169 `same-window-buffer-names', and `same-window-regexps' customize how certain\n\
2170 buffer names are handled.\n\
2171 \n\
2172 If optional argument FRAME is `visible', search all visible frames.\n\
2173 If FRAME is 0, search all visible and iconified frames.\n\
2174 If FRAME is t, search all frames.\n\
2175 If FRAME is a frame, search only that frame.\n\
2176 If FRAME is nil, search only the selected frame\n\
2177 (actually the last nonminibuffer frame),\n\
2178 unless `pop-up-frames' is non-nil,\n\
2179 which means search visible and iconified frames.")
2180 (buffer, not_this_window, frame)
2181 register Lisp_Object buffer, not_this_window, frame;
2182 {
2183 register Lisp_Object window, tem;
2184
2185 buffer = Fget_buffer (buffer);
2186 CHECK_BUFFER (buffer, 0);
2187
2188 if (!NILP (Vdisplay_buffer_function))
2189 return call2 (Vdisplay_buffer_function, buffer, not_this_window);
2190
2191 if (NILP (not_this_window)
2192 && XBUFFER (XWINDOW (selected_window)->buffer) == XBUFFER (buffer))
2193 return display_buffer_1 (selected_window);
2194
2195 /* See if the user has specified this buffer should appear
2196 in the selected window. */
2197 if (NILP (not_this_window))
2198 {
2199 tem = Fsame_window_p (XBUFFER (buffer)->name);
2200 if (!NILP (tem))
2201 {
2202 Fswitch_to_buffer (buffer, Qnil);
2203 return display_buffer_1 (selected_window);
2204 }
2205 }
2206
2207 /* If pop_up_frames,
2208 look for a window showing BUFFER on any visible or iconified frame.
2209 Otherwise search only the current frame. */
2210 if (! NILP (frame))
2211 tem = frame;
2212 else if (pop_up_frames || last_nonminibuf_frame == 0)
2213 XSETFASTINT (tem, 0);
2214 else
2215 XSETFRAME (tem, last_nonminibuf_frame);
2216 window = Fget_buffer_window (buffer, tem);
2217 if (!NILP (window)
2218 && (NILP (not_this_window) || !EQ (window, selected_window)))
2219 {
2220 return display_buffer_1 (window);
2221 }
2222
2223 /* Certain buffer names get special handling. */
2224 if (!NILP (Vspecial_display_function))
2225 {
2226 tem = Fspecial_display_p (XBUFFER (buffer)->name);
2227 if (EQ (tem, Qt))
2228 return call1 (Vspecial_display_function, buffer);
2229 if (CONSP (tem))
2230 return call2 (Vspecial_display_function, buffer, tem);
2231 }
2232
2233 /* If there are no frames open that have more than a minibuffer,
2234 we need to create a new frame. */
2235 if (pop_up_frames || last_nonminibuf_frame == 0)
2236 {
2237 window = Fframe_selected_window (call0 (Vpop_up_frame_function));
2238 Fset_window_buffer (window, buffer);
2239 return display_buffer_1 (window);
2240 }
2241
2242 if (pop_up_windows
2243 || FRAME_MINIBUF_ONLY_P (selected_frame)
2244 /* If the current frame is a special display frame,
2245 don't try to reuse its windows. */
2246 || !NILP (XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->dedicated)
2247 )
2248 {
2249 Lisp_Object frames;
2250
2251 frames = Qnil;
2252 if (FRAME_MINIBUF_ONLY_P (selected_frame))
2253 XSETFRAME (frames, last_nonminibuf_frame);
2254 /* Don't try to create a window if would get an error */
2255 if (split_height_threshold < window_min_height << 1)
2256 split_height_threshold = window_min_height << 1;
2257
2258 /* Note that both Fget_largest_window and Fget_lru_window
2259 ignore minibuffers and dedicated windows.
2260 This means they can return nil. */
2261
2262 /* If the frame we would try to split cannot be split,
2263 try other frames. */
2264 if (FRAME_NO_SPLIT_P (NILP (frames) ? selected_frame
2265 : last_nonminibuf_frame))
2266 {
2267 /* Try visible frames first. */
2268 window = Fget_largest_window (Qvisible);
2269 /* If that didn't work, try iconified frames. */
2270 if (NILP (window))
2271 window = Fget_largest_window (make_number (0));
2272 if (NILP (window))
2273 window = Fget_largest_window (Qt);
2274 }
2275 else
2276 window = Fget_largest_window (frames);
2277
2278 /* If we got a tall enough full-width window that can be split,
2279 split it. */
2280 if (!NILP (window)
2281 && ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
2282 && window_height (window) >= split_height_threshold
2283 && WINDOW_FULL_WIDTH_P (XWINDOW (window)))
2284 window = Fsplit_window (window, Qnil, Qnil);
2285 else
2286 {
2287 Lisp_Object upper, lower, other;
2288
2289 window = Fget_lru_window (frames);
2290 /* If the LRU window is selected, and big enough,
2291 and can be split, split it. */
2292 if (!NILP (window)
2293 && ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
2294 && (EQ (window, selected_window)
2295 || EQ (XWINDOW (window)->parent, Qnil))
2296 && window_height (window) >= window_min_height << 1)
2297 window = Fsplit_window (window, Qnil, Qnil);
2298 /* If Fget_lru_window returned nil, try other approaches. */
2299
2300 /* Try visible frames first. */
2301 if (NILP (window))
2302 window = Fget_buffer_window (buffer, Qvisible);
2303 if (NILP (window))
2304 window = Fget_largest_window (Qvisible);
2305 /* If that didn't work, try iconified frames. */
2306 if (NILP (window))
2307 window = Fget_buffer_window (buffer, make_number (0));
2308 if (NILP (window))
2309 window = Fget_largest_window (make_number (0));
2310 /* Try invisible frames. */
2311 if (NILP (window))
2312 window = Fget_buffer_window (buffer, Qt);
2313 if (NILP (window))
2314 window = Fget_largest_window (Qt);
2315 /* As a last resort, make a new frame. */
2316 if (NILP (window))
2317 window = Fframe_selected_window (call0 (Vpop_up_frame_function));
2318 /* If window appears above or below another,
2319 even out their heights. */
2320 other = upper = lower = Qnil;
2321 if (!NILP (XWINDOW (window)->prev))
2322 other = upper = XWINDOW (window)->prev, lower = window;
2323 if (!NILP (XWINDOW (window)->next))
2324 other = lower = XWINDOW (window)->next, upper = window;
2325 if (!NILP (other)
2326 /* Check that OTHER and WINDOW are vertically arrayed. */
2327 && !EQ (XWINDOW (other)->top, XWINDOW (window)->top)
2328 && (XFASTINT (XWINDOW (other)->height)
2329 > XFASTINT (XWINDOW (window)->height)))
2330 {
2331 int total = (XFASTINT (XWINDOW (other)->height)
2332 + XFASTINT (XWINDOW (window)->height));
2333 Lisp_Object old_selected_window;
2334 old_selected_window = selected_window;
2335
2336 selected_window = upper;
2337 change_window_height ((total / 2
2338 - XFASTINT (XWINDOW (upper)->height)),
2339 0);
2340 selected_window = old_selected_window;
2341 }
2342 }
2343 }
2344 else
2345 window = Fget_lru_window (Qnil);
2346
2347 Fset_window_buffer (window, buffer);
2348 return display_buffer_1 (window);
2349 }
2350
2351 void
2352 temp_output_buffer_show (buf)
2353 register Lisp_Object buf;
2354 {
2355 register struct buffer *old = current_buffer;
2356 register Lisp_Object window;
2357 register struct window *w;
2358
2359 XBUFFER (buf)->directory = current_buffer->directory;
2360
2361 Fset_buffer (buf);
2362 BUF_SAVE_MODIFF (XBUFFER (buf)) = MODIFF;
2363 BEGV = BEG;
2364 ZV = Z;
2365 SET_PT (BEG);
2366 XBUFFER (buf)->clip_changed = 1;
2367 set_buffer_internal (old);
2368
2369 if (!EQ (Vtemp_buffer_show_function, Qnil))
2370 call1 (Vtemp_buffer_show_function, buf);
2371 else
2372 {
2373 window = Fdisplay_buffer (buf, Qnil, Qnil);
2374
2375 if (XFRAME (XWINDOW (window)->frame) != selected_frame)
2376 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
2377 Vminibuf_scroll_window = window;
2378 w = XWINDOW (window);
2379 XSETFASTINT (w->hscroll, 0);
2380 set_marker_restricted_both (w->start, buf, 1, 1);
2381 set_marker_restricted_both (w->pointm, buf, 1, 1);
2382
2383 /* Run temp-buffer-show-hook, with the chosen window selected
2384 and it sbuffer current. */
2385 if (!NILP (Vrun_hooks))
2386 {
2387 Lisp_Object tem;
2388 tem = Fboundp (Qtemp_buffer_show_hook);
2389 if (!NILP (tem))
2390 {
2391 tem = Fsymbol_value (Qtemp_buffer_show_hook);
2392 if (!NILP (tem))
2393 {
2394 int count = specpdl_ptr - specpdl;
2395 Lisp_Object prev_window;
2396 prev_window = selected_window;
2397
2398 /* Select the window that was chosen, for running the hook. */
2399 record_unwind_protect (Fselect_window, prev_window);
2400 select_window_1 (window, 0);
2401 Fset_buffer (w->buffer);
2402 call1 (Vrun_hooks, Qtemp_buffer_show_hook);
2403 select_window_1 (prev_window, 0);
2404 unbind_to (count, Qnil);
2405 }
2406 }
2407 }
2408 }
2409 }
2410 \f
2411 static void
2412 make_dummy_parent (window)
2413 Lisp_Object window;
2414 {
2415 Lisp_Object new;
2416 register struct window *o, *p;
2417 register struct Lisp_Vector *vec;
2418 int i;
2419
2420 o = XWINDOW (window);
2421 vec = allocate_vectorlike ((EMACS_INT)VECSIZE (struct window));
2422 for (i = 0; i < VECSIZE (struct window); ++i)
2423 vec->contents[i] = ((struct Lisp_Vector *)o)->contents[i];
2424 vec->size = VECSIZE (struct window);
2425 p = (struct window *)vec;
2426 XSETWINDOW (new, p);
2427
2428 XSETFASTINT (p->sequence_number, ++sequence_number);
2429
2430 /* Put new into window structure in place of window */
2431 replace_window (window, new);
2432
2433 o->next = Qnil;
2434 o->prev = Qnil;
2435 o->vchild = Qnil;
2436 o->hchild = Qnil;
2437 o->parent = new;
2438
2439 p->start = Qnil;
2440 p->pointm = Qnil;
2441 p->buffer = Qnil;
2442 }
2443
2444 DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
2445 "Split WINDOW, putting SIZE lines in the first of the pair.\n\
2446 WINDOW defaults to selected one and SIZE to half its size.\n\
2447 If optional third arg HORFLAG is non-nil, split side by side\n\
2448 and put SIZE columns in the first of the pair. In that case,\n\
2449 SIZE includes that window's scroll bar, or the divider column to its right.")
2450 (window, size, horflag)
2451 Lisp_Object window, size, horflag;
2452 {
2453 register Lisp_Object new;
2454 register struct window *o, *p;
2455 FRAME_PTR fo;
2456 register int size_int;
2457
2458 if (NILP (window))
2459 window = selected_window;
2460 else
2461 CHECK_LIVE_WINDOW (window, 0);
2462
2463 o = XWINDOW (window);
2464 fo = XFRAME (WINDOW_FRAME (o));
2465
2466 if (NILP (size))
2467 {
2468 if (!NILP (horflag))
2469 /* Calculate the size of the left-hand window, by dividing
2470 the usable space in columns by two. */
2471 size_int = XFASTINT (o->width) >> 1;
2472 else
2473 size_int = XFASTINT (o->height) >> 1;
2474 }
2475 else
2476 {
2477 CHECK_NUMBER (size, 1);
2478 size_int = XINT (size);
2479 }
2480
2481 if (MINI_WINDOW_P (o))
2482 error ("Attempt to split minibuffer window");
2483
2484 check_min_window_sizes ();
2485
2486 if (NILP (horflag))
2487 {
2488 if (size_int < window_min_height)
2489 error ("Window height %d too small (after splitting)", size_int);
2490 if (size_int + window_min_height > XFASTINT (o->height))
2491 error ("Window height %d too small (after splitting)",
2492 XFASTINT (o->height) - size_int);
2493 if (NILP (o->parent)
2494 || NILP (XWINDOW (o->parent)->vchild))
2495 {
2496 make_dummy_parent (window);
2497 new = o->parent;
2498 XWINDOW (new)->vchild = window;
2499 }
2500 }
2501 else
2502 {
2503 if (size_int < window_min_width)
2504 error ("Window width %d too small (after splitting)", size_int);
2505
2506 if (size_int + window_min_width > XFASTINT (o->width))
2507 error ("Window width %d too small (after splitting)",
2508 XFASTINT (o->width) - size_int);
2509 if (NILP (o->parent)
2510 || NILP (XWINDOW (o->parent)->hchild))
2511 {
2512 make_dummy_parent (window);
2513 new = o->parent;
2514 XWINDOW (new)->hchild = window;
2515 }
2516 }
2517
2518 /* Now we know that window's parent is a vertical combination
2519 if we are dividing vertically, or a horizontal combination
2520 if we are making side-by-side windows */
2521
2522 windows_or_buffers_changed++;
2523 FRAME_WINDOW_SIZES_CHANGED (fo) = 1;
2524 new = make_window ();
2525 p = XWINDOW (new);
2526
2527 p->frame = o->frame;
2528 p->next = o->next;
2529 if (!NILP (p->next))
2530 XWINDOW (p->next)->prev = new;
2531 p->prev = window;
2532 o->next = new;
2533 p->parent = o->parent;
2534 p->buffer = Qt;
2535
2536 /* Apportion the available frame space among the two new windows */
2537
2538 if (!NILP (horflag))
2539 {
2540 p->height = o->height;
2541 p->top = o->top;
2542 XSETFASTINT (p->width, XFASTINT (o->width) - size_int);
2543 XSETFASTINT (o->width, size_int);
2544 XSETFASTINT (p->left, XFASTINT (o->left) + size_int);
2545 }
2546 else
2547 {
2548 p->left = o->left;
2549 p->width = o->width;
2550 XSETFASTINT (p->height, XFASTINT (o->height) - size_int);
2551 XSETFASTINT (o->height, size_int);
2552 XSETFASTINT (p->top, XFASTINT (o->top) + size_int);
2553 }
2554
2555 Fset_window_buffer (new, o->buffer);
2556
2557 return new;
2558 }
2559 \f
2560 DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
2561 "Make current window ARG lines bigger.\n\
2562 From program, optional second arg non-nil means grow 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 DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
2576 "Make current window ARG lines smaller.\n\
2577 From program, optional second arg non-nil means shrink sideways arg columns.")
2578 (arg, side)
2579 register Lisp_Object arg, side;
2580 {
2581 CHECK_NUMBER (arg, 0);
2582 change_window_height (-XINT (arg), !NILP (side));
2583
2584 if (! NILP (Vwindow_configuration_change_hook))
2585 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
2586
2587 return Qnil;
2588 }
2589
2590 int
2591 window_height (window)
2592 Lisp_Object window;
2593 {
2594 register struct window *p = XWINDOW (window);
2595 return XFASTINT (p->height);
2596 }
2597
2598 int
2599 window_width (window)
2600 Lisp_Object window;
2601 {
2602 register struct window *p = XWINDOW (window);
2603 return XFASTINT (p->width);
2604 }
2605
2606 #define MINSIZE(w) \
2607 (widthflag \
2608 ? window_min_width \
2609 : (MINI_WINDOW_P (XWINDOW (w)) ? 1 : window_min_height))
2610
2611 #define CURBEG(w) \
2612 *(widthflag ? (int *) &(XWINDOW (w)->left) : (int *) &(XWINDOW (w)->top))
2613
2614 #define CURSIZE(w) \
2615 *(widthflag ? (int *) &(XWINDOW (w)->width) : (int *) &(XWINDOW (w)->height))
2616
2617 /* Unlike set_window_height, this function
2618 also changes the heights of the siblings so as to
2619 keep everything consistent. */
2620
2621 void
2622 change_window_height (delta, widthflag)
2623 register int delta;
2624 int widthflag;
2625 {
2626 register Lisp_Object parent;
2627 Lisp_Object window;
2628 register struct window *p;
2629 int *sizep;
2630 int (*sizefun) P_ ((Lisp_Object))
2631 = widthflag ? window_width : window_height;
2632 register void (*setsizefun) P_ ((Lisp_Object, int, int))
2633 = (widthflag ? set_window_width : set_window_height);
2634 int maximum;
2635 Lisp_Object next, prev;
2636
2637 check_min_window_sizes ();
2638
2639 window = selected_window;
2640 while (1)
2641 {
2642 p = XWINDOW (window);
2643 parent = p->parent;
2644 if (NILP (parent))
2645 {
2646 if (widthflag)
2647 error ("No other window to side of this one");
2648 break;
2649 }
2650 if (widthflag ? !NILP (XWINDOW (parent)->hchild)
2651 : !NILP (XWINDOW (parent)->vchild))
2652 break;
2653 window = parent;
2654 }
2655
2656 sizep = &CURSIZE (window);
2657
2658 {
2659 register int maxdelta;
2660
2661 maxdelta = (!NILP (parent) ? (*sizefun) (parent) - *sizep
2662 : !NILP (p->next) ? (*sizefun) (p->next) - MINSIZE (p->next)
2663 : !NILP (p->prev) ? (*sizefun) (p->prev) - MINSIZE (p->prev)
2664 /* This is a frame with only one window, a minibuffer-only
2665 or a minibufferless frame. */
2666 : (delta = 0));
2667
2668 if (delta > maxdelta)
2669 /* This case traps trying to make the minibuffer
2670 the full frame, or make the only window aside from the
2671 minibuffer the full frame. */
2672 delta = maxdelta;
2673 }
2674
2675 if (*sizep + delta < MINSIZE (window))
2676 {
2677 delete_window (window);
2678 return;
2679 }
2680
2681 if (delta == 0)
2682 return;
2683
2684 /* Find the total we can get from other siblings. */
2685 maximum = 0;
2686 for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
2687 maximum += (*sizefun) (next) - MINSIZE (next);
2688 for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
2689 maximum += (*sizefun) (prev) - MINSIZE (prev);
2690
2691 /* If we can get it all from them, do so. */
2692 if (delta <= maximum)
2693 {
2694 Lisp_Object first_unaffected;
2695 Lisp_Object first_affected;
2696
2697 next = p->next;
2698 prev = p->prev;
2699 first_affected = window;
2700 /* Look at one sibling at a time,
2701 moving away from this window in both directions alternately,
2702 and take as much as we can get without deleting that sibling. */
2703 while (delta != 0)
2704 {
2705 if (delta == 0)
2706 break;
2707 if (! NILP (next))
2708 {
2709 int this_one = (*sizefun) (next) - MINSIZE (next);
2710 if (this_one > delta)
2711 this_one = delta;
2712
2713 (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
2714 (*setsizefun) (window, *sizep + this_one, 0);
2715
2716 delta -= this_one;
2717 next = XWINDOW (next)->next;
2718 }
2719 if (delta == 0)
2720 break;
2721 if (! NILP (prev))
2722 {
2723 int this_one = (*sizefun) (prev) - MINSIZE (prev);
2724 if (this_one > delta)
2725 this_one = delta;
2726
2727 first_affected = prev;
2728
2729 (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
2730 (*setsizefun) (window, *sizep + this_one, 0);
2731
2732 delta -= this_one;
2733 prev = XWINDOW (prev)->prev;
2734 }
2735 }
2736
2737 /* Now recalculate the edge positions of all the windows affected,
2738 based on the new sizes. */
2739 first_unaffected = next;
2740 prev = first_affected;
2741 for (next = XWINDOW (prev)->next; ! EQ (next, first_unaffected);
2742 prev = next, next = XWINDOW (next)->next)
2743 {
2744 CURBEG (next) = CURBEG (prev) + (*sizefun) (prev);
2745 /* This does not change size of NEXT,
2746 but it propagates the new top edge to its children */
2747 (*setsizefun) (next, (*sizefun) (next), 0);
2748 }
2749 }
2750 else
2751 {
2752 register int delta1;
2753 register int opht = (*sizefun) (parent);
2754
2755 /* If trying to grow this window to or beyond size of the parent,
2756 make delta1 so big that, on shrinking back down,
2757 all the siblings end up with less than one line and are deleted. */
2758 if (opht <= *sizep + delta)
2759 delta1 = opht * opht * 2;
2760 /* Otherwise, make delta1 just right so that if we add delta1
2761 lines to this window and to the parent, and then shrink
2762 the parent back to its original size, the new proportional
2763 size of this window will increase by delta. */
2764 else
2765 delta1 = (delta * opht * 100) / ((opht - *sizep - delta) * 100);
2766
2767 /* Add delta1 lines or columns to this window, and to the parent,
2768 keeping things consistent while not affecting siblings. */
2769 CURSIZE (parent) = opht + delta1;
2770 (*setsizefun) (window, *sizep + delta1, 0);
2771
2772 /* Squeeze out delta1 lines or columns from our parent,
2773 shriking this window and siblings proportionately.
2774 This brings parent back to correct size.
2775 Delta1 was calculated so this makes this window the desired size,
2776 taking it all out of the siblings. */
2777 (*setsizefun) (parent, opht, 0);
2778 }
2779
2780 XSETFASTINT (p->last_modified, 0);
2781 XSETFASTINT (p->last_overlay_modified, 0);
2782 }
2783 #undef MINSIZE
2784 #undef CURBEG
2785 #undef CURSIZE
2786
2787 \f
2788 /* Return number of lines of text (not counting mode line) in W. */
2789
2790 int
2791 window_internal_height (w)
2792 struct window *w;
2793 {
2794 int ht = XFASTINT (w->height);
2795
2796 if (MINI_WINDOW_P (w))
2797 return ht;
2798
2799 if (!NILP (w->parent) || !NILP (w->vchild) || !NILP (w->hchild)
2800 || !NILP (w->next) || !NILP (w->prev)
2801 || FRAME_WANTS_MODELINE_P (XFRAME (WINDOW_FRAME (w))))
2802 return ht - 1;
2803
2804 return ht;
2805 }
2806
2807
2808 /* Return the number of columns in W.
2809 Don't count columns occupied by scroll bars or the vertical bar
2810 separating W from the sibling to its right. */
2811 int
2812 window_internal_width (w)
2813 struct window *w;
2814 {
2815 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2816 int width = XINT (w->width);
2817
2818 /* Scroll bars occupy a few columns. */
2819 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2820 return width - FRAME_SCROLL_BAR_COLS (f);
2821
2822 /* The column of `|' characters separating side-by-side windows
2823 occupies one column only. */
2824 if (!WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
2825 return width - 1;
2826
2827 return width;
2828 }
2829
2830
2831 /* Scroll contents of window WINDOW up N lines.
2832 If WHOLE is nonzero, it means scroll N screenfuls instead. */
2833
2834 static void
2835 window_scroll (window, n, whole, noerror)
2836 Lisp_Object window;
2837 int n;
2838 int whole;
2839 int noerror;
2840 {
2841 register struct window *w = XWINDOW (window);
2842 register int opoint = PT;
2843 register int opoint_byte = PT_BYTE;
2844 register int pos, pos_byte;
2845 register int ht = window_internal_height (w);
2846 register Lisp_Object tem;
2847 int lose;
2848 Lisp_Object bolp, nmoved;
2849 int startpos;
2850 struct position posit;
2851 int original_vpos;
2852
2853 startpos = marker_position (w->start);
2854
2855 posit = *compute_motion (startpos, 0, 0, 0,
2856 PT, ht, 0,
2857 window_internal_width (w), XINT (w->hscroll),
2858 0, w);
2859 original_vpos = posit.vpos;
2860
2861 XSETFASTINT (tem, PT);
2862 tem = Fpos_visible_in_window_p (tem, window);
2863
2864 if (NILP (tem))
2865 {
2866 Fvertical_motion (make_number (- (ht / 2)), window);
2867 startpos = PT;
2868 }
2869
2870 SET_PT (startpos);
2871 lose = n < 0 && PT == BEGV;
2872 Fvertical_motion (make_number (n), window);
2873 pos = PT;
2874 pos_byte = PT_BYTE;
2875 bolp = Fbolp ();
2876 SET_PT_BOTH (opoint, opoint_byte);
2877
2878 if (lose)
2879 {
2880 if (noerror)
2881 return;
2882 else
2883 Fsignal (Qbeginning_of_buffer, Qnil);
2884 }
2885
2886 if (pos < ZV)
2887 {
2888 int this_scroll_margin = scroll_margin;
2889
2890 /* Don't use a scroll margin that is negative or too large. */
2891 if (this_scroll_margin < 0)
2892 this_scroll_margin = 0;
2893
2894 if (XINT (w->height) < 4 * scroll_margin)
2895 this_scroll_margin = XINT (w->height) / 4;
2896
2897 set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
2898 w->start_at_line_beg = bolp;
2899 w->update_mode_line = Qt;
2900 XSETFASTINT (w->last_modified, 0);
2901 XSETFASTINT (w->last_overlay_modified, 0);
2902 /* Set force_start so that redisplay_window will run
2903 the window-scroll-functions. */
2904 w->force_start = Qt;
2905
2906 if (whole && scroll_preserve_screen_position)
2907 {
2908 SET_PT_BOTH (pos, pos_byte);
2909 Fvertical_motion (make_number (original_vpos), window);
2910 }
2911 /* If we scrolled forward, put point enough lines down
2912 that it is outside the scroll margin. */
2913 else if (n > 0)
2914 {
2915 int top_margin;
2916
2917 if (this_scroll_margin > 0)
2918 {
2919 SET_PT_BOTH (pos, pos_byte);
2920 Fvertical_motion (make_number (this_scroll_margin), window);
2921 top_margin = PT;
2922 }
2923 else
2924 top_margin = pos;
2925
2926 if (top_margin <= opoint)
2927 SET_PT_BOTH (opoint, opoint_byte);
2928 else if (scroll_preserve_screen_position)
2929 {
2930 SET_PT_BOTH (pos, pos_byte);
2931 Fvertical_motion (make_number (original_vpos), window);
2932 }
2933 else
2934 SET_PT (top_margin);
2935 }
2936 else if (n < 0)
2937 {
2938 int bottom_margin;
2939
2940 /* If we scrolled backward, put point near the end of the window
2941 but not within the scroll margin. */
2942 SET_PT_BOTH (pos, pos_byte);
2943 tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
2944 if (XFASTINT (tem) == ht - this_scroll_margin)
2945 bottom_margin = PT;
2946 else
2947 bottom_margin = PT + 1;
2948
2949 if (bottom_margin > opoint)
2950 SET_PT_BOTH (opoint, opoint_byte);
2951 else
2952 {
2953 if (scroll_preserve_screen_position)
2954 {
2955 SET_PT_BOTH (pos, pos_byte);
2956 Fvertical_motion (make_number (original_vpos), window);
2957 }
2958 else
2959 Fvertical_motion (make_number (-1), window);
2960 }
2961 }
2962 }
2963 else
2964 {
2965 if (noerror)
2966 return;
2967 else
2968 Fsignal (Qend_of_buffer, Qnil);
2969 }
2970 }
2971 \f
2972 /* This is the guts of Fscroll_up and Fscroll_down. */
2973
2974 static void
2975 scroll_command (n, direction)
2976 register Lisp_Object n;
2977 int direction;
2978 {
2979 register int defalt;
2980 int count = specpdl_ptr - specpdl;
2981
2982 /* If selected window's buffer isn't current, make it current for the moment.
2983 But don't screw up if window_scroll gets an error. */
2984 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
2985 {
2986 record_unwind_protect (save_excursion_restore, save_excursion_save ());
2987 Fset_buffer (XWINDOW (selected_window)->buffer);
2988 }
2989
2990 defalt = (window_internal_height (XWINDOW (selected_window))
2991 - next_screen_context_lines);
2992 defalt = direction * (defalt < 1 ? 1 : defalt);
2993
2994 if (NILP (n))
2995 window_scroll (selected_window, defalt, 1, 0);
2996 else if (EQ (n, Qminus))
2997 window_scroll (selected_window, - defalt, 1, 0);
2998 else
2999 {
3000 n = Fprefix_numeric_value (n);
3001 window_scroll (selected_window, XINT (n) * direction, 0, 0);
3002 }
3003
3004 unbind_to (count, Qnil);
3005 }
3006
3007 DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
3008 "Scroll text of current window upward ARG lines; or near full screen if no ARG.\n\
3009 A near full screen is `next-screen-context-lines' less than a full screen.\n\
3010 Negative ARG means scroll downward.\n\
3011 If ARG is the atom `-', scroll downward by nearly full screen.\n\
3012 When calling from a program, supply as argument a number, nil, or `-'.")
3013 (arg)
3014 Lisp_Object arg;
3015 {
3016 scroll_command (arg, 1);
3017 return Qnil;
3018 }
3019
3020 DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
3021 "Scroll text of current window down ARG lines; or near full screen if no ARG.\n\
3022 A near full screen is `next-screen-context-lines' less than a full screen.\n\
3023 Negative ARG means scroll upward.\n\
3024 If ARG is the atom `-', scroll upward by nearly full screen.\n\
3025 When calling from a program, supply as argument a number, nil, or `-'.")
3026 (arg)
3027 Lisp_Object arg;
3028 {
3029 scroll_command (arg, -1);
3030 return Qnil;
3031 }
3032 \f
3033 DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0,
3034 "Return the other window for \"other window scroll\" commands.\n\
3035 If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
3036 specifies the window.\n\
3037 If `other-window-scroll-buffer' is non-nil, a window\n\
3038 showing that buffer is used.")
3039 ()
3040 {
3041 Lisp_Object window;
3042
3043 if (MINI_WINDOW_P (XWINDOW (selected_window))
3044 && !NILP (Vminibuf_scroll_window))
3045 window = Vminibuf_scroll_window;
3046 /* If buffer is specified, scroll that buffer. */
3047 else if (!NILP (Vother_window_scroll_buffer))
3048 {
3049 window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
3050 if (NILP (window))
3051 window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt, Qnil);
3052 }
3053 else
3054 {
3055 /* Nothing specified; look for a neighboring window on the same
3056 frame. */
3057 window = Fnext_window (selected_window, Qnil, Qnil);
3058
3059 if (EQ (window, selected_window))
3060 /* That didn't get us anywhere; look for a window on another
3061 visible frame. */
3062 do
3063 window = Fnext_window (window, Qnil, Qt);
3064 while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
3065 && ! EQ (window, selected_window));
3066 }
3067
3068 CHECK_LIVE_WINDOW (window, 0);
3069
3070 if (EQ (window, selected_window))
3071 error ("There is no other window");
3072
3073 return window;
3074 }
3075
3076 DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
3077 "Scroll next window upward ARG lines; or near full screen if no ARG.\n\
3078 A near full screen is `next-screen-context-lines' less than a full screen.\n\
3079 The next window is the one below the current one; or the one at the top\n\
3080 if the current one is at the bottom. Negative ARG means scroll downward.\n\
3081 If ARG is the atom `-', scroll downward by nearly full screen.\n\
3082 When calling from a program, supply as argument a number, nil, or `-'.\n\
3083 \n\
3084 If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
3085 specifies the window to scroll.\n\
3086 If `other-window-scroll-buffer' is non-nil, scroll the window\n\
3087 showing that buffer, popping the buffer up if necessary.")
3088 (arg)
3089 register Lisp_Object arg;
3090 {
3091 register Lisp_Object window;
3092 register int defalt;
3093 register struct window *w;
3094 register int count = specpdl_ptr - specpdl;
3095
3096 window = Fother_window_for_scrolling ();
3097
3098 w = XWINDOW (window);
3099 defalt = window_internal_height (w) - next_screen_context_lines;
3100 if (defalt < 1) defalt = 1;
3101
3102 /* Don't screw up if window_scroll gets an error. */
3103 record_unwind_protect (save_excursion_restore, save_excursion_save ());
3104
3105 Fset_buffer (w->buffer);
3106 SET_PT (marker_position (w->pointm));
3107
3108 if (NILP (arg))
3109 window_scroll (window, defalt, 1, 1);
3110 else if (EQ (arg, Qminus))
3111 window_scroll (window, -defalt, 1, 1);
3112 else
3113 {
3114 if (CONSP (arg))
3115 arg = Fcar (arg);
3116 CHECK_NUMBER (arg, 0);
3117 window_scroll (window, XINT (arg), 0, 1);
3118 }
3119
3120 set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
3121 unbind_to (count, Qnil);
3122
3123 return Qnil;
3124 }
3125 \f
3126 DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 1, "P",
3127 "Scroll selected window display ARG columns left.\n\
3128 Default for ARG is window width minus 2.")
3129 (arg)
3130 register Lisp_Object arg;
3131 {
3132
3133 if (NILP (arg))
3134 XSETFASTINT (arg, window_internal_width (XWINDOW (selected_window)) - 2);
3135 else
3136 arg = Fprefix_numeric_value (arg);
3137
3138 return
3139 Fset_window_hscroll (selected_window,
3140 make_number (XINT (XWINDOW (selected_window)->hscroll)
3141 + XINT (arg)));
3142 }
3143
3144 DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 1, "P",
3145 "Scroll selected window display ARG columns right.\n\
3146 Default for ARG is window width minus 2.")
3147 (arg)
3148 register Lisp_Object arg;
3149 {
3150 if (NILP (arg))
3151 XSETFASTINT (arg, window_internal_width (XWINDOW (selected_window)) - 2);
3152 else
3153 arg = Fprefix_numeric_value (arg);
3154
3155 return
3156 Fset_window_hscroll (selected_window,
3157 make_number (XINT (XWINDOW (selected_window)->hscroll)
3158 - XINT (arg)));
3159 }
3160
3161 DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
3162 "Center point in window and redisplay frame. With ARG, put point on line ARG.\n\
3163 The desired position of point is always relative to the current window.\n\
3164 Just C-u as prefix means put point in the center of the window.\n\
3165 If ARG is omitted or nil, erases the entire frame and then\n\
3166 redraws with point in the center of the current window.")
3167 (arg)
3168 register Lisp_Object arg;
3169 {
3170 register struct window *w = XWINDOW (selected_window);
3171 register int ht = window_internal_height (w);
3172 struct position pos;
3173 struct buffer *buf = XBUFFER (w->buffer);
3174 struct buffer *obuf = current_buffer;
3175
3176 if (NILP (arg))
3177 {
3178 extern int frame_garbaged;
3179
3180 SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
3181 XSETFASTINT (arg, ht / 2);
3182 }
3183 else if (CONSP (arg)) /* Just C-u. */
3184 {
3185 XSETFASTINT (arg, ht / 2);
3186 }
3187 else
3188 {
3189 arg = Fprefix_numeric_value (arg);
3190 CHECK_NUMBER (arg, 0);
3191 }
3192
3193 if (XINT (arg) < 0)
3194 XSETINT (arg, XINT (arg) + ht);
3195
3196 set_buffer_internal (buf);
3197 pos = *vmotion (PT, - XINT (arg), w);
3198
3199 set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
3200 w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
3201 || FETCH_BYTE (pos.bytepos - 1) == '\n')
3202 ? Qt : Qnil);
3203 w->force_start = Qt;
3204 set_buffer_internal (obuf);
3205
3206 return Qnil;
3207 }
3208 \f
3209 DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
3210 1, 1, "P",
3211 "Position point relative to window.\n\
3212 With no argument, position point at center of window.\n\
3213 An argument specifies vertical position within the window;\n\
3214 zero means top of window, negative means relative to bottom of window.")
3215 (arg)
3216 register Lisp_Object arg;
3217 {
3218 register struct window *w = XWINDOW (selected_window);
3219 register int height = window_internal_height (w);
3220 register int start;
3221 Lisp_Object window;
3222
3223 if (NILP (arg))
3224 XSETFASTINT (arg, height / 2);
3225 else
3226 {
3227 arg = Fprefix_numeric_value (arg);
3228 if (XINT (arg) < 0)
3229 XSETINT (arg, XINT (arg) + height);
3230 }
3231
3232 start = marker_position (w->start);
3233 XSETWINDOW (window, w);
3234 if (start < BEGV || start > ZV)
3235 {
3236 Fvertical_motion (make_number (- (height / 2)), window);
3237 set_marker_both (w->start, w->buffer, PT, PT_BYTE);
3238 w->start_at_line_beg = Fbolp ();
3239 w->force_start = Qt;
3240 }
3241 else
3242 Fgoto_char (w->start);
3243
3244 return Fvertical_motion (arg, window);
3245 }
3246 \f
3247 struct save_window_data
3248 {
3249 EMACS_INT size_from_Lisp_Vector_struct;
3250 struct Lisp_Vector *next_from_Lisp_Vector_struct;
3251 Lisp_Object frame_width, frame_height, frame_menu_bar_lines;
3252 Lisp_Object selected_frame;
3253 Lisp_Object current_window;
3254 Lisp_Object current_buffer;
3255 Lisp_Object minibuf_scroll_window;
3256 Lisp_Object root_window;
3257 Lisp_Object focus_frame;
3258 /* Record the values of window-min-width and window-min-height
3259 so that window sizes remain consistent with them. */
3260 Lisp_Object min_width, min_height;
3261 /* A vector, each of whose elements is a struct saved_window
3262 for one window. */
3263 Lisp_Object saved_windows;
3264 };
3265
3266 /* This is saved as a Lisp_Vector */
3267 struct saved_window
3268 {
3269 /* these first two must agree with struct Lisp_Vector in lisp.h */
3270 EMACS_INT size_from_Lisp_Vector_struct;
3271 struct Lisp_Vector *next_from_Lisp_Vector_struct;
3272
3273 Lisp_Object window;
3274 Lisp_Object buffer, start, pointm, mark;
3275 Lisp_Object left, top, width, height, hscroll;
3276 Lisp_Object parent, prev;
3277 Lisp_Object start_at_line_beg;
3278 Lisp_Object display_table;
3279 };
3280 #define SAVED_WINDOW_VECTOR_SIZE 14 /* Arg to Fmake_vector */
3281
3282 #define SAVED_WINDOW_N(swv,n) \
3283 ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
3284
3285 DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
3286 "Return t if OBJECT is a window-configuration object.")
3287 (object)
3288 Lisp_Object object;
3289 {
3290 if (WINDOW_CONFIGURATIONP (object))
3291 return Qt;
3292 return Qnil;
3293 }
3294
3295 DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
3296 "Return the frame that CONFIG, a window-configuration object, is about.")
3297 (config)
3298 Lisp_Object config;
3299 {
3300 register struct save_window_data *data;
3301 struct Lisp_Vector *saved_windows;
3302
3303 if (! WINDOW_CONFIGURATIONP (config))
3304 wrong_type_argument (Qwindow_configuration_p, config);
3305
3306 data = (struct save_window_data *) XVECTOR (config);
3307 saved_windows = XVECTOR (data->saved_windows);
3308 return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
3309 }
3310
3311 DEFUN ("set-window-configuration", Fset_window_configuration,
3312 Sset_window_configuration, 1, 1, 0,
3313 "Set the configuration of windows and buffers as specified by CONFIGURATION.\n\
3314 CONFIGURATION must be a value previously returned\n\
3315 by `current-window-configuration' (which see).\n\
3316 If CONFIGURATION was made from a frame that is now deleted,\n\
3317 only frame-independent values can be restored. In this case,\n\
3318 the return value is nil. Otherwise the value is t.")
3319 (configuration)
3320 Lisp_Object configuration;
3321 {
3322 register struct save_window_data *data;
3323 struct Lisp_Vector *saved_windows;
3324 Lisp_Object new_current_buffer;
3325 Lisp_Object frame;
3326 FRAME_PTR f;
3327 int old_point = -1;
3328
3329 while (!WINDOW_CONFIGURATIONP (configuration))
3330 wrong_type_argument (Qwindow_configuration_p, configuration);
3331
3332 data = (struct save_window_data *) XVECTOR (configuration);
3333 saved_windows = XVECTOR (data->saved_windows);
3334
3335 new_current_buffer = data->current_buffer;
3336 if (NILP (XBUFFER (new_current_buffer)->name))
3337 new_current_buffer = Qnil;
3338 else
3339 {
3340 if (XBUFFER (new_current_buffer) == current_buffer)
3341 old_point = PT;
3342
3343 }
3344
3345 frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
3346 f = XFRAME (frame);
3347
3348 /* If f is a dead frame, don't bother rebuilding its window tree.
3349 However, there is other stuff we should still try to do below. */
3350 if (FRAME_LIVE_P (f))
3351 {
3352 register struct window *w;
3353 register struct saved_window *p;
3354 int k;
3355
3356 /* If the frame has been resized since this window configuration was
3357 made, we change the frame to the size specified in the
3358 configuration, restore the configuration, and then resize it
3359 back. We keep track of the prevailing height in these variables. */
3360 int previous_frame_height = FRAME_HEIGHT (f);
3361 int previous_frame_width = FRAME_WIDTH (f);
3362 int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
3363
3364 /* The mouse highlighting code could get screwed up
3365 if it runs during this. */
3366 BLOCK_INPUT;
3367
3368 if (XFASTINT (data->frame_height) != previous_frame_height
3369 || XFASTINT (data->frame_width) != previous_frame_width)
3370 change_frame_size (f, XFASTINT (data->frame_height),
3371 XFASTINT (data->frame_width), 0, 0);
3372 #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
3373 if (XFASTINT (data->frame_menu_bar_lines)
3374 != previous_frame_menu_bar_lines)
3375 x_set_menu_bar_lines (f, data->frame_menu_bar_lines, make_number (0));
3376 #endif
3377
3378 if (! NILP (XWINDOW (selected_window)->buffer))
3379 {
3380 w = XWINDOW (selected_window);
3381 set_marker_both (w->pointm,
3382 w->buffer,
3383 BUF_PT (XBUFFER (w->buffer)),
3384 BUF_PT_BYTE (XBUFFER (w->buffer)));
3385 }
3386
3387 windows_or_buffers_changed++;
3388 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
3389
3390 /* Temporarily avoid any problems with windows that are smaller
3391 than they are supposed to be. */
3392 window_min_height = 1;
3393 window_min_width = 1;
3394
3395 /* Kludge Alert!
3396 Mark all windows now on frame as "deleted".
3397 Restoring the new configuration "undeletes" any that are in it.
3398
3399 Save their current buffers in their height fields, since we may
3400 need it later, if a buffer saved in the configuration is now
3401 dead. */
3402 delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
3403
3404 for (k = 0; k < saved_windows->size; k++)
3405 {
3406 p = SAVED_WINDOW_N (saved_windows, k);
3407 w = XWINDOW (p->window);
3408 w->next = Qnil;
3409
3410 if (!NILP (p->parent))
3411 w->parent = SAVED_WINDOW_N (saved_windows,
3412 XFASTINT (p->parent))->window;
3413 else
3414 w->parent = Qnil;
3415
3416 if (!NILP (p->prev))
3417 {
3418 w->prev = SAVED_WINDOW_N (saved_windows,
3419 XFASTINT (p->prev))->window;
3420 XWINDOW (w->prev)->next = p->window;
3421 }
3422 else
3423 {
3424 w->prev = Qnil;
3425 if (!NILP (w->parent))
3426 {
3427 if (EQ (p->width, XWINDOW (w->parent)->width))
3428 {
3429 XWINDOW (w->parent)->vchild = p->window;
3430 XWINDOW (w->parent)->hchild = Qnil;
3431 }
3432 else
3433 {
3434 XWINDOW (w->parent)->hchild = p->window;
3435 XWINDOW (w->parent)->vchild = Qnil;
3436 }
3437 }
3438 }
3439
3440 /* If we squirreled away the buffer in the window's height,
3441 restore it now. */
3442 if (BUFFERP (w->height))
3443 w->buffer = w->height;
3444 w->left = p->left;
3445 w->top = p->top;
3446 w->width = p->width;
3447 w->height = p->height;
3448 w->hscroll = p->hscroll;
3449 w->display_table = p->display_table;
3450 XSETFASTINT (w->last_modified, 0);
3451 XSETFASTINT (w->last_overlay_modified, 0);
3452
3453 /* Reinstall the saved buffer and pointers into it. */
3454 if (NILP (p->buffer))
3455 w->buffer = p->buffer;
3456 else
3457 {
3458 if (!NILP (XBUFFER (p->buffer)->name))
3459 /* If saved buffer is alive, install it. */
3460 {
3461 w->buffer = p->buffer;
3462 w->start_at_line_beg = p->start_at_line_beg;
3463 set_marker_restricted (w->start, p->start, w->buffer);
3464 set_marker_restricted (w->pointm, p->pointm, w->buffer);
3465 Fset_marker (XBUFFER (w->buffer)->mark,
3466 p->mark, w->buffer);
3467
3468 /* As documented in Fcurrent_window_configuration, don't
3469 save the location of point in the buffer which was current
3470 when the window configuration was recorded. */
3471 if (!EQ (p->buffer, new_current_buffer)
3472 && XBUFFER (p->buffer) == current_buffer)
3473 Fgoto_char (w->pointm);
3474 }
3475 else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
3476 /* Else unless window has a live buffer, get one. */
3477 {
3478 w->buffer = Fcdr (Fcar (Vbuffer_alist));
3479 /* This will set the markers to beginning of visible
3480 range. */
3481 set_marker_restricted (w->start, make_number (0), w->buffer);
3482 set_marker_restricted (w->pointm, make_number (0),w->buffer);
3483 w->start_at_line_beg = Qt;
3484 }
3485 else
3486 /* Keeping window's old buffer; make sure the markers
3487 are real. */
3488 {
3489 /* Set window markers at start of visible range. */
3490 if (XMARKER (w->start)->buffer == 0)
3491 set_marker_restricted (w->start, make_number (0),
3492 w->buffer);
3493 if (XMARKER (w->pointm)->buffer == 0)
3494 set_marker_restricted_both (w->pointm, w->buffer,
3495 BUF_PT (XBUFFER (w->buffer)),
3496 BUF_PT_BYTE (XBUFFER (w->buffer)));
3497 w->start_at_line_beg = Qt;
3498 }
3499 }
3500 }
3501
3502 FRAME_ROOT_WINDOW (f) = data->root_window;
3503 Fselect_window (data->current_window);
3504 XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
3505 = selected_window;
3506
3507 if (NILP (data->focus_frame)
3508 || (FRAMEP (data->focus_frame)
3509 && FRAME_LIVE_P (XFRAME (data->focus_frame))))
3510 Fredirect_frame_focus (frame, data->focus_frame);
3511
3512 #if 0 /* I don't understand why this is needed, and it causes problems
3513 when the frame's old selected window has been deleted. */
3514 if (f != selected_frame && FRAME_WINDOW_P (f))
3515 do_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)),
3516 Qnil, 0);
3517 #endif
3518
3519 /* Set the screen height to the value it had before this function. */
3520 if (previous_frame_height != FRAME_HEIGHT (f)
3521 || previous_frame_width != FRAME_WIDTH (f))
3522 change_frame_size (f, previous_frame_height, previous_frame_width,
3523 0, 0);
3524 #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
3525 if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
3526 x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
3527 make_number (0));
3528 #endif
3529
3530 UNBLOCK_INPUT;
3531
3532 /* Fselect_window will have made f the selected frame, so we
3533 reselect the proper frame here. Fhandle_switch_frame will change the
3534 selected window too, but that doesn't make the call to
3535 Fselect_window above totally superfluous; it still sets f's
3536 selected window. */
3537 if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
3538 do_switch_frame (data->selected_frame, Qnil, 0);
3539
3540 if (! NILP (Vwindow_configuration_change_hook)
3541 && ! NILP (Vrun_hooks))
3542 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
3543 }
3544
3545 if (!NILP (new_current_buffer))
3546 {
3547 Fset_buffer (new_current_buffer);
3548
3549 /* If the buffer that is current now is the same
3550 that was current before setting the window configuration,
3551 don't alter its PT. */
3552 if (old_point >= 0)
3553 SET_PT (old_point);
3554 }
3555
3556 /* Restore the minimum heights recorded in the configuration. */
3557 window_min_height = XINT (data->min_height);
3558 window_min_width = XINT (data->min_width);
3559
3560 Vminibuf_scroll_window = data->minibuf_scroll_window;
3561
3562 return (FRAME_LIVE_P (f) ? Qt : Qnil);
3563 }
3564
3565 /* Mark all windows now on frame as deleted
3566 by setting their buffers to nil. */
3567
3568 void
3569 delete_all_subwindows (w)
3570 register struct window *w;
3571 {
3572 if (!NILP (w->next))
3573 delete_all_subwindows (XWINDOW (w->next));
3574 if (!NILP (w->vchild))
3575 delete_all_subwindows (XWINDOW (w->vchild));
3576 if (!NILP (w->hchild))
3577 delete_all_subwindows (XWINDOW (w->hchild));
3578
3579 w->height = w->buffer; /* See Fset_window_configuration for excuse. */
3580
3581 if (!NILP (w->buffer))
3582 unshow_buffer (w);
3583
3584 /* We set all three of these fields to nil, to make sure that we can
3585 distinguish this dead window from any live window. Live leaf
3586 windows will have buffer set, and combination windows will have
3587 vchild or hchild set. */
3588 w->buffer = Qnil;
3589 w->vchild = Qnil;
3590 w->hchild = Qnil;
3591 }
3592 \f
3593 static int
3594 count_windows (window)
3595 register struct window *window;
3596 {
3597 register int count = 1;
3598 if (!NILP (window->next))
3599 count += count_windows (XWINDOW (window->next));
3600 if (!NILP (window->vchild))
3601 count += count_windows (XWINDOW (window->vchild));
3602 if (!NILP (window->hchild))
3603 count += count_windows (XWINDOW (window->hchild));
3604 return count;
3605 }
3606
3607 static int
3608 save_window_save (window, vector, i)
3609 Lisp_Object window;
3610 struct Lisp_Vector *vector;
3611 int i;
3612 {
3613 register struct saved_window *p;
3614 register struct window *w;
3615 register Lisp_Object tem;
3616
3617 for (;!NILP (window); window = w->next)
3618 {
3619 p = SAVED_WINDOW_N (vector, i);
3620 w = XWINDOW (window);
3621
3622 XSETFASTINT (w->temslot, i++);
3623 p->window = window;
3624 p->buffer = w->buffer;
3625 p->left = w->left;
3626 p->top = w->top;
3627 p->width = w->width;
3628 p->height = w->height;
3629 p->hscroll = w->hscroll;
3630 p->display_table = w->display_table;
3631 if (!NILP (w->buffer))
3632 {
3633 /* Save w's value of point in the window configuration.
3634 If w is the selected window, then get the value of point
3635 from the buffer; pointm is garbage in the selected window. */
3636 if (EQ (window, selected_window))
3637 {
3638 p->pointm = Fmake_marker ();
3639 set_marker_both (p->pointm, w->buffer,
3640 BUF_PT (XBUFFER (w->buffer)),
3641 BUF_PT_BYTE (XBUFFER (w->buffer)));
3642 }
3643 else
3644 p->pointm = Fcopy_marker (w->pointm, Qnil);
3645
3646 p->start = Fcopy_marker (w->start, Qnil);
3647 p->start_at_line_beg = w->start_at_line_beg;
3648
3649 tem = XBUFFER (w->buffer)->mark;
3650 p->mark = Fcopy_marker (tem, Qnil);
3651 }
3652 else
3653 {
3654 p->pointm = Qnil;
3655 p->start = Qnil;
3656 p->mark = Qnil;
3657 p->start_at_line_beg = Qnil;
3658 }
3659
3660 if (NILP (w->parent))
3661 p->parent = Qnil;
3662 else
3663 p->parent = XWINDOW (w->parent)->temslot;
3664
3665 if (NILP (w->prev))
3666 p->prev = Qnil;
3667 else
3668 p->prev = XWINDOW (w->prev)->temslot;
3669
3670 if (!NILP (w->vchild))
3671 i = save_window_save (w->vchild, vector, i);
3672 if (!NILP (w->hchild))
3673 i = save_window_save (w->hchild, vector, i);
3674 }
3675
3676 return i;
3677 }
3678
3679 DEFUN ("current-window-configuration", Fcurrent_window_configuration,
3680 Scurrent_window_configuration, 0, 1, 0,
3681 "Return an object representing the current window configuration of FRAME.\n\
3682 If FRAME is nil or omitted, use the selected frame.\n\
3683 This describes the number of windows, their sizes and current buffers,\n\
3684 and for each displayed buffer, where display starts, and the positions of\n\
3685 point and mark. An exception is made for point in the current buffer:\n\
3686 its value is -not- saved.\n\
3687 This also records the currently selected frame, and FRAME's focus\n\
3688 redirection (see `redirect-frame-focus').")
3689 (frame)
3690 Lisp_Object frame;
3691 {
3692 register Lisp_Object tem;
3693 register int n_windows;
3694 register struct save_window_data *data;
3695 register struct Lisp_Vector *vec;
3696 register int i;
3697 FRAME_PTR f;
3698
3699 if (NILP (frame))
3700 f = selected_frame;
3701 else
3702 {
3703 CHECK_LIVE_FRAME (frame, 0);
3704 f = XFRAME (frame);
3705 }
3706
3707 n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
3708 vec = allocate_vectorlike (VECSIZE (struct save_window_data));
3709 for (i = 0; i < VECSIZE (struct save_window_data); i++)
3710 vec->contents[i] = Qnil;
3711 vec->size = VECSIZE (struct save_window_data);
3712 data = (struct save_window_data *)vec;
3713
3714 XSETFASTINT (data->frame_width, FRAME_WIDTH (f));
3715 XSETFASTINT (data->frame_height, FRAME_HEIGHT (f));
3716 XSETFASTINT (data->frame_menu_bar_lines, FRAME_MENU_BAR_LINES (f));
3717 XSETFRAME (data->selected_frame, selected_frame);
3718 data->current_window = FRAME_SELECTED_WINDOW (f);
3719 XSETBUFFER (data->current_buffer, current_buffer);
3720 data->minibuf_scroll_window = Vminibuf_scroll_window;
3721 data->root_window = FRAME_ROOT_WINDOW (f);
3722 data->focus_frame = FRAME_FOCUS_FRAME (f);
3723 XSETINT (data->min_height, window_min_height);
3724 XSETINT (data->min_width, window_min_width);
3725 tem = Fmake_vector (make_number (n_windows), Qnil);
3726 data->saved_windows = tem;
3727 for (i = 0; i < n_windows; i++)
3728 XVECTOR (tem)->contents[i]
3729 = Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil);
3730 save_window_save (FRAME_ROOT_WINDOW (f),
3731 XVECTOR (tem), 0);
3732 XSETWINDOW_CONFIGURATION (tem, data);
3733 return (tem);
3734 }
3735
3736 DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
3737 0, UNEVALLED, 0,
3738 "Execute body, preserving window sizes and contents.\n\
3739 Restore which buffer appears in which window, where display starts,\n\
3740 and the value of point and mark for each window.\n\
3741 Also restore which buffer is current.\n\
3742 But do not preserve point in the current buffer.\n\
3743 Does not restore the value of point in current buffer.")
3744 (args)
3745 Lisp_Object args;
3746 {
3747 register Lisp_Object val;
3748 register int count = specpdl_ptr - specpdl;
3749
3750 record_unwind_protect (Fset_window_configuration,
3751 Fcurrent_window_configuration (Qnil));
3752 val = Fprogn (args);
3753 return unbind_to (count, val);
3754 }
3755 \f
3756 /* Return 1 if window configurations C1 and C2
3757 describe the same state of affairs. This is used by Fequal. */
3758
3759 int
3760 compare_window_configurations (c1, c2, ignore_positions)
3761 Lisp_Object c1, c2;
3762 int ignore_positions;
3763 {
3764 register struct save_window_data *d1, *d2;
3765 struct Lisp_Vector *sw1, *sw2;
3766 int i;
3767
3768 d1 = (struct save_window_data *) XVECTOR (c1);
3769 d2 = (struct save_window_data *) XVECTOR (c2);
3770 sw1 = XVECTOR (d1->saved_windows);
3771 sw2 = XVECTOR (d2->saved_windows);
3772
3773 if (! EQ (d1->frame_width, d2->frame_width))
3774 return 0;
3775 if (! EQ (d1->frame_height, d2->frame_height))
3776 return 0;
3777 if (! EQ (d1->frame_menu_bar_lines, d2->frame_menu_bar_lines))
3778 return 0;
3779 if (! EQ (d1->selected_frame, d2->selected_frame))
3780 return 0;
3781 /* Don't compare the current_window field directly.
3782 Instead see w1_is_current and w2_is_current, below. */
3783 if (! EQ (d1->current_buffer, d2->current_buffer))
3784 return 0;
3785 if (! ignore_positions)
3786 if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
3787 return 0;
3788 /* Don't compare the root_window field.
3789 We don't require the two configurations
3790 to use the same window object,
3791 and the two root windows must be equivalent
3792 if everything else compares equal. */
3793 if (! EQ (d1->focus_frame, d2->focus_frame))
3794 return 0;
3795 if (! EQ (d1->min_width, d2->min_width))
3796 return 0;
3797 if (! EQ (d1->min_height, d2->min_height))
3798 return 0;
3799
3800 /* Verify that the two confis have the same number of windows. */
3801 if (sw1->size != sw2->size)
3802 return 0;
3803
3804 for (i = 0; i < sw1->size; i++)
3805 {
3806 struct saved_window *p1, *p2;
3807 int w1_is_current, w2_is_current;
3808
3809 p1 = SAVED_WINDOW_N (sw1, i);
3810 p2 = SAVED_WINDOW_N (sw2, i);
3811
3812 /* Verify that the current windows in the two
3813 configurations correspond to each other. */
3814 w1_is_current = EQ (d1->current_window, p1->window);
3815 w2_is_current = EQ (d2->current_window, p2->window);
3816
3817 if (w1_is_current != w2_is_current)
3818 return 0;
3819
3820 /* Verify that the corresponding windows do match. */
3821 if (! EQ (p1->buffer, p2->buffer))
3822 return 0;
3823 if (! EQ (p1->left, p2->left))
3824 return 0;
3825 if (! EQ (p1->top, p2->top))
3826 return 0;
3827 if (! EQ (p1->width, p2->width))
3828 return 0;
3829 if (! EQ (p1->height, p2->height))
3830 return 0;
3831 if (! EQ (p1->display_table, p2->display_table))
3832 return 0;
3833 if (! EQ (p1->parent, p2->parent))
3834 return 0;
3835 if (! EQ (p1->prev, p2->prev))
3836 return 0;
3837 if (! ignore_positions)
3838 {
3839 if (! EQ (p1->hscroll, p2->hscroll))
3840 return 0;
3841 if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
3842 return 0;
3843 if (NILP (Fequal (p1->start, p2->start)))
3844 return 0;
3845 if (NILP (Fequal (p1->pointm, p2->pointm)))
3846 return 0;
3847 if (NILP (Fequal (p1->mark, p2->mark)))
3848 return 0;
3849 }
3850 }
3851
3852 return 1;
3853 }
3854
3855 DEFUN ("compare-window-configurations", Fcompare_window_configurations,
3856 Scompare_window_configurations, 2, 2, 0,
3857 "Compare two window configurations as regards the structure of windows.\n\
3858 This function ignores details such as the values of point and mark\n\
3859 and scrolling positions.")
3860 (x, y)
3861 Lisp_Object x, y;
3862 {
3863 if (compare_window_configurations (x, y, 1))
3864 return Qt;
3865 return Qnil;
3866 }
3867 \f
3868 void
3869 init_window_once ()
3870 {
3871 selected_frame = make_terminal_frame ();
3872 XSETFRAME (Vterminal_frame, selected_frame);
3873 minibuf_window = selected_frame->minibuffer_window;
3874 selected_window = selected_frame->selected_window;
3875 last_nonminibuf_frame = selected_frame;
3876
3877 window_initialized = 1;
3878 }
3879
3880 void
3881 syms_of_window ()
3882 {
3883 staticpro (&Qwindow_configuration_change_hook);
3884 Qwindow_configuration_change_hook
3885 = intern ("window-configuration-change-hook");
3886
3887 Qwindowp = intern ("windowp");
3888 staticpro (&Qwindowp);
3889
3890 Qwindow_configuration_p = intern ("window-configuration-p");
3891 staticpro (&Qwindow_configuration_p);
3892
3893 Qwindow_live_p = intern ("window-live-p");
3894 staticpro (&Qwindow_live_p);
3895
3896 Qtemp_buffer_show_hook = intern ("temp-buffer-show-hook");
3897 staticpro (&Qtemp_buffer_show_hook);
3898
3899 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
3900 "Non-nil means call as function to display a help buffer.\n\
3901 The function is called with one argument, the buffer to be displayed.\n\
3902 Used by `with-output-to-temp-buffer'.\n\
3903 If this function is used, then it must do the entire job of showing\n\
3904 the buffer; `temp-buffer-show-hook' is not run unless this function runs it.");
3905 Vtemp_buffer_show_function = Qnil;
3906
3907 DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
3908 "If non-nil, function to call to handle `display-buffer'.\n\
3909 It will receive two args, the buffer and a flag which if non-nil means\n\
3910 that the currently selected window is not acceptable.\n\
3911 Commands such as `switch-to-buffer-other-window' and `find-file-other-window'\n\
3912 work using this function.");
3913 Vdisplay_buffer_function = Qnil;
3914
3915 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
3916 "Non-nil means it is the window that C-M-v in minibuffer should scroll.");
3917 Vminibuf_scroll_window = Qnil;
3918
3919 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
3920 "If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.");
3921 Vother_window_scroll_buffer = Qnil;
3922
3923 DEFVAR_BOOL ("pop-up-frames", &pop_up_frames,
3924 "*Non-nil means `display-buffer' should make a separate frame.");
3925 pop_up_frames = 0;
3926
3927 DEFVAR_LISP ("pop-up-frame-function", &Vpop_up_frame_function,
3928 "Function to call to handle automatic new frame creation.\n\
3929 It is called with no arguments and should return a newly created frame.\n\
3930 \n\
3931 A typical value might be `(lambda () (new-frame pop-up-frame-alist))'\n\
3932 where `pop-up-frame-alist' would hold the default frame parameters.");
3933 Vpop_up_frame_function = Qnil;
3934
3935 DEFVAR_LISP ("special-display-buffer-names", &Vspecial_display_buffer_names,
3936 "*List of buffer names that should have their own special frames.\n\
3937 Displaying a buffer whose name is in this list makes a special frame for it\n\
3938 using `special-display-function'. See also `special-display-regexps'.\n\
3939 \n\
3940 An element of the list can be a list instead of just a string.\n\
3941 There are two ways to use a list as an element:\n\
3942 (BUFFER FRAME-PARAMETERS...) (BUFFER FUNCTION OTHER-ARGS...)\n\
3943 In the first case, FRAME-PARAMETERS are used to create the frame.\n\
3944 In the latter case, FUNCTION is called with BUFFER as the first argument,\n\
3945 followed by OTHER-ARGS--it can display BUFFER in any way it likes.\n\
3946 All this is done by the function found in `special-display-function'.\n\
3947 \n\
3948 If this variable appears \"not to work\", because you add a name to it\n\
3949 but that buffer still appears in the selected window, look at the\n\
3950 values of `same-window-buffer-names' and `same-window-regexps'.\n\
3951 Those variables take precedence over this one.");
3952 Vspecial_display_buffer_names = Qnil;
3953
3954 DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
3955 "*List of regexps saying which buffers should have their own special frames.\n\
3956 If a buffer name matches one of these regexps, it gets its own frame.\n\
3957 Displaying a buffer whose name is in this list makes a special frame for it\n\
3958 using `special-display-function'.\n\
3959 \n\
3960 An element of the list can be a list instead of just a string.\n\
3961 There are two ways to use a list as an element:\n\
3962 (REGEXP FRAME-PARAMETERS...) (REGEXP FUNCTION OTHER-ARGS...)\n\
3963 In the first case, FRAME-PARAMETERS are used to create the frame.\n\
3964 In the latter case, FUNCTION is called with the buffer as first argument,\n\
3965 followed by OTHER-ARGS--it can display the buffer in any way it likes.\n\
3966 All this is done by the function found in `special-display-function'.\n\
3967 \n\
3968 If this variable appears \"not to work\", because you add a regexp to it\n\
3969 but the matching buffers still appear in the selected window, look at the\n\
3970 values of `same-window-buffer-names' and `same-window-regexps'.\n\
3971 Those variables take precedence over this one.");
3972 Vspecial_display_regexps = Qnil;
3973
3974 DEFVAR_LISP ("special-display-function", &Vspecial_display_function,
3975 "Function to call to make a new frame for a special buffer.\n\
3976 It is called with two arguments, the buffer and optional buffer specific\n\
3977 data, and should return a window displaying that buffer.\n\
3978 The default value makes a separate frame for the buffer,\n\
3979 using `special-display-frame-alist' to specify the frame parameters.\n\
3980 \n\
3981 A buffer is special if its is listed in `special-display-buffer-names'\n\
3982 or matches a regexp in `special-display-regexps'.");
3983 Vspecial_display_function = Qnil;
3984
3985 DEFVAR_LISP ("same-window-buffer-names", &Vsame_window_buffer_names,
3986 "*List of buffer names that should appear in the selected window.\n\
3987 Displaying one of these buffers using `display-buffer' or `pop-to-buffer'\n\
3988 switches to it in the selected window, rather than making it appear\n\
3989 in some other window.\n\
3990 \n\
3991 An element of the list can be a cons cell instead of just a string.\n\
3992 Then the car must be a string, which specifies the buffer name.\n\
3993 This is for compatibility with `special-display-buffer-names';\n\
3994 the cdr of the cons cell is ignored.\n\
3995 \n\
3996 See also `same-window-regexps'.");
3997 Vsame_window_buffer_names = Qnil;
3998
3999 DEFVAR_LISP ("same-window-regexps", &Vsame_window_regexps,
4000 "*List of regexps saying which buffers should appear in the selected window.\n\
4001 If a buffer name matches one of these regexps, then displaying it\n\
4002 using `display-buffer' or `pop-to-buffer' switches to it\n\
4003 in the selected window, rather than making it appear in some other window.\n\
4004 \n\
4005 An element of the list can be a cons cell instead of just a string.\n\
4006 Then the car must be a string, which specifies the buffer name.\n\
4007 This is for compatibility with `special-display-buffer-names';\n\
4008 the cdr of the cons cell is ignored.\n\
4009 \n\
4010 See also `same-window-buffer-names'.");
4011 Vsame_window_regexps = Qnil;
4012
4013 DEFVAR_BOOL ("pop-up-windows", &pop_up_windows,
4014 "*Non-nil means display-buffer should make new windows.");
4015 pop_up_windows = 1;
4016
4017 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
4018 "*Number of lines of continuity when scrolling by screenfuls.");
4019 next_screen_context_lines = 2;
4020
4021 DEFVAR_INT ("split-height-threshold", &split_height_threshold,
4022 "*display-buffer would prefer to split the largest window if this large.\n\
4023 If there is only one window, it is split regardless of this value.");
4024 split_height_threshold = 500;
4025
4026 DEFVAR_INT ("window-min-height", &window_min_height,
4027 "*Delete any window less than this tall (including its mode line).");
4028 window_min_height = 4;
4029
4030 DEFVAR_INT ("window-min-width", &window_min_width,
4031 "*Delete any window less than this wide.");
4032 window_min_width = 10;
4033
4034 DEFVAR_BOOL ("scroll-preserve-screen-position",
4035 &scroll_preserve_screen_position,
4036 "*Nonzero means scroll commands move point to keep its screen line unchanged.");
4037 scroll_preserve_screen_position = 0;
4038
4039 DEFVAR_LISP ("window-configuration-change-hook",
4040 &Vwindow_configuration_change_hook,
4041 "Functions to call when window configuration changes.\n\
4042 The selected frame is the one whose configuration has changed.");
4043 Vwindow_configuration_change_hook = Qnil;
4044
4045 defsubr (&Sselected_window);
4046 defsubr (&Sminibuffer_window);
4047 defsubr (&Swindow_minibuffer_p);
4048 defsubr (&Swindowp);
4049 defsubr (&Swindow_live_p);
4050 defsubr (&Spos_visible_in_window_p);
4051 defsubr (&Swindow_buffer);
4052 defsubr (&Swindow_height);
4053 defsubr (&Swindow_width);
4054 defsubr (&Swindow_hscroll);
4055 defsubr (&Sset_window_hscroll);
4056 defsubr (&Swindow_redisplay_end_trigger);
4057 defsubr (&Sset_window_redisplay_end_trigger);
4058 defsubr (&Swindow_edges);
4059 defsubr (&Scoordinates_in_window_p);
4060 defsubr (&Swindow_at);
4061 defsubr (&Swindow_point);
4062 defsubr (&Swindow_start);
4063 defsubr (&Swindow_end);
4064 defsubr (&Sset_window_point);
4065 defsubr (&Sset_window_start);
4066 defsubr (&Swindow_dedicated_p);
4067 defsubr (&Sset_window_dedicated_p);
4068 defsubr (&Swindow_display_table);
4069 defsubr (&Sset_window_display_table);
4070 defsubr (&Snext_window);
4071 defsubr (&Sprevious_window);
4072 defsubr (&Sother_window);
4073 defsubr (&Sget_lru_window);
4074 defsubr (&Sget_largest_window);
4075 defsubr (&Sget_buffer_window);
4076 defsubr (&Sdelete_other_windows);
4077 defsubr (&Sdelete_windows_on);
4078 defsubr (&Sreplace_buffer_in_windows);
4079 defsubr (&Sdelete_window);
4080 defsubr (&Sset_window_buffer);
4081 defsubr (&Sselect_window);
4082 defsubr (&Sspecial_display_p);
4083 defsubr (&Ssame_window_p);
4084 defsubr (&Sdisplay_buffer);
4085 defsubr (&Ssplit_window);
4086 defsubr (&Senlarge_window);
4087 defsubr (&Sshrink_window);
4088 defsubr (&Sscroll_up);
4089 defsubr (&Sscroll_down);
4090 defsubr (&Sscroll_left);
4091 defsubr (&Sscroll_right);
4092 defsubr (&Sother_window_for_scrolling);
4093 defsubr (&Sscroll_other_window);
4094 defsubr (&Srecenter);
4095 defsubr (&Smove_to_window_line);
4096 defsubr (&Swindow_configuration_p);
4097 defsubr (&Swindow_configuration_frame);
4098 defsubr (&Sset_window_configuration);
4099 defsubr (&Scurrent_window_configuration);
4100 defsubr (&Ssave_window_excursion);
4101 defsubr (&Scompare_window_configurations);
4102 }
4103
4104 void
4105 keys_of_window ()
4106 {
4107 initial_define_key (control_x_map, '1', "delete-other-windows");
4108 initial_define_key (control_x_map, '2', "split-window");
4109 initial_define_key (control_x_map, '0', "delete-window");
4110 initial_define_key (control_x_map, 'o', "other-window");
4111 initial_define_key (control_x_map, '^', "enlarge-window");
4112 initial_define_key (control_x_map, '<', "scroll-left");
4113 initial_define_key (control_x_map, '>', "scroll-right");
4114
4115 initial_define_key (global_map, Ctl ('V'), "scroll-up");
4116 initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
4117 initial_define_key (meta_map, 'v', "scroll-down");
4118
4119 initial_define_key (global_map, Ctl('L'), "recenter");
4120 initial_define_key (meta_map, 'r', "move-to-window-line");
4121 }