(Fwindow_end): Don't call temp_set_pt_both with
[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 "dispextern.h"
33 #include "blockinput.h"
34 #include "intervals.h"
35
36 #ifdef HAVE_X_WINDOWS
37 #include "xterm.h"
38 #endif /* HAVE_X_WINDOWS */
39
40 #ifndef max
41 #define max(a, b) ((a) < (b) ? (b) : (a))
42 #endif
43
44
45 Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
46 Lisp_Object Qwindow_size_fixed, Qleft_bitmap_area, Qright_bitmap_area;
47 extern Lisp_Object Qheight, Qwidth;
48
49 static struct window *decode_window P_ ((Lisp_Object));
50 static Lisp_Object select_window_1 P_ ((Lisp_Object, int));
51 static int count_windows P_ ((struct window *));
52 static int get_leaf_windows P_ ((struct window *, struct window **, int));
53 static void window_scroll P_ ((Lisp_Object, int, int, int));
54 static void window_scroll_pixel_based P_ ((Lisp_Object, int, int, int));
55 static void window_scroll_line_based P_ ((Lisp_Object, int, int, int));
56 static int window_min_size_1 P_ ((struct window *, int));
57 static int window_min_size P_ ((struct window *, int, int, int *));
58 static void size_window P_ ((Lisp_Object, int, int, int));
59 static void foreach_window_1 P_ ((struct window *, void (*fn) (), int, int,
60 int, int));
61 static void freeze_window_start P_ ((struct window *, int));
62 static int window_fixed_size_p P_ ((struct window *, int, int));
63 static void enlarge_window P_ ((Lisp_Object, int, int));
64
65
66 /* This is the window in which the terminal's cursor should
67 be left when nothing is being done with it. This must
68 always be a leaf window, and its buffer is selected by
69 the top level editing loop at the end of each command.
70
71 This value is always the same as
72 FRAME_SELECTED_WINDOW (selected_frame). */
73
74 Lisp_Object selected_window;
75
76 /* The mini-buffer window of the selected frame.
77 Note that you cannot test for mini-bufferness of an arbitrary window
78 by comparing against this; but you can test for mini-bufferness of
79 the selected window. */
80
81 Lisp_Object minibuf_window;
82
83 /* Non-nil means it is the window for C-M-v to scroll
84 when the mini-buffer is selected. */
85
86 Lisp_Object Vminibuf_scroll_window;
87
88 /* Non-nil means this is the buffer whose window C-M-v should scroll. */
89
90 Lisp_Object Vother_window_scroll_buffer;
91
92 /* Non-nil means it's function to call to display temp buffers. */
93
94 Lisp_Object Vtemp_buffer_show_function;
95
96 /* If a window gets smaller than either of these, it is removed. */
97
98 int window_min_height;
99 int window_min_width;
100
101 /* Nonzero implies Fdisplay_buffer should create windows. */
102
103 int pop_up_windows;
104
105 /* Nonzero implies make new frames for Fdisplay_buffer. */
106
107 int pop_up_frames;
108
109 /* Non-nil means use this function instead of default */
110
111 Lisp_Object Vpop_up_frame_function;
112
113 /* Function to call to handle Fdisplay_buffer. */
114
115 Lisp_Object Vdisplay_buffer_function;
116
117 /* List of buffer *names* for buffers that should have their own frames. */
118
119 Lisp_Object Vspecial_display_buffer_names;
120
121 /* List of regexps for buffer names that should have their own frames. */
122
123 Lisp_Object Vspecial_display_regexps;
124
125 /* Function to pop up a special frame. */
126
127 Lisp_Object Vspecial_display_function;
128
129 /* List of buffer *names* for buffers to appear in selected window. */
130
131 Lisp_Object Vsame_window_buffer_names;
132
133 /* List of regexps for buffer names to appear in selected window. */
134
135 Lisp_Object Vsame_window_regexps;
136
137 /* Hook run at end of temp_output_buffer_show. */
138
139 Lisp_Object Qtemp_buffer_show_hook;
140
141 /* Fdisplay_buffer always splits the largest window
142 if that window is more than this high. */
143
144 int split_height_threshold;
145
146 /* Number of lines of continuity in scrolling by screenfuls. */
147
148 int next_screen_context_lines;
149
150 /* Incremented for each window created. */
151
152 static int sequence_number;
153
154 /* Nonzero after init_window_once has finished. */
155
156 static int window_initialized;
157
158 /* Hook to run when window config changes. */
159
160 Lisp_Object Qwindow_configuration_change_hook;
161 Lisp_Object Vwindow_configuration_change_hook;
162
163 /* Nonzero means scroll commands try to put point
164 at the same screen height as previously. */
165
166 Lisp_Object Vscroll_preserve_screen_position;
167
168 #if 0 /* This isn't used anywhere. */
169 /* Nonzero means we can split a frame even if it is "unsplittable". */
170 static int inhibit_frame_unsplittable;
171 #endif /* 0 */
172
173 #define min(a, b) ((a) < (b) ? (a) : (b))
174
175 extern int scroll_margin;
176
177 extern Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
178 \f
179 DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
180 "Returns t if OBJECT is a window.")
181 (object)
182 Lisp_Object object;
183 {
184 return WINDOWP (object) ? Qt : Qnil;
185 }
186
187 DEFUN ("window-live-p", Fwindow_live_p, Swindow_live_p, 1, 1, 0,
188 "Returns t if OBJECT is a window which is currently visible.")
189 (object)
190 Lisp_Object object;
191 {
192 return (WINDOWP (object) && ! NILP (XWINDOW (object)->buffer) ? Qt : Qnil);
193 }
194
195 Lisp_Object
196 make_window ()
197 {
198 Lisp_Object val;
199 register struct window *p;
200 register struct Lisp_Vector *vec;
201 int i;
202
203 vec = allocate_vectorlike ((EMACS_INT) VECSIZE (struct window));
204 for (i = 0; i < VECSIZE (struct window); i++)
205 vec->contents[i] = Qnil;
206 vec->size = VECSIZE (struct window);
207 p = (struct window *) vec;
208 XSETFASTINT (p->sequence_number, ++sequence_number);
209 XSETFASTINT (p->left, 0);
210 XSETFASTINT (p->top, 0);
211 XSETFASTINT (p->height, 0);
212 XSETFASTINT (p->width, 0);
213 XSETFASTINT (p->hscroll, 0);
214 p->orig_top = p->orig_height = Qnil;
215 p->start = Fmake_marker ();
216 p->pointm = Fmake_marker ();
217 XSETFASTINT (p->use_time, 0);
218 p->frame = Qnil;
219 p->display_table = Qnil;
220 p->dedicated = Qnil;
221 p->pseudo_window_p = 0;
222 bzero (&p->cursor, sizeof (p->cursor));
223 bzero (&p->last_cursor, sizeof (p->last_cursor));
224 bzero (&p->phys_cursor, sizeof (p->phys_cursor));
225 p->desired_matrix = p->current_matrix = 0;
226 p->phys_cursor_type = -1;
227 p->must_be_updated_p = 0;
228 XSETFASTINT (p->window_end_vpos, 0);
229 XSETFASTINT (p->window_end_pos, 0);
230 p->window_end_valid = Qnil;
231 p->vscroll = 0;
232 XSETWINDOW (val, p);
233 XSETFASTINT (p->last_point, 0);
234 p->frozen_window_start_p = 0;
235 return val;
236 }
237
238 DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0,
239 "Return the window that the cursor now appears in and commands apply to.")
240 ()
241 {
242 return selected_window;
243 }
244
245 DEFUN ("minibuffer-window", Fminibuffer_window, Sminibuffer_window, 0, 1, 0,
246 "Return the window used now for minibuffers.\n\
247 If the optional argument FRAME is specified, return the minibuffer window\n\
248 used by that frame.")
249 (frame)
250 Lisp_Object frame;
251 {
252 if (NILP (frame))
253 frame = selected_frame;
254 CHECK_LIVE_FRAME (frame, 0);
255 return FRAME_MINIBUF_WINDOW (XFRAME (frame));
256 }
257
258 DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1, 0,
259 "Returns non-nil if WINDOW is a minibuffer window.")
260 (window)
261 Lisp_Object window;
262 {
263 struct window *w = decode_window (window);
264 return (MINI_WINDOW_P (w) ? Qt : Qnil);
265 }
266
267 DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
268 Spos_visible_in_window_p, 0, 2, 0,
269 "Return t if position POS is currently on the frame in WINDOW.\n\
270 Returns nil if that position is scrolled vertically out of view.\n\
271 POS defaults to point; WINDOW, to the selected window.")
272 (pos, window)
273 Lisp_Object pos, window;
274 {
275 register struct window *w;
276 register int posint;
277 register struct buffer *buf;
278 struct text_pos top;
279 Lisp_Object in_window;
280
281 if (NILP (pos))
282 posint = PT;
283 else
284 {
285 CHECK_NUMBER_COERCE_MARKER (pos, 0);
286 posint = XINT (pos);
287 }
288
289 w = decode_window (window);
290 buf = XBUFFER (w->buffer);
291 SET_TEXT_POS_FROM_MARKER (top, w->start);
292
293 /* If position above window, it's not visible. */
294 if (posint < CHARPOS (top))
295 in_window = Qnil;
296 else if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf)
297 && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (buf)
298 && posint < BUF_Z (buf) - XFASTINT (w->window_end_pos))
299 /* If frame is up to date, and POSINT is < window end pos, use
300 that info. This doesn't work for POSINT == end pos, because
301 the window end pos is actually the position _after_ the last
302 char in the window. */
303 in_window = Qt;
304 else if (posint > BUF_ZV (buf))
305 in_window = Qnil;
306 else if (CHARPOS (top) < BUF_BEGV (buf) || CHARPOS (top) > BUF_ZV (buf))
307 /* If window start is out of range, do something reasonable. */
308 in_window = Qnil;
309 else
310 {
311 struct it it;
312 start_display (&it, w, top);
313 move_it_to (&it, posint, 0, it.last_visible_y, -1,
314 MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
315 in_window = IT_CHARPOS (it) == posint ? Qt : Qnil;
316 }
317
318 return in_window;
319 }
320 \f
321 static struct window *
322 decode_window (window)
323 register Lisp_Object window;
324 {
325 if (NILP (window))
326 return XWINDOW (selected_window);
327
328 CHECK_LIVE_WINDOW (window, 0);
329 return XWINDOW (window);
330 }
331
332 DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
333 "Return the buffer that WINDOW is displaying.")
334 (window)
335 Lisp_Object window;
336 {
337 return decode_window (window)->buffer;
338 }
339
340 DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0,
341 "Return the number of lines in WINDOW (including its mode line).")
342 (window)
343 Lisp_Object window;
344 {
345 return decode_window (window)->height;
346 }
347
348 DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
349 "Return the number of display columns in WINDOW.\n\
350 This is the width that is usable columns available for text in WINDOW.\n\
351 If you want to find out how many columns WINDOW takes up,\n\
352 use (let ((edges (window-edges))) (- (nth 2 edges) (nth 0 edges))).")
353 (window)
354 Lisp_Object window;
355 {
356 return make_number (window_internal_width (decode_window (window)));
357 }
358
359 DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
360 "Return the number of columns by which WINDOW is scrolled from left margin.")
361 (window)
362 Lisp_Object window;
363 {
364 return decode_window (window)->hscroll;
365 }
366
367 DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
368 "Set number of columns WINDOW is scrolled from left margin to NCOL.\n\
369 NCOL should be zero or positive.")
370 (window, ncol)
371 register Lisp_Object window, ncol;
372 {
373 register struct window *w;
374
375 CHECK_NUMBER (ncol, 1);
376 if (XINT (ncol) < 0) XSETFASTINT (ncol, 0);
377 w = decode_window (window);
378 if (XINT (w->hscroll) != XINT (ncol))
379 /* Prevent redisplay shortcuts */
380 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
381 w->hscroll = ncol;
382 return ncol;
383 }
384
385 DEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger,
386 Swindow_redisplay_end_trigger, 0, 1, 0,
387 "Return WINDOW's redisplay end trigger value.\n\
388 See `set-window-redisplay-end-trigger' for more information.")
389 (window)
390 Lisp_Object window;
391 {
392 return decode_window (window)->redisplay_end_trigger;
393 }
394
395 DEFUN ("set-window-redisplay-end-trigger", Fset_window_redisplay_end_trigger,
396 Sset_window_redisplay_end_trigger, 2, 2, 0,
397 "Set WINDOW's redisplay end trigger value to VALUE.\n\
398 VALUE should be a buffer position (typically a marker) or nil.\n\
399 If it is a buffer position, then if redisplay in WINDOW reaches a position\n\
400 beyond VALUE, the functions in `redisplay-end-trigger-functions' are called\n\
401 with two arguments: WINDOW, and the end trigger value.\n\
402 Afterwards the end-trigger value is reset to nil.")
403 (window, value)
404 register Lisp_Object window, value;
405 {
406 register struct window *w;
407
408 w = decode_window (window);
409 w->redisplay_end_trigger = value;
410 return value;
411 }
412
413 DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0,
414 "Return a list of the edge coordinates of WINDOW.\n\
415 \(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.\n\
416 RIGHT is one more than the rightmost column used by WINDOW,\n\
417 and BOTTOM is one more than the bottommost row used by WINDOW\n\
418 and its mode-line.")
419 (window)
420 Lisp_Object window;
421 {
422 register struct window *w = decode_window (window);
423
424 return Fcons (w->left, Fcons (w->top,
425 Fcons (make_number (WINDOW_RIGHT_EDGE (w)),
426 Fcons (make_number (XFASTINT (w->top)
427 + XFASTINT (w->height)),
428 Qnil))));
429 }
430
431 /* Test if the character at column *X, row *Y is within window W.
432 If it is not, return 0;
433 if it is in the window's text area,
434 set *x and *y to its location relative to the upper left corner
435 of the window, and
436 return 1;
437 if it is on the window's modeline, return 2;
438 if it is on the border between the window and its right sibling,
439 return 3.
440 if it is on the window's top line, return 4;
441 if it is in the bitmap area to the left/right of the window,
442 return 5 or 6, and convert *X and *Y to window-relative corrdinates.
443
444 X and Y are frame relative pixel coordinates. */
445
446 static int
447 coordinates_in_window (w, x, y)
448 register struct window *w;
449 register int *x, *y;
450 {
451 struct frame *f = XFRAME (WINDOW_FRAME (w));
452 int left_x, right_x, top_y, bottom_y;
453 int flags_area_width = FRAME_LEFT_FLAGS_AREA_WIDTH (f);
454
455 if (w->pseudo_window_p)
456 {
457 left_x = 0;
458 right_x = XFASTINT (w->width) * CANON_Y_UNIT (f);
459 top_y = WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
460 bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
461 }
462 else
463 {
464 left_x = WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
465 right_x = WINDOW_DISPLAY_RIGHT_EDGE_PIXEL_X (w);
466 top_y = WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
467 bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
468 }
469
470 if (*y < top_y
471 || *y >= bottom_y
472 || *x < (left_x
473 - flags_area_width
474 - (FRAME_LEFT_SCROLL_BAR_WIDTH (f)
475 * CANON_X_UNIT (f)))
476 || *x > right_x + flags_area_width)
477 /* Completely outside anything interesting. */
478 return 0;
479 else if (WINDOW_WANTS_MODELINE_P (w)
480 && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
481 /* On the mode line. */
482 return 2;
483 else if (WINDOW_WANTS_HEADER_LINE_P (w)
484 && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
485 /* On the top line. */
486 return 4;
487 else if (*x < left_x || *x >= right_x)
488 {
489 /* Other lines than the mode line don't include flags areas and
490 scroll bars on the left. */
491
492 /* Convert X and Y to window-relative pixel coordinates. */
493 *x -= left_x;
494 *y -= top_y;
495 return *x < left_x ? 5 : 6;
496 }
497 else if (!w->pseudo_window_p
498 && !WINDOW_RIGHTMOST_P (w)
499 && *x >= right_x - CANON_X_UNIT (f))
500 /* On the border on the right side of the window? Assume that
501 this area begins at RIGHT_X minus a canonical char width. */
502 return 3;
503 else
504 {
505 /* Convert X and Y to window-relative pixel coordinates. */
506 *x -= left_x;
507 *y -= top_y;
508 return 1;
509 }
510 }
511
512 DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
513 Scoordinates_in_window_p, 2, 2, 0,
514 "Return non-nil if COORDINATES are in WINDOW.\n\
515 COORDINATES is a cons of the form (X . Y), X and Y being distances\n\
516 measured in characters from the upper-left corner of the frame.\n\
517 (0 . 0) denotes the character in the upper left corner of the\n\
518 frame.\n\
519 If COORDINATES are in the text portion of WINDOW,\n\
520 the coordinates relative to the window are returned.\n\
521 If they are in the mode line of WINDOW, `mode-line' is returned.\n\
522 If they are in the top mode line of WINDOW, `header-line' is returned.\n\
523 If they are in the bitmap-area to the left of the window,\n\
524 `left-bitmap-area' is returned, if they are in the area on the right of\n\
525 the window, `right-bitmap-area' is returned.\n\
526 If they are on the border between WINDOW and its right sibling,\n\
527 `vertical-line' is returned.")
528 (coordinates, window)
529 register Lisp_Object coordinates, window;
530 {
531 struct window *w;
532 struct frame *f;
533 int x, y;
534 Lisp_Object lx, ly;
535
536 CHECK_LIVE_WINDOW (window, 0);
537 w = XWINDOW (window);
538 f = XFRAME (w->frame);
539 CHECK_CONS (coordinates, 1);
540 lx = Fcar (coordinates);
541 ly = Fcdr (coordinates);
542 CHECK_NUMBER_OR_FLOAT (lx, 1);
543 CHECK_NUMBER_OR_FLOAT (ly, 1);
544 x = PIXEL_X_FROM_CANON_X (f, lx);
545 y = PIXEL_Y_FROM_CANON_Y (f, ly);
546
547 switch (coordinates_in_window (w, &x, &y))
548 {
549 case 0: /* NOT in window at all. */
550 return Qnil;
551
552 case 1: /* In text part of window. */
553 /* X and Y are now window relative pixel coordinates.
554 Convert them to canonical char units before returning
555 them. */
556 return Fcons (CANON_X_FROM_PIXEL_X (f, x),
557 CANON_Y_FROM_PIXEL_Y (f, y));
558
559 case 2: /* In mode line of window. */
560 return Qmode_line;
561
562 case 3: /* On right border of window. */
563 return Qvertical_line;
564
565 case 4:
566 return Qheader_line;
567
568 case 5:
569 return Qleft_bitmap_area;
570
571 case 6:
572 return Qright_bitmap_area;
573
574 default:
575 abort ();
576 }
577 }
578
579 /* Find the window containing frame-relative pixel position X/Y and
580 return it as a Lisp_Object. If X, Y is on the window's modeline,
581 set *PART to 1; if it is on the separating line between the window
582 and its right sibling, set it to 2; otherwise set it to 0. If
583 there is no window under X, Y return nil and leave *PART
584 unmodified. TOOL_BAR_P non-zero means detect tool-bar windows. */
585
586 Lisp_Object
587 window_from_coordinates (frame, x, y, part, tool_bar_p)
588 FRAME_PTR frame;
589 int x, y;
590 int *part;
591 int tool_bar_p;
592 {
593 register Lisp_Object tem, first;
594 int found;
595
596 tem = first = FRAME_SELECTED_WINDOW (frame);
597
598 do
599 {
600 found = coordinates_in_window (XWINDOW (tem), &x, &y);
601
602 if (found)
603 {
604 *part = found - 1;
605 return tem;
606 }
607
608 tem = Fnext_window (tem, Qt, Qlambda);
609 }
610 while (!EQ (tem, first));
611
612 /* See if it's in the tool bar window, if a tool bar exists. */
613 if (tool_bar_p
614 && WINDOWP (frame->tool_bar_window)
615 && XFASTINT (XWINDOW (frame->tool_bar_window)->height)
616 && coordinates_in_window (XWINDOW (frame->tool_bar_window), &x, &y))
617 {
618 *part = 0;
619 return frame->tool_bar_window;
620 }
621
622 return Qnil;
623 }
624
625 DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
626 "Return window containing coordinates X and Y on FRAME.\n\
627 If omitted, FRAME defaults to the currently selected frame.\n\
628 The top left corner of the frame is considered to be row 0,\n\
629 column 0.")
630 (x, y, frame)
631 Lisp_Object x, y, frame;
632 {
633 int part;
634 struct frame *f;
635
636 if (NILP (frame))
637 frame = selected_frame;
638 CHECK_LIVE_FRAME (frame, 2);
639 f = XFRAME (frame);
640
641 /* Check that arguments are integers or floats. */
642 CHECK_NUMBER_OR_FLOAT (x, 0);
643 CHECK_NUMBER_OR_FLOAT (y, 1);
644
645 return window_from_coordinates (f,
646 PIXEL_X_FROM_CANON_X (f, x),
647 PIXEL_Y_FROM_CANON_Y (f, y),
648 &part, 0);
649 }
650
651 DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
652 "Return current value of point in WINDOW.\n\
653 For a nonselected window, this is the value point would have\n\
654 if that window were selected.\n\
655 \n\
656 Note that, when WINDOW is the selected window and its buffer\n\
657 is also currently selected, the value returned is the same as (point).\n\
658 It would be more strictly correct to return the `top-level' value\n\
659 of point, outside of any save-excursion forms.\n\
660 But that is hard to define.")
661 (window)
662 Lisp_Object window;
663 {
664 register struct window *w = decode_window (window);
665
666 if (w == XWINDOW (selected_window)
667 && current_buffer == XBUFFER (w->buffer))
668 return Fpoint ();
669 return Fmarker_position (w->pointm);
670 }
671
672 DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
673 "Return position at which display currently starts in WINDOW.\n\
674 This is updated by redisplay or by calling `set-window-start'.")
675 (window)
676 Lisp_Object window;
677 {
678 return Fmarker_position (decode_window (window)->start);
679 }
680
681 /* This is text temporarily removed from the doc string below.
682
683 This function returns nil if the position is not currently known.\n\
684 That happens when redisplay is preempted and doesn't finish.\n\
685 If in that case you want to compute where the end of the window would\n\
686 have been if redisplay had finished, do this:\n\
687 (save-excursion\n\
688 (goto-char (window-start window))\n\
689 (vertical-motion (1- (window-height window)) window)\n\
690 (point))") */
691
692 DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
693 "Return position at which display currently ends in WINDOW.\n\
694 This is updated by redisplay, when it runs to completion.\n\
695 Simply changing the buffer text or setting `window-start'\n\
696 does not update this value.\n\
697 If UP-TO-DATE is non-nil, compute the up-to-date position\n\
698 if it isn't already recorded.")
699 (window, update)
700 Lisp_Object window, update;
701 {
702 Lisp_Object value;
703 struct window *w = decode_window (window);
704 Lisp_Object buf;
705
706 buf = w->buffer;
707 CHECK_BUFFER (buf, 0);
708
709 #if 0 /* This change broke some things. We should make it later. */
710 /* If we don't know the end position, return nil.
711 The user can compute it with vertical-motion if he wants to.
712 It would be nicer to do it automatically,
713 but that's so slow that it would probably bother people. */
714 if (NILP (w->window_end_valid))
715 return Qnil;
716 #endif
717
718 if (! NILP (update)
719 && ! (! NILP (w->window_end_valid)
720 && XFASTINT (w->last_modified) >= MODIFF))
721 {
722 int opoint = PT, opoint_byte = PT_BYTE;
723
724 /* In case W->start is out of the range, use something
725 reasonable. This situation occured when loading a file with
726 `-l' containing a call to `rmail' with subsequent other
727 commands. At the end, W->start happened to be BEG, while
728 rmail had already narrowed the buffer. This leads to an
729 abort in temp_set_pt_both. */
730 if (XMARKER (w->start)->charpos < BEGV)
731 TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
732 else if (XMARKER (w->start)->charpos > ZV)
733 TEMP_SET_PT_BOTH (ZV, ZV_BYTE);
734 else
735 TEMP_SET_PT_BOTH (XMARKER (w->start)->charpos,
736 XMARKER (w->start)->bytepos);
737
738 Fvertical_motion (make_number (window_internal_height (w)), Qnil);
739 XSETINT (value, PT);
740 TEMP_SET_PT_BOTH (opoint, opoint_byte);
741 }
742 else
743 XSETINT (value,
744 BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
745
746 return value;
747 }
748
749 DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
750 "Make point value in WINDOW be at position POS in WINDOW's buffer.")
751 (window, pos)
752 Lisp_Object window, pos;
753 {
754 register struct window *w = decode_window (window);
755
756 CHECK_NUMBER_COERCE_MARKER (pos, 1);
757 if (w == XWINDOW (selected_window)
758 && XBUFFER (w->buffer) == current_buffer)
759 Fgoto_char (pos);
760 else
761 set_marker_restricted (w->pointm, pos, w->buffer);
762
763 return pos;
764 }
765
766 DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
767 "Make display in WINDOW start at position POS in WINDOW's buffer.\n\
768 Optional third arg NOFORCE non-nil inhibits next redisplay\n\
769 from overriding motion of point in order to display at this exact start.")
770 (window, pos, noforce)
771 Lisp_Object window, pos, noforce;
772 {
773 register struct window *w = decode_window (window);
774
775 CHECK_NUMBER_COERCE_MARKER (pos, 1);
776 set_marker_restricted (w->start, pos, w->buffer);
777 /* this is not right, but much easier than doing what is right. */
778 w->start_at_line_beg = Qnil;
779 if (NILP (noforce))
780 w->force_start = Qt;
781 w->update_mode_line = Qt;
782 XSETFASTINT (w->last_modified, 0);
783 XSETFASTINT (w->last_overlay_modified, 0);
784 if (!EQ (window, selected_window))
785 windows_or_buffers_changed++;
786
787 return pos;
788 }
789
790 DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
791 1, 1, 0,
792 "Return WINDOW's dedicated object, usually t or nil.\n\
793 See also `set-window-dedicated-p'.")
794 (window)
795 Lisp_Object window;
796 {
797 return decode_window (window)->dedicated;
798 }
799
800 DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p,
801 Sset_window_dedicated_p, 2, 2, 0,
802 "Control whether WINDOW is dedicated to the buffer it displays.\n\
803 If it is dedicated, Emacs will not automatically change\n\
804 which buffer appears in it.\n\
805 The second argument is the new value for the dedication flag;\n\
806 non-nil means yes.")
807 (window, arg)
808 Lisp_Object window, arg;
809 {
810 register struct window *w = decode_window (window);
811
812 if (NILP (arg))
813 w->dedicated = Qnil;
814 else
815 w->dedicated = Qt;
816
817 return w->dedicated;
818 }
819
820 DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
821 0, 1, 0,
822 "Return the display-table that WINDOW is using.")
823 (window)
824 Lisp_Object window;
825 {
826 return decode_window (window)->display_table;
827 }
828
829 /* Get the display table for use on window W. This is either W's
830 display table or W's buffer's display table. Ignore the specified
831 tables if they are not valid; if no valid table is specified,
832 return 0. */
833
834 struct Lisp_Char_Table *
835 window_display_table (w)
836 struct window *w;
837 {
838 Lisp_Object tem;
839 tem = w->display_table;
840 if (DISP_TABLE_P (tem))
841 return XCHAR_TABLE (tem);
842 if (NILP (w->buffer))
843 return 0;
844
845 tem = XBUFFER (w->buffer)->display_table;
846 if (DISP_TABLE_P (tem))
847 return XCHAR_TABLE (tem);
848 tem = Vstandard_display_table;
849 if (DISP_TABLE_P (tem))
850 return XCHAR_TABLE (tem);
851 return 0;
852 }
853
854 DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_display_table, 2, 2, 0,
855 "Set WINDOW's display-table to TABLE.")
856 (window, table)
857 register Lisp_Object window, table;
858 {
859 register struct window *w;
860
861 w = decode_window (window);
862 w->display_table = table;
863 return table;
864 }
865 \f
866 /* Record info on buffer window w is displaying
867 when it is about to cease to display that buffer. */
868 static void
869 unshow_buffer (w)
870 register struct window *w;
871 {
872 Lisp_Object buf;
873 struct buffer *b;
874
875 buf = w->buffer;
876 b = XBUFFER (buf);
877 if (b != XMARKER (w->pointm)->buffer)
878 abort ();
879
880 if (w == XWINDOW (b->last_selected_window))
881 b->last_selected_window = Qnil;
882
883 #if 0
884 if (w == XWINDOW (selected_window)
885 || ! EQ (buf, XWINDOW (selected_window)->buffer))
886 /* Do this except when the selected window's buffer
887 is being removed from some other window. */
888 #endif
889 /* last_window_start records the start position that this buffer
890 had in the last window to be disconnected from it.
891 Now that this statement is unconditional,
892 it is possible for the buffer to be displayed in the
893 selected window, while last_window_start reflects another
894 window which was recently showing the same buffer.
895 Some people might say that might be a good thing. Let's see. */
896 b->last_window_start = marker_position (w->start);
897
898 /* Point in the selected window's buffer
899 is actually stored in that buffer, and the window's pointm isn't used.
900 So don't clobber point in that buffer. */
901 if (! EQ (buf, XWINDOW (selected_window)->buffer))
902 temp_set_point_both (b,
903 clip_to_bounds (BUF_BEGV (b),
904 XMARKER (w->pointm)->charpos,
905 BUF_ZV (b)),
906 clip_to_bounds (BUF_BEGV_BYTE (b),
907 marker_byte_position (w->pointm),
908 BUF_ZV_BYTE (b)));
909 }
910
911 /* Put replacement into the window structure in place of old. */
912 static void
913 replace_window (old, replacement)
914 Lisp_Object old, replacement;
915 {
916 register Lisp_Object tem;
917 register struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
918
919 /* If OLD is its frame's root_window, then replacement is the new
920 root_window for that frame. */
921
922 if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
923 FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
924
925 p->left = o->left;
926 p->top = o->top;
927 p->width = o->width;
928 p->height = o->height;
929 p->desired_matrix = p->current_matrix = 0;
930 p->vscroll = 0;
931 bzero (&p->cursor, sizeof (p->cursor));
932 bzero (&p->last_cursor, sizeof (p->last_cursor));
933 bzero (&p->phys_cursor, sizeof (p->phys_cursor));
934 p->phys_cursor_type = -1;
935 p->must_be_updated_p = 0;
936 p->pseudo_window_p = 0;
937 XSETFASTINT (p->window_end_vpos, 0);
938 XSETFASTINT (p->window_end_pos, 0);
939 p->window_end_valid = Qnil;
940 p->frozen_window_start_p = 0;
941 p->orig_top = p->orig_height = Qnil;
942
943 p->next = tem = o->next;
944 if (!NILP (tem))
945 XWINDOW (tem)->prev = replacement;
946
947 p->prev = tem = o->prev;
948 if (!NILP (tem))
949 XWINDOW (tem)->next = replacement;
950
951 p->parent = tem = o->parent;
952 if (!NILP (tem))
953 {
954 if (EQ (XWINDOW (tem)->vchild, old))
955 XWINDOW (tem)->vchild = replacement;
956 if (EQ (XWINDOW (tem)->hchild, old))
957 XWINDOW (tem)->hchild = replacement;
958 }
959
960 /*** Here, if replacement is a vertical combination
961 and so is its new parent, we should make replacement's
962 children be children of that parent instead. ***/
963 }
964
965 DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
966 "Remove WINDOW from the display. Default is selected window.")
967 (window)
968 register Lisp_Object window;
969 {
970 delete_window (window);
971
972 if (! NILP (Vwindow_configuration_change_hook)
973 && ! NILP (Vrun_hooks))
974 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
975
976 return Qnil;
977 }
978
979 void
980 delete_window (window)
981 register Lisp_Object window;
982 {
983 register Lisp_Object tem, parent, sib;
984 register struct window *p;
985 register struct window *par;
986 FRAME_PTR frame;
987
988 /* Because this function is called by other C code on non-leaf
989 windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
990 so we can't decode_window here. */
991 if (NILP (window))
992 window = selected_window;
993 else
994 CHECK_WINDOW (window, 0);
995 p = XWINDOW (window);
996
997 /* It's okay to delete an already-deleted window. */
998 if (NILP (p->buffer)
999 && NILP (p->hchild)
1000 && NILP (p->vchild))
1001 return;
1002
1003 parent = p->parent;
1004 if (NILP (parent))
1005 error ("Attempt to delete minibuffer or sole ordinary window");
1006 par = XWINDOW (parent);
1007
1008 windows_or_buffers_changed++;
1009 frame = XFRAME (WINDOW_FRAME (p));
1010 FRAME_WINDOW_SIZES_CHANGED (frame) = 1;
1011
1012 /* Are we trying to delete any frame's selected window? */
1013 {
1014 Lisp_Object frame, pwindow;
1015
1016 /* See if the frame's selected window is either WINDOW
1017 or any subwindow of it, by finding all that window's parents
1018 and comparing each one with WINDOW. */
1019 frame = WINDOW_FRAME (XWINDOW (window));
1020 pwindow = FRAME_SELECTED_WINDOW (XFRAME (frame));
1021
1022 while (!NILP (pwindow))
1023 {
1024 if (EQ (window, pwindow))
1025 break;
1026 pwindow = XWINDOW (pwindow)->parent;
1027 }
1028
1029 if (EQ (window, pwindow))
1030 {
1031 Lisp_Object alternative;
1032 alternative = Fnext_window (window, Qlambda, Qnil);
1033
1034 /* If we're about to delete the selected window on the
1035 selected frame, then we should use Fselect_window to select
1036 the new window. On the other hand, if we're about to
1037 delete the selected window on any other frame, we shouldn't do
1038 anything but set the frame's selected_window slot. */
1039 if (EQ (window, selected_window))
1040 Fselect_window (alternative);
1041 else
1042 FRAME_SELECTED_WINDOW (XFRAME (frame)) = alternative;
1043 }
1044 }
1045
1046 tem = p->buffer;
1047 /* tem is null for dummy parent windows
1048 (which have inferiors but not any contents themselves) */
1049 if (!NILP (tem))
1050 {
1051 unshow_buffer (p);
1052 unchain_marker (p->pointm);
1053 unchain_marker (p->start);
1054 }
1055
1056 /* Free window glyph matrices.
1057 It is sure that they are allocated again when ADJUST_GLYPHS
1058 is called. */
1059 free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (frame)));
1060
1061 tem = p->next;
1062 if (!NILP (tem))
1063 XWINDOW (tem)->prev = p->prev;
1064
1065 tem = p->prev;
1066 if (!NILP (tem))
1067 XWINDOW (tem)->next = p->next;
1068
1069 if (EQ (window, par->hchild))
1070 par->hchild = p->next;
1071 if (EQ (window, par->vchild))
1072 par->vchild = p->next;
1073
1074 /* Find one of our siblings to give our space to. */
1075 sib = p->prev;
1076 if (NILP (sib))
1077 {
1078 /* If p gives its space to its next sibling, that sibling needs
1079 to have its top/left side pulled back to where p's is.
1080 set_window_{height,width} will re-position the sibling's
1081 children. */
1082 sib = p->next;
1083 XWINDOW (sib)->top = p->top;
1084 XWINDOW (sib)->left = p->left;
1085 }
1086
1087 /* Stretch that sibling. */
1088 if (!NILP (par->vchild))
1089 set_window_height (sib,
1090 XFASTINT (XWINDOW (sib)->height) + XFASTINT (p->height),
1091 1);
1092 if (!NILP (par->hchild))
1093 set_window_width (sib,
1094 XFASTINT (XWINDOW (sib)->width) + XFASTINT (p->width),
1095 1);
1096
1097 /* If parent now has only one child,
1098 put the child into the parent's place. */
1099 tem = par->hchild;
1100 if (NILP (tem))
1101 tem = par->vchild;
1102 if (NILP (XWINDOW (tem)->next))
1103 replace_window (parent, tem);
1104
1105 /* Since we may be deleting combination windows, we must make sure that
1106 not only p but all its children have been marked as deleted. */
1107 if (! NILP (p->hchild))
1108 delete_all_subwindows (XWINDOW (p->hchild));
1109 else if (! NILP (p->vchild))
1110 delete_all_subwindows (XWINDOW (p->vchild));
1111
1112 /* Mark this window as deleted. */
1113 p->buffer = p->hchild = p->vchild = Qnil;
1114
1115 /* Adjust glyph matrices. */
1116 adjust_glyphs (frame);
1117 }
1118 \f
1119
1120 extern Lisp_Object next_frame (), prev_frame ();
1121
1122 /* This comment supplies the doc string for `next-window',
1123 for make-docfile to see. We cannot put this in the real DEFUN
1124 due to limits in the Unix cpp.
1125
1126 DEFUN ("next-window", Ffoo, Sfoo, 0, 3, 0,
1127 "Return next window after WINDOW in canonical ordering of windows.\n\
1128 If omitted, WINDOW defaults to the selected window.\n\
1129 \n\
1130 Optional second arg MINIBUF t means count the minibuffer window even\n\
1131 if not active. MINIBUF nil or omitted means count the minibuffer iff\n\
1132 it is active. MINIBUF neither t nor nil means not to count the\n\
1133 minibuffer even if it is active.\n\
1134 \n\
1135 Several frames may share a single minibuffer; if the minibuffer\n\
1136 counts, all windows on all frames that share that minibuffer count\n\
1137 too. Therefore, `next-window' can be used to iterate through the\n\
1138 set of windows even when the minibuffer is on another frame. If the\n\
1139 minibuffer does not count, only windows from WINDOW's frame count.\n\
1140 \n\
1141 Optional third arg ALL-FRAMES t means include windows on all frames.\n\
1142 ALL-FRAMES nil or omitted means cycle within the frames as specified\n\
1143 above. ALL-FRAMES = `visible' means include windows on all visible frames.\n\
1144 ALL-FRAMES = 0 means include windows on all visible and iconified frames.\n\
1145 If ALL-FRAMES is a frame, restrict search to windows on that frame.\n\
1146 Anything else means restrict to WINDOW's frame.\n\
1147 \n\
1148 If you use consistent values for MINIBUF and ALL-FRAMES, you can use\n\
1149 `next-window' to iterate through the entire cycle of acceptable\n\
1150 windows, eventually ending up back at the window you started with.\n\
1151 `previous-window' traverses the same cycle, in the reverse order.")
1152 (window, minibuf, all_frames) */
1153
1154 DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
1155 0)
1156 (window, minibuf, all_frames)
1157 register Lisp_Object window, minibuf, all_frames;
1158 {
1159 register Lisp_Object tem;
1160 Lisp_Object start_window;
1161
1162 if (NILP (window))
1163 window = selected_window;
1164 else
1165 CHECK_LIVE_WINDOW (window, 0);
1166
1167 start_window = window;
1168
1169 /* minibuf == nil may or may not include minibuffers.
1170 Decide if it does. */
1171 if (NILP (minibuf))
1172 minibuf = (minibuf_level ? minibuf_window : Qlambda);
1173 else if (! EQ (minibuf, Qt))
1174 minibuf = Qlambda;
1175 /* Now minibuf can be t => count all minibuffer windows,
1176 lambda => count none of them,
1177 or a specific minibuffer window (the active one) to count. */
1178
1179 /* all_frames == nil doesn't specify which frames to include. */
1180 if (NILP (all_frames))
1181 all_frames = (! EQ (minibuf, Qlambda)
1182 ? (FRAME_MINIBUF_WINDOW
1183 (XFRAME
1184 (WINDOW_FRAME
1185 (XWINDOW (window)))))
1186 : Qnil);
1187 else if (EQ (all_frames, Qvisible))
1188 ;
1189 else if (XFASTINT (all_frames) == 0)
1190 ;
1191 else if (FRAMEP (all_frames) && ! EQ (all_frames, Fwindow_frame (window)))
1192 /* If all_frames is a frame and window arg isn't on that frame, just
1193 return the first window on the frame. */
1194 return Fframe_first_window (all_frames);
1195 else if (! EQ (all_frames, Qt))
1196 all_frames = Qnil;
1197 /* Now all_frames is t meaning search all frames,
1198 nil meaning search just current frame,
1199 visible meaning search just visible frames,
1200 0 meaning search visible and iconified frames,
1201 or a window, meaning search the frame that window belongs to. */
1202
1203 /* Do this loop at least once, to get the next window, and perhaps
1204 again, if we hit the minibuffer and that is not acceptable. */
1205 do
1206 {
1207 /* Find a window that actually has a next one. This loop
1208 climbs up the tree. */
1209 while (tem = XWINDOW (window)->next, NILP (tem))
1210 if (tem = XWINDOW (window)->parent, !NILP (tem))
1211 window = tem;
1212 else
1213 {
1214 /* We've reached the end of this frame.
1215 Which other frames are acceptable? */
1216 tem = WINDOW_FRAME (XWINDOW (window));
1217 if (! NILP (all_frames))
1218 {
1219 Lisp_Object tem1;
1220
1221 tem1 = tem;
1222 tem = next_frame (tem, all_frames);
1223 /* In the case where the minibuffer is active,
1224 and we include its frame as well as the selected one,
1225 next_frame may get stuck in that frame.
1226 If that happens, go back to the selected frame
1227 so we can complete the cycle. */
1228 if (EQ (tem, tem1))
1229 tem = selected_frame;
1230 }
1231 tem = FRAME_ROOT_WINDOW (XFRAME (tem));
1232
1233 break;
1234 }
1235
1236 window = tem;
1237
1238 /* If we're in a combination window, find its first child and
1239 recurse on that. Otherwise, we've found the window we want. */
1240 while (1)
1241 {
1242 if (!NILP (XWINDOW (window)->hchild))
1243 window = XWINDOW (window)->hchild;
1244 else if (!NILP (XWINDOW (window)->vchild))
1245 window = XWINDOW (window)->vchild;
1246 else break;
1247 }
1248
1249 QUIT;
1250 }
1251 /* Which windows are acceptable?
1252 Exit the loop and accept this window if
1253 this isn't a minibuffer window,
1254 or we're accepting all minibuffer windows,
1255 or this is the active minibuffer and we are accepting that one, or
1256 we've come all the way around and we're back at the original window. */
1257 while (MINI_WINDOW_P (XWINDOW (window))
1258 && ! EQ (minibuf, Qt)
1259 && ! EQ (minibuf, window)
1260 && ! EQ (window, start_window));
1261
1262 return window;
1263 }
1264
1265 /* This comment supplies the doc string for `previous-window',
1266 for make-docfile to see. We cannot put this in the real DEFUN
1267 due to limits in the Unix cpp.
1268
1269 DEFUN ("previous-window", Ffoo, Sfoo, 0, 3, 0,
1270 "Return the window preceding WINDOW in canonical ordering of windows.\n\
1271 If omitted, WINDOW defaults to the selected window.\n\
1272 \n\
1273 Optional second arg MINIBUF t means count the minibuffer window even\n\
1274 if not active. MINIBUF nil or omitted means count the minibuffer iff\n\
1275 it is active. MINIBUF neither t nor nil means not to count the\n\
1276 minibuffer even if it is active.\n\
1277 \n\
1278 Several frames may share a single minibuffer; if the minibuffer\n\
1279 counts, all windows on all frames that share that minibuffer count\n\
1280 too. Therefore, `previous-window' can be used to iterate through\n\
1281 the set of windows even when the minibuffer is on another frame. If\n\
1282 the minibuffer does not count, only windows from WINDOW's frame count\n\
1283 \n\
1284 Optional third arg ALL-FRAMES t means include windows on all frames.\n\
1285 ALL-FRAMES nil or omitted means cycle within the frames as specified\n\
1286 above. ALL-FRAMES = `visible' means include windows on all visible frames.\n\
1287 ALL-FRAMES = 0 means include windows on all visible and iconified frames.\n\
1288 If ALL-FRAMES is a frame, restrict search to windows on that frame.\n\
1289 Anything else means restrict to WINDOW's frame.\n\
1290 \n\
1291 If you use consistent values for MINIBUF and ALL-FRAMES, you can use\n\
1292 `previous-window' to iterate through the entire cycle of acceptable\n\
1293 windows, eventually ending up back at the window you started with.\n\
1294 `next-window' traverses the same cycle, in the reverse order.")
1295 (window, minibuf, all_frames) */
1296
1297
1298 DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
1299 0)
1300 (window, minibuf, all_frames)
1301 register Lisp_Object window, minibuf, all_frames;
1302 {
1303 register Lisp_Object tem;
1304 Lisp_Object start_window;
1305
1306 if (NILP (window))
1307 window = selected_window;
1308 else
1309 CHECK_LIVE_WINDOW (window, 0);
1310
1311 start_window = window;
1312
1313 /* minibuf == nil may or may not include minibuffers.
1314 Decide if it does. */
1315 if (NILP (minibuf))
1316 minibuf = (minibuf_level ? minibuf_window : Qlambda);
1317 else if (! EQ (minibuf, Qt))
1318 minibuf = Qlambda;
1319 /* Now minibuf can be t => count all minibuffer windows,
1320 lambda => count none of them,
1321 or a specific minibuffer window (the active one) to count. */
1322
1323 /* all_frames == nil doesn't specify which frames to include.
1324 Decide which frames it includes. */
1325 if (NILP (all_frames))
1326 all_frames = (! EQ (minibuf, Qlambda)
1327 ? (FRAME_MINIBUF_WINDOW
1328 (XFRAME
1329 (WINDOW_FRAME
1330 (XWINDOW (window)))))
1331 : Qnil);
1332 else if (EQ (all_frames, Qvisible))
1333 ;
1334 else if (XFASTINT (all_frames) == 0)
1335 ;
1336 else if (FRAMEP (all_frames) && ! EQ (all_frames, Fwindow_frame (window)))
1337 /* If all_frames is a frame and window arg isn't on that frame, just
1338 return the first window on the frame. */
1339 return Fframe_first_window (all_frames);
1340 else if (! EQ (all_frames, Qt))
1341 all_frames = Qnil;
1342 /* Now all_frames is t meaning search all frames,
1343 nil meaning search just current frame,
1344 visible meaning search just visible frames,
1345 0 meaning search visible and iconified frames,
1346 or a window, meaning search the frame that window belongs to. */
1347
1348 /* Do this loop at least once, to get the previous window, and perhaps
1349 again, if we hit the minibuffer and that is not acceptable. */
1350 do
1351 {
1352 /* Find a window that actually has a previous one. This loop
1353 climbs up the tree. */
1354 while (tem = XWINDOW (window)->prev, NILP (tem))
1355 if (tem = XWINDOW (window)->parent, !NILP (tem))
1356 window = tem;
1357 else
1358 {
1359 /* We have found the top window on the frame.
1360 Which frames are acceptable? */
1361 tem = WINDOW_FRAME (XWINDOW (window));
1362 if (! NILP (all_frames))
1363 /* It's actually important that we use prev_frame here,
1364 rather than next_frame. All the windows acceptable
1365 according to the given parameters should form a ring;
1366 Fnext_window and Fprevious_window should go back and
1367 forth around the ring. If we use next_frame here,
1368 then Fnext_window and Fprevious_window take different
1369 paths through the set of acceptable windows.
1370 window_loop assumes that these `ring' requirement are
1371 met. */
1372 {
1373 Lisp_Object tem1;
1374
1375 tem1 = tem;
1376 tem = prev_frame (tem, all_frames);
1377 /* In the case where the minibuffer is active,
1378 and we include its frame as well as the selected one,
1379 next_frame may get stuck in that frame.
1380 If that happens, go back to the selected frame
1381 so we can complete the cycle. */
1382 if (EQ (tem, tem1))
1383 tem = selected_frame;
1384 }
1385 /* If this frame has a minibuffer, find that window first,
1386 because it is conceptually the last window in that frame. */
1387 if (FRAME_HAS_MINIBUF_P (XFRAME (tem)))
1388 tem = FRAME_MINIBUF_WINDOW (XFRAME (tem));
1389 else
1390 tem = FRAME_ROOT_WINDOW (XFRAME (tem));
1391
1392 break;
1393 }
1394
1395 window = tem;
1396 /* If we're in a combination window, find its last child and
1397 recurse on that. Otherwise, we've found the window we want. */
1398 while (1)
1399 {
1400 if (!NILP (XWINDOW (window)->hchild))
1401 window = XWINDOW (window)->hchild;
1402 else if (!NILP (XWINDOW (window)->vchild))
1403 window = XWINDOW (window)->vchild;
1404 else break;
1405 while (tem = XWINDOW (window)->next, !NILP (tem))
1406 window = tem;
1407 }
1408 }
1409 /* Which windows are acceptable?
1410 Exit the loop and accept this window if
1411 this isn't a minibuffer window,
1412 or we're accepting all minibuffer windows,
1413 or this is the active minibuffer and we are accepting that one, or
1414 we've come all the way around and we're back at the original window. */
1415 while (MINI_WINDOW_P (XWINDOW (window))
1416 && ! EQ (minibuf, Qt)
1417 && ! EQ (minibuf, window)
1418 && ! EQ (window, start_window));
1419
1420 return window;
1421 }
1422
1423 DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
1424 "Select the ARG'th different window on this frame.\n\
1425 All windows on current frame are arranged in a cyclic order.\n\
1426 This command selects the window ARG steps away in that order.\n\
1427 A negative ARG moves in the opposite order. If the optional second\n\
1428 argument ALL_FRAMES is non-nil, cycle through all frames.")
1429 (arg, all_frames)
1430 register Lisp_Object arg, all_frames;
1431 {
1432 register int i;
1433 register Lisp_Object w;
1434
1435 CHECK_NUMBER (arg, 0);
1436 w = selected_window;
1437 i = XINT (arg);
1438
1439 while (i > 0)
1440 {
1441 w = Fnext_window (w, Qnil, all_frames);
1442 i--;
1443 }
1444 while (i < 0)
1445 {
1446 w = Fprevious_window (w, Qnil, all_frames);
1447 i++;
1448 }
1449 Fselect_window (w);
1450 return Qnil;
1451 }
1452 \f
1453 /* Look at all windows, performing an operation specified by TYPE
1454 with argument OBJ.
1455 If FRAMES is Qt, look at all frames;
1456 Qnil, look at just the selected frame;
1457 Qvisible, look at visible frames;
1458 a frame, just look at windows on that frame.
1459 If MINI is non-zero, perform the operation on minibuffer windows too.
1460 */
1461
1462 enum window_loop
1463 {
1464 WINDOW_LOOP_UNUSED,
1465 GET_BUFFER_WINDOW, /* Arg is buffer */
1466 GET_LRU_WINDOW, /* Arg is t for full-width windows only */
1467 DELETE_OTHER_WINDOWS, /* Arg is window not to delete */
1468 DELETE_BUFFER_WINDOWS, /* Arg is buffer */
1469 GET_LARGEST_WINDOW,
1470 UNSHOW_BUFFER, /* Arg is buffer */
1471 CHECK_ALL_WINDOWS
1472 };
1473
1474 static Lisp_Object
1475 window_loop (type, obj, mini, frames)
1476 enum window_loop type;
1477 register Lisp_Object obj, frames;
1478 int mini;
1479 {
1480 register Lisp_Object w;
1481 register Lisp_Object best_window;
1482 register Lisp_Object next_window;
1483 register Lisp_Object last_window;
1484 FRAME_PTR frame;
1485 Lisp_Object frame_arg;
1486 frame_arg = Qt;
1487
1488 /* If we're only looping through windows on a particular frame,
1489 frame points to that frame. If we're looping through windows
1490 on all frames, frame is 0. */
1491 if (FRAMEP (frames))
1492 frame = XFRAME (frames);
1493 else if (NILP (frames))
1494 frame = SELECTED_FRAME ();
1495 else
1496 frame = 0;
1497 if (frame)
1498 frame_arg = Qlambda;
1499 else if (XFASTINT (frames) == 0)
1500 frame_arg = frames;
1501 else if (EQ (frames, Qvisible))
1502 frame_arg = frames;
1503
1504 /* frame_arg is Qlambda to stick to one frame,
1505 Qvisible to consider all visible frames,
1506 or Qt otherwise. */
1507
1508 /* Pick a window to start with. */
1509 if (WINDOWP (obj))
1510 w = obj;
1511 else if (frame)
1512 w = FRAME_SELECTED_WINDOW (frame);
1513 else
1514 w = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
1515
1516 /* Figure out the last window we're going to mess with. Since
1517 Fnext_window, given the same options, is guaranteed to go in a
1518 ring, we can just use Fprevious_window to find the last one.
1519
1520 We can't just wait until we hit the first window again, because
1521 it might be deleted. */
1522
1523 last_window = Fprevious_window (w, mini ? Qt : Qnil, frame_arg);
1524
1525 best_window = Qnil;
1526 for (;;)
1527 {
1528 /* Pick the next window now, since some operations will delete
1529 the current window. */
1530 next_window = Fnext_window (w, mini ? Qt : Qnil, frame_arg);
1531
1532 /* Note that we do not pay attention here to whether
1533 the frame is visible, since Fnext_window skips non-visible frames
1534 if that is desired, under the control of frame_arg. */
1535 if (! MINI_WINDOW_P (XWINDOW (w))
1536 /* For UNSHOW_BUFFER, we must always consider all windows. */
1537 || type == UNSHOW_BUFFER
1538 || (mini && minibuf_level > 0))
1539 switch (type)
1540 {
1541 case GET_BUFFER_WINDOW:
1542 if (XBUFFER (XWINDOW (w)->buffer) == XBUFFER (obj)
1543 /* Don't find any minibuffer window
1544 except the one that is currently in use. */
1545 && (MINI_WINDOW_P (XWINDOW (w))
1546 ? EQ (w, minibuf_window) : 1))
1547 return w;
1548 break;
1549
1550 case GET_LRU_WINDOW:
1551 /* t as arg means consider only full-width windows */
1552 if (!NILP (obj) && !WINDOW_FULL_WIDTH_P (XWINDOW (w)))
1553 break;
1554 /* Ignore dedicated windows and minibuffers. */
1555 if (MINI_WINDOW_P (XWINDOW (w))
1556 || !NILP (XWINDOW (w)->dedicated))
1557 break;
1558 if (NILP (best_window)
1559 || (XFASTINT (XWINDOW (best_window)->use_time)
1560 > XFASTINT (XWINDOW (w)->use_time)))
1561 best_window = w;
1562 break;
1563
1564 case DELETE_OTHER_WINDOWS:
1565 if (XWINDOW (w) != XWINDOW (obj))
1566 Fdelete_window (w);
1567 break;
1568
1569 case DELETE_BUFFER_WINDOWS:
1570 if (EQ (XWINDOW (w)->buffer, obj))
1571 {
1572 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
1573
1574 /* If this window is dedicated, and in a frame of its own,
1575 kill the frame. */
1576 if (EQ (w, FRAME_ROOT_WINDOW (f))
1577 && !NILP (XWINDOW (w)->dedicated)
1578 && other_visible_frames (f))
1579 {
1580 /* Skip the other windows on this frame.
1581 There might be one, the minibuffer! */
1582 if (! EQ (w, last_window))
1583 while (f == XFRAME (WINDOW_FRAME (XWINDOW (next_window))))
1584 {
1585 /* As we go, check for the end of the loop.
1586 We mustn't start going around a second time. */
1587 if (EQ (next_window, last_window))
1588 {
1589 last_window = w;
1590 break;
1591 }
1592 next_window = Fnext_window (next_window,
1593 mini ? Qt : Qnil,
1594 frame_arg);
1595 }
1596 /* Now we can safely delete the frame. */
1597 Fdelete_frame (WINDOW_FRAME (XWINDOW (w)), Qnil);
1598 }
1599 else
1600 /* If we're deleting the buffer displayed in the only window
1601 on the frame, find a new buffer to display there. */
1602 if (NILP (XWINDOW (w)->parent))
1603 {
1604 Lisp_Object new_buffer;
1605 new_buffer = Fother_buffer (obj, Qnil,
1606 XWINDOW (w)->frame);
1607 if (NILP (new_buffer))
1608 new_buffer
1609 = Fget_buffer_create (build_string ("*scratch*"));
1610 Fset_window_buffer (w, new_buffer);
1611 if (EQ (w, selected_window))
1612 Fset_buffer (XWINDOW (w)->buffer);
1613 }
1614 else
1615 Fdelete_window (w);
1616 }
1617 break;
1618
1619 case GET_LARGEST_WINDOW:
1620 /* Ignore dedicated windows and minibuffers. */
1621 if (MINI_WINDOW_P (XWINDOW (w))
1622 || !NILP (XWINDOW (w)->dedicated))
1623 break;
1624 {
1625 struct window *best_window_ptr = XWINDOW (best_window);
1626 struct window *w_ptr = XWINDOW (w);
1627 if (NILP (best_window)
1628 || (XFASTINT (w_ptr->height) * XFASTINT (w_ptr->width)
1629 > (XFASTINT (best_window_ptr->height)
1630 * XFASTINT (best_window_ptr->width))))
1631 best_window = w;
1632 }
1633 break;
1634
1635 case UNSHOW_BUFFER:
1636 if (EQ (XWINDOW (w)->buffer, obj))
1637 {
1638 /* Find another buffer to show in this window. */
1639 Lisp_Object another_buffer;
1640 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
1641 another_buffer = Fother_buffer (obj, Qnil, XWINDOW (w)->frame);
1642 if (NILP (another_buffer))
1643 another_buffer
1644 = Fget_buffer_create (build_string ("*scratch*"));
1645 /* If this window is dedicated, and in a frame of its own,
1646 kill the frame. */
1647 if (EQ (w, FRAME_ROOT_WINDOW (f))
1648 && !NILP (XWINDOW (w)->dedicated)
1649 && other_visible_frames (f))
1650 {
1651 /* Skip the other windows on this frame.
1652 There might be one, the minibuffer! */
1653 if (! EQ (w, last_window))
1654 while (f == XFRAME (WINDOW_FRAME (XWINDOW (next_window))))
1655 {
1656 /* As we go, check for the end of the loop.
1657 We mustn't start going around a second time. */
1658 if (EQ (next_window, last_window))
1659 {
1660 last_window = w;
1661 break;
1662 }
1663 next_window = Fnext_window (next_window,
1664 mini ? Qt : Qnil,
1665 frame_arg);
1666 }
1667 /* Now we can safely delete the frame. */
1668 Fdelete_frame (WINDOW_FRAME (XWINDOW (w)), Qnil);
1669 }
1670 else
1671 {
1672 /* Otherwise show a different buffer in the window. */
1673 XWINDOW (w)->dedicated = Qnil;
1674 Fset_window_buffer (w, another_buffer);
1675 if (EQ (w, selected_window))
1676 Fset_buffer (XWINDOW (w)->buffer);
1677 }
1678 }
1679 break;
1680
1681 /* Check for a window that has a killed buffer. */
1682 case CHECK_ALL_WINDOWS:
1683 if (! NILP (XWINDOW (w)->buffer)
1684 && NILP (XBUFFER (XWINDOW (w)->buffer)->name))
1685 abort ();
1686 }
1687
1688 if (EQ (w, last_window))
1689 break;
1690
1691 w = next_window;
1692 }
1693
1694 return best_window;
1695 }
1696
1697 /* Used for debugging. Abort if any window has a dead buffer. */
1698
1699 void
1700 check_all_windows ()
1701 {
1702 window_loop (CHECK_ALL_WINDOWS, Qnil, 1, Qt);
1703 }
1704
1705 DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
1706 "Return the window least recently selected or used for display.\n\
1707 If optional argument FRAME is `visible', search all visible frames.\n\
1708 If FRAME is 0, search all visible and iconified frames.\n\
1709 If FRAME is t, search all frames.\n\
1710 If FRAME is nil, search only the selected frame.\n\
1711 If FRAME is a frame, search only that frame.")
1712 (frame)
1713 Lisp_Object frame;
1714 {
1715 register Lisp_Object w;
1716 /* First try for a window that is full-width */
1717 w = window_loop (GET_LRU_WINDOW, Qt, 0, frame);
1718 if (!NILP (w) && !EQ (w, selected_window))
1719 return w;
1720 /* If none of them, try the rest */
1721 return window_loop (GET_LRU_WINDOW, Qnil, 0, frame);
1722 }
1723
1724 DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 1, 0,
1725 "Return the largest window in area.\n\
1726 If optional argument FRAME is `visible', search all visible frames.\n\
1727 If FRAME is 0, search all visible and iconified frames.\n\
1728 If FRAME is t, search all frames.\n\
1729 If FRAME is nil, search only the selected frame.\n\
1730 If FRAME is a frame, search only that frame.")
1731 (frame)
1732 Lisp_Object frame;
1733 {
1734 return window_loop (GET_LARGEST_WINDOW, Qnil, 0,
1735 frame);
1736 }
1737
1738 DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 1, 2, 0,
1739 "Return a window currently displaying BUFFER, or nil if none.\n\
1740 If optional argument FRAME is `visible', search all visible frames.\n\
1741 If optional argument FRAME is 0, search all visible and iconified frames.\n\
1742 If FRAME is t, search all frames.\n\
1743 If FRAME is nil, search only the selected frame.\n\
1744 If FRAME is a frame, search only that frame.")
1745 (buffer, frame)
1746 Lisp_Object buffer, frame;
1747 {
1748 buffer = Fget_buffer (buffer);
1749 if (BUFFERP (buffer))
1750 return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame);
1751 else
1752 return Qnil;
1753 }
1754
1755 DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
1756 0, 1, "",
1757 "Make WINDOW (or the selected window) fill its frame.\n\
1758 Only the frame WINDOW is on is affected.\n\
1759 This function tries to reduce display jumps\n\
1760 by keeping the text previously visible in WINDOW\n\
1761 in the same place on the frame. Doing this depends on\n\
1762 the value of (window-start WINDOW), so if calling this function\n\
1763 in a program gives strange scrolling, make sure the window-start\n\
1764 value is reasonable when this function is called.")
1765 (window)
1766 Lisp_Object window;
1767 {
1768 struct window *w;
1769 int startpos;
1770 int top;
1771
1772 if (NILP (window))
1773 window = selected_window;
1774 else
1775 CHECK_LIVE_WINDOW (window, 0);
1776
1777 w = XWINDOW (window);
1778
1779 startpos = marker_position (w->start);
1780 top = XFASTINT (w->top) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
1781
1782 if (MINI_WINDOW_P (w) && top > 0)
1783 error ("Can't expand minibuffer to full frame");
1784
1785 window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_FRAME (w));
1786
1787 /* Try to minimize scrolling, by setting the window start to the point
1788 will cause the text at the old window start to be at the same place
1789 on the frame. But don't try to do this if the window start is
1790 outside the visible portion (as might happen when the display is
1791 not current, due to typeahead). */
1792 if (startpos >= BUF_BEGV (XBUFFER (w->buffer))
1793 && startpos <= BUF_ZV (XBUFFER (w->buffer)))
1794 {
1795 struct position pos;
1796 struct buffer *obuf = current_buffer;
1797
1798 Fset_buffer (w->buffer);
1799 /* This computation used to temporarily move point, but that can
1800 have unwanted side effects due to text properties. */
1801 pos = *vmotion (startpos, -top, w);
1802
1803 set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
1804 w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
1805 || FETCH_BYTE (pos.bytepos - 1) == '\n') ? Qt
1806 : Qnil);
1807 /* We need to do this, so that the window-scroll-functions
1808 get called. */
1809 w->optional_new_start = Qt;
1810
1811 set_buffer_internal (obuf);
1812 }
1813
1814 return Qnil;
1815 }
1816
1817 DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
1818 1, 2, "bDelete windows on (buffer): ",
1819 "Delete all windows showing BUFFER.\n\
1820 Optional second argument FRAME controls which frames are affected.\n\
1821 If optional argument FRAME is `visible', search all visible frames.\n\
1822 If FRAME is 0, search all visible and iconified frames.\n\
1823 If FRAME is nil, search all frames.\n\
1824 If FRAME is t, search only the selected frame.\n\
1825 If FRAME is a frame, search only that frame.")
1826 (buffer, frame)
1827 Lisp_Object buffer, frame;
1828 {
1829 /* FRAME uses t and nil to mean the opposite of what window_loop
1830 expects. */
1831 if (NILP (frame))
1832 frame = Qt;
1833 else if (EQ (frame, Qt))
1834 frame = Qnil;
1835
1836 if (!NILP (buffer))
1837 {
1838 buffer = Fget_buffer (buffer);
1839 CHECK_BUFFER (buffer, 0);
1840 window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
1841 }
1842
1843 return Qnil;
1844 }
1845
1846 DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
1847 Sreplace_buffer_in_windows,
1848 1, 1, "bReplace buffer in windows: ",
1849 "Replace BUFFER with some other buffer in all windows showing it.")
1850 (buffer)
1851 Lisp_Object buffer;
1852 {
1853 if (!NILP (buffer))
1854 {
1855 buffer = Fget_buffer (buffer);
1856 CHECK_BUFFER (buffer, 0);
1857 window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
1858 }
1859 return Qnil;
1860 }
1861
1862 /* Replace BUFFER with some other buffer in all windows
1863 of all frames, even those on other keyboards. */
1864
1865 void
1866 replace_buffer_in_all_windows (buffer)
1867 Lisp_Object buffer;
1868 {
1869 #ifdef MULTI_KBOARD
1870 Lisp_Object tail, frame;
1871
1872 /* A single call to window_loop won't do the job
1873 because it only considers frames on the current keyboard.
1874 So loop manually over frames, and handle each one. */
1875 FOR_EACH_FRAME (tail, frame)
1876 window_loop (UNSHOW_BUFFER, buffer, 1, frame);
1877 #else
1878 window_loop (UNSHOW_BUFFER, buffer, 1, Qt);
1879 #endif
1880 }
1881 \f
1882 /* Set the height of WINDOW and all its inferiors. */
1883
1884 /* The smallest acceptable dimensions for a window. Anything smaller
1885 might crash Emacs. */
1886
1887 #define MIN_SAFE_WINDOW_WIDTH (2)
1888 #define MIN_SAFE_WINDOW_HEIGHT (2)
1889
1890 /* Make sure that window_min_height and window_min_width are
1891 not too small; if they are, set them to safe minima. */
1892
1893 static void
1894 check_min_window_sizes ()
1895 {
1896 /* Smaller values might permit a crash. */
1897 if (window_min_width < MIN_SAFE_WINDOW_WIDTH)
1898 window_min_width = MIN_SAFE_WINDOW_WIDTH;
1899 if (window_min_height < MIN_SAFE_WINDOW_HEIGHT)
1900 window_min_height = MIN_SAFE_WINDOW_HEIGHT;
1901 }
1902
1903 /* If *ROWS or *COLS are too small a size for FRAME, set them to the
1904 minimum allowable size. */
1905
1906 void
1907 check_frame_size (frame, rows, cols)
1908 FRAME_PTR frame;
1909 int *rows, *cols;
1910 {
1911 /* For height, we have to see:
1912 whether the frame has a minibuffer,
1913 whether it wants a mode line, and
1914 whether it has a menu bar. */
1915 int min_height =
1916 (FRAME_MINIBUF_ONLY_P (frame) ? MIN_SAFE_WINDOW_HEIGHT - 1
1917 : (! FRAME_HAS_MINIBUF_P (frame)) ? MIN_SAFE_WINDOW_HEIGHT
1918 : 2 * MIN_SAFE_WINDOW_HEIGHT - 1);
1919
1920 if (FRAME_TOP_MARGIN (frame) > 0)
1921 min_height += FRAME_TOP_MARGIN (frame);
1922
1923 if (*rows < min_height)
1924 *rows = min_height;
1925 if (*cols < MIN_SAFE_WINDOW_WIDTH)
1926 *cols = MIN_SAFE_WINDOW_WIDTH;
1927 }
1928
1929
1930 /* Value is non-zero if window W is fixed-size. WIDTH_P non-zero means
1931 check if W's width can be changed, otherwise check W's height.
1932 CHECK_SIBLINGS_P non-zero means check resizablity of WINDOW's
1933 siblings, too. If none of the siblings is resizable, WINDOW isn't
1934 either. */
1935
1936 static int
1937 window_fixed_size_p (w, width_p, check_siblings_p)
1938 struct window *w;
1939 int width_p, check_siblings_p;
1940 {
1941 int fixed_p;
1942 struct window *c;
1943
1944 if (!NILP (w->hchild))
1945 {
1946 c = XWINDOW (w->hchild);
1947
1948 if (width_p)
1949 {
1950 /* A horiz. combination is fixed-width if all of if its
1951 children are. */
1952 while (c && window_fixed_size_p (c, width_p, 0))
1953 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
1954 fixed_p = c == NULL;
1955 }
1956 else
1957 {
1958 /* A horiz. combination is fixed-height if one of if its
1959 children is. */
1960 while (c && !window_fixed_size_p (c, width_p, 0))
1961 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
1962 fixed_p = c != NULL;
1963 }
1964 }
1965 else if (!NILP (w->vchild))
1966 {
1967 c = XWINDOW (w->vchild);
1968
1969 if (width_p)
1970 {
1971 /* A vert. combination is fixed-width if one of if its
1972 children is. */
1973 while (c && !window_fixed_size_p (c, width_p, 0))
1974 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
1975 fixed_p = c != NULL;
1976 }
1977 else
1978 {
1979 /* A vert. combination is fixed-height if all of if its
1980 children are. */
1981 while (c && window_fixed_size_p (c, width_p, 0))
1982 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
1983 fixed_p = c == NULL;
1984 }
1985 }
1986 else if (BUFFERP (w->buffer))
1987 {
1988 if (w->height_fixed_p && !width_p)
1989 fixed_p = 1;
1990 else
1991 {
1992 struct buffer *old = current_buffer;
1993 Lisp_Object val;
1994
1995 current_buffer = XBUFFER (w->buffer);
1996 val = find_symbol_value (Qwindow_size_fixed);
1997 current_buffer = old;
1998
1999 fixed_p = 0;
2000 if (!EQ (val, Qunbound))
2001 {
2002 fixed_p = !NILP (val);
2003
2004 if (fixed_p
2005 && ((EQ (val, Qheight) && width_p)
2006 || (EQ (val, Qwidth) && !width_p)))
2007 fixed_p = 0;
2008 }
2009 }
2010
2011 /* Can't tell if this one is resizable without looking at
2012 siblings. If all siblings are fixed-size this one is too. */
2013 if (!fixed_p && check_siblings_p && WINDOWP (w->parent))
2014 {
2015 Lisp_Object child;
2016
2017 for (child = w->prev; !NILP (child); child = XWINDOW (child)->prev)
2018 if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
2019 break;
2020
2021 if (NILP (child))
2022 for (child = w->next; !NILP (child); child = XWINDOW (child)->next)
2023 if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
2024 break;
2025
2026 if (NILP (child))
2027 fixed_p = 1;
2028 }
2029 }
2030 else
2031 fixed_p = 1;
2032
2033 return fixed_p;
2034 }
2035
2036
2037 /* Return the minimum size of window W, not taking fixed-width windows
2038 into account. WIDTH_P non-zero means return the minimum width,
2039 otherwise return the minimum height. If W is a combination window,
2040 compute the minimum size from the minimum sizes of W's children. */
2041
2042 static int
2043 window_min_size_1 (w, width_p)
2044 struct window *w;
2045 int width_p;
2046 {
2047 struct window *c;
2048 int size;
2049
2050 if (!NILP (w->hchild))
2051 {
2052 c = XWINDOW (w->hchild);
2053 size = 0;
2054
2055 if (width_p)
2056 {
2057 /* The min width of a horizontal combination is
2058 the sum of the min widths of its children. */
2059 while (c)
2060 {
2061 size += window_min_size_1 (c, width_p);
2062 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2063 }
2064 }
2065 else
2066 {
2067 /* The min height a horizontal combination equals
2068 the maximum of all min height of its children. */
2069 while (c)
2070 {
2071 int min_size = window_min_size_1 (c, width_p);
2072 size = max (min_size, size);
2073 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2074 }
2075 }
2076 }
2077 else if (!NILP (w->vchild))
2078 {
2079 c = XWINDOW (w->vchild);
2080 size = 0;
2081
2082 if (width_p)
2083 {
2084 /* The min width of a vertical combination is
2085 the maximum of the min widths of its children. */
2086 while (c)
2087 {
2088 int min_size = window_min_size_1 (c, width_p);
2089 size = max (min_size, size);
2090 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2091 }
2092 }
2093 else
2094 {
2095 /* The min height of a vertical combination equals
2096 the sum of the min height of its children. */
2097 while (c)
2098 {
2099 size += window_min_size_1 (c, width_p);
2100 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2101 }
2102 }
2103 }
2104 else
2105 {
2106 if (width_p)
2107 size = window_min_width;
2108 else
2109 {
2110 if (MINI_WINDOW_P (w)
2111 || (!WINDOW_WANTS_MODELINE_P (w)
2112 && !WINDOW_WANTS_HEADER_LINE_P (w)))
2113 size = 1;
2114 else
2115 size = window_min_height;
2116 }
2117 }
2118
2119 return size;
2120 }
2121
2122
2123 /* Return the minimum size of window W, taking fixed-size windows into
2124 account. WIDTH_P non-zero means return the minimum width,
2125 otherwise return the minimum height. IGNORE_FIXED_P non-zero means
2126 ignore if W is fixed-size. Set *FIXED to 1 if W is fixed-size
2127 unless FIXED is null. */
2128
2129 static int
2130 window_min_size (w, width_p, ignore_fixed_p, fixed)
2131 struct window *w;
2132 int width_p, ignore_fixed_p, *fixed;
2133 {
2134 int size, fixed_p;
2135
2136 if (ignore_fixed_p)
2137 fixed_p = 0;
2138 else
2139 fixed_p = window_fixed_size_p (w, width_p, 1);
2140
2141 if (fixed)
2142 *fixed = fixed_p;
2143
2144 if (fixed_p)
2145 size = width_p ? XFASTINT (w->width) : XFASTINT (w->height);
2146 else
2147 size = window_min_size_1 (w, width_p);
2148
2149 return size;
2150 }
2151
2152
2153 /* Set WINDOW's height or width to SIZE. WIDTH_P non-zero means set
2154 WINDOW's width. Resize WINDOW's children, if any, so that they
2155 keep their proportionate size relative to WINDOW. Propagate
2156 WINDOW's top or left edge position to children. Delete windows
2157 that become too small unless NODELETE_P is non-zero. */
2158
2159 static void
2160 size_window (window, size, width_p, nodelete_p)
2161 Lisp_Object window;
2162 int size, width_p, nodelete_p;
2163 {
2164 struct window *w = XWINDOW (window);
2165 struct window *c;
2166 Lisp_Object child, *forward, *sideward;
2167 int old_size, min_size;
2168
2169 check_min_window_sizes ();
2170
2171 /* If the window has been "too small" at one point,
2172 don't delete it for being "too small" in the future.
2173 Preserve it as long as that is at all possible. */
2174 if (width_p)
2175 {
2176 old_size = XFASTINT (w->width);
2177 min_size = window_min_width;
2178 }
2179 else
2180 {
2181 old_size = XFASTINT (w->height);
2182 min_size = window_min_height;
2183 }
2184
2185 if (old_size < window_min_width)
2186 w->too_small_ok = Qt;
2187
2188 /* Maybe delete WINDOW if it's too small. */
2189 if (!nodelete_p && !NILP (w->parent))
2190 {
2191 int min_size;
2192
2193 if (!MINI_WINDOW_P (w) && !NILP (w->too_small_ok))
2194 min_size = width_p ? MIN_SAFE_WINDOW_WIDTH : MIN_SAFE_WINDOW_HEIGHT;
2195 else
2196 min_size = width_p ? window_min_width : window_min_height;
2197
2198 if (size < min_size)
2199 {
2200 delete_window (window);
2201 return;
2202 }
2203 }
2204
2205 /* Set redisplay hints. */
2206 XSETFASTINT (w->last_modified, 0);
2207 XSETFASTINT (w->last_overlay_modified, 0);
2208 windows_or_buffers_changed++;
2209 FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
2210
2211 if (width_p)
2212 {
2213 sideward = &w->vchild;
2214 forward = &w->hchild;
2215 XSETFASTINT (w->width, size);
2216 }
2217 else
2218 {
2219 sideward = &w->hchild;
2220 forward = &w->vchild;
2221 XSETFASTINT (w->height, size);
2222 }
2223
2224 if (!NILP (*sideward))
2225 {
2226 for (child = *sideward; !NILP (child); child = c->next)
2227 {
2228 c = XWINDOW (child);
2229 if (width_p)
2230 c->left = w->left;
2231 else
2232 c->top = w->top;
2233 size_window (child, size, width_p, nodelete_p);
2234 }
2235 }
2236 else if (!NILP (*forward))
2237 {
2238 int fixed_size, each, extra, n;
2239 int resize_fixed_p, nfixed;
2240 int last_pos, first_pos, nchildren;
2241
2242 /* Determine the fixed-size portion of the this window, and the
2243 number of child windows. */
2244 fixed_size = nchildren = nfixed = 0;
2245 for (child = *forward; !NILP (child); child = c->next, ++nchildren)
2246 {
2247 c = XWINDOW (child);
2248 if (window_fixed_size_p (c, width_p, 0))
2249 {
2250 fixed_size += (width_p
2251 ? XFASTINT (c->width) : XFASTINT (c->height));
2252 ++nfixed;
2253 }
2254 }
2255
2256 /* If the new size is smaller than fixed_size, or if there
2257 aren't any resizable windows, allow resizing fixed-size
2258 windows. */
2259 resize_fixed_p = nfixed == nchildren || size < fixed_size;
2260
2261 /* Compute how many lines/columns to add to each child. The
2262 value of extra takes care of rounding errors. */
2263 n = resize_fixed_p ? nchildren : nchildren - nfixed;
2264 each = (size - old_size) / n;
2265 extra = (size - old_size) - n * each;
2266
2267 /* Compute new children heights and edge positions. */
2268 first_pos = width_p ? XFASTINT (w->left) : XFASTINT (w->top);
2269 last_pos = first_pos;
2270 for (child = *forward; !NILP (child); child = c->next)
2271 {
2272 int new_size, old_size;
2273
2274 c = XWINDOW (child);
2275 old_size = width_p ? XFASTINT (c->width) : XFASTINT (c->height);
2276 new_size = old_size;
2277
2278 /* The top or left edge position of this child equals the
2279 bottom or right edge of its predecessor. */
2280 if (width_p)
2281 c->left = make_number (last_pos);
2282 else
2283 c->top = make_number (last_pos);
2284
2285 /* If this child can be resized, do it. */
2286 if (resize_fixed_p || !window_fixed_size_p (c, width_p, 0))
2287 {
2288 new_size = old_size + each + extra;
2289 extra = 0;
2290 }
2291
2292 /* Set new height. Note that size_window also propagates
2293 edge positions to children, so it's not a no-op if we
2294 didn't change the child's size. */
2295 size_window (child, new_size, width_p, 1);
2296
2297 /* Remember the bottom/right edge position of this child; it
2298 will be used to set the top/left edge of the next child. */
2299 last_pos += new_size;
2300 }
2301
2302 /* We should have covered the parent exactly with child windows. */
2303 xassert (size == last_pos - first_pos);
2304
2305 /* Now delete any children that became too small. */
2306 if (!nodelete_p)
2307 for (child = *forward; !NILP (child); child = c->next)
2308 {
2309 int child_size;
2310 c = XWINDOW (child);
2311 child_size = width_p ? XFASTINT (c->width) : XFASTINT (c->height);
2312 size_window (child, child_size, width_p, 0);
2313 }
2314 }
2315 }
2316
2317 /* Set WINDOW's height to HEIGHT, and recursively change the height of
2318 WINDOW's children. NODELETE non-zero means don't delete windows
2319 that become too small in the process. (The caller should check
2320 later and do so if appropriate.) */
2321
2322 void
2323 set_window_height (window, height, nodelete)
2324 Lisp_Object window;
2325 int height;
2326 int nodelete;
2327 {
2328 size_window (window, height, 0, nodelete);
2329 }
2330
2331
2332 /* Set WINDOW's width to WIDTH, and recursively change the width of
2333 WINDOW's children. NODELETE non-zero means don't delete windows
2334 that become too small in the process. (The caller should check
2335 later and do so if appropriate.) */
2336
2337 void
2338 set_window_width (window, width, nodelete)
2339 Lisp_Object window;
2340 int width;
2341 int nodelete;
2342 {
2343 size_window (window, width, 1, nodelete);
2344 }
2345
2346 \f
2347 int window_select_count;
2348
2349 Lisp_Object
2350 Fset_window_buffer_unwind (obuf)
2351 Lisp_Object obuf;
2352 {
2353 Fset_buffer (obuf);
2354 return Qnil;
2355 }
2356
2357
2358 /* Make WINDOW display BUFFER as its contents. RUN_HOOKS_P non-zero
2359 means it's allowed to run hooks. See make_frame for a case where
2360 it's not allowed. */
2361
2362 void
2363 set_window_buffer (window, buffer, run_hooks_p)
2364 Lisp_Object window, buffer;
2365 int run_hooks_p;
2366 {
2367 struct window *w = XWINDOW (window);
2368 struct buffer *b = XBUFFER (buffer);
2369 int count = specpdl_ptr - specpdl;
2370
2371 w->buffer = buffer;
2372
2373 if (EQ (window, selected_window))
2374 b->last_selected_window = window;
2375
2376 /* Update time stamps of buffer display. */
2377 if (INTEGERP (b->display_count))
2378 XSETINT (b->display_count, XINT (b->display_count) + 1);
2379 b->display_time = Fcurrent_time ();
2380
2381 XSETFASTINT (w->window_end_pos, 0);
2382 XSETFASTINT (w->window_end_vpos, 0);
2383 bzero (&w->last_cursor, sizeof w->last_cursor);
2384 w->window_end_valid = Qnil;
2385 XSETFASTINT (w->hscroll, 0);
2386 set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
2387 set_marker_restricted (w->start,
2388 make_number (b->last_window_start),
2389 buffer);
2390 w->start_at_line_beg = Qnil;
2391 w->force_start = Qnil;
2392 XSETFASTINT (w->last_modified, 0);
2393 XSETFASTINT (w->last_overlay_modified, 0);
2394 windows_or_buffers_changed++;
2395
2396 /* We must select BUFFER for running the window-scroll-functions.
2397 If WINDOW is selected, switch permanently.
2398 Otherwise, switch but go back to the ambient buffer afterward. */
2399 if (EQ (window, selected_window))
2400 Fset_buffer (buffer);
2401 /* We can't check ! NILP (Vwindow_scroll_functions) here
2402 because that might itself be a local variable. */
2403 else if (window_initialized)
2404 {
2405 record_unwind_protect (Fset_window_buffer_unwind, Fcurrent_buffer ());
2406 Fset_buffer (buffer);
2407 }
2408
2409 /* Set left and right marginal area width from buffer. */
2410 Fset_window_margins (window, b->left_margin_width, b->right_margin_width);
2411
2412 if (run_hooks_p)
2413 {
2414 if (! NILP (Vwindow_scroll_functions))
2415 run_hook_with_args_2 (Qwindow_scroll_functions, window,
2416 Fmarker_position (w->start));
2417
2418 if (! NILP (Vwindow_configuration_change_hook)
2419 && ! NILP (Vrun_hooks))
2420 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
2421 }
2422
2423 unbind_to (count, Qnil);
2424 }
2425
2426
2427 DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 2, 0,
2428 "Make WINDOW display BUFFER as its contents.\n\
2429 BUFFER can be a buffer or buffer name.")
2430 (window, buffer)
2431 register Lisp_Object window, buffer;
2432 {
2433 register Lisp_Object tem;
2434 register struct window *w = decode_window (window);
2435
2436 buffer = Fget_buffer (buffer);
2437 CHECK_BUFFER (buffer, 1);
2438
2439 if (NILP (XBUFFER (buffer)->name))
2440 error ("Attempt to display deleted buffer");
2441
2442 tem = w->buffer;
2443 if (NILP (tem))
2444 error ("Window is deleted");
2445 else if (! EQ (tem, Qt)) /* w->buffer is t when the window
2446 is first being set up. */
2447 {
2448 if (!NILP (w->dedicated) && !EQ (tem, buffer))
2449 error ("Window is dedicated to `%s'",
2450 XSTRING (XBUFFER (tem)->name)->data);
2451
2452 unshow_buffer (w);
2453 }
2454
2455 set_window_buffer (window, buffer, 1);
2456 return Qnil;
2457 }
2458
2459 DEFUN ("select-window", Fselect_window, Sselect_window, 1, 1, 0,
2460 "Select WINDOW. Most editing will apply to WINDOW's buffer.\n\
2461 If WINDOW is not already selected, also make WINDOW's buffer current.\n\
2462 Note that the main editor command loop\n\
2463 selects the buffer of the selected window before each command.")
2464 (window)
2465 register Lisp_Object window;
2466 {
2467 return select_window_1 (window, 1);
2468 }
2469 \f
2470 static Lisp_Object
2471 select_window_1 (window, recordflag)
2472 register Lisp_Object window;
2473 int recordflag;
2474 {
2475 register struct window *w;
2476 register struct window *ow = XWINDOW (selected_window);
2477 struct frame *sf;
2478
2479 CHECK_LIVE_WINDOW (window, 0);
2480
2481 w = XWINDOW (window);
2482
2483 if (NILP (w->buffer))
2484 error ("Trying to select deleted window or non-leaf window");
2485
2486 XSETFASTINT (w->use_time, ++window_select_count);
2487 if (EQ (window, selected_window))
2488 return window;
2489
2490 if (! NILP (ow->buffer))
2491 set_marker_both (ow->pointm, ow->buffer,
2492 BUF_PT (XBUFFER (ow->buffer)),
2493 BUF_PT_BYTE (XBUFFER (ow->buffer)));
2494
2495 selected_window = window;
2496 sf = SELECTED_FRAME ();
2497 if (XFRAME (WINDOW_FRAME (w)) != sf)
2498 {
2499 XFRAME (WINDOW_FRAME (w))->selected_window = window;
2500 /* Use this rather than Fhandle_switch_frame
2501 so that FRAME_FOCUS_FRAME is moved appropriately as we
2502 move around in the state where a minibuffer in a separate
2503 frame is active. */
2504 Fselect_frame (WINDOW_FRAME (w), Qnil);
2505 }
2506 else
2507 sf->selected_window = window;
2508
2509 if (recordflag)
2510 record_buffer (w->buffer);
2511 Fset_buffer (w->buffer);
2512
2513 XBUFFER (w->buffer)->last_selected_window = window;
2514
2515 /* Go to the point recorded in the window.
2516 This is important when the buffer is in more
2517 than one window. It also matters when
2518 redisplay_window has altered point after scrolling,
2519 because it makes the change only in the window. */
2520 {
2521 register int new_point = marker_position (w->pointm);
2522 if (new_point < BEGV)
2523 SET_PT (BEGV);
2524 else if (new_point > ZV)
2525 SET_PT (ZV);
2526 else
2527 SET_PT (new_point);
2528 }
2529
2530 windows_or_buffers_changed++;
2531 return window;
2532 }
2533 \f
2534 /* Deiconify the frame containing the window WINDOW,
2535 unless it is the selected frame;
2536 then return WINDOW.
2537
2538 The reason for the exception for the selected frame
2539 is that it seems better not to change the selected frames visibility
2540 merely because of displaying a different buffer in it.
2541 The deiconification is useful when a buffer gets shown in
2542 another frame that you were not using lately. */
2543
2544 static Lisp_Object
2545 display_buffer_1 (window)
2546 Lisp_Object window;
2547 {
2548 Lisp_Object frame = XWINDOW (window)->frame;
2549 FRAME_PTR f = XFRAME (frame);
2550
2551 FRAME_SAMPLE_VISIBILITY (f);
2552
2553 if (!EQ (frame, selected_frame))
2554 {
2555 if (FRAME_ICONIFIED_P (f))
2556 Fmake_frame_visible (frame);
2557 else if (FRAME_VISIBLE_P (f))
2558 Fraise_frame (frame);
2559 }
2560
2561 return window;
2562 }
2563
2564 DEFUN ("special-display-p", Fspecial_display_p, Sspecial_display_p, 1, 1, 0,
2565 "Returns non-nil if a buffer named BUFFER-NAME would be created specially.\n\
2566 The value is actually t if the frame should be called with default frame\n\
2567 parameters, and a list of frame parameters if they were specified.\n\
2568 See `special-display-buffer-names', and `special-display-regexps'.")
2569 (buffer_name)
2570 Lisp_Object buffer_name;
2571 {
2572 Lisp_Object tem;
2573
2574 CHECK_STRING (buffer_name, 1);
2575
2576 tem = Fmember (buffer_name, Vspecial_display_buffer_names);
2577 if (!NILP (tem))
2578 return Qt;
2579
2580 tem = Fassoc (buffer_name, Vspecial_display_buffer_names);
2581 if (!NILP (tem))
2582 return XCDR (tem);
2583
2584 for (tem = Vspecial_display_regexps; CONSP (tem); tem = XCDR (tem))
2585 {
2586 Lisp_Object car = XCAR (tem);
2587 if (STRINGP (car)
2588 && fast_string_match (car, buffer_name) >= 0)
2589 return Qt;
2590 else if (CONSP (car)
2591 && STRINGP (XCAR (car))
2592 && fast_string_match (XCAR (car), buffer_name) >= 0)
2593 return XCDR (car);
2594 }
2595 return Qnil;
2596 }
2597
2598 DEFUN ("same-window-p", Fsame_window_p, Ssame_window_p, 1, 1, 0,
2599 "Returns non-nil if a new buffer named BUFFER-NAME would use the same window.\n\
2600 See `same-window-buffer-names' and `same-window-regexps'.")
2601 (buffer_name)
2602 Lisp_Object buffer_name;
2603 {
2604 Lisp_Object tem;
2605
2606 CHECK_STRING (buffer_name, 1);
2607
2608 tem = Fmember (buffer_name, Vsame_window_buffer_names);
2609 if (!NILP (tem))
2610 return Qt;
2611
2612 tem = Fassoc (buffer_name, Vsame_window_buffer_names);
2613 if (!NILP (tem))
2614 return Qt;
2615
2616 for (tem = Vsame_window_regexps; CONSP (tem); tem = XCDR (tem))
2617 {
2618 Lisp_Object car = XCAR (tem);
2619 if (STRINGP (car)
2620 && fast_string_match (car, buffer_name) >= 0)
2621 return Qt;
2622 else if (CONSP (car)
2623 && STRINGP (XCAR (car))
2624 && fast_string_match (XCAR (car), buffer_name) >= 0)
2625 return Qt;
2626 }
2627 return Qnil;
2628 }
2629
2630 /* Use B so the default is (other-buffer). */
2631 DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 3,
2632 "BDisplay buffer: \nP",
2633 "Make BUFFER appear in some window but don't select it.\n\
2634 BUFFER can be a buffer or a buffer name.\n\
2635 If BUFFER is shown already in some window, just use that one,\n\
2636 unless the window is the selected window and the optional second\n\
2637 argument NOT-THIS-WINDOW is non-nil (interactively, with prefix arg).\n\
2638 If `pop-up-frames' is non-nil, make a new frame if no window shows BUFFER.\n\
2639 Returns the window displaying BUFFER.\n\
2640 \n\
2641 The variables `special-display-buffer-names', `special-display-regexps',\n\
2642 `same-window-buffer-names', and `same-window-regexps' customize how certain\n\
2643 buffer names are handled.\n\
2644 \n\
2645 If optional argument FRAME is `visible', search all visible frames.\n\
2646 If FRAME is 0, search all visible and iconified frames.\n\
2647 If FRAME is t, search all frames.\n\
2648 If FRAME is a frame, search only that frame.\n\
2649 If FRAME is nil, search only the selected frame\n\
2650 (actually the last nonminibuffer frame),\n\
2651 unless `pop-up-frames' is non-nil,\n\
2652 which means search visible and iconified frames.")
2653 (buffer, not_this_window, frame)
2654 register Lisp_Object buffer, not_this_window, frame;
2655 {
2656 register Lisp_Object window, tem, swp;
2657 struct frame *f;
2658
2659 swp = Qnil;
2660 buffer = Fget_buffer (buffer);
2661 CHECK_BUFFER (buffer, 0);
2662
2663 if (!NILP (Vdisplay_buffer_function))
2664 return call2 (Vdisplay_buffer_function, buffer, not_this_window);
2665
2666 if (NILP (not_this_window)
2667 && XBUFFER (XWINDOW (selected_window)->buffer) == XBUFFER (buffer))
2668 return display_buffer_1 (selected_window);
2669
2670 /* See if the user has specified this buffer should appear
2671 in the selected window. */
2672 if (NILP (not_this_window))
2673 {
2674 swp = Fsame_window_p (XBUFFER (buffer)->name);
2675 if (!NILP (swp) && !no_switch_window (selected_window))
2676 {
2677 Fswitch_to_buffer (buffer, Qnil);
2678 return display_buffer_1 (selected_window);
2679 }
2680 }
2681
2682 /* If pop_up_frames,
2683 look for a window showing BUFFER on any visible or iconified frame.
2684 Otherwise search only the current frame. */
2685 if (! NILP (frame))
2686 tem = frame;
2687 else if (pop_up_frames || last_nonminibuf_frame == 0)
2688 XSETFASTINT (tem, 0);
2689 else
2690 XSETFRAME (tem, last_nonminibuf_frame);
2691 window = Fget_buffer_window (buffer, tem);
2692 if (!NILP (window)
2693 && (NILP (not_this_window) || !EQ (window, selected_window)))
2694 {
2695 return display_buffer_1 (window);
2696 }
2697
2698 /* Certain buffer names get special handling. */
2699 if (!NILP (Vspecial_display_function) && NILP (swp))
2700 {
2701 tem = Fspecial_display_p (XBUFFER (buffer)->name);
2702 if (EQ (tem, Qt))
2703 return call1 (Vspecial_display_function, buffer);
2704 if (CONSP (tem))
2705 return call2 (Vspecial_display_function, buffer, tem);
2706 }
2707
2708 /* If there are no frames open that have more than a minibuffer,
2709 we need to create a new frame. */
2710 if (pop_up_frames || last_nonminibuf_frame == 0)
2711 {
2712 window = Fframe_selected_window (call0 (Vpop_up_frame_function));
2713 Fset_window_buffer (window, buffer);
2714 return display_buffer_1 (window);
2715 }
2716
2717 f = SELECTED_FRAME ();
2718 if (pop_up_windows
2719 || FRAME_MINIBUF_ONLY_P (f)
2720 /* If the current frame is a special display frame,
2721 don't try to reuse its windows. */
2722 || !NILP (XWINDOW (FRAME_ROOT_WINDOW (f))->dedicated))
2723 {
2724 Lisp_Object frames;
2725
2726 frames = Qnil;
2727 if (FRAME_MINIBUF_ONLY_P (f))
2728 XSETFRAME (frames, last_nonminibuf_frame);
2729 /* Don't try to create a window if would get an error */
2730 if (split_height_threshold < window_min_height << 1)
2731 split_height_threshold = window_min_height << 1;
2732
2733 /* Note that both Fget_largest_window and Fget_lru_window
2734 ignore minibuffers and dedicated windows.
2735 This means they can return nil. */
2736
2737 /* If the frame we would try to split cannot be split,
2738 try other frames. */
2739 if (FRAME_NO_SPLIT_P (NILP (frames) ? f : last_nonminibuf_frame))
2740 {
2741 /* Try visible frames first. */
2742 window = Fget_largest_window (Qvisible);
2743 /* If that didn't work, try iconified frames. */
2744 if (NILP (window))
2745 window = Fget_largest_window (make_number (0));
2746 if (NILP (window))
2747 window = Fget_largest_window (Qt);
2748 }
2749 else
2750 window = Fget_largest_window (frames);
2751
2752 /* If we got a tall enough full-width window that can be split,
2753 split it. */
2754 if (!NILP (window)
2755 && ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
2756 && window_height (window) >= split_height_threshold
2757 && WINDOW_FULL_WIDTH_P (XWINDOW (window)))
2758 window = Fsplit_window (window, Qnil, Qnil);
2759 else
2760 {
2761 Lisp_Object upper, lower, other;
2762
2763 window = Fget_lru_window (frames);
2764 /* If the LRU window is selected, and big enough,
2765 and can be split, split it. */
2766 if (!NILP (window)
2767 && ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
2768 && (EQ (window, selected_window)
2769 || EQ (XWINDOW (window)->parent, Qnil))
2770 && window_height (window) >= window_min_height << 1)
2771 window = Fsplit_window (window, Qnil, Qnil);
2772 /* If Fget_lru_window returned nil, try other approaches. */
2773
2774 /* Try visible frames first. */
2775 if (NILP (window))
2776 window = Fget_buffer_window (buffer, Qvisible);
2777 if (NILP (window))
2778 window = Fget_largest_window (Qvisible);
2779 /* If that didn't work, try iconified frames. */
2780 if (NILP (window))
2781 window = Fget_buffer_window (buffer, make_number (0));
2782 if (NILP (window))
2783 window = Fget_largest_window (make_number (0));
2784 /* Try invisible frames. */
2785 if (NILP (window))
2786 window = Fget_buffer_window (buffer, Qt);
2787 if (NILP (window))
2788 window = Fget_largest_window (Qt);
2789 /* As a last resort, make a new frame. */
2790 if (NILP (window))
2791 window = Fframe_selected_window (call0 (Vpop_up_frame_function));
2792 /* If window appears above or below another,
2793 even out their heights. */
2794 other = upper = lower = Qnil;
2795 if (!NILP (XWINDOW (window)->prev))
2796 other = upper = XWINDOW (window)->prev, lower = window;
2797 if (!NILP (XWINDOW (window)->next))
2798 other = lower = XWINDOW (window)->next, upper = window;
2799 if (!NILP (other)
2800 /* Check that OTHER and WINDOW are vertically arrayed. */
2801 && !EQ (XWINDOW (other)->top, XWINDOW (window)->top)
2802 && (XFASTINT (XWINDOW (other)->height)
2803 > XFASTINT (XWINDOW (window)->height)))
2804 {
2805 int total = (XFASTINT (XWINDOW (other)->height)
2806 + XFASTINT (XWINDOW (window)->height));
2807 enlarge_window (upper,
2808 total / 2 - XFASTINT (XWINDOW (upper)->height),
2809 0);
2810 }
2811 }
2812 }
2813 else
2814 window = Fget_lru_window (Qnil);
2815
2816 Fset_window_buffer (window, buffer);
2817 return display_buffer_1 (window);
2818 }
2819
2820 void
2821 temp_output_buffer_show (buf)
2822 register Lisp_Object buf;
2823 {
2824 register struct buffer *old = current_buffer;
2825 register Lisp_Object window;
2826 register struct window *w;
2827
2828 XBUFFER (buf)->directory = current_buffer->directory;
2829
2830 Fset_buffer (buf);
2831 BUF_SAVE_MODIFF (XBUFFER (buf)) = MODIFF;
2832 BEGV = BEG;
2833 ZV = Z;
2834 SET_PT (BEG);
2835 XBUFFER (buf)->prevent_redisplay_optimizations_p = 1;
2836 set_buffer_internal (old);
2837
2838 if (!EQ (Vtemp_buffer_show_function, Qnil))
2839 call1 (Vtemp_buffer_show_function, buf);
2840 else
2841 {
2842 window = Fdisplay_buffer (buf, Qnil, Qnil);
2843
2844 if (!EQ (XWINDOW (window)->frame, selected_frame))
2845 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
2846 Vminibuf_scroll_window = window;
2847 w = XWINDOW (window);
2848 XSETFASTINT (w->hscroll, 0);
2849 set_marker_restricted_both (w->start, buf, 1, 1);
2850 set_marker_restricted_both (w->pointm, buf, 1, 1);
2851
2852 /* Run temp-buffer-show-hook, with the chosen window selected
2853 and it sbuffer current. */
2854 if (!NILP (Vrun_hooks))
2855 {
2856 Lisp_Object tem;
2857 tem = Fboundp (Qtemp_buffer_show_hook);
2858 if (!NILP (tem))
2859 {
2860 tem = Fsymbol_value (Qtemp_buffer_show_hook);
2861 if (!NILP (tem))
2862 {
2863 int count = specpdl_ptr - specpdl;
2864 Lisp_Object prev_window;
2865 prev_window = selected_window;
2866
2867 /* Select the window that was chosen, for running the hook. */
2868 record_unwind_protect (Fselect_window, prev_window);
2869 select_window_1 (window, 0);
2870 Fset_buffer (w->buffer);
2871 call1 (Vrun_hooks, Qtemp_buffer_show_hook);
2872 select_window_1 (prev_window, 0);
2873 unbind_to (count, Qnil);
2874 }
2875 }
2876 }
2877 }
2878 }
2879 \f
2880 static void
2881 make_dummy_parent (window)
2882 Lisp_Object window;
2883 {
2884 Lisp_Object new;
2885 register struct window *o, *p;
2886 register struct Lisp_Vector *vec;
2887 int i;
2888
2889 o = XWINDOW (window);
2890 vec = allocate_vectorlike ((EMACS_INT)VECSIZE (struct window));
2891 for (i = 0; i < VECSIZE (struct window); ++i)
2892 vec->contents[i] = ((struct Lisp_Vector *)o)->contents[i];
2893 vec->size = VECSIZE (struct window);
2894 p = (struct window *)vec;
2895 XSETWINDOW (new, p);
2896
2897 XSETFASTINT (p->sequence_number, ++sequence_number);
2898
2899 /* Put new into window structure in place of window */
2900 replace_window (window, new);
2901
2902 o->next = Qnil;
2903 o->prev = Qnil;
2904 o->vchild = Qnil;
2905 o->hchild = Qnil;
2906 o->parent = new;
2907
2908 p->start = Qnil;
2909 p->pointm = Qnil;
2910 p->buffer = Qnil;
2911 }
2912
2913 DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
2914 "Split WINDOW, putting SIZE lines in the first of the pair.\n\
2915 WINDOW defaults to selected one and SIZE to half its size.\n\
2916 If optional third arg HORFLAG is non-nil, split side by side\n\
2917 and put SIZE columns in the first of the pair. In that case,\n\
2918 SIZE includes that window's scroll bar, or the divider column to its right.")
2919 (window, size, horflag)
2920 Lisp_Object window, size, horflag;
2921 {
2922 register Lisp_Object new;
2923 register struct window *o, *p;
2924 FRAME_PTR fo;
2925 register int size_int;
2926
2927 if (NILP (window))
2928 window = selected_window;
2929 else
2930 CHECK_LIVE_WINDOW (window, 0);
2931
2932 o = XWINDOW (window);
2933 fo = XFRAME (WINDOW_FRAME (o));
2934
2935 if (NILP (size))
2936 {
2937 if (!NILP (horflag))
2938 /* Calculate the size of the left-hand window, by dividing
2939 the usable space in columns by two.
2940 We round up, since the left-hand window may include
2941 a dividing line, while the right-hand may not. */
2942 size_int = (XFASTINT (o->width) + 1) >> 1;
2943 else
2944 size_int = XFASTINT (o->height) >> 1;
2945 }
2946 else
2947 {
2948 CHECK_NUMBER (size, 1);
2949 size_int = XINT (size);
2950 }
2951
2952 if (MINI_WINDOW_P (o))
2953 error ("Attempt to split minibuffer window");
2954 else if (window_fixed_size_p (o, !NILP (horflag), 0))
2955 error ("Attempt to split fixed-size window");
2956
2957 check_min_window_sizes ();
2958
2959 if (NILP (horflag))
2960 {
2961 if (size_int < window_min_height)
2962 error ("Window height %d too small (after splitting)", size_int);
2963 if (size_int + window_min_height > XFASTINT (o->height))
2964 error ("Window height %d too small (after splitting)",
2965 XFASTINT (o->height) - size_int);
2966 if (NILP (o->parent)
2967 || NILP (XWINDOW (o->parent)->vchild))
2968 {
2969 make_dummy_parent (window);
2970 new = o->parent;
2971 XWINDOW (new)->vchild = window;
2972 }
2973 }
2974 else
2975 {
2976 if (size_int < window_min_width)
2977 error ("Window width %d too small (after splitting)", size_int);
2978
2979 if (size_int + window_min_width > XFASTINT (o->width))
2980 error ("Window width %d too small (after splitting)",
2981 XFASTINT (o->width) - size_int);
2982 if (NILP (o->parent)
2983 || NILP (XWINDOW (o->parent)->hchild))
2984 {
2985 make_dummy_parent (window);
2986 new = o->parent;
2987 XWINDOW (new)->hchild = window;
2988 }
2989 }
2990
2991 /* Now we know that window's parent is a vertical combination
2992 if we are dividing vertically, or a horizontal combination
2993 if we are making side-by-side windows */
2994
2995 windows_or_buffers_changed++;
2996 FRAME_WINDOW_SIZES_CHANGED (fo) = 1;
2997 new = make_window ();
2998 p = XWINDOW (new);
2999
3000 p->frame = o->frame;
3001 p->next = o->next;
3002 if (!NILP (p->next))
3003 XWINDOW (p->next)->prev = new;
3004 p->prev = window;
3005 o->next = new;
3006 p->parent = o->parent;
3007 p->buffer = Qt;
3008 p->window_end_valid = Qnil;
3009 bzero (&p->last_cursor, sizeof p->last_cursor);
3010
3011 /* Apportion the available frame space among the two new windows */
3012
3013 if (!NILP (horflag))
3014 {
3015 p->height = o->height;
3016 p->top = o->top;
3017 XSETFASTINT (p->width, XFASTINT (o->width) - size_int);
3018 XSETFASTINT (o->width, size_int);
3019 XSETFASTINT (p->left, XFASTINT (o->left) + size_int);
3020 }
3021 else
3022 {
3023 p->left = o->left;
3024 p->width = o->width;
3025 XSETFASTINT (p->height, XFASTINT (o->height) - size_int);
3026 XSETFASTINT (o->height, size_int);
3027 XSETFASTINT (p->top, XFASTINT (o->top) + size_int);
3028 }
3029
3030 /* Adjust glyph matrices. */
3031 adjust_glyphs (fo);
3032 Fset_window_buffer (new, o->buffer);
3033 return new;
3034 }
3035 \f
3036 DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
3037 "Make current window ARG lines bigger.\n\
3038 From program, optional second arg non-nil means grow sideways ARG columns.")
3039 (arg, side)
3040 register Lisp_Object arg, side;
3041 {
3042 CHECK_NUMBER (arg, 0);
3043 enlarge_window (selected_window, XINT (arg), !NILP (side));
3044
3045 if (! NILP (Vwindow_configuration_change_hook))
3046 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
3047
3048 return Qnil;
3049 }
3050
3051 DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
3052 "Make current window ARG lines smaller.\n\
3053 From program, optional second arg non-nil means shrink sideways arg columns.")
3054 (arg, side)
3055 register Lisp_Object arg, side;
3056 {
3057 CHECK_NUMBER (arg, 0);
3058 enlarge_window (selected_window, -XINT (arg), !NILP (side));
3059
3060 if (! NILP (Vwindow_configuration_change_hook))
3061 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
3062
3063 return Qnil;
3064 }
3065
3066 int
3067 window_height (window)
3068 Lisp_Object window;
3069 {
3070 register struct window *p = XWINDOW (window);
3071 return XFASTINT (p->height);
3072 }
3073
3074 int
3075 window_width (window)
3076 Lisp_Object window;
3077 {
3078 register struct window *p = XWINDOW (window);
3079 return XFASTINT (p->width);
3080 }
3081
3082
3083 #define CURBEG(w) \
3084 *(widthflag ? (int *) &(XWINDOW (w)->left) : (int *) &(XWINDOW (w)->top))
3085
3086 #define CURSIZE(w) \
3087 *(widthflag ? (int *) &(XWINDOW (w)->width) : (int *) &(XWINDOW (w)->height))
3088
3089
3090 /* Enlarge selected_window by DELTA. WIDTHFLAG non-zero means
3091 increase its width. Siblings of the selected window are resized to
3092 fullfil the size request. If they become too small in the process,
3093 they will be deleted. */
3094
3095 static void
3096 enlarge_window (window, delta, widthflag)
3097 Lisp_Object window;
3098 int delta, widthflag;
3099 {
3100 Lisp_Object parent, next, prev;
3101 struct window *p;
3102 int *sizep, maximum;
3103 int (*sizefun) P_ ((Lisp_Object))
3104 = widthflag ? window_width : window_height;
3105 void (*setsizefun) P_ ((Lisp_Object, int, int))
3106 = (widthflag ? set_window_width : set_window_height);
3107
3108 /* Check values of window_min_width and window_min_height for
3109 validity. */
3110 check_min_window_sizes ();
3111
3112 /* Give up if this window cannot be resized. */
3113 if (window_fixed_size_p (XWINDOW (window), widthflag, 1))
3114 error ("Window is not resizable");
3115
3116 /* Find the parent of the selected window. */
3117 while (1)
3118 {
3119 p = XWINDOW (window);
3120 parent = p->parent;
3121
3122 if (NILP (parent))
3123 {
3124 if (widthflag)
3125 error ("No other window to side of this one");
3126 break;
3127 }
3128
3129 if (widthflag
3130 ? !NILP (XWINDOW (parent)->hchild)
3131 : !NILP (XWINDOW (parent)->vchild))
3132 break;
3133
3134 window = parent;
3135 }
3136
3137 sizep = &CURSIZE (window);
3138
3139 {
3140 register int maxdelta;
3141
3142 maxdelta = (!NILP (parent) ? (*sizefun) (parent) - *sizep
3143 : !NILP (p->next) ? ((*sizefun) (p->next)
3144 - window_min_size (XWINDOW (p->next),
3145 widthflag, 0, 0))
3146 : !NILP (p->prev) ? ((*sizefun) (p->prev)
3147 - window_min_size (XWINDOW (p->prev),
3148 widthflag, 0, 0))
3149 /* This is a frame with only one window, a minibuffer-only
3150 or a minibufferless frame. */
3151 : (delta = 0));
3152
3153 if (delta > maxdelta)
3154 /* This case traps trying to make the minibuffer
3155 the full frame, or make the only window aside from the
3156 minibuffer the full frame. */
3157 delta = maxdelta;
3158 }
3159
3160 if (*sizep + delta < window_min_size (XWINDOW (window), widthflag, 0, 0))
3161 {
3162 delete_window (window);
3163 return;
3164 }
3165
3166 if (delta == 0)
3167 return;
3168
3169 /* Find the total we can get from other siblings. */
3170 maximum = 0;
3171 for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
3172 maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
3173 widthflag, 0, 0);
3174 for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
3175 maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
3176 widthflag, 0, 0);
3177
3178 /* If we can get it all from them, do so. */
3179 if (delta <= maximum)
3180 {
3181 Lisp_Object first_unaffected;
3182 Lisp_Object first_affected;
3183 int fixed_p;
3184
3185 next = p->next;
3186 prev = p->prev;
3187 first_affected = window;
3188 /* Look at one sibling at a time,
3189 moving away from this window in both directions alternately,
3190 and take as much as we can get without deleting that sibling. */
3191 while (delta != 0 && (!NILP (next) || !NILP (prev)))
3192 {
3193 if (! NILP (next))
3194 {
3195 int this_one = ((*sizefun) (next)
3196 - window_min_size (XWINDOW (next),
3197 widthflag, 0, &fixed_p));
3198 if (!fixed_p)
3199 {
3200 if (this_one > delta)
3201 this_one = delta;
3202
3203 (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
3204 (*setsizefun) (window, *sizep + this_one, 0);
3205
3206 delta -= this_one;
3207 }
3208
3209 next = XWINDOW (next)->next;
3210 }
3211
3212 if (delta == 0)
3213 break;
3214
3215 if (! NILP (prev))
3216 {
3217 int this_one = ((*sizefun) (prev)
3218 - window_min_size (XWINDOW (prev),
3219 widthflag, 0, &fixed_p));
3220 if (!fixed_p)
3221 {
3222 if (this_one > delta)
3223 this_one = delta;
3224
3225 first_affected = prev;
3226
3227 (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
3228 (*setsizefun) (window, *sizep + this_one, 0);
3229
3230 delta -= this_one;
3231 }
3232
3233 prev = XWINDOW (prev)->prev;
3234 }
3235 }
3236
3237 xassert (delta == 0);
3238
3239 /* Now recalculate the edge positions of all the windows affected,
3240 based on the new sizes. */
3241 first_unaffected = next;
3242 prev = first_affected;
3243 for (next = XWINDOW (prev)->next; ! EQ (next, first_unaffected);
3244 prev = next, next = XWINDOW (next)->next)
3245 {
3246 CURBEG (next) = CURBEG (prev) + (*sizefun) (prev);
3247 /* This does not change size of NEXT,
3248 but it propagates the new top edge to its children */
3249 (*setsizefun) (next, (*sizefun) (next), 0);
3250 }
3251 }
3252 else
3253 {
3254 register int delta1;
3255 register int opht = (*sizefun) (parent);
3256
3257 /* If trying to grow this window to or beyond size of the parent,
3258 make delta1 so big that, on shrinking back down,
3259 all the siblings end up with less than one line and are deleted. */
3260 if (opht <= *sizep + delta)
3261 delta1 = opht * opht * 2;
3262 else
3263 {
3264 /* Otherwise, make delta1 just right so that if we add
3265 delta1 lines to this window and to the parent, and then
3266 shrink the parent back to its original size, the new
3267 proportional size of this window will increase by delta.
3268
3269 The function size_window will compute the new height h'
3270 of the window from delta1 as:
3271
3272 e = delta1/n
3273 x = delta1 - delta1/n * n for the 1st resizable child
3274 h' = h + e + x
3275
3276 where n is the number of children that can be resized.
3277 We can ignore x by choosing a delta1 that is a multiple of
3278 n. We want the height of this window to come out as
3279
3280 h' = h + delta
3281
3282 So, delta1 must be
3283
3284 h + e = h + delta
3285 delta1/n = delta
3286 delta1 = n * delta.
3287
3288 The number of children n rquals the number of resizable
3289 children of this window + 1 because we know window itself
3290 is resizable (otherwise we would have signalled an error. */
3291
3292 struct window *w = XWINDOW (window);
3293 Lisp_Object s;
3294 int n = 1;
3295
3296 for (s = w->next; !NILP (s); s = XWINDOW (s)->next)
3297 if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
3298 ++n;
3299 for (s = w->prev; !NILP (s); s = XWINDOW (s)->prev)
3300 if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
3301 ++n;
3302
3303 delta1 = n * delta;
3304 }
3305
3306 /* Add delta1 lines or columns to this window, and to the parent,
3307 keeping things consistent while not affecting siblings. */
3308 CURSIZE (parent) = opht + delta1;
3309 (*setsizefun) (window, *sizep + delta1, 0);
3310
3311 /* Squeeze out delta1 lines or columns from our parent,
3312 shriking this window and siblings proportionately.
3313 This brings parent back to correct size.
3314 Delta1 was calculated so this makes this window the desired size,
3315 taking it all out of the siblings. */
3316 (*setsizefun) (parent, opht, 0);
3317 }
3318
3319 XSETFASTINT (p->last_modified, 0);
3320 XSETFASTINT (p->last_overlay_modified, 0);
3321
3322 /* Adjust glyph matrices. */
3323 adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
3324 }
3325
3326 #undef CURBEG
3327 #undef CURSIZE
3328
3329
3330 \f
3331 /***********************************************************************
3332 Resizing Mini-Windows
3333 ***********************************************************************/
3334
3335 static void shrink_window_lowest_first P_ ((struct window *, int));
3336
3337 enum save_restore_action
3338 {
3339 CHECK_ORIG_SIZES,
3340 SAVE_ORIG_SIZES,
3341 RESTORE_ORIG_SIZES
3342 };
3343
3344 static int save_restore_orig_size P_ ((struct window *,
3345 enum save_restore_action));
3346
3347 /* Shrink windows rooted in window W to HEIGHT. Take the space needed
3348 from lowest windows first. */
3349
3350 static void
3351 shrink_window_lowest_first (w, height)
3352 struct window *w;
3353 int height;
3354 {
3355 struct window *c;
3356 Lisp_Object child;
3357 int old_height;
3358
3359 xassert (!MINI_WINDOW_P (w));
3360
3361 /* Set redisplay hints. */
3362 XSETFASTINT (w->last_modified, 0);
3363 XSETFASTINT (w->last_overlay_modified, 0);
3364 windows_or_buffers_changed++;
3365 FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
3366
3367 old_height = XFASTINT (w->height);
3368 XSETFASTINT (w->height, height);
3369
3370 if (!NILP (w->hchild))
3371 {
3372 for (child = w->hchild; !NILP (child); child = c->next)
3373 {
3374 c = XWINDOW (child);
3375 c->top = w->top;
3376 shrink_window_lowest_first (c, height);
3377 }
3378 }
3379 else if (!NILP (w->vchild))
3380 {
3381 Lisp_Object last_child;
3382 int delta = old_height - height;
3383 int last_top;
3384
3385 /* Find the last child. We are taking space from lowest windows
3386 first, so we iterate over children from the last child
3387 backwards. */
3388 for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
3389 last_child = child;
3390
3391 /* Assign new heights. We leave only MIN_SAFE_WINDOW_HEIGHT. */
3392 for (child = last_child; delta && !NILP (child); child = c->prev)
3393 {
3394 int this_one;
3395
3396 c = XWINDOW (child);
3397 this_one = XFASTINT (c->height) - MIN_SAFE_WINDOW_HEIGHT;
3398
3399 if (this_one > delta)
3400 this_one = delta;
3401
3402 shrink_window_lowest_first (c, XFASTINT (c->height) - this_one);
3403 delta -= this_one;
3404 }
3405
3406 /* Compute new positions. */
3407 last_top = w->top;
3408 for (child = w->vchild; !NILP (child); child = c->next)
3409 {
3410 c = XWINDOW (child);
3411 c->top = make_number (last_top);
3412 shrink_window_lowest_first (c, XFASTINT (c->height));
3413 last_top += XFASTINT (c->height);
3414 }
3415 }
3416 }
3417
3418
3419 /* Save, restore, or check positions and sizes in the window tree
3420 rooted at W. ACTION says what to do.
3421
3422 If ACTION is CHECK_ORIG_SIZES, check if orig_top and orig_height
3423 members are valid for all windows in the window tree. Value is
3424 non-zero if they are valid.
3425
3426 If ACTION is SAVE_ORIG_SIZES, save members top and height in
3427 orig_top and orig_height for all windows in the tree.
3428
3429 If ACTION is RESTORE_ORIG_SIZES, restore top and height from
3430 values stored in orig_top and orig_height for all windows. */
3431
3432 static int
3433 save_restore_orig_size (w, action)
3434 struct window *w;
3435 enum save_restore_action action;
3436 {
3437 int success_p = 1;
3438
3439 while (w)
3440 {
3441 if (!NILP (w->hchild))
3442 {
3443 if (!save_restore_orig_size (XWINDOW (w->hchild), action))
3444 success_p = 0;
3445 }
3446 else if (!NILP (w->vchild))
3447 {
3448 if (!save_restore_orig_size (XWINDOW (w->vchild), action))
3449 success_p = 0;
3450 }
3451
3452 switch (action)
3453 {
3454 case CHECK_ORIG_SIZES:
3455 if (!INTEGERP (w->orig_top) || !INTEGERP (w->orig_height))
3456 return 0;
3457 break;
3458
3459 case SAVE_ORIG_SIZES:
3460 w->orig_top = w->top;
3461 w->orig_height = w->height;
3462 XSETFASTINT (w->last_modified, 0);
3463 XSETFASTINT (w->last_overlay_modified, 0);
3464 break;
3465
3466 case RESTORE_ORIG_SIZES:
3467 xassert (INTEGERP (w->orig_top) && INTEGERP (w->orig_height));
3468 w->top = w->orig_top;
3469 w->height = w->orig_height;
3470 w->orig_height = w->orig_top = Qnil;
3471 XSETFASTINT (w->last_modified, 0);
3472 XSETFASTINT (w->last_overlay_modified, 0);
3473 break;
3474
3475 default:
3476 abort ();
3477 }
3478
3479 w = NILP (w->next) ? NULL : XWINDOW (w->next);
3480 }
3481
3482 return success_p;
3483 }
3484
3485
3486 /* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we can
3487 without deleting other windows. */
3488
3489 void
3490 grow_mini_window (w, delta)
3491 struct window *w;
3492 int delta;
3493 {
3494 struct frame *f = XFRAME (w->frame);
3495 struct window *root;
3496
3497 xassert (MINI_WINDOW_P (w));
3498 xassert (delta >= 0);
3499
3500 /* Check values of window_min_width and window_min_height for
3501 validity. */
3502 check_min_window_sizes ();
3503
3504 /* Compute how much we can enlarge the mini-window without deleting
3505 other windows. */
3506 root = XWINDOW (FRAME_ROOT_WINDOW (f));
3507 if (delta)
3508 {
3509 int min_height = window_min_size (root, 0, 0, 0);
3510 if (XFASTINT (root->height) - delta < min_height)
3511 delta = XFASTINT (root->height) - min_height;
3512 }
3513
3514 if (delta)
3515 {
3516 /* Save original window sizes and positions, if not already done. */
3517 if (!save_restore_orig_size (root, CHECK_ORIG_SIZES))
3518 save_restore_orig_size (root, SAVE_ORIG_SIZES);
3519
3520 /* Shrink other windows. */
3521 shrink_window_lowest_first (root, XFASTINT (root->height) - delta);
3522
3523 /* Grow the mini-window. */
3524 w->top = make_number (XFASTINT (root->top) + XFASTINT (root)->height);
3525 w->height = make_number (XFASTINT (w->height) + delta);
3526 XSETFASTINT (w->last_modified, 0);
3527 XSETFASTINT (w->last_overlay_modified, 0);
3528
3529 adjust_glyphs (f);
3530 }
3531 }
3532
3533
3534 /* Shrink mini-window W. If there is recorded info about window sizes
3535 before a call to grow_mini_window, restore recorded window sizes.
3536 Otherwise, if the mini-window is higher than 1 line, resize it to 1
3537 line. */
3538
3539 void
3540 shrink_mini_window (w)
3541 struct window *w;
3542 {
3543 struct frame *f = XFRAME (w->frame);
3544 struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
3545
3546 if (save_restore_orig_size (root, CHECK_ORIG_SIZES))
3547 {
3548 save_restore_orig_size (root, RESTORE_ORIG_SIZES);
3549 adjust_glyphs (f);
3550 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
3551 windows_or_buffers_changed = 1;
3552 }
3553 else if (XFASTINT (w->height) > 1)
3554 {
3555 Lisp_Object window;
3556 XSETWINDOW (window, w);
3557 enlarge_window (window, 1 - XFASTINT (w->height), 0);
3558 }
3559 }
3560
3561
3562 \f
3563 /* Mark window cursors off for all windows in the window tree rooted
3564 at W by setting their phys_cursor_on_p flag to zero. Called from
3565 xterm.c, e.g. when a frame is cleared and thereby all cursors on
3566 the frame are cleared. */
3567
3568 void
3569 mark_window_cursors_off (w)
3570 struct window *w;
3571 {
3572 while (w)
3573 {
3574 if (!NILP (w->hchild))
3575 mark_window_cursors_off (XWINDOW (w->hchild));
3576 else if (!NILP (w->vchild))
3577 mark_window_cursors_off (XWINDOW (w->vchild));
3578 else
3579 w->phys_cursor_on_p = 0;
3580
3581 w = NILP (w->next) ? 0 : XWINDOW (w->next);
3582 }
3583 }
3584
3585
3586 /* Return number of lines of text (not counting mode line) in W. */
3587
3588 int
3589 window_internal_height (w)
3590 struct window *w;
3591 {
3592 int ht = XFASTINT (w->height);
3593
3594 if (MINI_WINDOW_P (w))
3595 return ht;
3596
3597 if (!NILP (w->parent) || !NILP (w->vchild) || !NILP (w->hchild)
3598 || !NILP (w->next) || !NILP (w->prev)
3599 || FRAME_WANTS_MODELINE_P (XFRAME (WINDOW_FRAME (w))))
3600 return ht - 1;
3601
3602 return ht;
3603 }
3604
3605
3606 /* Return the number of columns in W.
3607 Don't count columns occupied by scroll bars or the vertical bar
3608 separating W from the sibling to its right. */
3609
3610 int
3611 window_internal_width (w)
3612 struct window *w;
3613 {
3614 struct frame *f = XFRAME (WINDOW_FRAME (w));
3615 int width = XINT (w->width);
3616
3617 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
3618 /* Scroll bars occupy a few columns. */
3619 width -= FRAME_SCROLL_BAR_COLS (f);
3620 else if (!WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
3621 /* The column of `|' characters separating side-by-side windows
3622 occupies one column only. */
3623 width -= 1;
3624
3625 /* On window-systems, areas to the left and right of the window
3626 are used to display bitmaps there. */
3627 if (FRAME_WINDOW_P (f))
3628 width -= FRAME_FLAGS_AREA_COLS (f);
3629
3630 return width;
3631 }
3632
3633 \f
3634 /************************************************************************
3635 Window Scrolling
3636 ***********************************************************************/
3637
3638 /* Scroll contents of window WINDOW up. If WHOLE is non-zero, scroll
3639 one screen-full, which is defined as the height of the window minus
3640 next_screen_context_lines. If WHOLE is zero, scroll up N lines
3641 instead. Negative values of N mean scroll down. NOERROR non-zero
3642 means don't signal an error if we try to move over BEGV or ZV,
3643 respectively. */
3644
3645 static void
3646 window_scroll (window, n, whole, noerror)
3647 Lisp_Object window;
3648 int n;
3649 int whole;
3650 int noerror;
3651 {
3652 /* If we must, use the pixel-based version which is much slower than
3653 the line-based one but can handle varying line heights. */
3654 if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
3655 window_scroll_pixel_based (window, n, whole, noerror);
3656 else
3657 window_scroll_line_based (window, n, whole, noerror);
3658 }
3659
3660
3661 /* Implementation of window_scroll that works based on pixel line
3662 heights. See the comment of window_scroll for parameter
3663 descriptions. */
3664
3665 static void
3666 window_scroll_pixel_based (window, n, whole, noerror)
3667 Lisp_Object window;
3668 int n;
3669 int whole;
3670 int noerror;
3671 {
3672 struct it it;
3673 struct window *w = XWINDOW (window);
3674 struct text_pos start;
3675 Lisp_Object tem;
3676 int this_scroll_margin;
3677 int preserve_y;
3678
3679 SET_TEXT_POS_FROM_MARKER (start, w->start);
3680
3681 /* If PT is not visible in WINDOW, move back one half of
3682 the screen. */
3683 XSETFASTINT (tem, PT);
3684 tem = Fpos_visible_in_window_p (tem, window);
3685 if (NILP (tem))
3686 {
3687 /* Move backward half the height of the window. Performance note:
3688 vmotion used here is about 10% faster, but would give wrong
3689 results for variable height lines. */
3690 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
3691 it.current_y = it.last_visible_y;
3692 move_it_vertically (&it, -it.last_visible_y / 2);
3693
3694 /* The function move_iterator_vertically may move over more than
3695 the specified y-distance. If it->w is small, e.g. a
3696 mini-buffer window, we may end up in front of the window's
3697 display area. This is the case when Start displaying at the
3698 start of the line containing PT in this case. */
3699 if (it.current_y <= 0)
3700 {
3701 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
3702 move_it_vertically (&it, 0);
3703 it.current_y = 0;
3704 }
3705
3706 start = it.current.pos;
3707 }
3708
3709 /* If scroll_preserve_screen_position is non-zero, we try to set
3710 point in the same window line as it is now, so get that line. */
3711 if (!NILP (Vscroll_preserve_screen_position))
3712 {
3713 start_display (&it, w, start);
3714 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
3715 preserve_y = it.current_y;
3716 }
3717 else
3718 preserve_y = -1;
3719
3720 /* Move iterator it from start the specified distance forward or
3721 backward. The result is the new window start. */
3722 start_display (&it, w, start);
3723 if (whole)
3724 {
3725 int screen_full = (it.last_visible_y
3726 - next_screen_context_lines * CANON_Y_UNIT (it.f));
3727 int direction = n < 0 ? -1 : 1;
3728 move_it_vertically (&it, direction * screen_full);
3729 }
3730 else
3731 move_it_by_lines (&it, n, 1);
3732
3733 /* End if we end up at ZV or BEGV. */
3734 if ((n > 0 && IT_CHARPOS (it) == ZV)
3735 || (n < 0 && IT_CHARPOS (it) == CHARPOS (start)))
3736 {
3737 if (noerror)
3738 return;
3739 else if (IT_CHARPOS (it) == ZV)
3740 Fsignal (Qend_of_buffer, Qnil);
3741 else
3742 Fsignal (Qbeginning_of_buffer, Qnil);
3743 }
3744
3745 /* Set the window start, and set up the window for redisplay. */
3746 set_marker_restricted (w->start, make_number (IT_CHARPOS (it)), w->buffer);
3747 w->start_at_line_beg = Fbolp ();
3748 w->update_mode_line = Qt;
3749 XSETFASTINT (w->last_modified, 0);
3750 XSETFASTINT (w->last_overlay_modified, 0);
3751 /* Set force_start so that redisplay_window will run the
3752 window-scroll-functions. */
3753 w->force_start = Qt;
3754
3755 it.current_y = it.vpos = 0;
3756
3757 /* Preserve the screen position if we must. */
3758 if (preserve_y >= 0)
3759 {
3760 move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
3761 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
3762 }
3763 else
3764 {
3765 /* Move PT out of scroll margins. */
3766 this_scroll_margin = max (0, scroll_margin);
3767 this_scroll_margin = min (this_scroll_margin, XFASTINT (w->height) / 4);
3768 this_scroll_margin *= CANON_Y_UNIT (it.f);
3769
3770 if (n > 0)
3771 {
3772 /* We moved the window start towards ZV, so PT may be now
3773 in the scroll margin at the top. */
3774 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
3775 while (it.current_y < this_scroll_margin)
3776 move_it_by_lines (&it, 1, 1);
3777 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
3778 }
3779 else if (n < 0)
3780 {
3781 /* We moved the window start towards BEGV, so PT may be now
3782 in the scroll margin at the bottom. */
3783 move_it_to (&it, PT, -1,
3784 it.last_visible_y - this_scroll_margin - 1, -1,
3785 MOVE_TO_POS | MOVE_TO_Y);
3786
3787 /* Don't put point on a partially visible line at the end. */
3788 if (it.current_y + it.max_ascent + it.max_descent
3789 > it.last_visible_y)
3790 move_it_by_lines (&it, -1, 0);
3791
3792 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
3793 }
3794 }
3795 }
3796
3797
3798 /* Implementation of window_scroll that works based on screen lines.
3799 See the comment of window_scroll for parameter descriptions. */
3800
3801 static void
3802 window_scroll_line_based (window, n, whole, noerror)
3803 Lisp_Object window;
3804 int n;
3805 int whole;
3806 int noerror;
3807 {
3808 register struct window *w = XWINDOW (window);
3809 register int opoint = PT, opoint_byte = PT_BYTE;
3810 register int pos, pos_byte;
3811 register int ht = window_internal_height (w);
3812 register Lisp_Object tem;
3813 int lose;
3814 Lisp_Object bolp;
3815 int startpos;
3816 struct position posit;
3817 int original_vpos;
3818
3819 startpos = marker_position (w->start);
3820
3821 posit = *compute_motion (startpos, 0, 0, 0,
3822 PT, ht, 0,
3823 window_internal_width (w), XINT (w->hscroll),
3824 0, w);
3825 original_vpos = posit.vpos;
3826
3827 XSETFASTINT (tem, PT);
3828 tem = Fpos_visible_in_window_p (tem, window);
3829
3830 if (NILP (tem))
3831 {
3832 Fvertical_motion (make_number (- (ht / 2)), window);
3833 startpos = PT;
3834 }
3835
3836 SET_PT (startpos);
3837 lose = n < 0 && PT == BEGV;
3838 Fvertical_motion (make_number (n), window);
3839 pos = PT;
3840 pos_byte = PT_BYTE;
3841 bolp = Fbolp ();
3842 SET_PT_BOTH (opoint, opoint_byte);
3843
3844 if (lose)
3845 {
3846 if (noerror)
3847 return;
3848 else
3849 Fsignal (Qbeginning_of_buffer, Qnil);
3850 }
3851
3852 if (pos < ZV)
3853 {
3854 int this_scroll_margin = scroll_margin;
3855
3856 /* Don't use a scroll margin that is negative or too large. */
3857 if (this_scroll_margin < 0)
3858 this_scroll_margin = 0;
3859
3860 if (XINT (w->height) < 4 * scroll_margin)
3861 this_scroll_margin = XINT (w->height) / 4;
3862
3863 set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
3864 w->start_at_line_beg = bolp;
3865 w->update_mode_line = Qt;
3866 XSETFASTINT (w->last_modified, 0);
3867 XSETFASTINT (w->last_overlay_modified, 0);
3868 /* Set force_start so that redisplay_window will run
3869 the window-scroll-functions. */
3870 w->force_start = Qt;
3871
3872 if (whole && !NILP (Vscroll_preserve_screen_position))
3873 {
3874 SET_PT_BOTH (pos, pos_byte);
3875 Fvertical_motion (make_number (original_vpos), window);
3876 }
3877 /* If we scrolled forward, put point enough lines down
3878 that it is outside the scroll margin. */
3879 else if (n > 0)
3880 {
3881 int top_margin;
3882
3883 if (this_scroll_margin > 0)
3884 {
3885 SET_PT_BOTH (pos, pos_byte);
3886 Fvertical_motion (make_number (this_scroll_margin), window);
3887 top_margin = PT;
3888 }
3889 else
3890 top_margin = pos;
3891
3892 if (top_margin <= opoint)
3893 SET_PT_BOTH (opoint, opoint_byte);
3894 else if (!NILP (Vscroll_preserve_screen_position))
3895 {
3896 SET_PT_BOTH (pos, pos_byte);
3897 Fvertical_motion (make_number (original_vpos), window);
3898 }
3899 else
3900 SET_PT (top_margin);
3901 }
3902 else if (n < 0)
3903 {
3904 int bottom_margin;
3905
3906 /* If we scrolled backward, put point near the end of the window
3907 but not within the scroll margin. */
3908 SET_PT_BOTH (pos, pos_byte);
3909 tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
3910 if (XFASTINT (tem) == ht - this_scroll_margin)
3911 bottom_margin = PT;
3912 else
3913 bottom_margin = PT + 1;
3914
3915 if (bottom_margin > opoint)
3916 SET_PT_BOTH (opoint, opoint_byte);
3917 else
3918 {
3919 if (!NILP (Vscroll_preserve_screen_position))
3920 {
3921 SET_PT_BOTH (pos, pos_byte);
3922 Fvertical_motion (make_number (original_vpos), window);
3923 }
3924 else
3925 Fvertical_motion (make_number (-1), window);
3926 }
3927 }
3928 }
3929 else
3930 {
3931 if (noerror)
3932 return;
3933 else
3934 Fsignal (Qend_of_buffer, Qnil);
3935 }
3936 }
3937
3938
3939 /* Scroll selected_window up or down. If N is nil, scroll a
3940 screen-full which is defined as the height of the window minus
3941 next_screen_context_lines. If N is the symbol `-', scroll.
3942 DIRECTION may be 1 meaning to scroll down, or -1 meaning to scroll
3943 up. This is the guts of Fscroll_up and Fscroll_down. */
3944
3945 static void
3946 scroll_command (n, direction)
3947 Lisp_Object n;
3948 int direction;
3949 {
3950 register int defalt;
3951 int count = specpdl_ptr - specpdl;
3952
3953 xassert (abs (direction) == 1);
3954
3955 /* If selected window's buffer isn't current, make it current for
3956 the moment. But don't screw up if window_scroll gets an error. */
3957 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
3958 {
3959 record_unwind_protect (save_excursion_restore, save_excursion_save ());
3960 Fset_buffer (XWINDOW (selected_window)->buffer);
3961
3962 /* Make redisplay consider other windows than just selected_window. */
3963 ++windows_or_buffers_changed;
3964 }
3965
3966 defalt = (window_internal_height (XWINDOW (selected_window))
3967 - next_screen_context_lines);
3968 defalt = direction * (defalt < 1 ? 1 : defalt);
3969
3970 if (NILP (n))
3971 window_scroll (selected_window, defalt, 1, 0);
3972 else if (EQ (n, Qminus))
3973 window_scroll (selected_window, - defalt, 1, 0);
3974 else
3975 {
3976 n = Fprefix_numeric_value (n);
3977 window_scroll (selected_window, XINT (n) * direction, 0, 0);
3978 }
3979
3980 unbind_to (count, Qnil);
3981 }
3982
3983 DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
3984 "Scroll text of current window upward ARG lines; or near full screen if no ARG.\n\
3985 A near full screen is `next-screen-context-lines' less than a full screen.\n\
3986 Negative ARG means scroll downward.\n\
3987 If ARG is the atom `-', scroll downward by nearly full screen.\n\
3988 When calling from a program, supply as argument a number, nil, or `-'.")
3989 (arg)
3990 Lisp_Object arg;
3991 {
3992 scroll_command (arg, 1);
3993 return Qnil;
3994 }
3995
3996 DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
3997 "Scroll text of current window down ARG lines; or near full screen if no ARG.\n\
3998 A near full screen is `next-screen-context-lines' less than a full screen.\n\
3999 Negative ARG means scroll upward.\n\
4000 If ARG is the atom `-', scroll upward by nearly full screen.\n\
4001 When calling from a program, supply as argument a number, nil, or `-'.")
4002 (arg)
4003 Lisp_Object arg;
4004 {
4005 scroll_command (arg, -1);
4006 return Qnil;
4007 }
4008 \f
4009 DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0,
4010 "Return the other window for \"other window scroll\" commands.\n\
4011 If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
4012 specifies the window.\n\
4013 If `other-window-scroll-buffer' is non-nil, a window\n\
4014 showing that buffer is used.")
4015 ()
4016 {
4017 Lisp_Object window;
4018
4019 if (MINI_WINDOW_P (XWINDOW (selected_window))
4020 && !NILP (Vminibuf_scroll_window))
4021 window = Vminibuf_scroll_window;
4022 /* If buffer is specified, scroll that buffer. */
4023 else if (!NILP (Vother_window_scroll_buffer))
4024 {
4025 window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
4026 if (NILP (window))
4027 window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt, Qnil);
4028 }
4029 else
4030 {
4031 /* Nothing specified; look for a neighboring window on the same
4032 frame. */
4033 window = Fnext_window (selected_window, Qnil, Qnil);
4034
4035 if (EQ (window, selected_window))
4036 /* That didn't get us anywhere; look for a window on another
4037 visible frame. */
4038 do
4039 window = Fnext_window (window, Qnil, Qt);
4040 while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
4041 && ! EQ (window, selected_window));
4042 }
4043
4044 CHECK_LIVE_WINDOW (window, 0);
4045
4046 if (EQ (window, selected_window))
4047 error ("There is no other window");
4048
4049 return window;
4050 }
4051
4052 DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
4053 "Scroll next window upward ARG lines; or near full screen if no ARG.\n\
4054 A near full screen is `next-screen-context-lines' less than a full screen.\n\
4055 The next window is the one below the current one; or the one at the top\n\
4056 if the current one is at the bottom. Negative ARG means scroll downward.\n\
4057 If ARG is the atom `-', scroll downward by nearly full screen.\n\
4058 When calling from a program, supply as argument a number, nil, or `-'.\n\
4059 \n\
4060 If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
4061 specifies the window to scroll.\n\
4062 If `other-window-scroll-buffer' is non-nil, scroll the window\n\
4063 showing that buffer, popping the buffer up if necessary.")
4064 (arg)
4065 register Lisp_Object arg;
4066 {
4067 register Lisp_Object window;
4068 register int defalt;
4069 register struct window *w;
4070 register int count = specpdl_ptr - specpdl;
4071
4072 window = Fother_window_for_scrolling ();
4073
4074 w = XWINDOW (window);
4075 defalt = window_internal_height (w) - next_screen_context_lines;
4076 if (defalt < 1) defalt = 1;
4077
4078 /* Don't screw up if window_scroll gets an error. */
4079 record_unwind_protect (save_excursion_restore, save_excursion_save ());
4080 ++windows_or_buffers_changed;
4081
4082 Fset_buffer (w->buffer);
4083 SET_PT (marker_position (w->pointm));
4084
4085 if (NILP (arg))
4086 window_scroll (window, defalt, 1, 1);
4087 else if (EQ (arg, Qminus))
4088 window_scroll (window, -defalt, 1, 1);
4089 else
4090 {
4091 if (CONSP (arg))
4092 arg = Fcar (arg);
4093 CHECK_NUMBER (arg, 0);
4094 window_scroll (window, XINT (arg), 0, 1);
4095 }
4096
4097 set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
4098 unbind_to (count, Qnil);
4099
4100 return Qnil;
4101 }
4102 \f
4103 DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 1, "P",
4104 "Scroll selected window display ARG columns left.\n\
4105 Default for ARG is window width minus 2.")
4106 (arg)
4107 register Lisp_Object arg;
4108 {
4109
4110 if (NILP (arg))
4111 XSETFASTINT (arg, window_internal_width (XWINDOW (selected_window)) - 2);
4112 else
4113 arg = Fprefix_numeric_value (arg);
4114
4115 return
4116 Fset_window_hscroll (selected_window,
4117 make_number (XINT (XWINDOW (selected_window)->hscroll)
4118 + XINT (arg)));
4119 }
4120
4121 DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 1, "P",
4122 "Scroll selected window display ARG columns right.\n\
4123 Default for ARG is window width minus 2.")
4124 (arg)
4125 register Lisp_Object arg;
4126 {
4127 if (NILP (arg))
4128 XSETFASTINT (arg, window_internal_width (XWINDOW (selected_window)) - 2);
4129 else
4130 arg = Fprefix_numeric_value (arg);
4131
4132 return
4133 Fset_window_hscroll (selected_window,
4134 make_number (XINT (XWINDOW (selected_window)->hscroll)
4135 - XINT (arg)));
4136 }
4137
4138 DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
4139 "Center point in window and redisplay frame. With ARG, put point on line ARG.\n\
4140 The desired position of point is always relative to the current window.\n\
4141 Just C-u as prefix means put point in the center of the window.\n\
4142 If ARG is omitted or nil, erases the entire frame and then\n\
4143 redraws with point in the center of the current window.")
4144 (arg)
4145 register Lisp_Object arg;
4146 {
4147 register struct window *w = XWINDOW (selected_window);
4148 register int ht = window_internal_height (w);
4149 struct position pos;
4150 struct buffer *buf = XBUFFER (w->buffer);
4151 struct buffer *obuf = current_buffer;
4152
4153 if (NILP (arg))
4154 {
4155 extern int frame_garbaged;
4156
4157 Fredraw_frame (w->frame);
4158 SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
4159 XSETFASTINT (arg, ht / 2);
4160 }
4161 else if (CONSP (arg)) /* Just C-u. */
4162 {
4163 XSETFASTINT (arg, ht / 2);
4164 }
4165 else
4166 {
4167 arg = Fprefix_numeric_value (arg);
4168 CHECK_NUMBER (arg, 0);
4169 }
4170
4171 if (XINT (arg) < 0)
4172 XSETINT (arg, XINT (arg) + ht);
4173
4174 set_buffer_internal (buf);
4175 pos = *vmotion (PT, - XINT (arg), w);
4176
4177 set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
4178 w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
4179 || FETCH_BYTE (pos.bytepos - 1) == '\n')
4180 ? Qt : Qnil);
4181 w->force_start = Qt;
4182 set_buffer_internal (obuf);
4183
4184 return Qnil;
4185 }
4186 \f
4187 DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
4188 1, 1, "P",
4189 "Position point relative to window.\n\
4190 With no argument, position point at center of window.\n\
4191 An argument specifies vertical position within the window;\n\
4192 zero means top of window, negative means relative to bottom of window.")
4193 (arg)
4194 register Lisp_Object arg;
4195 {
4196 register struct window *w = XWINDOW (selected_window);
4197 register int height = window_internal_height (w);
4198 register int start;
4199 Lisp_Object window;
4200
4201 if (NILP (arg))
4202 XSETFASTINT (arg, height / 2);
4203 else
4204 {
4205 arg = Fprefix_numeric_value (arg);
4206 if (XINT (arg) < 0)
4207 XSETINT (arg, XINT (arg) + height);
4208 }
4209
4210 start = marker_position (w->start);
4211 XSETWINDOW (window, w);
4212 if (start < BEGV || start > ZV)
4213 {
4214 Fvertical_motion (make_number (- (height / 2)), window);
4215 set_marker_both (w->start, w->buffer, PT, PT_BYTE);
4216 w->start_at_line_beg = Fbolp ();
4217 w->force_start = Qt;
4218 }
4219 else
4220 Fgoto_char (w->start);
4221
4222 return Fvertical_motion (arg, window);
4223 }
4224
4225
4226 \f
4227 /***********************************************************************
4228 Window Configuration
4229 ***********************************************************************/
4230
4231 struct save_window_data
4232 {
4233 EMACS_INT size_from_Lisp_Vector_struct;
4234 struct Lisp_Vector *next_from_Lisp_Vector_struct;
4235 Lisp_Object frame_width, frame_height, frame_menu_bar_lines;
4236 Lisp_Object frame_tool_bar_lines;
4237 Lisp_Object selected_frame;
4238 Lisp_Object current_window;
4239 Lisp_Object current_buffer;
4240 Lisp_Object minibuf_scroll_window;
4241 Lisp_Object root_window;
4242 Lisp_Object focus_frame;
4243 /* Record the values of window-min-width and window-min-height
4244 so that window sizes remain consistent with them. */
4245 Lisp_Object min_width, min_height;
4246 /* A vector, each of whose elements is a struct saved_window
4247 for one window. */
4248 Lisp_Object saved_windows;
4249 };
4250
4251 /* This is saved as a Lisp_Vector */
4252 struct saved_window
4253 {
4254 /* these first two must agree with struct Lisp_Vector in lisp.h */
4255 EMACS_INT size_from_Lisp_Vector_struct;
4256 struct Lisp_Vector *next_from_Lisp_Vector_struct;
4257
4258 Lisp_Object window;
4259 Lisp_Object buffer, start, pointm, mark;
4260 Lisp_Object left, top, width, height, hscroll;
4261 Lisp_Object parent, prev;
4262 Lisp_Object start_at_line_beg;
4263 Lisp_Object display_table;
4264 };
4265 #define SAVED_WINDOW_VECTOR_SIZE 14 /* Arg to Fmake_vector */
4266
4267 #define SAVED_WINDOW_N(swv,n) \
4268 ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
4269
4270 DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
4271 "Return t if OBJECT is a window-configuration object.")
4272 (object)
4273 Lisp_Object object;
4274 {
4275 if (WINDOW_CONFIGURATIONP (object))
4276 return Qt;
4277 return Qnil;
4278 }
4279
4280 DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
4281 "Return the frame that CONFIG, a window-configuration object, is about.")
4282 (config)
4283 Lisp_Object config;
4284 {
4285 register struct save_window_data *data;
4286 struct Lisp_Vector *saved_windows;
4287
4288 if (! WINDOW_CONFIGURATIONP (config))
4289 wrong_type_argument (Qwindow_configuration_p, config);
4290
4291 data = (struct save_window_data *) XVECTOR (config);
4292 saved_windows = XVECTOR (data->saved_windows);
4293 return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
4294 }
4295
4296 DEFUN ("set-window-configuration", Fset_window_configuration,
4297 Sset_window_configuration, 1, 1, 0,
4298 "Set the configuration of windows and buffers as specified by CONFIGURATION.\n\
4299 CONFIGURATION must be a value previously returned\n\
4300 by `current-window-configuration' (which see).\n\
4301 If CONFIGURATION was made from a frame that is now deleted,\n\
4302 only frame-independent values can be restored. In this case,\n\
4303 the return value is nil. Otherwise the value is t.")
4304 (configuration)
4305 Lisp_Object configuration;
4306 {
4307 register struct save_window_data *data;
4308 struct Lisp_Vector *saved_windows;
4309 Lisp_Object new_current_buffer;
4310 Lisp_Object frame;
4311 FRAME_PTR f;
4312 int old_point = -1;
4313
4314 while (!WINDOW_CONFIGURATIONP (configuration))
4315 wrong_type_argument (Qwindow_configuration_p, configuration);
4316
4317 data = (struct save_window_data *) XVECTOR (configuration);
4318 saved_windows = XVECTOR (data->saved_windows);
4319
4320 new_current_buffer = data->current_buffer;
4321 if (NILP (XBUFFER (new_current_buffer)->name))
4322 new_current_buffer = Qnil;
4323 else
4324 {
4325 if (XBUFFER (new_current_buffer) == current_buffer)
4326 old_point = PT;
4327
4328 }
4329
4330 frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
4331 f = XFRAME (frame);
4332
4333 /* If f is a dead frame, don't bother rebuilding its window tree.
4334 However, there is other stuff we should still try to do below. */
4335 if (FRAME_LIVE_P (f))
4336 {
4337 register struct window *w;
4338 register struct saved_window *p;
4339 struct window *root_window;
4340 struct window **leaf_windows;
4341 int n_leaf_windows;
4342 int k, i;
4343
4344 /* If the frame has been resized since this window configuration was
4345 made, we change the frame to the size specified in the
4346 configuration, restore the configuration, and then resize it
4347 back. We keep track of the prevailing height in these variables. */
4348 int previous_frame_height = FRAME_HEIGHT (f);
4349 int previous_frame_width = FRAME_WIDTH (f);
4350 int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
4351 int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
4352
4353 /* The mouse highlighting code could get screwed up
4354 if it runs during this. */
4355 BLOCK_INPUT;
4356
4357 if (XFASTINT (data->frame_height) != previous_frame_height
4358 || XFASTINT (data->frame_width) != previous_frame_width)
4359 change_frame_size (f, XFASTINT (data->frame_height),
4360 XFASTINT (data->frame_width), 0, 0, 0);
4361 #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
4362 if (XFASTINT (data->frame_menu_bar_lines)
4363 != previous_frame_menu_bar_lines)
4364 x_set_menu_bar_lines (f, data->frame_menu_bar_lines, make_number (0));
4365 #ifdef HAVE_WINDOW_SYSTEM
4366 if (XFASTINT (data->frame_tool_bar_lines)
4367 != previous_frame_tool_bar_lines)
4368 x_set_tool_bar_lines (f, data->frame_tool_bar_lines, make_number (0));
4369 #endif
4370 #endif
4371
4372 if (! NILP (XWINDOW (selected_window)->buffer))
4373 {
4374 w = XWINDOW (selected_window);
4375 set_marker_both (w->pointm,
4376 w->buffer,
4377 BUF_PT (XBUFFER (w->buffer)),
4378 BUF_PT_BYTE (XBUFFER (w->buffer)));
4379 }
4380
4381 windows_or_buffers_changed++;
4382 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
4383
4384 /* Problem: Freeing all matrices and later allocating them again
4385 is a serious redisplay flickering problem. What we would
4386 really like to do is to free only those matrices not reused
4387 below. */
4388 root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
4389 leaf_windows
4390 = (struct window **) alloca (count_windows (root_window)
4391 * sizeof (struct window *));
4392 n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
4393
4394 /* Temporarily avoid any problems with windows that are smaller
4395 than they are supposed to be. */
4396 window_min_height = 1;
4397 window_min_width = 1;
4398
4399 /* Kludge Alert!
4400 Mark all windows now on frame as "deleted".
4401 Restoring the new configuration "undeletes" any that are in it.
4402
4403 Save their current buffers in their height fields, since we may
4404 need it later, if a buffer saved in the configuration is now
4405 dead. */
4406 delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
4407
4408 for (k = 0; k < saved_windows->size; k++)
4409 {
4410 p = SAVED_WINDOW_N (saved_windows, k);
4411 w = XWINDOW (p->window);
4412 w->next = Qnil;
4413
4414 if (!NILP (p->parent))
4415 w->parent = SAVED_WINDOW_N (saved_windows,
4416 XFASTINT (p->parent))->window;
4417 else
4418 w->parent = Qnil;
4419
4420 if (!NILP (p->prev))
4421 {
4422 w->prev = SAVED_WINDOW_N (saved_windows,
4423 XFASTINT (p->prev))->window;
4424 XWINDOW (w->prev)->next = p->window;
4425 }
4426 else
4427 {
4428 w->prev = Qnil;
4429 if (!NILP (w->parent))
4430 {
4431 if (EQ (p->width, XWINDOW (w->parent)->width))
4432 {
4433 XWINDOW (w->parent)->vchild = p->window;
4434 XWINDOW (w->parent)->hchild = Qnil;
4435 }
4436 else
4437 {
4438 XWINDOW (w->parent)->hchild = p->window;
4439 XWINDOW (w->parent)->vchild = Qnil;
4440 }
4441 }
4442 }
4443
4444 /* If we squirreled away the buffer in the window's height,
4445 restore it now. */
4446 if (BUFFERP (w->height))
4447 w->buffer = w->height;
4448 w->left = p->left;
4449 w->top = p->top;
4450 w->width = p->width;
4451 w->height = p->height;
4452 w->hscroll = p->hscroll;
4453 w->display_table = p->display_table;
4454 XSETFASTINT (w->last_modified, 0);
4455 XSETFASTINT (w->last_overlay_modified, 0);
4456
4457 /* Reinstall the saved buffer and pointers into it. */
4458 if (NILP (p->buffer))
4459 w->buffer = p->buffer;
4460 else
4461 {
4462 if (!NILP (XBUFFER (p->buffer)->name))
4463 /* If saved buffer is alive, install it. */
4464 {
4465 w->buffer = p->buffer;
4466 w->start_at_line_beg = p->start_at_line_beg;
4467 set_marker_restricted (w->start, p->start, w->buffer);
4468 set_marker_restricted (w->pointm, p->pointm, w->buffer);
4469 Fset_marker (XBUFFER (w->buffer)->mark,
4470 p->mark, w->buffer);
4471
4472 /* As documented in Fcurrent_window_configuration, don't
4473 save the location of point in the buffer which was current
4474 when the window configuration was recorded. */
4475 if (!EQ (p->buffer, new_current_buffer)
4476 && XBUFFER (p->buffer) == current_buffer)
4477 Fgoto_char (w->pointm);
4478 }
4479 else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
4480 /* Else unless window has a live buffer, get one. */
4481 {
4482 w->buffer = Fcdr (Fcar (Vbuffer_alist));
4483 /* This will set the markers to beginning of visible
4484 range. */
4485 set_marker_restricted (w->start, make_number (0), w->buffer);
4486 set_marker_restricted (w->pointm, make_number (0),w->buffer);
4487 w->start_at_line_beg = Qt;
4488 }
4489 else
4490 /* Keeping window's old buffer; make sure the markers
4491 are real. */
4492 {
4493 /* Set window markers at start of visible range. */
4494 if (XMARKER (w->start)->buffer == 0)
4495 set_marker_restricted (w->start, make_number (0),
4496 w->buffer);
4497 if (XMARKER (w->pointm)->buffer == 0)
4498 set_marker_restricted_both (w->pointm, w->buffer,
4499 BUF_PT (XBUFFER (w->buffer)),
4500 BUF_PT_BYTE (XBUFFER (w->buffer)));
4501 w->start_at_line_beg = Qt;
4502 }
4503 }
4504 }
4505
4506 FRAME_ROOT_WINDOW (f) = data->root_window;
4507 Fselect_window (data->current_window);
4508 XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
4509 = selected_window;
4510
4511 if (NILP (data->focus_frame)
4512 || (FRAMEP (data->focus_frame)
4513 && FRAME_LIVE_P (XFRAME (data->focus_frame))))
4514 Fredirect_frame_focus (frame, data->focus_frame);
4515
4516 #if 0 /* I don't understand why this is needed, and it causes problems
4517 when the frame's old selected window has been deleted. */
4518 if (f != selected_frame && FRAME_WINDOW_P (f))
4519 do_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)),
4520 Qnil, 0);
4521 #endif
4522
4523 /* Set the screen height to the value it had before this function. */
4524 if (previous_frame_height != FRAME_HEIGHT (f)
4525 || previous_frame_width != FRAME_WIDTH (f))
4526 change_frame_size (f, previous_frame_height, previous_frame_width,
4527 0, 0, 0);
4528 #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
4529 if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
4530 x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
4531 make_number (0));
4532 #ifdef HAVE_WINDOW_SYSTEM
4533 if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
4534 x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
4535 make_number (0));
4536 #endif
4537 #endif
4538
4539 /* Now, free glyph matrices in windows that were not reused. */
4540 for (i = 0; i < n_leaf_windows; ++i)
4541 if (NILP (leaf_windows[i]->buffer))
4542 {
4543 /* Assert it's not reused as a combination. */
4544 xassert (NILP (leaf_windows[i]->hchild)
4545 && NILP (leaf_windows[i]->vchild));
4546 free_window_matrices (leaf_windows[i]);
4547 SET_FRAME_GARBAGED (f);
4548 }
4549
4550 adjust_glyphs (f);
4551
4552 UNBLOCK_INPUT;
4553
4554 /* Fselect_window will have made f the selected frame, so we
4555 reselect the proper frame here. Fhandle_switch_frame will change the
4556 selected window too, but that doesn't make the call to
4557 Fselect_window above totally superfluous; it still sets f's
4558 selected window. */
4559 if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
4560 do_switch_frame (data->selected_frame, Qnil, 0);
4561
4562 if (! NILP (Vwindow_configuration_change_hook)
4563 && ! NILP (Vrun_hooks))
4564 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
4565 }
4566
4567 if (!NILP (new_current_buffer))
4568 {
4569 Fset_buffer (new_current_buffer);
4570
4571 /* If the buffer that is current now is the same
4572 that was current before setting the window configuration,
4573 don't alter its PT. */
4574 if (old_point >= 0)
4575 SET_PT (old_point);
4576 }
4577
4578 /* Restore the minimum heights recorded in the configuration. */
4579 window_min_height = XINT (data->min_height);
4580 window_min_width = XINT (data->min_width);
4581
4582 Vminibuf_scroll_window = data->minibuf_scroll_window;
4583
4584 return (FRAME_LIVE_P (f) ? Qt : Qnil);
4585 }
4586
4587 /* Mark all windows now on frame as deleted
4588 by setting their buffers to nil. */
4589
4590 void
4591 delete_all_subwindows (w)
4592 register struct window *w;
4593 {
4594 if (!NILP (w->next))
4595 delete_all_subwindows (XWINDOW (w->next));
4596 if (!NILP (w->vchild))
4597 delete_all_subwindows (XWINDOW (w->vchild));
4598 if (!NILP (w->hchild))
4599 delete_all_subwindows (XWINDOW (w->hchild));
4600
4601 w->height = w->buffer; /* See Fset_window_configuration for excuse. */
4602
4603 if (!NILP (w->buffer))
4604 unshow_buffer (w);
4605
4606 /* We set all three of these fields to nil, to make sure that we can
4607 distinguish this dead window from any live window. Live leaf
4608 windows will have buffer set, and combination windows will have
4609 vchild or hchild set. */
4610 w->buffer = Qnil;
4611 w->vchild = Qnil;
4612 w->hchild = Qnil;
4613 }
4614 \f
4615 static int
4616 count_windows (window)
4617 register struct window *window;
4618 {
4619 register int count = 1;
4620 if (!NILP (window->next))
4621 count += count_windows (XWINDOW (window->next));
4622 if (!NILP (window->vchild))
4623 count += count_windows (XWINDOW (window->vchild));
4624 if (!NILP (window->hchild))
4625 count += count_windows (XWINDOW (window->hchild));
4626 return count;
4627 }
4628
4629
4630 /* Fill vector FLAT with leaf windows under W, starting at index I.
4631 Value is last index + 1. */
4632
4633 static int
4634 get_leaf_windows (w, flat, i)
4635 struct window *w;
4636 struct window **flat;
4637 int i;
4638 {
4639 while (w)
4640 {
4641 if (!NILP (w->hchild))
4642 i = get_leaf_windows (XWINDOW (w->hchild), flat, i);
4643 else if (!NILP (w->vchild))
4644 i = get_leaf_windows (XWINDOW (w->vchild), flat, i);
4645 else
4646 flat[i++] = w;
4647
4648 w = NILP (w->next) ? 0 : XWINDOW (w->next);
4649 }
4650
4651 return i;
4652 }
4653
4654
4655 /* Return a pointer to the glyph W's physical cursor is on. Value is
4656 null if W's current matrix is invalid, so that no meaningfull glyph
4657 can be returned. */
4658
4659 struct glyph *
4660 get_phys_cursor_glyph (w)
4661 struct window *w;
4662 {
4663 struct glyph_row *row;
4664 struct glyph *glyph;
4665
4666 if (w->phys_cursor.vpos >= 0
4667 && w->phys_cursor.vpos < w->current_matrix->nrows
4668 && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
4669 row->enabled_p)
4670 && row->used[TEXT_AREA] > w->phys_cursor.hpos)
4671 glyph = row->glyphs[TEXT_AREA] + w->phys_cursor.hpos;
4672 else
4673 glyph = NULL;
4674
4675 return glyph;
4676 }
4677
4678
4679 static int
4680 save_window_save (window, vector, i)
4681 Lisp_Object window;
4682 struct Lisp_Vector *vector;
4683 int i;
4684 {
4685 register struct saved_window *p;
4686 register struct window *w;
4687 register Lisp_Object tem;
4688
4689 for (;!NILP (window); window = w->next)
4690 {
4691 p = SAVED_WINDOW_N (vector, i);
4692 w = XWINDOW (window);
4693
4694 XSETFASTINT (w->temslot, i++);
4695 p->window = window;
4696 p->buffer = w->buffer;
4697 p->left = w->left;
4698 p->top = w->top;
4699 p->width = w->width;
4700 p->height = w->height;
4701 p->hscroll = w->hscroll;
4702 p->display_table = w->display_table;
4703 if (!NILP (w->buffer))
4704 {
4705 /* Save w's value of point in the window configuration.
4706 If w is the selected window, then get the value of point
4707 from the buffer; pointm is garbage in the selected window. */
4708 if (EQ (window, selected_window))
4709 {
4710 p->pointm = Fmake_marker ();
4711 set_marker_both (p->pointm, w->buffer,
4712 BUF_PT (XBUFFER (w->buffer)),
4713 BUF_PT_BYTE (XBUFFER (w->buffer)));
4714 }
4715 else
4716 p->pointm = Fcopy_marker (w->pointm, Qnil);
4717
4718 p->start = Fcopy_marker (w->start, Qnil);
4719 p->start_at_line_beg = w->start_at_line_beg;
4720
4721 tem = XBUFFER (w->buffer)->mark;
4722 p->mark = Fcopy_marker (tem, Qnil);
4723 }
4724 else
4725 {
4726 p->pointm = Qnil;
4727 p->start = Qnil;
4728 p->mark = Qnil;
4729 p->start_at_line_beg = Qnil;
4730 }
4731
4732 if (NILP (w->parent))
4733 p->parent = Qnil;
4734 else
4735 p->parent = XWINDOW (w->parent)->temslot;
4736
4737 if (NILP (w->prev))
4738 p->prev = Qnil;
4739 else
4740 p->prev = XWINDOW (w->prev)->temslot;
4741
4742 if (!NILP (w->vchild))
4743 i = save_window_save (w->vchild, vector, i);
4744 if (!NILP (w->hchild))
4745 i = save_window_save (w->hchild, vector, i);
4746 }
4747
4748 return i;
4749 }
4750
4751 DEFUN ("current-window-configuration", Fcurrent_window_configuration,
4752 Scurrent_window_configuration, 0, 1, 0,
4753 "Return an object representing the current window configuration of FRAME.\n\
4754 If FRAME is nil or omitted, use the selected frame.\n\
4755 This describes the number of windows, their sizes and current buffers,\n\
4756 and for each displayed buffer, where display starts, and the positions of\n\
4757 point and mark. An exception is made for point in the current buffer:\n\
4758 its value is -not- saved.\n\
4759 This also records the currently selected frame, and FRAME's focus\n\
4760 redirection (see `redirect-frame-focus').")
4761 (frame)
4762 Lisp_Object frame;
4763 {
4764 register Lisp_Object tem;
4765 register int n_windows;
4766 register struct save_window_data *data;
4767 register struct Lisp_Vector *vec;
4768 register int i;
4769 FRAME_PTR f;
4770
4771 if (NILP (frame))
4772 frame = selected_frame;
4773 CHECK_LIVE_FRAME (frame, 0);
4774 f = XFRAME (frame);
4775
4776 n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
4777 vec = allocate_vectorlike (VECSIZE (struct save_window_data));
4778 for (i = 0; i < VECSIZE (struct save_window_data); i++)
4779 vec->contents[i] = Qnil;
4780 vec->size = VECSIZE (struct save_window_data);
4781 data = (struct save_window_data *)vec;
4782
4783 XSETFASTINT (data->frame_width, FRAME_WIDTH (f));
4784 XSETFASTINT (data->frame_height, FRAME_HEIGHT (f));
4785 XSETFASTINT (data->frame_menu_bar_lines, FRAME_MENU_BAR_LINES (f));
4786 XSETFASTINT (data->frame_tool_bar_lines, FRAME_TOOL_BAR_LINES (f));
4787 data->selected_frame = selected_frame;
4788 data->current_window = FRAME_SELECTED_WINDOW (f);
4789 XSETBUFFER (data->current_buffer, current_buffer);
4790 data->minibuf_scroll_window = Vminibuf_scroll_window;
4791 data->root_window = FRAME_ROOT_WINDOW (f);
4792 data->focus_frame = FRAME_FOCUS_FRAME (f);
4793 XSETINT (data->min_height, window_min_height);
4794 XSETINT (data->min_width, window_min_width);
4795 tem = Fmake_vector (make_number (n_windows), Qnil);
4796 data->saved_windows = tem;
4797 for (i = 0; i < n_windows; i++)
4798 XVECTOR (tem)->contents[i]
4799 = Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil);
4800 save_window_save (FRAME_ROOT_WINDOW (f),
4801 XVECTOR (tem), 0);
4802 XSETWINDOW_CONFIGURATION (tem, data);
4803 return (tem);
4804 }
4805
4806 DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
4807 0, UNEVALLED, 0,
4808 "Execute body, preserving window sizes and contents.\n\
4809 Restore which buffer appears in which window, where display starts,\n\
4810 and the value of point and mark for each window.\n\
4811 Also restore which buffer is current.\n\
4812 But do not preserve point in the current buffer.\n\
4813 Does not restore the value of point in current buffer.")
4814 (args)
4815 Lisp_Object args;
4816 {
4817 register Lisp_Object val;
4818 register int count = specpdl_ptr - specpdl;
4819
4820 record_unwind_protect (Fset_window_configuration,
4821 Fcurrent_window_configuration (Qnil));
4822 val = Fprogn (args);
4823 return unbind_to (count, val);
4824 }
4825
4826 \f
4827 /***********************************************************************
4828 Marginal Areas
4829 ***********************************************************************/
4830
4831 DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
4832 2, 3, "",
4833 "Set width of marginal areas of window WINDOW.\n\
4834 If window is nil or omitted, set margins of the currently selected window.\n\
4835 First parameter LEFT-WIDTH specifies the number of character\n\
4836 cells to reserve for the left marginal area. Second parameter\n\
4837 RIGHT-WIDTH does the same for the right marginal area.\n\
4838 A nil width parameter means no margin.")
4839 (window, left, right)
4840 Lisp_Object window, left, right;
4841 {
4842 struct window *w = decode_window (window);
4843
4844 if (!NILP (left))
4845 CHECK_NUMBER_OR_FLOAT (left, 1);
4846 if (!NILP (right))
4847 CHECK_NUMBER_OR_FLOAT (right, 2);
4848
4849 /* Check widths < 0 and translate a zero width to nil.
4850 Margins that are too wide have to be checked elsewhere. */
4851 if ((INTEGERP (left) && XINT (left) < 0)
4852 || (FLOATP (left) && XFLOAT_DATA (left) <= 0))
4853 XSETFASTINT (left, 0);
4854 if (INTEGERP (left) && XFASTINT (left) == 0)
4855 left = Qnil;
4856
4857 if ((INTEGERP (right) && XINT (right) < 0)
4858 || (FLOATP (right) && XFLOAT_DATA (right) <= 0))
4859 XSETFASTINT (right, 0);
4860 if (INTEGERP (right) && XFASTINT (right) == 0)
4861 right = Qnil;
4862
4863 w->left_margin_width = left;
4864 w->right_margin_width = right;
4865
4866 ++windows_or_buffers_changed;
4867 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
4868 return Qnil;
4869 }
4870
4871
4872 DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
4873 0, 1, 0,
4874 "Get width of marginal areas of window WINDOW.\n\
4875 If WINDOW is omitted or nil, use the currently selected window.\n\
4876 Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).\n\
4877 If a marginal area does not exist, its width will be returned\n\
4878 as nil.")
4879 (window)
4880 Lisp_Object window;
4881 {
4882 struct window *w = decode_window (window);
4883 return Fcons (w->left_margin_width, w->right_margin_width);
4884 }
4885
4886
4887 \f
4888 /***********************************************************************
4889 Smooth scrolling
4890 ***********************************************************************/
4891
4892 DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 1, 0,
4893 "Return the amount by which WINDOW is scrolled vertically.\n\
4894 Use the selected window if WINDOW is nil or omitted.\n\
4895 Value is a multiple of the canonical character height of WINDOW.")
4896 (window)
4897 Lisp_Object window;
4898 {
4899 Lisp_Object result;
4900 struct frame *f;
4901 struct window *w;
4902
4903 if (NILP (window))
4904 window = selected_window;
4905 else
4906 CHECK_WINDOW (window, 0);
4907 w = XWINDOW (window);
4908 f = XFRAME (w->frame);
4909
4910 if (FRAME_WINDOW_P (f))
4911 result = CANON_Y_FROM_PIXEL_Y (f, -w->vscroll);
4912 else
4913 result = make_number (0);
4914 return result;
4915 }
4916
4917
4918 DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
4919 2, 2, 0,
4920 "Set amount by which WINDOW should be scrolled vertically to VSCROLL.\n\
4921 WINDOW nil or omitted means use the selected window. VSCROLL is a\n\
4922 non-negative multiple of the canonical character height of WINDOW.")
4923 (window, vscroll)
4924 Lisp_Object window, vscroll;
4925 {
4926 struct window *w;
4927 struct frame *f;
4928
4929 if (NILP (window))
4930 window = selected_window;
4931 else
4932 CHECK_WINDOW (window, 0);
4933 CHECK_NUMBER_OR_FLOAT (vscroll, 1);
4934
4935 w = XWINDOW (window);
4936 f = XFRAME (w->frame);
4937
4938 if (FRAME_WINDOW_P (f))
4939 {
4940 int old_dy = w->vscroll;
4941
4942 w->vscroll = - CANON_Y_UNIT (f) * XFLOATINT (vscroll);
4943 w->vscroll = min (w->vscroll, 0);
4944
4945 /* Adjust glyph matrix of the frame if the virtual display
4946 area becomes larger than before. */
4947 if (w->vscroll < 0 && w->vscroll < old_dy)
4948 adjust_glyphs (f);
4949
4950 /* Prevent redisplay shortcuts. */
4951 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
4952 }
4953
4954 return Fwindow_vscroll (window);
4955 }
4956
4957 \f
4958 /* Call FN for all leaf windows on frame F. FN is called with the
4959 first argument being a pointer to the leaf window, and with
4960 additional arguments A1..A4. */
4961
4962 void
4963 foreach_window (f, fn, a1, a2, a3, a4)
4964 struct frame *f;
4965 void (* fn) ();
4966 int a1, a2, a3, a4;
4967 {
4968 foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, a1, a2, a3, a4);
4969 }
4970
4971
4972 /* Helper function for foreach_window. Call FN for all leaf windows
4973 reachable from W. FN is called with the first argument being a
4974 pointer to the leaf window, and with additional arguments A1..A4. */
4975
4976 static void
4977 foreach_window_1 (w, fn, a1, a2, a3, a4)
4978 struct window *w;
4979 void (* fn) ();
4980 int a1, a2, a3, a4;
4981 {
4982 while (w)
4983 {
4984 if (!NILP (w->hchild))
4985 foreach_window_1 (XWINDOW (w->hchild), fn, a1, a2, a3, a4);
4986 else if (!NILP (w->vchild))
4987 foreach_window_1 (XWINDOW (w->vchild), fn, a1, a2, a3, a4);
4988 else
4989 fn (w, a1, a2, a3, a4);
4990
4991 w = NILP (w->next) ? 0 : XWINDOW (w->next);
4992 }
4993 }
4994
4995
4996 /* Freeze or unfreeze the window start of W if unless it is a
4997 mini-window or the selected window. FREEZE_P non-zero means freeze
4998 the window start. */
4999
5000 static void
5001 freeze_window_start (w, freeze_p)
5002 struct window *w;
5003 int freeze_p;
5004 {
5005 if (w == XWINDOW (selected_window)
5006 || MINI_WINDOW_P (w)
5007 || (MINI_WINDOW_P (XWINDOW (selected_window))
5008 && w == XWINDOW (Vminibuf_scroll_window)))
5009 freeze_p = 0;
5010
5011 w->frozen_window_start_p = freeze_p;
5012 }
5013
5014
5015 /* Freeze or unfreeze the window starts of all leaf windows on frame
5016 F, except the selected window and a mini-window. FREEZE_P non-zero
5017 means freeze the window start. */
5018
5019 void
5020 freeze_window_starts (f, freeze_p)
5021 struct frame *f;
5022 int freeze_p;
5023 {
5024 foreach_window (f, freeze_window_start, freeze_p);
5025 }
5026
5027 \f
5028 /***********************************************************************
5029 Initialization
5030 ***********************************************************************/
5031
5032 /* Return 1 if window configurations C1 and C2
5033 describe the same state of affairs. This is used by Fequal. */
5034
5035 int
5036 compare_window_configurations (c1, c2, ignore_positions)
5037 Lisp_Object c1, c2;
5038 int ignore_positions;
5039 {
5040 register struct save_window_data *d1, *d2;
5041 struct Lisp_Vector *sw1, *sw2;
5042 int i;
5043
5044 d1 = (struct save_window_data *) XVECTOR (c1);
5045 d2 = (struct save_window_data *) XVECTOR (c2);
5046 sw1 = XVECTOR (d1->saved_windows);
5047 sw2 = XVECTOR (d2->saved_windows);
5048
5049 if (! EQ (d1->frame_width, d2->frame_width))
5050 return 0;
5051 if (! EQ (d1->frame_height, d2->frame_height))
5052 return 0;
5053 if (! EQ (d1->frame_menu_bar_lines, d2->frame_menu_bar_lines))
5054 return 0;
5055 if (! EQ (d1->selected_frame, d2->selected_frame))
5056 return 0;
5057 /* Don't compare the current_window field directly.
5058 Instead see w1_is_current and w2_is_current, below. */
5059 if (! EQ (d1->current_buffer, d2->current_buffer))
5060 return 0;
5061 if (! ignore_positions)
5062 if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
5063 return 0;
5064 /* Don't compare the root_window field.
5065 We don't require the two configurations
5066 to use the same window object,
5067 and the two root windows must be equivalent
5068 if everything else compares equal. */
5069 if (! EQ (d1->focus_frame, d2->focus_frame))
5070 return 0;
5071 if (! EQ (d1->min_width, d2->min_width))
5072 return 0;
5073 if (! EQ (d1->min_height, d2->min_height))
5074 return 0;
5075
5076 /* Verify that the two confis have the same number of windows. */
5077 if (sw1->size != sw2->size)
5078 return 0;
5079
5080 for (i = 0; i < sw1->size; i++)
5081 {
5082 struct saved_window *p1, *p2;
5083 int w1_is_current, w2_is_current;
5084
5085 p1 = SAVED_WINDOW_N (sw1, i);
5086 p2 = SAVED_WINDOW_N (sw2, i);
5087
5088 /* Verify that the current windows in the two
5089 configurations correspond to each other. */
5090 w1_is_current = EQ (d1->current_window, p1->window);
5091 w2_is_current = EQ (d2->current_window, p2->window);
5092
5093 if (w1_is_current != w2_is_current)
5094 return 0;
5095
5096 /* Verify that the corresponding windows do match. */
5097 if (! EQ (p1->buffer, p2->buffer))
5098 return 0;
5099 if (! EQ (p1->left, p2->left))
5100 return 0;
5101 if (! EQ (p1->top, p2->top))
5102 return 0;
5103 if (! EQ (p1->width, p2->width))
5104 return 0;
5105 if (! EQ (p1->height, p2->height))
5106 return 0;
5107 if (! EQ (p1->display_table, p2->display_table))
5108 return 0;
5109 if (! EQ (p1->parent, p2->parent))
5110 return 0;
5111 if (! EQ (p1->prev, p2->prev))
5112 return 0;
5113 if (! ignore_positions)
5114 {
5115 if (! EQ (p1->hscroll, p2->hscroll))
5116 return 0;
5117 if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
5118 return 0;
5119 if (NILP (Fequal (p1->start, p2->start)))
5120 return 0;
5121 if (NILP (Fequal (p1->pointm, p2->pointm)))
5122 return 0;
5123 if (NILP (Fequal (p1->mark, p2->mark)))
5124 return 0;
5125 }
5126 }
5127
5128 return 1;
5129 }
5130
5131 DEFUN ("compare-window-configurations", Fcompare_window_configurations,
5132 Scompare_window_configurations, 2, 2, 0,
5133 "Compare two window configurations as regards the structure of windows.\n\
5134 This function ignores details such as the values of point and mark\n\
5135 and scrolling positions.")
5136 (x, y)
5137 Lisp_Object x, y;
5138 {
5139 if (compare_window_configurations (x, y, 1))
5140 return Qt;
5141 return Qnil;
5142 }
5143 \f
5144 void
5145 init_window_once ()
5146 {
5147 struct frame *f = make_terminal_frame ();
5148 XSETFRAME (selected_frame, f);
5149 Vterminal_frame = selected_frame;
5150 minibuf_window = f->minibuffer_window;
5151 selected_window = f->selected_window;
5152 last_nonminibuf_frame = f;
5153
5154 window_initialized = 1;
5155 }
5156
5157 void
5158 syms_of_window ()
5159 {
5160 Qleft_bitmap_area = intern ("left-bitmap-area");
5161 staticpro (&Qleft_bitmap_area);
5162 Qright_bitmap_area = intern ("right-bitmap-area");
5163 staticpro (&Qright_bitmap_area);
5164
5165 Qwindow_size_fixed = intern ("window-size-fixed");
5166 staticpro (&Qwindow_size_fixed);
5167
5168 staticpro (&Qwindow_configuration_change_hook);
5169 Qwindow_configuration_change_hook
5170 = intern ("window-configuration-change-hook");
5171
5172 Qwindowp = intern ("windowp");
5173 staticpro (&Qwindowp);
5174
5175 Qwindow_configuration_p = intern ("window-configuration-p");
5176 staticpro (&Qwindow_configuration_p);
5177
5178 Qwindow_live_p = intern ("window-live-p");
5179 staticpro (&Qwindow_live_p);
5180
5181 Qtemp_buffer_show_hook = intern ("temp-buffer-show-hook");
5182 staticpro (&Qtemp_buffer_show_hook);
5183
5184 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
5185 "Non-nil means call as function to display a help buffer.\n\
5186 The function is called with one argument, the buffer to be displayed.\n\
5187 Used by `with-output-to-temp-buffer'.\n\
5188 If this function is used, then it must do the entire job of showing\n\
5189 the buffer; `temp-buffer-show-hook' is not run unless this function runs it.");
5190 Vtemp_buffer_show_function = Qnil;
5191
5192 DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
5193 "If non-nil, function to call to handle `display-buffer'.\n\
5194 It will receive two args, the buffer and a flag which if non-nil means\n\
5195 that the currently selected window is not acceptable.\n\
5196 Commands such as `switch-to-buffer-other-window' and `find-file-other-window'\n\
5197 work using this function.");
5198 Vdisplay_buffer_function = Qnil;
5199
5200 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
5201 "Non-nil means it is the window that C-M-v in minibuffer should scroll.");
5202 Vminibuf_scroll_window = Qnil;
5203
5204 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
5205 "If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.");
5206 Vother_window_scroll_buffer = Qnil;
5207
5208 DEFVAR_BOOL ("pop-up-frames", &pop_up_frames,
5209 "*Non-nil means `display-buffer' should make a separate frame.");
5210 pop_up_frames = 0;
5211
5212 DEFVAR_LISP ("pop-up-frame-function", &Vpop_up_frame_function,
5213 "Function to call to handle automatic new frame creation.\n\
5214 It is called with no arguments and should return a newly created frame.\n\
5215 \n\
5216 A typical value might be `(lambda () (new-frame pop-up-frame-alist))'\n\
5217 where `pop-up-frame-alist' would hold the default frame parameters.");
5218 Vpop_up_frame_function = Qnil;
5219
5220 DEFVAR_LISP ("special-display-buffer-names", &Vspecial_display_buffer_names,
5221 "*List of buffer names that should have their own special frames.\n\
5222 Displaying a buffer whose name is in this list makes a special frame for it\n\
5223 using `special-display-function'. See also `special-display-regexps'.\n\
5224 \n\
5225 An element of the list can be a list instead of just a string.\n\
5226 There are two ways to use a list as an element:\n\
5227 (BUFFER FRAME-PARAMETERS...) (BUFFER FUNCTION OTHER-ARGS...)\n\
5228 In the first case, FRAME-PARAMETERS are used to create the frame.\n\
5229 In the latter case, FUNCTION is called with BUFFER as the first argument,\n\
5230 followed by OTHER-ARGS--it can display BUFFER in any way it likes.\n\
5231 All this is done by the function found in `special-display-function'.\n\
5232 \n\
5233 If this variable appears \"not to work\", because you add a name to it\n\
5234 but that buffer still appears in the selected window, look at the\n\
5235 values of `same-window-buffer-names' and `same-window-regexps'.\n\
5236 Those variables take precedence over this one.");
5237 Vspecial_display_buffer_names = Qnil;
5238
5239 DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
5240 "*List of regexps saying which buffers should have their own special frames.\n\
5241 If a buffer name matches one of these regexps, it gets its own frame.\n\
5242 Displaying a buffer whose name is in this list makes a special frame for it\n\
5243 using `special-display-function'.\n\
5244 \n\
5245 An element of the list can be a list instead of just a string.\n\
5246 There are two ways to use a list as an element:\n\
5247 (REGEXP FRAME-PARAMETERS...) (REGEXP FUNCTION OTHER-ARGS...)\n\
5248 In the first case, FRAME-PARAMETERS are used to create the frame.\n\
5249 In the latter case, FUNCTION is called with the buffer as first argument,\n\
5250 followed by OTHER-ARGS--it can display the buffer in any way it likes.\n\
5251 All this is done by the function found in `special-display-function'.\n\
5252 \n\
5253 If this variable appears \"not to work\", because you add a regexp to it\n\
5254 but the matching buffers still appear in the selected window, look at the\n\
5255 values of `same-window-buffer-names' and `same-window-regexps'.\n\
5256 Those variables take precedence over this one.");
5257 Vspecial_display_regexps = Qnil;
5258
5259 DEFVAR_LISP ("special-display-function", &Vspecial_display_function,
5260 "Function to call to make a new frame for a special buffer.\n\
5261 It is called with two arguments, the buffer and optional buffer specific\n\
5262 data, and should return a window displaying that buffer.\n\
5263 The default value makes a separate frame for the buffer,\n\
5264 using `special-display-frame-alist' to specify the frame parameters.\n\
5265 \n\
5266 A buffer is special if its is listed in `special-display-buffer-names'\n\
5267 or matches a regexp in `special-display-regexps'.");
5268 Vspecial_display_function = Qnil;
5269
5270 DEFVAR_LISP ("same-window-buffer-names", &Vsame_window_buffer_names,
5271 "*List of buffer names that should appear in the selected window.\n\
5272 Displaying one of these buffers using `display-buffer' or `pop-to-buffer'\n\
5273 switches to it in the selected window, rather than making it appear\n\
5274 in some other window.\n\
5275 \n\
5276 An element of the list can be a cons cell instead of just a string.\n\
5277 Then the car must be a string, which specifies the buffer name.\n\
5278 This is for compatibility with `special-display-buffer-names';\n\
5279 the cdr of the cons cell is ignored.\n\
5280 \n\
5281 See also `same-window-regexps'.");
5282 Vsame_window_buffer_names = Qnil;
5283
5284 DEFVAR_LISP ("same-window-regexps", &Vsame_window_regexps,
5285 "*List of regexps saying which buffers should appear in the selected window.\n\
5286 If a buffer name matches one of these regexps, then displaying it\n\
5287 using `display-buffer' or `pop-to-buffer' switches to it\n\
5288 in the selected window, rather than making it appear in some other window.\n\
5289 \n\
5290 An element of the list can be a cons cell instead of just a string.\n\
5291 Then the car must be a string, which specifies the buffer name.\n\
5292 This is for compatibility with `special-display-buffer-names';\n\
5293 the cdr of the cons cell is ignored.\n\
5294 \n\
5295 See also `same-window-buffer-names'.");
5296 Vsame_window_regexps = Qnil;
5297
5298 DEFVAR_BOOL ("pop-up-windows", &pop_up_windows,
5299 "*Non-nil means display-buffer should make new windows.");
5300 pop_up_windows = 1;
5301
5302 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
5303 "*Number of lines of continuity when scrolling by screenfuls.");
5304 next_screen_context_lines = 2;
5305
5306 DEFVAR_INT ("split-height-threshold", &split_height_threshold,
5307 "*display-buffer would prefer to split the largest window if this large.\n\
5308 If there is only one window, it is split regardless of this value.");
5309 split_height_threshold = 500;
5310
5311 DEFVAR_INT ("window-min-height", &window_min_height,
5312 "*Delete any window less than this tall (including its mode line).");
5313 window_min_height = 4;
5314
5315 DEFVAR_INT ("window-min-width", &window_min_width,
5316 "*Delete any window less than this wide.");
5317 window_min_width = 10;
5318
5319 DEFVAR_LISP ("scroll-preserve-screen-position",
5320 &Vscroll_preserve_screen_position,
5321 "*Nonzero means scroll commands move point to keep its screen line unchanged.");
5322 Vscroll_preserve_screen_position = Qnil;
5323
5324 DEFVAR_LISP ("window-configuration-change-hook",
5325 &Vwindow_configuration_change_hook,
5326 "Functions to call when window configuration changes.\n\
5327 The selected frame is the one whose configuration has changed.");
5328 Vwindow_configuration_change_hook = Qnil;
5329
5330 defsubr (&Sselected_window);
5331 defsubr (&Sminibuffer_window);
5332 defsubr (&Swindow_minibuffer_p);
5333 defsubr (&Swindowp);
5334 defsubr (&Swindow_live_p);
5335 defsubr (&Spos_visible_in_window_p);
5336 defsubr (&Swindow_buffer);
5337 defsubr (&Swindow_height);
5338 defsubr (&Swindow_width);
5339 defsubr (&Swindow_hscroll);
5340 defsubr (&Sset_window_hscroll);
5341 defsubr (&Swindow_redisplay_end_trigger);
5342 defsubr (&Sset_window_redisplay_end_trigger);
5343 defsubr (&Swindow_edges);
5344 defsubr (&Scoordinates_in_window_p);
5345 defsubr (&Swindow_at);
5346 defsubr (&Swindow_point);
5347 defsubr (&Swindow_start);
5348 defsubr (&Swindow_end);
5349 defsubr (&Sset_window_point);
5350 defsubr (&Sset_window_start);
5351 defsubr (&Swindow_dedicated_p);
5352 defsubr (&Sset_window_dedicated_p);
5353 defsubr (&Swindow_display_table);
5354 defsubr (&Sset_window_display_table);
5355 defsubr (&Snext_window);
5356 defsubr (&Sprevious_window);
5357 defsubr (&Sother_window);
5358 defsubr (&Sget_lru_window);
5359 defsubr (&Sget_largest_window);
5360 defsubr (&Sget_buffer_window);
5361 defsubr (&Sdelete_other_windows);
5362 defsubr (&Sdelete_windows_on);
5363 defsubr (&Sreplace_buffer_in_windows);
5364 defsubr (&Sdelete_window);
5365 defsubr (&Sset_window_buffer);
5366 defsubr (&Sselect_window);
5367 defsubr (&Sspecial_display_p);
5368 defsubr (&Ssame_window_p);
5369 defsubr (&Sdisplay_buffer);
5370 defsubr (&Ssplit_window);
5371 defsubr (&Senlarge_window);
5372 defsubr (&Sshrink_window);
5373 defsubr (&Sscroll_up);
5374 defsubr (&Sscroll_down);
5375 defsubr (&Sscroll_left);
5376 defsubr (&Sscroll_right);
5377 defsubr (&Sother_window_for_scrolling);
5378 defsubr (&Sscroll_other_window);
5379 defsubr (&Srecenter);
5380 defsubr (&Smove_to_window_line);
5381 defsubr (&Swindow_configuration_p);
5382 defsubr (&Swindow_configuration_frame);
5383 defsubr (&Sset_window_configuration);
5384 defsubr (&Scurrent_window_configuration);
5385 defsubr (&Ssave_window_excursion);
5386 defsubr (&Sset_window_margins);
5387 defsubr (&Swindow_margins);
5388 defsubr (&Swindow_vscroll);
5389 defsubr (&Sset_window_vscroll);
5390 defsubr (&Scompare_window_configurations);
5391 }
5392
5393 void
5394 keys_of_window ()
5395 {
5396 initial_define_key (control_x_map, '1', "delete-other-windows");
5397 initial_define_key (control_x_map, '2', "split-window");
5398 initial_define_key (control_x_map, '0', "delete-window");
5399 initial_define_key (control_x_map, 'o', "other-window");
5400 initial_define_key (control_x_map, '^', "enlarge-window");
5401 initial_define_key (control_x_map, '<', "scroll-left");
5402 initial_define_key (control_x_map, '>', "scroll-right");
5403
5404 initial_define_key (global_map, Ctl ('V'), "scroll-up");
5405 initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
5406 initial_define_key (meta_map, 'v', "scroll-down");
5407
5408 initial_define_key (global_map, Ctl('L'), "recenter");
5409 initial_define_key (meta_map, 'r', "move-to-window-line");
5410 }