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