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