1/* Window creation, deletion and examination for GNU Emacs.
2   Does not include redisplay.
3   Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1996, 1997, 1998, 2000,
4                 2001, 2002, 2003, 2004, 2005, 2006, 2007 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., 51 Franklin Street, Fifth Floor,
21Boston, MA 02110-1301, USA.  */
22
23#include <config.h>
24#include "lisp.h"
25#include "buffer.h"
26#include "keyboard.h"
27#include "keymap.h"
28#include "frame.h"
29#include "window.h"
30#include "commands.h"
31#include "indent.h"
32#include "termchar.h"
33#include "disptab.h"
34#include "dispextern.h"
35#include "blockinput.h"
36#include "intervals.h"
37
38#ifdef HAVE_X_WINDOWS
39#include "xterm.h"
40#endif	/* HAVE_X_WINDOWS */
41#ifdef WINDOWSNT
42#include "w32term.h"
43#endif
44#ifdef MSDOS
45#include "msdos.h"
46#endif
47#ifdef MAC_OS
48#include "macterm.h"
49#endif
50
51
52Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
53Lisp_Object Qscroll_up, Qscroll_down;
54Lisp_Object Qwindow_size_fixed;
55extern Lisp_Object Qleft_margin, Qright_margin;
56
57static int displayed_window_lines P_ ((struct window *));
58static struct window *decode_window P_ ((Lisp_Object));
59static int count_windows P_ ((struct window *));
60static int get_leaf_windows P_ ((struct window *, struct window **, int));
61static void window_scroll P_ ((Lisp_Object, int, int, int));
62static void window_scroll_pixel_based P_ ((Lisp_Object, int, int, int));
63static void window_scroll_line_based P_ ((Lisp_Object, int, int, int));
64static int window_min_size_1 P_ ((struct window *, int));
65static int window_min_size P_ ((struct window *, int, int, int *));
66static void size_window P_ ((Lisp_Object, int, int, int, int, int));
67static int freeze_window_start P_ ((struct window *, void *));
68static int window_fixed_size_p P_ ((struct window *, int, int));
69static void enlarge_window P_ ((Lisp_Object, int, int));
70static Lisp_Object window_list P_ ((void));
71static int add_window_to_list P_ ((struct window *, void *));
72static int candidate_window_p P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
73				   Lisp_Object));
74static Lisp_Object next_window P_ ((Lisp_Object, Lisp_Object,
75				    Lisp_Object, int));
76static void decode_next_window_args P_ ((Lisp_Object *, Lisp_Object *,
77					 Lisp_Object *));
78static int foreach_window_1 P_ ((struct window *,
79				 int (* fn) (struct window *, void *),
80				 void *));
81static Lisp_Object window_list_1 P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
82
83/* This is the window in which the terminal's cursor should
84   be left when nothing is being done with it.  This must
85   always be a leaf window, and its buffer is selected by
86   the top level editing loop at the end of each command.
87
88   This value is always the same as
89   FRAME_SELECTED_WINDOW (selected_frame).  */
90
91Lisp_Object selected_window;
92
93/* A list of all windows for use by next_window and Fwindow_list.
94   Functions creating or deleting windows should invalidate this cache
95   by setting it to nil.  */
96
97Lisp_Object Vwindow_list;
98
99/* The mini-buffer window of the selected frame.
100   Note that you cannot test for mini-bufferness of an arbitrary window
101   by comparing against this; but you can test for mini-bufferness of
102   the selected window.  */
103
104Lisp_Object minibuf_window;
105
106/* Non-nil means it is the window whose mode line should be
107   shown as the selected window when the minibuffer is selected.  */
108
109Lisp_Object minibuf_selected_window;
110
111/* Non-nil means it is the window for C-M-v to scroll
112   when the mini-buffer is selected.  */
113
114Lisp_Object Vminibuf_scroll_window;
115
116/* Non-nil means this is the buffer whose window C-M-v should scroll.  */
117
118Lisp_Object Vother_window_scroll_buffer;
119
120/* Non-nil means it's function to call to display temp buffers.  */
121
122Lisp_Object Vtemp_buffer_show_function;
123
124/* Non-zero means line and page scrolling on tall lines (with images)
125   does partial scrolling by modifying window-vscroll.  */
126
127int auto_window_vscroll_p;
128
129/* Non-zero means to use mode-line-inactive face in all windows but the
130   selected-window and the minibuffer-scroll-window when the
131   minibuffer is active.  */
132int mode_line_in_non_selected_windows;
133
134/* If a window gets smaller than either of these, it is removed. */
135
136EMACS_INT window_min_height;
137EMACS_INT window_min_width;
138
139/* Nonzero implies Fdisplay_buffer should create windows. */
140
141int pop_up_windows;
142
143/* Nonzero implies make new frames for Fdisplay_buffer.  */
144
145int pop_up_frames;
146
147/* Nonzero means reuse existing frames for displaying buffers.  */
148
149int display_buffer_reuse_frames;
150
151/* Non-nil means use this function instead of default */
152
153Lisp_Object Vpop_up_frame_function;
154
155/* Function to call to handle Fdisplay_buffer.  */
156
157Lisp_Object Vdisplay_buffer_function;
158
159/* Non-nil means that Fdisplay_buffer should even the heights of windows.  */
160
161Lisp_Object Veven_window_heights;
162
163/* List of buffer *names* for buffers that should have their own frames.  */
164
165Lisp_Object Vspecial_display_buffer_names;
166
167/* List of regexps for buffer names that should have their own frames.  */
168
169Lisp_Object Vspecial_display_regexps;
170
171/* Function to pop up a special frame.  */
172
173Lisp_Object Vspecial_display_function;
174
175/* List of buffer *names* for buffers to appear in selected window.  */
176
177Lisp_Object Vsame_window_buffer_names;
178
179/* List of regexps for buffer names to appear in selected window.  */
180
181Lisp_Object Vsame_window_regexps;
182
183/* Hook run at end of temp_output_buffer_show.  */
184
185Lisp_Object Qtemp_buffer_show_hook;
186
187/* Fdisplay_buffer always splits the largest window
188   if that window is more than this high.  */
189
190EMACS_INT split_height_threshold;
191
192/* Number of lines of continuity in scrolling by screenfuls.  */
193
194EMACS_INT next_screen_context_lines;
195
196/* Incremented for each window created.  */
197
198static int sequence_number;
199
200/* Nonzero after init_window_once has finished.  */
201
202static int window_initialized;
203
204/* Hook to run when window config changes.  */
205
206Lisp_Object Qwindow_configuration_change_hook;
207Lisp_Object Vwindow_configuration_change_hook;
208
209/* Non-nil means scroll commands try to put point
210   at the same screen height as previously.  */
211
212Lisp_Object Vscroll_preserve_screen_position;
213
214/* Incremented by 1 whenever a window is deleted.  */
215
216int window_deletion_count;
217
218/* Used by the function window_scroll_pixel_based */
219
220static int window_scroll_pixel_based_preserve_y;
221
222#if 0 /* This isn't used anywhere.  */
223/* Nonzero means we can split a frame even if it is "unsplittable".  */
224static int inhibit_frame_unsplittable;
225#endif /* 0 */
226
227extern EMACS_INT scroll_margin;
228
229extern Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
230
231DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
232       doc: /* Returns t if OBJECT is a window.  */)
233     (object)
234     Lisp_Object object;
235{
236  return WINDOWP (object) ? Qt : Qnil;
237}
238
239DEFUN ("window-live-p", Fwindow_live_p, Swindow_live_p, 1, 1, 0,
240       doc: /* Returns t if OBJECT is a window which is currently visible.  */)
241     (object)
242     Lisp_Object object;
243{
244  return WINDOW_LIVE_P (object) ? Qt : Qnil;
245}
246
247Lisp_Object
248make_window ()
249{
250  Lisp_Object val;
251  register struct window *p;
252
253  p = allocate_window ();
254  ++sequence_number;
255  XSETFASTINT (p->sequence_number, sequence_number);
256  XSETFASTINT (p->left_col, 0);
257  XSETFASTINT (p->top_line, 0);
258  XSETFASTINT (p->total_lines, 0);
259  XSETFASTINT (p->total_cols, 0);
260  XSETFASTINT (p->hscroll, 0);
261  XSETFASTINT (p->min_hscroll, 0);
262  p->orig_top_line = p->orig_total_lines = Qnil;
263  p->start = Fmake_marker ();
264  p->pointm = Fmake_marker ();
265  XSETFASTINT (p->use_time, 0);
266  p->frame = Qnil;
267  p->display_table = Qnil;
268  p->dedicated = Qnil;
269  p->pseudo_window_p = 0;
270  bzero (&p->cursor, sizeof (p->cursor));
271  bzero (&p->last_cursor, sizeof (p->last_cursor));
272  bzero (&p->phys_cursor, sizeof (p->phys_cursor));
273  p->desired_matrix = p->current_matrix = 0;
274  p->nrows_scale_factor = p->ncols_scale_factor = 1;
275  p->phys_cursor_type = -1;
276  p->phys_cursor_width = -1;
277  p->must_be_updated_p = 0;
278  XSETFASTINT (p->window_end_vpos, 0);
279  XSETFASTINT (p->window_end_pos, 0);
280  p->window_end_valid = Qnil;
281  p->vscroll = 0;
282  XSETWINDOW (val, p);
283  XSETFASTINT (p->last_point, 0);
284  p->frozen_window_start_p = 0;
285  p->last_cursor_off_p = p->cursor_off_p = 0;
286  p->left_margin_cols = Qnil;
287  p->right_margin_cols = Qnil;
288  p->left_fringe_width = Qnil;
289  p->right_fringe_width = Qnil;
290  p->fringes_outside_margins = Qnil;
291  p->scroll_bar_width = Qnil;
292  p->vertical_scroll_bar_type = Qt;
293
294  Vwindow_list = Qnil;
295  return val;
296}
297
298DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0,
299       doc: /* Return the window that the cursor now appears in and commands apply to.  */)
300     ()
301{
302  return selected_window;
303}
304
305DEFUN ("minibuffer-window", Fminibuffer_window, Sminibuffer_window, 0, 1, 0,
306       doc: /* Return the window used now for minibuffers.
307If the optional argument FRAME is specified, return the minibuffer window
308used by that frame.  */)
309     (frame)
310    Lisp_Object frame;
311{
312  if (NILP (frame))
313    frame = selected_frame;
314  CHECK_LIVE_FRAME (frame);
315  return FRAME_MINIBUF_WINDOW (XFRAME (frame));
316}
317
318DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1, 0,
319       doc: /* Returns non-nil if WINDOW is a minibuffer window.
320WINDOW defaults to the selected window.  */)
321     (window)
322     Lisp_Object window;
323{
324  struct window *w = decode_window (window);
325  return MINI_WINDOW_P (w) ? Qt : Qnil;
326}
327
328
329DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
330       Spos_visible_in_window_p, 0, 3, 0,
331       doc: /* Return non-nil if position POS is currently on the frame in WINDOW.
332Return nil if that position is scrolled vertically out of view.
333If a character is only partially visible, nil is returned, unless the
334optional argument PARTIALLY is non-nil.
335If POS is only out of view because of horizontal scrolling, return non-nil.
336If POS is t, it specifies the position of the last visible glyph in WINDOW.
337POS defaults to point in WINDOW; WINDOW defaults to the selected window.
338
339If POS is visible, return t if PARTIALLY is nil; if PARTIALLY is non-nil,
340return value is a list of 2 or 6 elements (X Y [RTOP RBOT ROWH VPOS]),
341where X and Y are the pixel coordinates relative to the top left corner
342of the window.  The remaining elements are omitted if the character after
343POS is fully visible; otherwise, RTOP and RBOT are the number of pixels
344off-window at the top and bottom of the row, ROWH is the height of the
345display row, and VPOS is the row number (0-based) containing POS.  */)
346     (pos, window, partially)
347     Lisp_Object pos, window, partially;
348{
349  register struct window *w;
350  register int posint;
351  register struct buffer *buf;
352  struct text_pos top;
353  Lisp_Object in_window = Qnil;
354  int rtop, rbot, rowh, vpos, fully_p = 1;
355  int x, y;
356
357  w = decode_window (window);
358  buf = XBUFFER (w->buffer);
359  SET_TEXT_POS_FROM_MARKER (top, w->start);
360
361  if (EQ (pos, Qt))
362    posint = -1;
363  else if (!NILP (pos))
364    {
365      CHECK_NUMBER_COERCE_MARKER (pos);
366      posint = XINT (pos);
367    }
368  else if (w == XWINDOW (selected_window))
369    posint = PT;
370  else
371    posint = XMARKER (w->pointm)->charpos;
372
373  /* If position is above window start or outside buffer boundaries,
374     or if window start is out of range, position is not visible.  */
375  if ((EQ (pos, Qt)
376       || (posint >= CHARPOS (top) && posint <= BUF_ZV (buf)))
377      && CHARPOS (top) >= BUF_BEGV (buf)
378      && CHARPOS (top) <= BUF_ZV (buf)
379      && pos_visible_p (w, posint, &x, &y, &rtop, &rbot, &rowh, &vpos)
380      && (fully_p = !rtop && !rbot, (!NILP (partially) || fully_p)))
381    in_window = Qt;
382
383  if (!NILP (in_window) && !NILP (partially))
384    {
385      Lisp_Object part = Qnil;
386      if (!fully_p)
387	part = list4 (make_number (rtop), make_number (rbot),
388			make_number (rowh), make_number (vpos));
389      in_window = Fcons (make_number (x),
390			 Fcons (make_number (y), part));
391    }
392
393  return in_window;
394}
395
396DEFUN ("window-line-height", Fwindow_line_height,
397       Swindow_line_height, 0, 2, 0,
398       doc: /* Return height in pixels of text line LINE in window WINDOW.
399If WINDOW is nil or omitted, use selected window.
400
401Return height of current line if LINE is omitted or nil.  Return height of
402header or mode line if LINE is `header-line' and `mode-line'.
403Otherwise, LINE is a text line number starting from 0.  A negative number
404counts from the end of the window.
405
406Value is a list (HEIGHT VPOS YPOS OFFBOT), where HEIGHT is the height
407in pixels of the visible part of the line, VPOS and YPOS are the
408vertical position in lines and pixels of the line, relative to the top
409of the first text line, and OFFBOT is the number of off-window pixels at
410the bottom of the text line.  If there are off-window pixels at the top
411of the (first) text line, YPOS is negative.
412
413Return nil if window display is not up-to-date.  In that case, use
414`pos-visible-in-window-p' to obtain the information.  */)
415     (line, window)
416     Lisp_Object line, window;
417{
418  register struct window *w;
419  register struct buffer *b;
420  struct glyph_row *row, *end_row;
421  int max_y, crop, i, n;
422
423  w = decode_window (window);
424
425  if (noninteractive
426      || w->pseudo_window_p)
427    return Qnil;
428
429  CHECK_BUFFER (w->buffer);
430  b = XBUFFER (w->buffer);
431
432  /* Fail if current matrix is not up-to-date.  */
433  if (NILP (w->window_end_valid)
434      || current_buffer->clip_changed
435      || current_buffer->prevent_redisplay_optimizations_p
436      || XFASTINT (w->last_modified) < BUF_MODIFF (b)
437      || XFASTINT (w->last_overlay_modified) < BUF_OVERLAY_MODIFF (b))
438    return Qnil;
439
440  if (NILP (line))
441    {
442      i = w->cursor.vpos;
443      if (i < 0 || i >= w->current_matrix->nrows
444	  || (row = MATRIX_ROW (w->current_matrix, i), !row->enabled_p))
445	return Qnil;
446      max_y = window_text_bottom_y (w);
447      goto found_row;
448    }
449
450  if (EQ (line, Qheader_line))
451    {
452      if (!WINDOW_WANTS_HEADER_LINE_P (w))
453	return Qnil;
454      row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
455      if (!row->enabled_p)
456	return Qnil;
457      return list4 (make_number (row->height),
458		    make_number (0), make_number (0),
459		    make_number (0));
460    }
461
462  if (EQ (line, Qmode_line))
463    {
464      row = MATRIX_MODE_LINE_ROW (w->current_matrix);
465      if (!row->enabled_p)
466	return Qnil;
467      return list4 (make_number (row->height),
468		    make_number (0), /* not accurate */
469		    make_number (WINDOW_HEADER_LINE_HEIGHT (w)
470				 + window_text_bottom_y (w)),
471		    make_number (0));
472    }
473
474  CHECK_NUMBER (line);
475  n = XINT (line);
476
477  row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
478  end_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
479  max_y = window_text_bottom_y (w);
480  i = 0;
481
482  while ((n < 0 || i < n)
483	 && row <= end_row && row->enabled_p
484	 && row->y + row->height < max_y)
485    row++, i++;
486
487  if (row > end_row || !row->enabled_p)
488    return Qnil;
489
490  if (++n < 0)
491    {
492      if (-n > i)
493	return Qnil;
494      row += n;
495      i += n;
496    }
497
498 found_row:
499  crop = max (0, (row->y + row->height) - max_y);
500  return list4 (make_number (row->height + min (0, row->y) - crop),
501		make_number (i),
502		make_number (row->y),
503		make_number (crop));
504}
505
506
507
508static struct window *
509decode_window (window)
510     register Lisp_Object window;
511{
512  if (NILP (window))
513    return XWINDOW (selected_window);
514
515  CHECK_LIVE_WINDOW (window);
516  return XWINDOW (window);
517}
518
519static struct window *
520decode_any_window (window)
521     register Lisp_Object window;
522{
523  if (NILP (window))
524    return XWINDOW (selected_window);
525
526  CHECK_WINDOW (window);
527  return XWINDOW (window);
528}
529
530DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
531       doc: /* Return the buffer that WINDOW is displaying.
532WINDOW defaults to the selected window.  */)
533     (window)
534     Lisp_Object window;
535{
536  return decode_window (window)->buffer;
537}
538
539DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0,
540       doc: /* Return the number of lines in WINDOW (including its mode line).
541WINDOW defaults to the selected window.  */)
542     (window)
543     Lisp_Object window;
544{
545  return decode_any_window (window)->total_lines;
546}
547
548DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
549       doc: /* Return the number of display columns in WINDOW.
550This is the width that is usable columns available for text in WINDOW.
551If you want to find out how many columns WINDOW takes up,
552use  (let ((edges (window-edges))) (- (nth 2 edges) (nth 0 edges))).  */)
553     (window)
554     Lisp_Object window;
555{
556  return make_number (window_box_text_cols (decode_any_window (window)));
557}
558
559DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
560       doc: /* Return the number of columns by which WINDOW is scrolled from left margin.
561WINDOW defaults to the selected window.  */)
562     (window)
563     Lisp_Object window;
564{
565  return decode_window (window)->hscroll;
566}
567
568DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
569       doc: /* Set number of columns WINDOW is scrolled from left margin to NCOL.
570Return NCOL.  NCOL should be zero or positive.
571
572Note that if `automatic-hscrolling' is non-nil, you cannot scroll the
573window so that the location of point moves off-window.  */)
574     (window, ncol)
575     Lisp_Object window, ncol;
576{
577  struct window *w = decode_window (window);
578  int hscroll;
579
580  CHECK_NUMBER (ncol);
581  hscroll = max (0, XINT (ncol));
582
583  /* Prevent redisplay shortcuts when changing the hscroll.  */
584  if (XINT (w->hscroll) != hscroll)
585    XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
586
587  w->hscroll = make_number (hscroll);
588  return ncol;
589}
590
591DEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger,
592       Swindow_redisplay_end_trigger, 0, 1, 0,
593       doc: /* Return WINDOW's redisplay end trigger value.
594WINDOW defaults to the selected window.
595See `set-window-redisplay-end-trigger' for more information.  */)
596     (window)
597     Lisp_Object window;
598{
599  return decode_window (window)->redisplay_end_trigger;
600}
601
602DEFUN ("set-window-redisplay-end-trigger", Fset_window_redisplay_end_trigger,
603       Sset_window_redisplay_end_trigger, 2, 2, 0,
604       doc: /* Set WINDOW's redisplay end trigger value to VALUE.
605VALUE should be a buffer position (typically a marker) or nil.
606If it is a buffer position, then if redisplay in WINDOW reaches a position
607beyond VALUE, the functions in `redisplay-end-trigger-functions' are called
608with two arguments: WINDOW, and the end trigger value.
609Afterwards the end-trigger value is reset to nil.  */)
610     (window, value)
611     register Lisp_Object window, value;
612{
613  register struct window *w;
614
615  w = decode_window (window);
616  w->redisplay_end_trigger = value;
617  return value;
618}
619
620DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0,
621       doc: /* Return a list of the edge coordinates of WINDOW.
622\(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.
623RIGHT is one more than the rightmost column occupied by WINDOW,
624and BOTTOM is one more than the bottommost row occupied by WINDOW.
625The edges include the space used by the window's scroll bar,
626display margins, fringes, header line, and mode line, if it has them.
627To get the edges of the actual text area, use `window-inside-edges'.  */)
628     (window)
629     Lisp_Object window;
630{
631  register struct window *w = decode_any_window (window);
632
633  return Fcons (make_number (WINDOW_LEFT_EDGE_COL (w)),
634	 Fcons (make_number (WINDOW_TOP_EDGE_LINE (w)),
635	 Fcons (make_number (WINDOW_RIGHT_EDGE_COL (w)),
636	 Fcons (make_number (WINDOW_BOTTOM_EDGE_LINE (w)),
637		Qnil))));
638}
639
640DEFUN ("window-pixel-edges", Fwindow_pixel_edges, Swindow_pixel_edges, 0, 1, 0,
641       doc: /* Return a list of the edge pixel coordinates of WINDOW.
642\(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.
643RIGHT is one more than the rightmost x position occupied by WINDOW,
644and BOTTOM is one more than the bottommost y position occupied by WINDOW.
645The pixel edges include the space used by the window's scroll bar,
646display margins, fringes, header line, and mode line, if it has them.
647To get the edges of the actual text area, use `window-inside-pixel-edges'.  */)
648     (window)
649     Lisp_Object window;
650{
651  register struct window *w = decode_any_window (window);
652
653  return Fcons (make_number (WINDOW_LEFT_EDGE_X (w)),
654	 Fcons (make_number (WINDOW_TOP_EDGE_Y (w)),
655	 Fcons (make_number (WINDOW_RIGHT_EDGE_X (w)),
656	 Fcons (make_number (WINDOW_BOTTOM_EDGE_Y (w)),
657		Qnil))));
658}
659
660DEFUN ("window-inside-edges", Fwindow_inside_edges, Swindow_inside_edges, 0, 1, 0,
661       doc: /* Return a list of the edge coordinates of WINDOW.
662\(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.
663RIGHT is one more than the rightmost column used by text in WINDOW,
664and BOTTOM is one more than the bottommost row used by text in WINDOW.
665The inside edges do not include the space used by the window's scroll bar,
666display margins, fringes, header line, and/or mode line.  */)
667     (window)
668     Lisp_Object window;
669{
670  register struct window *w = decode_any_window (window);
671
672  return list4 (make_number (WINDOW_BOX_LEFT_EDGE_COL (w)
673			     + WINDOW_LEFT_MARGIN_COLS (w)
674			     + WINDOW_LEFT_FRINGE_COLS (w)),
675		make_number (WINDOW_TOP_EDGE_LINE (w)
676			     + WINDOW_HEADER_LINE_LINES (w)),
677		make_number (WINDOW_BOX_RIGHT_EDGE_COL (w)
678			     - WINDOW_RIGHT_MARGIN_COLS (w)
679			     - WINDOW_RIGHT_FRINGE_COLS (w)),
680		make_number (WINDOW_BOTTOM_EDGE_LINE (w)
681			     - WINDOW_MODE_LINE_LINES (w)));
682}
683
684DEFUN ("window-inside-pixel-edges", Fwindow_inside_pixel_edges, Swindow_inside_pixel_edges, 0, 1, 0,
685       doc: /* Return a list of the edge pixel coordinates of WINDOW.
686\(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.
687RIGHT is one more than the rightmost x position used by text in WINDOW,
688and BOTTOM is one more than the bottommost y position used by text in WINDOW.
689The inside edges do not include the space used by the window's scroll bar,
690display margins, fringes, header line, and/or mode line.  */)
691     (window)
692     Lisp_Object window;
693{
694  register struct window *w = decode_any_window (window);
695
696  return list4 (make_number (WINDOW_BOX_LEFT_EDGE_X (w)
697			     + WINDOW_LEFT_MARGIN_WIDTH (w)
698			     + WINDOW_LEFT_FRINGE_WIDTH (w)),
699		make_number (WINDOW_TOP_EDGE_Y (w)
700			     + WINDOW_HEADER_LINE_HEIGHT (w)),
701		make_number (WINDOW_BOX_RIGHT_EDGE_X (w)
702			     - WINDOW_RIGHT_MARGIN_WIDTH (w)
703			     - WINDOW_RIGHT_FRINGE_WIDTH (w)),
704		make_number (WINDOW_BOTTOM_EDGE_Y (w)
705			     - WINDOW_MODE_LINE_HEIGHT (w)));
706}
707
708/* Test if the character at column *X, row *Y is within window W.
709   If it is not, return ON_NOTHING;
710   if it is in the window's text area,
711      set *x and *y to its location relative to the upper left corner
712         of the window, and
713      return ON_TEXT;
714   if it is on the window's modeline, return ON_MODE_LINE;
715   if it is on the border between the window and its right sibling,
716      return ON_VERTICAL_BORDER.
717   if it is on a scroll bar,
718      return ON_SCROLL_BAR.
719   if it is on the window's top line, return ON_HEADER_LINE;
720   if it is in left or right fringe of the window,
721      return ON_LEFT_FRINGE or ON_RIGHT_FRINGE, and convert *X and *Y
722      to window-relative coordinates;
723   if it is in the marginal area to the left/right of the window,
724      return ON_LEFT_MARGIN or ON_RIGHT_MARGIN, and convert *X and *Y
725      to window-relative coordinates.
726
727   X and Y are frame relative pixel coordinates.  */
728
729static enum window_part
730coordinates_in_window (w, x, y)
731     register struct window *w;
732     register int *x, *y;
733{
734  struct frame *f = XFRAME (WINDOW_FRAME (w));
735  int left_x, right_x, top_y, bottom_y;
736  enum window_part part;
737  int ux = FRAME_COLUMN_WIDTH (f);
738  int x0 = WINDOW_LEFT_EDGE_X (w);
739  int x1 = WINDOW_RIGHT_EDGE_X (w);
740  /* The width of the area where the vertical line can be dragged.
741     (Between mode lines for instance.  */
742  int grabbable_width = ux;
743  int lmargin_width, rmargin_width, text_left, text_right;
744
745  /* In what's below, we subtract 1 when computing right_x because we
746     want the rightmost pixel, which is given by left_pixel+width-1.  */
747  if (w->pseudo_window_p)
748    {
749      left_x = 0;
750      right_x = WINDOW_TOTAL_WIDTH (w) - 1;
751      top_y = WINDOW_TOP_EDGE_Y (w);
752      bottom_y = WINDOW_BOTTOM_EDGE_Y (w);
753    }
754  else
755    {
756      left_x = WINDOW_BOX_LEFT_EDGE_X (w);
757      right_x = WINDOW_BOX_RIGHT_EDGE_X (w) - 1;
758      top_y = WINDOW_TOP_EDGE_Y (w);
759      bottom_y = WINDOW_BOTTOM_EDGE_Y (w);
760    }
761
762  /* Outside any interesting row?  */
763  if (*y < top_y || *y >= bottom_y)
764    return ON_NOTHING;
765
766  /* On the mode line or header line?  If it's near the start of
767     the mode or header line of window that's has a horizontal
768     sibling, say it's on the vertical line.  That's to be able
769     to resize windows horizontally in case we're using toolkit
770     scroll bars.  */
771
772  if (WINDOW_WANTS_MODELINE_P (w)
773      && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
774    {
775      part = ON_MODE_LINE;
776
777    header_vertical_border_check:
778      /* We're somewhere on the mode line.  We consider the place
779	 between mode lines of horizontally adjacent mode lines
780	 as the vertical border.    If scroll bars on the left,
781	 return the right window.  */
782      if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
783	  || WINDOW_RIGHTMOST_P (w))
784	{
785	  if (!WINDOW_LEFTMOST_P (w) && abs (*x - x0) < grabbable_width)
786	    {
787	      /* Convert X and Y to window relative coordinates.
788		 Vertical border is at the left edge of window.  */
789	      *x = max (0, *x - x0);
790	      *y -= top_y;
791	      return ON_VERTICAL_BORDER;
792	    }
793	}
794      else
795	{
796	  if (abs (*x - x1) < grabbable_width)
797	    {
798	      /* Convert X and Y to window relative coordinates.
799		 Vertical border is at the right edge of window.  */
800	      *x = min (x1, *x) - x0;
801	      *y -= top_y;
802	      return ON_VERTICAL_BORDER;
803	    }
804	}
805
806      if (*x < x0 || *x >= x1)
807	return ON_NOTHING;
808
809      /* Convert X and Y to window relative coordinates.
810	 Mode line starts at left edge of window.  */
811      *x -= x0;
812      *y -= top_y;
813      return part;
814    }
815
816  if (WINDOW_WANTS_HEADER_LINE_P (w)
817      && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
818    {
819      part = ON_HEADER_LINE;
820      goto header_vertical_border_check;
821    }
822
823  if (*x < x0 || *x >= x1)
824    return ON_NOTHING;
825
826  /* Outside any interesting column?  */
827  if (*x < left_x || *x > right_x)
828    {
829      *y -= top_y;
830      return ON_SCROLL_BAR;
831    }
832
833  lmargin_width = window_box_width (w, LEFT_MARGIN_AREA);
834  rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA);
835
836  text_left = window_box_left (w, TEXT_AREA);
837  text_right = text_left + window_box_width (w, TEXT_AREA);
838
839  if (FRAME_WINDOW_P (f))
840    {
841      if (!w->pseudo_window_p
842	  && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
843	  && !WINDOW_RIGHTMOST_P (w)
844	  && (abs (*x - right_x) < grabbable_width))
845	{
846	  /* Convert X and Y to window relative coordinates.
847	     Vertical border is at the right edge of window.  */
848	  *x = min (right_x, *x) - left_x;
849	  *y -= top_y;
850	  return ON_VERTICAL_BORDER;
851	}
852    }
853  else
854    {
855      /* Need to say "*x > right_x" rather than >=, since on character
856	 terminals, the vertical line's x coordinate is right_x.  */
857      if (!w->pseudo_window_p
858	  && !WINDOW_RIGHTMOST_P (w)
859	  && *x > right_x - ux)
860	{
861	  /* On the border on the right side of the window?  Assume that
862	     this area begins at RIGHT_X minus a canonical char width.  */
863	  *x = min (right_x, *x) - left_x;
864	  *y -= top_y;
865	  return ON_VERTICAL_BORDER;
866	}
867    }
868
869  if (*x < text_left)
870    {
871      if (lmargin_width > 0
872	  && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
873	      ? (*x >= left_x + WINDOW_LEFT_FRINGE_WIDTH (w))
874	      : (*x < left_x + lmargin_width)))
875	{
876	  *x -= left_x;
877	  if (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
878	    *x -= WINDOW_LEFT_FRINGE_WIDTH (w);
879	  *y -= top_y;
880	  return ON_LEFT_MARGIN;
881	}
882
883      /* Convert X and Y to window-relative pixel coordinates.  */
884      *x -= left_x;
885      *y -= top_y;
886      return ON_LEFT_FRINGE;
887    }
888
889  if (*x >= text_right)
890    {
891      if (rmargin_width > 0
892	  && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
893	      ? (*x < right_x - WINDOW_RIGHT_FRINGE_WIDTH (w))
894	      : (*x >= right_x - rmargin_width)))
895	{
896	  *x -= right_x - rmargin_width;
897	  if (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
898	    *x += WINDOW_RIGHT_FRINGE_WIDTH (w);
899	  *y -= top_y;
900	  return ON_RIGHT_MARGIN;
901	}
902
903      /* Convert X and Y to window-relative pixel coordinates.  */
904      *x -= left_x + WINDOW_LEFT_FRINGE_WIDTH (w);
905      *y -= top_y;
906      return ON_RIGHT_FRINGE;
907    }
908
909  /* Everything special ruled out - must be on text area */
910  *x -= text_left;
911  *y -= top_y;
912  return ON_TEXT;
913}
914
915
916DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
917       Scoordinates_in_window_p, 2, 2, 0,
918       doc: /* Return non-nil if COORDINATES are in WINDOW.
919COORDINATES is a cons of the form (X . Y), X and Y being distances
920measured in characters from the upper-left corner of the frame.
921\(0 .  0) denotes the character in the upper left corner of the
922frame.
923If COORDINATES are in the text portion of WINDOW,
924   the coordinates relative to the window are returned.
925If they are in the mode line of WINDOW, `mode-line' is returned.
926If they are in the top mode line of WINDOW, `header-line' is returned.
927If they are in the left fringe of WINDOW, `left-fringe' is returned.
928If they are in the right fringe of WINDOW, `right-fringe' is returned.
929If they are on the border between WINDOW and its right sibling,
930  `vertical-line' is returned.
931If they are in the windows's left or right marginal areas, `left-margin'\n\
932  or `right-margin' is returned.  */)
933     (coordinates, window)
934     register Lisp_Object coordinates, window;
935{
936  struct window *w;
937  struct frame *f;
938  int x, y;
939  Lisp_Object lx, ly;
940
941  CHECK_WINDOW (window);
942  w = XWINDOW (window);
943  f = XFRAME (w->frame);
944  CHECK_CONS (coordinates);
945  lx = Fcar (coordinates);
946  ly = Fcdr (coordinates);
947  CHECK_NUMBER_OR_FLOAT (lx);
948  CHECK_NUMBER_OR_FLOAT (ly);
949  x = FRAME_PIXEL_X_FROM_CANON_X (f, lx) + FRAME_INTERNAL_BORDER_WIDTH (f);
950  y = FRAME_PIXEL_Y_FROM_CANON_Y (f, ly) + FRAME_INTERNAL_BORDER_WIDTH (f);
951
952  switch (coordinates_in_window (w, &x, &y))
953    {
954    case ON_NOTHING:
955      return Qnil;
956
957    case ON_TEXT:
958      /* X and Y are now window relative pixel coordinates.  Convert
959	 them to canonical char units before returning them.  */
960      return Fcons (FRAME_CANON_X_FROM_PIXEL_X (f, x),
961		    FRAME_CANON_Y_FROM_PIXEL_Y (f, y));
962
963    case ON_MODE_LINE:
964      return Qmode_line;
965
966    case ON_VERTICAL_BORDER:
967      return Qvertical_line;
968
969    case ON_HEADER_LINE:
970      return Qheader_line;
971
972    case ON_LEFT_FRINGE:
973      return Qleft_fringe;
974
975    case ON_RIGHT_FRINGE:
976      return Qright_fringe;
977
978    case ON_LEFT_MARGIN:
979      return Qleft_margin;
980
981    case ON_RIGHT_MARGIN:
982      return Qright_margin;
983
984    case ON_SCROLL_BAR:
985      /* Historically we are supposed to return nil in this case.  */
986      return Qnil;
987
988    default:
989      abort ();
990    }
991}
992
993
994/* Callback for foreach_window, used in window_from_coordinates.
995   Check if window W contains coordinates specified by USER_DATA which
996   is actually a pointer to a struct check_window_data CW.
997
998   Check if window W contains coordinates *CW->x and *CW->y.  If it
999   does, return W in *CW->window, as Lisp_Object, and return in
1000   *CW->part the part of the window under coordinates *X,*Y.  Return
1001   zero from this function to stop iterating over windows.  */
1002
1003struct check_window_data
1004{
1005  Lisp_Object *window;
1006  int *x, *y;
1007  enum window_part *part;
1008};
1009
1010static int
1011check_window_containing (w, user_data)
1012     struct window *w;
1013     void *user_data;
1014{
1015  struct check_window_data *cw = (struct check_window_data *) user_data;
1016  enum window_part found;
1017  int continue_p = 1;
1018
1019  found = coordinates_in_window (w, cw->x, cw->y);
1020  if (found != ON_NOTHING)
1021    {
1022      *cw->part = found;
1023      XSETWINDOW (*cw->window, w);
1024      continue_p = 0;
1025    }
1026
1027  return continue_p;
1028}
1029
1030
1031/* Find the window containing frame-relative pixel position X/Y and
1032   return it as a Lisp_Object.
1033
1034   If X, Y is on one of the window's special `window_part' elements,
1035   set *PART to the id of that element, and return X and Y converted
1036   to window relative coordinates in WX and WY.
1037
1038   If there is no window under X, Y return nil and leave *PART
1039   unmodified.  TOOL_BAR_P non-zero means detect tool-bar windows.
1040
1041   This function was previously implemented with a loop cycling over
1042   windows with Fnext_window, and starting with the frame's selected
1043   window.  It turned out that this doesn't work with an
1044   implementation of next_window using Vwindow_list, because
1045   FRAME_SELECTED_WINDOW (F) is not always contained in the window
1046   tree of F when this function is called asynchronously from
1047   note_mouse_highlight.  The original loop didn't terminate in this
1048   case.  */
1049
1050Lisp_Object
1051window_from_coordinates (f, x, y, part, wx, wy, tool_bar_p)
1052     struct frame *f;
1053     int x, y;
1054     enum window_part *part;
1055     int *wx, *wy;
1056     int tool_bar_p;
1057{
1058  Lisp_Object window;
1059  struct check_window_data cw;
1060  enum window_part dummy;
1061
1062  if (part == 0)
1063    part = &dummy;
1064
1065  window = Qnil;
1066  cw.window = &window, cw.x = &x, cw.y = &y; cw.part = part;
1067  foreach_window (f, check_window_containing, &cw);
1068
1069  /* If not found above, see if it's in the tool bar window, if a tool
1070     bar exists.  */
1071  if (NILP (window)
1072      && tool_bar_p
1073      && WINDOWP (f->tool_bar_window)
1074      && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0
1075      && (coordinates_in_window (XWINDOW (f->tool_bar_window), &x, &y)
1076	  != ON_NOTHING))
1077    {
1078      *part = ON_TEXT;
1079      window = f->tool_bar_window;
1080    }
1081
1082  if (wx) *wx = x;
1083  if (wy) *wy = y;
1084
1085  return window;
1086}
1087
1088DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
1089       doc: /* Return window containing coordinates X and Y on FRAME.
1090If omitted, FRAME defaults to the currently selected frame.
1091The top left corner of the frame is considered to be row 0,
1092column 0.  */)
1093     (x, y, frame)
1094     Lisp_Object x, y, frame;
1095{
1096  struct frame *f;
1097
1098  if (NILP (frame))
1099    frame = selected_frame;
1100  CHECK_LIVE_FRAME (frame);
1101  f = XFRAME (frame);
1102
1103  /* Check that arguments are integers or floats.  */
1104  CHECK_NUMBER_OR_FLOAT (x);
1105  CHECK_NUMBER_OR_FLOAT (y);
1106
1107  return window_from_coordinates (f,
1108				  (FRAME_PIXEL_X_FROM_CANON_X (f, x)
1109				   + FRAME_INTERNAL_BORDER_WIDTH (f)),
1110				  (FRAME_PIXEL_Y_FROM_CANON_Y (f, y)
1111				   + FRAME_INTERNAL_BORDER_WIDTH (f)),
1112				  0, 0, 0, 0);
1113}
1114
1115DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
1116       doc: /* Return current value of point in WINDOW.
1117WINDOW defaults to the selected window.
1118
1119For a nonselected window, this is the value point would have
1120if that window were selected.
1121
1122Note that, when WINDOW is the selected window and its buffer
1123is also currently selected, the value returned is the same as (point).
1124It would be more strictly correct to return the `top-level' value
1125of point, outside of any save-excursion forms.
1126But that is hard to define.  */)
1127     (window)
1128     Lisp_Object window;
1129{
1130  register struct window *w = decode_window (window);
1131
1132  if (w == XWINDOW (selected_window)
1133      && current_buffer == XBUFFER (w->buffer))
1134    return Fpoint ();
1135  return Fmarker_position (w->pointm);
1136}
1137
1138DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
1139       doc: /* Return position at which display currently starts in WINDOW.
1140WINDOW defaults to the selected window.
1141This is updated by redisplay or by calling `set-window-start'.  */)
1142     (window)
1143     Lisp_Object window;
1144{
1145  return Fmarker_position (decode_window (window)->start);
1146}
1147
1148/* This is text temporarily removed from the doc string below.
1149
1150This function returns nil if the position is not currently known.
1151That happens when redisplay is preempted and doesn't finish.
1152If in that case you want to compute where the end of the window would
1153have been if redisplay had finished, do this:
1154    (save-excursion
1155      (goto-char (window-start window))
1156      (vertical-motion (1- (window-height window)) window)
1157      (point))")  */
1158
1159DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
1160       doc: /* Return position at which display currently ends in WINDOW.
1161WINDOW defaults to the selected window.
1162This is updated by redisplay, when it runs to completion.
1163Simply changing the buffer text or setting `window-start'
1164does not update this value.
1165Return nil if there is no recorded value.  \(This can happen if the
1166last redisplay of WINDOW was preempted, and did not finish.)
1167If UPDATE is non-nil, compute the up-to-date position
1168if it isn't already recorded.  */)
1169     (window, update)
1170     Lisp_Object window, update;
1171{
1172  Lisp_Object value;
1173  struct window *w = decode_window (window);
1174  Lisp_Object buf;
1175  struct buffer *b;
1176
1177  buf = w->buffer;
1178  CHECK_BUFFER (buf);
1179  b = XBUFFER (buf);
1180
1181#if 0 /* This change broke some things.  We should make it later.  */
1182  /* If we don't know the end position, return nil.
1183     The user can compute it with vertical-motion if he wants to.
1184     It would be nicer to do it automatically,
1185     but that's so slow that it would probably bother people.  */
1186  if (NILP (w->window_end_valid))
1187    return Qnil;
1188#endif
1189
1190  if (! NILP (update)
1191      && ! (! NILP (w->window_end_valid)
1192	    && XFASTINT (w->last_modified) >= BUF_MODIFF (b)
1193	    && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (b))
1194      && !noninteractive)
1195    {
1196      struct text_pos startp;
1197      struct it it;
1198      struct buffer *old_buffer = NULL;
1199
1200      /* Cannot use Fvertical_motion because that function doesn't
1201	 cope with variable-height lines.  */
1202      if (b != current_buffer)
1203	{
1204	  old_buffer = current_buffer;
1205	  set_buffer_internal (b);
1206	}
1207
1208      /* In case W->start is out of the range, use something
1209         reasonable.  This situation occurred when loading a file with
1210         `-l' containing a call to `rmail' with subsequent other
1211         commands.  At the end, W->start happened to be BEG, while
1212         rmail had already narrowed the buffer.  */
1213      if (XMARKER (w->start)->charpos < BEGV)
1214	SET_TEXT_POS (startp, BEGV, BEGV_BYTE);
1215      else if (XMARKER (w->start)->charpos > ZV)
1216	SET_TEXT_POS (startp, ZV, ZV_BYTE);
1217      else
1218	SET_TEXT_POS_FROM_MARKER (startp, w->start);
1219
1220      start_display (&it, w, startp);
1221      move_it_vertically (&it, window_box_height (w));
1222      if (it.current_y < it.last_visible_y)
1223	move_it_past_eol (&it);
1224      value = make_number (IT_CHARPOS (it));
1225
1226      if (old_buffer)
1227	set_buffer_internal (old_buffer);
1228    }
1229  else
1230    XSETINT (value, BUF_Z (b) - XFASTINT (w->window_end_pos));
1231
1232  return value;
1233}
1234
1235DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
1236       doc: /* Make point value in WINDOW be at position POS in WINDOW's buffer.
1237Return POS.  */)
1238     (window, pos)
1239     Lisp_Object window, pos;
1240{
1241  register struct window *w = decode_window (window);
1242
1243  CHECK_NUMBER_COERCE_MARKER (pos);
1244  if (w == XWINDOW (selected_window)
1245      && XBUFFER (w->buffer) == current_buffer)
1246    Fgoto_char (pos);
1247  else
1248    set_marker_restricted (w->pointm, pos, w->buffer);
1249
1250  /* We have to make sure that redisplay updates the window to show
1251     the new value of point.  */
1252  if (!EQ (window, selected_window))
1253    ++windows_or_buffers_changed;
1254
1255  return pos;
1256}
1257
1258DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
1259       doc: /* Make display in WINDOW start at position POS in WINDOW's buffer.
1260Return POS.
1261Optional third arg NOFORCE non-nil inhibits next redisplay
1262from overriding motion of point in order to display at this exact start.  */)
1263     (window, pos, noforce)
1264     Lisp_Object window, pos, noforce;
1265{
1266  register struct window *w = decode_window (window);
1267
1268  CHECK_NUMBER_COERCE_MARKER (pos);
1269  set_marker_restricted (w->start, pos, w->buffer);
1270  /* this is not right, but much easier than doing what is right. */
1271  w->start_at_line_beg = Qnil;
1272  if (NILP (noforce))
1273    w->force_start = Qt;
1274  w->update_mode_line = Qt;
1275  XSETFASTINT (w->last_modified, 0);
1276  XSETFASTINT (w->last_overlay_modified, 0);
1277  if (!EQ (window, selected_window))
1278    windows_or_buffers_changed++;
1279
1280  return pos;
1281}
1282
1283DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
1284       1, 1, 0,
1285       doc: /* Return WINDOW's dedicated object, usually t or nil.
1286See also `set-window-dedicated-p'.  */)
1287     (window)
1288     Lisp_Object window;
1289{
1290  return decode_window (window)->dedicated;
1291}
1292
1293DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p,
1294       Sset_window_dedicated_p, 2, 2, 0,
1295       doc: /* Control whether WINDOW is dedicated to the buffer it displays.
1296If it is dedicated, Emacs will not automatically change
1297which buffer appears in it.
1298The second argument is the new value for the dedication flag;
1299non-nil means yes. */)
1300     (window, arg)
1301     Lisp_Object window, arg;
1302{
1303  register struct window *w = decode_window (window);
1304
1305  w->dedicated = arg;
1306
1307  return w->dedicated;
1308}
1309
1310DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
1311       0, 1, 0,
1312       doc: /* Return the display-table that WINDOW is using.
1313WINDOW defaults to the selected window.  */)
1314     (window)
1315     Lisp_Object window;
1316{
1317  return decode_window (window)->display_table;
1318}
1319
1320/* Get the display table for use on window W.  This is either W's
1321   display table or W's buffer's display table.  Ignore the specified
1322   tables if they are not valid; if no valid table is specified,
1323   return 0.  */
1324
1325struct Lisp_Char_Table *
1326window_display_table (w)
1327     struct window *w;
1328{
1329  struct Lisp_Char_Table *dp = NULL;
1330
1331  if (DISP_TABLE_P (w->display_table))
1332    dp = XCHAR_TABLE (w->display_table);
1333  else if (BUFFERP (w->buffer))
1334    {
1335      struct buffer *b = XBUFFER (w->buffer);
1336
1337      if (DISP_TABLE_P (b->display_table))
1338	dp = XCHAR_TABLE (b->display_table);
1339      else if (DISP_TABLE_P (Vstandard_display_table))
1340	dp = XCHAR_TABLE (Vstandard_display_table);
1341    }
1342
1343  return dp;
1344}
1345
1346DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_display_table, 2, 2, 0,
1347       doc: /* Set WINDOW's display-table to TABLE.  */)
1348     (window, table)
1349     register Lisp_Object window, table;
1350{
1351  register struct window *w;
1352
1353  w = decode_window (window);
1354  w->display_table = table;
1355  return table;
1356}
1357
1358/* Record info on buffer window w is displaying
1359   when it is about to cease to display that buffer.  */
1360static void
1361unshow_buffer (w)
1362     register struct window *w;
1363{
1364  Lisp_Object buf;
1365  struct buffer *b;
1366
1367  buf = w->buffer;
1368  b = XBUFFER (buf);
1369  if (b != XMARKER (w->pointm)->buffer)
1370    abort ();
1371
1372#if 0
1373  if (w == XWINDOW (selected_window)
1374      || ! EQ (buf, XWINDOW (selected_window)->buffer))
1375    /* Do this except when the selected window's buffer
1376       is being removed from some other window.  */
1377#endif
1378    /* last_window_start records the start position that this buffer
1379       had in the last window to be disconnected from it.
1380       Now that this statement is unconditional,
1381       it is possible for the buffer to be displayed in the
1382       selected window, while last_window_start reflects another
1383       window which was recently showing the same buffer.
1384       Some people might say that might be a good thing.  Let's see.  */
1385    b->last_window_start = marker_position (w->start);
1386
1387  /* Point in the selected window's buffer
1388     is actually stored in that buffer, and the window's pointm isn't used.
1389     So don't clobber point in that buffer.  */
1390  if (! EQ (buf, XWINDOW (selected_window)->buffer)
1391      /* This line helps to fix Horsley's testbug.el bug.  */
1392      && !(WINDOWP (b->last_selected_window)
1393	   && w != XWINDOW (b->last_selected_window)
1394	   && EQ (buf, XWINDOW (b->last_selected_window)->buffer)))
1395    temp_set_point_both (b,
1396			 clip_to_bounds (BUF_BEGV (b),
1397					 XMARKER (w->pointm)->charpos,
1398					 BUF_ZV (b)),
1399			 clip_to_bounds (BUF_BEGV_BYTE (b),
1400					 marker_byte_position (w->pointm),
1401					 BUF_ZV_BYTE (b)));
1402
1403  if (WINDOWP (b->last_selected_window)
1404      && w == XWINDOW (b->last_selected_window))
1405    b->last_selected_window = Qnil;
1406}
1407
1408/* Put replacement into the window structure in place of old. */
1409static void
1410replace_window (old, replacement)
1411     Lisp_Object old, replacement;
1412{
1413  register Lisp_Object tem;
1414  register struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
1415
1416  /* If OLD is its frame's root_window, then replacement is the new
1417     root_window for that frame.  */
1418
1419  if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
1420    FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
1421
1422  p->left_col = o->left_col;
1423  p->top_line = o->top_line;
1424  p->total_cols = o->total_cols;
1425  p->total_lines = o->total_lines;
1426  p->desired_matrix = p->current_matrix = 0;
1427  p->vscroll = 0;
1428  bzero (&p->cursor, sizeof (p->cursor));
1429  bzero (&p->last_cursor, sizeof (p->last_cursor));
1430  bzero (&p->phys_cursor, sizeof (p->phys_cursor));
1431  p->phys_cursor_type = -1;
1432  p->phys_cursor_width = -1;
1433  p->must_be_updated_p = 0;
1434  p->pseudo_window_p = 0;
1435  XSETFASTINT (p->window_end_vpos, 0);
1436  XSETFASTINT (p->window_end_pos, 0);
1437  p->window_end_valid = Qnil;
1438  p->frozen_window_start_p = 0;
1439  p->orig_top_line = p->orig_total_lines = Qnil;
1440
1441  p->next = tem = o->next;
1442  if (!NILP (tem))
1443    XWINDOW (tem)->prev = replacement;
1444
1445  p->prev = tem = o->prev;
1446  if (!NILP (tem))
1447    XWINDOW (tem)->next = replacement;
1448
1449  p->parent = tem = o->parent;
1450  if (!NILP (tem))
1451    {
1452      if (EQ (XWINDOW (tem)->vchild, old))
1453	XWINDOW (tem)->vchild = replacement;
1454      if (EQ (XWINDOW (tem)->hchild, old))
1455	XWINDOW (tem)->hchild = replacement;
1456    }
1457
1458/*** Here, if replacement is a vertical combination
1459and so is its new parent, we should make replacement's
1460children be children of that parent instead.  ***/
1461}
1462
1463DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
1464       doc: /* Remove WINDOW from the display.  Default is selected window.  */)
1465     (window)
1466     register Lisp_Object window;
1467{
1468  delete_window (window);
1469
1470  if (! NILP (Vwindow_configuration_change_hook)
1471      && ! NILP (Vrun_hooks))
1472    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
1473
1474  return Qnil;
1475}
1476
1477void
1478delete_window (window)
1479     register Lisp_Object window;
1480{
1481  register Lisp_Object tem, parent, sib;
1482  register struct window *p;
1483  register struct window *par;
1484  struct frame *f;
1485
1486  /* Because this function is called by other C code on non-leaf
1487     windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
1488     so we can't decode_window here.  */
1489  if (NILP (window))
1490    window = selected_window;
1491  else
1492    CHECK_WINDOW (window);
1493  p = XWINDOW (window);
1494
1495  /* It's a no-op to delete an already-deleted window.  */
1496  if (NILP (p->buffer)
1497      && NILP (p->hchild)
1498      && NILP (p->vchild))
1499    return;
1500
1501  parent = p->parent;
1502  if (NILP (parent))
1503    error ("Attempt to delete minibuffer or sole ordinary window");
1504  par = XWINDOW (parent);
1505
1506  windows_or_buffers_changed++;
1507  Vwindow_list = Qnil;
1508  f = XFRAME (WINDOW_FRAME (p));
1509  FRAME_WINDOW_SIZES_CHANGED (f) = 1;
1510
1511  /* Are we trying to delete any frame's selected window?  */
1512  {
1513    Lisp_Object swindow, pwindow;
1514
1515    /* See if the frame's selected window is either WINDOW
1516       or any subwindow of it, by finding all that window's parents
1517       and comparing each one with WINDOW.  */
1518    swindow = FRAME_SELECTED_WINDOW (f);
1519
1520    while (1)
1521      {
1522	pwindow = swindow;
1523	while (!NILP (pwindow))
1524	  {
1525	    if (EQ (window, pwindow))
1526	      break;
1527	    pwindow = XWINDOW (pwindow)->parent;
1528	  }
1529
1530	/* If the window being deleted is not a parent of SWINDOW,
1531	   then SWINDOW is ok as the new selected window.  */
1532	if (!EQ (window, pwindow))
1533	  break;
1534	/* Otherwise, try another window for SWINDOW.  */
1535	swindow = Fnext_window (swindow, Qlambda, Qnil);;
1536
1537	/* If we get back to the frame's selected window,
1538	   it means there was no acceptable alternative,
1539	   so we cannot delete.  */
1540	if (EQ (swindow, FRAME_SELECTED_WINDOW (f)))
1541	  error ("Cannot delete window");
1542      }
1543
1544    /* If we need to change SWINDOW, do it.  */
1545    if (! EQ (swindow, FRAME_SELECTED_WINDOW (f)))
1546      {
1547	/* If we're about to delete the selected window on the
1548	   selected frame, then we should use Fselect_window to select
1549	   the new window.  On the other hand, if we're about to
1550	   delete the selected window on any other frame, we shouldn't do
1551	   anything but set the frame's selected_window slot.  */
1552	if (EQ (FRAME_SELECTED_WINDOW (f), selected_window))
1553	  Fselect_window (swindow, Qnil);
1554	else
1555	  FRAME_SELECTED_WINDOW (f) = swindow;
1556      }
1557  }
1558
1559  /* Now we know we can delete this one.  */
1560  window_deletion_count++;
1561
1562  tem = p->buffer;
1563  /* tem is null for dummy parent windows
1564     (which have inferiors but not any contents themselves) */
1565  if (!NILP (tem))
1566    {
1567      unshow_buffer (p);
1568      unchain_marker (XMARKER (p->pointm));
1569      unchain_marker (XMARKER (p->start));
1570    }
1571
1572  /* Free window glyph matrices.  It is sure that they are allocated
1573     again when ADJUST_GLYPHS is called.  Block input so that expose
1574     events and other events that access glyph matrices are not
1575     processed while we are changing them.  */
1576  BLOCK_INPUT;
1577  free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (f)));
1578
1579  tem = p->next;
1580  if (!NILP (tem))
1581    XWINDOW (tem)->prev = p->prev;
1582
1583  tem = p->prev;
1584  if (!NILP (tem))
1585    XWINDOW (tem)->next = p->next;
1586
1587  if (EQ (window, par->hchild))
1588    par->hchild = p->next;
1589  if (EQ (window, par->vchild))
1590    par->vchild = p->next;
1591
1592  /* Find one of our siblings to give our space to.  */
1593  sib = p->prev;
1594  if (NILP (sib))
1595    {
1596      /* If p gives its space to its next sibling, that sibling needs
1597	 to have its top/left side pulled back to where p's is.
1598	 set_window_{height,width} will re-position the sibling's
1599	 children.  */
1600      sib = p->next;
1601      XWINDOW (sib)->top_line = p->top_line;
1602      XWINDOW (sib)->left_col = p->left_col;
1603    }
1604
1605  /* Stretch that sibling.  */
1606  if (!NILP (par->vchild))
1607    set_window_height (sib,
1608		       XFASTINT (XWINDOW (sib)->total_lines) + XFASTINT (p->total_lines),
1609		       1);
1610  if (!NILP (par->hchild))
1611    set_window_width (sib,
1612		      XFASTINT (XWINDOW (sib)->total_cols) + XFASTINT (p->total_cols),
1613		      1);
1614
1615  /* If parent now has only one child,
1616     put the child into the parent's place.  */
1617  tem = par->hchild;
1618  if (NILP (tem))
1619    tem = par->vchild;
1620  if (NILP (XWINDOW (tem)->next)) {
1621    replace_window (parent, tem);
1622    par = XWINDOW (tem);
1623  }
1624
1625  /* Since we may be deleting combination windows, we must make sure that
1626     not only p but all its children have been marked as deleted.  */
1627  if (! NILP (p->hchild))
1628    delete_all_subwindows (XWINDOW (p->hchild));
1629  else if (! NILP (p->vchild))
1630    delete_all_subwindows (XWINDOW (p->vchild));
1631
1632  /* Mark this window as deleted.  */
1633  p->buffer = p->hchild = p->vchild = Qnil;
1634
1635  if (! NILP (par->parent))
1636    par = XWINDOW (par->parent);
1637
1638  /* Check if we have a v/hchild with a v/hchild.  In that case remove
1639     one of them.  */
1640
1641  if (! NILP (par->vchild) && ! NILP (XWINDOW (par->vchild)->vchild))
1642    {
1643      p = XWINDOW (par->vchild);
1644      par->vchild = p->vchild;
1645      tem = p->vchild;
1646    }
1647  else if (! NILP (par->hchild) && ! NILP (XWINDOW (par->hchild)->hchild))
1648    {
1649      p = XWINDOW (par->hchild);
1650      par->hchild = p->hchild;
1651      tem = p->hchild;
1652    }
1653  else
1654    p = 0;
1655
1656  if (p)
1657    {
1658      while (! NILP (tem)) {
1659        XWINDOW (tem)->parent = p->parent;
1660        if (NILP (XWINDOW (tem)->next))
1661          break;
1662        tem = XWINDOW (tem)->next;
1663      }
1664      if (! NILP (tem)) {
1665        /* The next of the v/hchild we are removing is now the next of the
1666           last child for the v/hchild:
1667           Before v/hchild -> v/hchild -> next1 -> next2
1668                    |
1669                     -> next3
1670           After:  v/hchild -> next1 -> next2 -> next3
1671        */
1672        XWINDOW (tem)->next = p->next;
1673        if (! NILP (p->next))
1674          XWINDOW (p->next)->prev = tem;
1675      }
1676      p->next = p->prev = p->vchild = p->hchild = p->buffer = Qnil;
1677    }
1678
1679
1680  /* Adjust glyph matrices. */
1681  adjust_glyphs (f);
1682  UNBLOCK_INPUT;
1683}
1684
1685
1686
1687/***********************************************************************
1688			     Window List
1689 ***********************************************************************/
1690
1691/* Add window W to *USER_DATA.  USER_DATA is actually a Lisp_Object
1692   pointer.  This is a callback function for foreach_window, used in
1693   function window_list.  */
1694
1695static int
1696add_window_to_list (w, user_data)
1697     struct window *w;
1698     void *user_data;
1699{
1700  Lisp_Object *list = (Lisp_Object *) user_data;
1701  Lisp_Object window;
1702  XSETWINDOW (window, w);
1703  *list = Fcons (window, *list);
1704  return 1;
1705}
1706
1707
1708/* Return a list of all windows, for use by next_window.  If
1709   Vwindow_list is a list, return that list.  Otherwise, build a new
1710   list, cache it in Vwindow_list, and return that.  */
1711
1712static Lisp_Object
1713window_list ()
1714{
1715  if (!CONSP (Vwindow_list))
1716    {
1717      Lisp_Object tail;
1718
1719      Vwindow_list = Qnil;
1720      for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
1721	{
1722	  Lisp_Object args[2];
1723
1724	  /* We are visiting windows in canonical order, and add
1725	     new windows at the front of args[1], which means we
1726	     have to reverse this list at the end.  */
1727	  args[1] = Qnil;
1728	  foreach_window (XFRAME (XCAR (tail)), add_window_to_list, &args[1]);
1729	  args[0] = Vwindow_list;
1730	  args[1] = Fnreverse (args[1]);
1731	  Vwindow_list = Fnconc (2, args);
1732	}
1733    }
1734
1735  return Vwindow_list;
1736}
1737
1738
1739/* Value is non-zero if WINDOW satisfies the constraints given by
1740   OWINDOW, MINIBUF and ALL_FRAMES.
1741
1742   MINIBUF	t means WINDOW may be minibuffer windows.
1743		`lambda' means WINDOW may not be a minibuffer window.
1744		a window means a specific minibuffer window
1745
1746   ALL_FRAMES	t means search all frames,
1747		nil means search just current frame,
1748		`visible' means search just visible frames,
1749		0 means search visible and iconified frames,
1750		a window means search the frame that window belongs to,
1751		a frame means consider windows on that frame, only.  */
1752
1753static int
1754candidate_window_p (window, owindow, minibuf, all_frames)
1755     Lisp_Object window, owindow, minibuf, all_frames;
1756{
1757  struct window *w = XWINDOW (window);
1758  struct frame *f = XFRAME (w->frame);
1759  int candidate_p = 1;
1760
1761  if (!BUFFERP (w->buffer))
1762    candidate_p = 0;
1763  else if (MINI_WINDOW_P (w)
1764           && (EQ (minibuf, Qlambda)
1765	       || (WINDOWP (minibuf) && !EQ (minibuf, window))))
1766    {
1767      /* If MINIBUF is `lambda' don't consider any mini-windows.
1768         If it is a window, consider only that one.  */
1769      candidate_p = 0;
1770    }
1771  else if (EQ (all_frames, Qt))
1772    candidate_p = 1;
1773  else if (NILP (all_frames))
1774    {
1775      xassert (WINDOWP (owindow));
1776      candidate_p = EQ (w->frame, XWINDOW (owindow)->frame);
1777    }
1778  else if (EQ (all_frames, Qvisible))
1779    {
1780      FRAME_SAMPLE_VISIBILITY (f);
1781      candidate_p = FRAME_VISIBLE_P (f);
1782    }
1783  else if (INTEGERP (all_frames) && XINT (all_frames) == 0)
1784    {
1785      FRAME_SAMPLE_VISIBILITY (f);
1786      candidate_p = FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f);
1787    }
1788  else if (WINDOWP (all_frames))
1789    candidate_p = (EQ (FRAME_MINIBUF_WINDOW (f), all_frames)
1790		   || EQ (XWINDOW (all_frames)->frame, w->frame)
1791		   || EQ (XWINDOW (all_frames)->frame, FRAME_FOCUS_FRAME (f)));
1792  else if (FRAMEP (all_frames))
1793    candidate_p = EQ (all_frames, w->frame);
1794
1795  return candidate_p;
1796}
1797
1798
1799/* Decode arguments as allowed by Fnext_window, Fprevious_window, and
1800   Fwindow_list.  See there for the meaning of WINDOW, MINIBUF, and
1801   ALL_FRAMES.  */
1802
1803static void
1804decode_next_window_args (window, minibuf, all_frames)
1805     Lisp_Object *window, *minibuf, *all_frames;
1806{
1807  if (NILP (*window))
1808    *window = selected_window;
1809  else
1810    CHECK_LIVE_WINDOW (*window);
1811
1812  /* MINIBUF nil may or may not include minibuffers.  Decide if it
1813     does.  */
1814  if (NILP (*minibuf))
1815    *minibuf = minibuf_level ? minibuf_window : Qlambda;
1816  else if (!EQ (*minibuf, Qt))
1817    *minibuf = Qlambda;
1818
1819  /* Now *MINIBUF can be t => count all minibuffer windows, `lambda'
1820     => count none of them, or a specific minibuffer window (the
1821     active one) to count.  */
1822
1823  /* ALL_FRAMES nil doesn't specify which frames to include.  */
1824  if (NILP (*all_frames))
1825    *all_frames = (!EQ (*minibuf, Qlambda)
1826		   ? FRAME_MINIBUF_WINDOW (XFRAME (XWINDOW (*window)->frame))
1827		   : Qnil);
1828  else if (EQ (*all_frames, Qvisible))
1829    ;
1830  else if (EQ (*all_frames, make_number (0)))
1831    ;
1832  else if (FRAMEP (*all_frames))
1833    ;
1834  else if (!EQ (*all_frames, Qt))
1835    *all_frames = Qnil;
1836
1837  /* Now *ALL_FRAMES is t meaning search all frames, nil meaning
1838     search just current frame, `visible' meaning search just visible
1839     frames, 0 meaning search visible and iconified frames, or a
1840     window, meaning search the frame that window belongs to, or a
1841     frame, meaning consider windows on that frame, only.  */
1842}
1843
1844
1845/* Return the next or previous window of WINDOW in canonical ordering
1846   of windows.  NEXT_P non-zero means return the next window.  See the
1847   documentation string of next-window for the meaning of MINIBUF and
1848   ALL_FRAMES.  */
1849
1850static Lisp_Object
1851next_window (window, minibuf, all_frames, next_p)
1852     Lisp_Object window, minibuf, all_frames;
1853     int next_p;
1854{
1855  decode_next_window_args (&window, &minibuf, &all_frames);
1856
1857  /* If ALL_FRAMES is a frame, and WINDOW isn't on that frame, just
1858     return the first window on the frame.  */
1859  if (FRAMEP (all_frames)
1860      && !EQ (all_frames, XWINDOW (window)->frame))
1861    return Fframe_first_window (all_frames);
1862
1863  if (next_p)
1864    {
1865      Lisp_Object list;
1866
1867      /* Find WINDOW in the list of all windows.  */
1868      list = Fmemq (window, window_list ());
1869
1870      /* Scan forward from WINDOW to the end of the window list.  */
1871      if (CONSP (list))
1872	for (list = XCDR (list); CONSP (list); list = XCDR (list))
1873	  if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
1874	    break;
1875
1876      /* Scan from the start of the window list up to WINDOW.  */
1877      if (!CONSP (list))
1878	for (list = Vwindow_list;
1879	     CONSP (list) && !EQ (XCAR (list), window);
1880	     list = XCDR (list))
1881	  if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
1882	    break;
1883
1884      if (CONSP (list))
1885	window = XCAR (list);
1886    }
1887  else
1888    {
1889      Lisp_Object candidate, list;
1890
1891      /* Scan through the list of windows for candidates.  If there are
1892	 candidate windows in front of WINDOW, the last one of these
1893	 is the one we want.  If there are candidates following WINDOW
1894	 in the list, again the last one of these is the one we want.  */
1895      candidate = Qnil;
1896      for (list = window_list (); CONSP (list); list = XCDR (list))
1897	{
1898	  if (EQ (XCAR (list), window))
1899	    {
1900	      if (WINDOWP (candidate))
1901		break;
1902	    }
1903	  else if (candidate_window_p (XCAR (list), window, minibuf,
1904				       all_frames))
1905	    candidate = XCAR (list);
1906	}
1907
1908      if (WINDOWP (candidate))
1909	window = candidate;
1910    }
1911
1912  return window;
1913}
1914
1915
1916DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
1917       doc: /* Return next window after WINDOW in canonical ordering of windows.
1918If omitted, WINDOW defaults to the selected window.
1919
1920Optional second arg MINIBUF t means count the minibuffer window even
1921if not active.  MINIBUF nil or omitted means count the minibuffer iff
1922it is active.  MINIBUF neither t nor nil means not to count the
1923minibuffer even if it is active.
1924
1925Several frames may share a single minibuffer; if the minibuffer
1926counts, all windows on all frames that share that minibuffer count
1927too.  Therefore, `next-window' can be used to iterate through the
1928set of windows even when the minibuffer is on another frame.  If the
1929minibuffer does not count, only windows from WINDOW's frame count.
1930
1931Optional third arg ALL-FRAMES t means include windows on all frames.
1932ALL-FRAMES nil or omitted means cycle within the frames as specified
1933above.  ALL-FRAMES = `visible' means include windows on all visible frames.
1934ALL-FRAMES = 0 means include windows on all visible and iconified frames.
1935If ALL-FRAMES is a frame, restrict search to windows on that frame.
1936Anything else means restrict to WINDOW's frame.
1937
1938If you use consistent values for MINIBUF and ALL-FRAMES, you can use
1939`next-window' to iterate through the entire cycle of acceptable
1940windows, eventually ending up back at the window you started with.
1941`previous-window' traverses the same cycle, in the reverse order.  */)
1942     (window, minibuf, all_frames)
1943     Lisp_Object window, minibuf, all_frames;
1944{
1945  return next_window (window, minibuf, all_frames, 1);
1946}
1947
1948
1949DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
1950       doc: /* Return the window preceding WINDOW in canonical ordering of windows.
1951If omitted, WINDOW defaults to the selected window.
1952
1953Optional second arg MINIBUF t means count the minibuffer window even
1954if not active.  MINIBUF nil or omitted means count the minibuffer iff
1955it is active.  MINIBUF neither t nor nil means not to count the
1956minibuffer even if it is active.
1957
1958Several frames may share a single minibuffer; if the minibuffer
1959counts, all windows on all frames that share that minibuffer count
1960too.  Therefore, `previous-window' can be used to iterate through
1961the set of windows even when the minibuffer is on another frame.  If
1962the minibuffer does not count, only windows from WINDOW's frame count
1963
1964Optional third arg ALL-FRAMES t means include windows on all frames.
1965ALL-FRAMES nil or omitted means cycle within the frames as specified
1966above.  ALL-FRAMES = `visible' means include windows on all visible frames.
1967ALL-FRAMES = 0 means include windows on all visible and iconified frames.
1968If ALL-FRAMES is a frame, restrict search to windows on that frame.
1969Anything else means restrict to WINDOW's frame.
1970
1971If you use consistent values for MINIBUF and ALL-FRAMES, you can use
1972`previous-window' to iterate through the entire cycle of acceptable
1973windows, eventually ending up back at the window you started with.
1974`next-window' traverses the same cycle, in the reverse order.  */)
1975     (window, minibuf, all_frames)
1976     Lisp_Object window, minibuf, all_frames;
1977{
1978  return next_window (window, minibuf, all_frames, 0);
1979}
1980
1981
1982DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
1983       doc: /* Select the ARG'th different window on this frame.
1984All windows on current frame are arranged in a cyclic order.
1985This command selects the window ARG steps away in that order.
1986A negative ARG moves in the opposite order.  The optional second
1987argument ALL-FRAMES has the same meaning as in `next-window', which see.  */)
1988     (arg, all_frames)
1989     Lisp_Object arg, all_frames;
1990{
1991  Lisp_Object window;
1992  int i;
1993
1994  CHECK_NUMBER (arg);
1995  window = selected_window;
1996
1997  for (i = XINT (arg); i > 0; --i)
1998    window = Fnext_window (window, Qnil, all_frames);
1999  for (; i < 0; ++i)
2000    window = Fprevious_window (window, Qnil, all_frames);
2001
2002  Fselect_window (window, Qnil);
2003  return Qnil;
2004}
2005
2006
2007DEFUN ("window-list", Fwindow_list, Swindow_list, 0, 3, 0,
2008       doc: /* Return a list of windows on FRAME, starting with WINDOW.
2009FRAME nil or omitted means use the selected frame.
2010WINDOW nil or omitted means use the selected window.
2011MINIBUF t means include the minibuffer window, even if it isn't active.
2012MINIBUF nil or omitted means include the minibuffer window only
2013if it's active.
2014MINIBUF neither nil nor t means never include the minibuffer window.  */)
2015     (frame, minibuf, window)
2016     Lisp_Object frame, minibuf, window;
2017{
2018  if (NILP (window))
2019    window = FRAMEP (frame) ? XFRAME (frame)->selected_window : selected_window;
2020  CHECK_WINDOW (window);
2021  if (NILP (frame))
2022    frame = selected_frame;
2023
2024  if (!EQ (frame, XWINDOW (window)->frame))
2025    error ("Window is on a different frame");
2026
2027  return window_list_1 (window, minibuf, frame);
2028}
2029
2030
2031/* Return a list of windows in canonical ordering.  Arguments are like
2032   for `next-window'.  */
2033
2034static Lisp_Object
2035window_list_1 (window, minibuf, all_frames)
2036     Lisp_Object window, minibuf, all_frames;
2037{
2038  Lisp_Object tail, list, rest;
2039
2040  decode_next_window_args (&window, &minibuf, &all_frames);
2041  list = Qnil;
2042
2043  for (tail = window_list (); CONSP (tail); tail = XCDR (tail))
2044    if (candidate_window_p (XCAR (tail), window, minibuf, all_frames))
2045      list = Fcons (XCAR (tail), list);
2046
2047  /* Rotate the list to start with WINDOW.  */
2048  list = Fnreverse (list);
2049  rest = Fmemq (window, list);
2050  if (!NILP (rest) && !EQ (rest, list))
2051    {
2052      for (tail = list; !EQ (XCDR (tail), rest); tail = XCDR (tail))
2053	;
2054      XSETCDR (tail, Qnil);
2055      list = nconc2 (rest, list);
2056    }
2057  return list;
2058}
2059
2060
2061
2062/* Look at all windows, performing an operation specified by TYPE
2063   with argument OBJ.
2064   If FRAMES is Qt, look at all frames;
2065                Qnil, look at just the selected frame;
2066		Qvisible, look at visible frames;
2067	        a frame, just look at windows on that frame.
2068   If MINI is non-zero, perform the operation on minibuffer windows too.  */
2069
2070enum window_loop
2071{
2072  WINDOW_LOOP_UNUSED,
2073  GET_BUFFER_WINDOW,		/* Arg is buffer */
2074  GET_LRU_WINDOW,		/* Arg is t for full-width windows only */
2075  DELETE_OTHER_WINDOWS,		/* Arg is window not to delete */
2076  DELETE_BUFFER_WINDOWS,	/* Arg is buffer */
2077  GET_LARGEST_WINDOW,
2078  UNSHOW_BUFFER,		/* Arg is buffer */
2079  REDISPLAY_BUFFER_WINDOWS,	/* Arg is buffer */
2080  CHECK_ALL_WINDOWS
2081};
2082
2083static Lisp_Object
2084window_loop (type, obj, mini, frames)
2085     enum window_loop type;
2086     Lisp_Object obj, frames;
2087     int mini;
2088{
2089  Lisp_Object window, windows, best_window, frame_arg;
2090  struct frame *f;
2091  struct gcpro gcpro1;
2092
2093  /* If we're only looping through windows on a particular frame,
2094     frame points to that frame.  If we're looping through windows
2095     on all frames, frame is 0.  */
2096  if (FRAMEP (frames))
2097    f = XFRAME (frames);
2098  else if (NILP (frames))
2099    f = SELECTED_FRAME ();
2100  else
2101    f = NULL;
2102
2103  if (f)
2104    frame_arg = Qlambda;
2105  else if (EQ (frames, make_number (0)))
2106    frame_arg = frames;
2107  else if (EQ (frames, Qvisible))
2108    frame_arg = frames;
2109  else
2110    frame_arg = Qt;
2111
2112  /* frame_arg is Qlambda to stick to one frame,
2113     Qvisible to consider all visible frames,
2114     or Qt otherwise.  */
2115
2116  /* Pick a window to start with.  */
2117  if (WINDOWP (obj))
2118    window = obj;
2119  else if (f)
2120    window = FRAME_SELECTED_WINDOW (f);
2121  else
2122    window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
2123
2124  windows = window_list_1 (window, mini ? Qt : Qnil, frame_arg);
2125  GCPRO1 (windows);
2126  best_window = Qnil;
2127
2128  for (; CONSP (windows); windows = XCDR (windows))
2129    {
2130      struct window *w;
2131
2132      window = XCAR (windows);
2133      w = XWINDOW (window);
2134
2135      /* Note that we do not pay attention here to whether the frame
2136	 is visible, since Fwindow_list skips non-visible frames if
2137	 that is desired, under the control of frame_arg.  */
2138      if (!MINI_WINDOW_P (w)
2139	  /* For UNSHOW_BUFFER, we must always consider all windows.  */
2140	  || type == UNSHOW_BUFFER
2141	  || (mini && minibuf_level > 0))
2142	switch (type)
2143	  {
2144	  case GET_BUFFER_WINDOW:
2145	    if (EQ (w->buffer, obj)
2146		/* Don't find any minibuffer window
2147		   except the one that is currently in use.  */
2148		&& (MINI_WINDOW_P (w)
2149		    ? EQ (window, minibuf_window)
2150		    : 1))
2151	      {
2152		if (NILP (best_window))
2153		  best_window = window;
2154		else if (EQ (window, selected_window))
2155		  /* For compatibility with 20.x, prefer to return
2156		     selected-window.  */
2157		  best_window = window;
2158	      }
2159	    break;
2160
2161	  case GET_LRU_WINDOW:
2162	    /* `obj' is an integer encoding a bitvector.
2163	       `obj & 1' means consider only full-width windows.
2164	       `obj & 2' means consider also dedicated windows. */
2165	    if (((XINT (obj) & 1) && !WINDOW_FULL_WIDTH_P (w))
2166		|| (!(XINT (obj) & 2) && !NILP (w->dedicated))
2167		/* Minibuffer windows are always ignored.  */
2168		|| MINI_WINDOW_P (w))
2169	      break;
2170	    if (NILP (best_window)
2171		|| (XFASTINT (XWINDOW (best_window)->use_time)
2172		    > XFASTINT (w->use_time)))
2173	      best_window = window;
2174	    break;
2175
2176	  case DELETE_OTHER_WINDOWS:
2177	    if (!EQ (window, obj))
2178	      Fdelete_window (window);
2179	    break;
2180
2181	  case DELETE_BUFFER_WINDOWS:
2182	    if (EQ (w->buffer, obj))
2183	      {
2184		struct frame *f = XFRAME (WINDOW_FRAME (w));
2185
2186		/* If this window is dedicated, and in a frame of its own,
2187		   kill the frame.  */
2188		if (EQ (window, FRAME_ROOT_WINDOW (f))
2189		    && !NILP (w->dedicated)
2190		    && other_visible_frames (f))
2191		  {
2192		    /* Skip the other windows on this frame.
2193		       There might be one, the minibuffer!  */
2194		    while (CONSP (XCDR (windows))
2195			   && EQ (XWINDOW (XCAR (windows))->frame,
2196				  XWINDOW (XCAR (XCDR (windows)))->frame))
2197		      windows = XCDR (windows);
2198
2199		    /* Now we can safely delete the frame.  */
2200		    Fdelete_frame (w->frame, Qnil);
2201		  }
2202		else if (NILP (w->parent))
2203		  {
2204		    /* If we're deleting the buffer displayed in the
2205		       only window on the frame, find a new buffer to
2206		       display there.  */
2207		    Lisp_Object buffer;
2208		    buffer = Fother_buffer (obj, Qnil, w->frame);
2209		    Fset_window_buffer (window, buffer, Qnil);
2210		    if (EQ (window, selected_window))
2211		      Fset_buffer (w->buffer);
2212		  }
2213		else
2214		  Fdelete_window (window);
2215	      }
2216	    break;
2217
2218	  case GET_LARGEST_WINDOW:
2219	    { /* nil `obj' means to ignore dedicated windows.  */
2220	      /* Ignore dedicated windows and minibuffers.  */
2221	      if (MINI_WINDOW_P (w) || (NILP (obj) && !NILP (w->dedicated)))
2222		break;
2223
2224	      if (NILP (best_window))
2225		best_window = window;
2226	      else
2227		{
2228		  struct window *b = XWINDOW (best_window);
2229		  if (XFASTINT (w->total_lines) * XFASTINT (w->total_cols)
2230		      > XFASTINT (b->total_lines) * XFASTINT (b->total_cols))
2231		    best_window = window;
2232		}
2233	    }
2234	    break;
2235
2236	  case UNSHOW_BUFFER:
2237	    if (EQ (w->buffer, obj))
2238	      {
2239		Lisp_Object buffer;
2240		struct frame *f = XFRAME (w->frame);
2241
2242		/* Find another buffer to show in this window.  */
2243		buffer = Fother_buffer (obj, Qnil, w->frame);
2244
2245		/* If this window is dedicated, and in a frame of its own,
2246		   kill the frame.  */
2247		if (EQ (window, FRAME_ROOT_WINDOW (f))
2248		    && !NILP (w->dedicated)
2249		    && other_visible_frames (f))
2250		  {
2251		    /* Skip the other windows on this frame.
2252		       There might be one, the minibuffer!  */
2253		    while (CONSP (XCDR (windows))
2254			   && EQ (XWINDOW (XCAR (windows))->frame,
2255				  XWINDOW (XCAR (XCDR (windows)))->frame))
2256		      windows = XCDR (windows);
2257
2258		    /* Now we can safely delete the frame.  */
2259		    Fdelete_frame (w->frame, Qnil);
2260		  }
2261		else if (!NILP (w->dedicated) && !NILP (w->parent))
2262		  {
2263		    Lisp_Object window;
2264		    XSETWINDOW (window, w);
2265		    /* If this window is dedicated and not the only window
2266		       in its frame, then kill it.  */
2267		    Fdelete_window (window);
2268		  }
2269		else
2270		  {
2271		    /* Otherwise show a different buffer in the window.  */
2272		    w->dedicated = Qnil;
2273		    Fset_window_buffer (window, buffer, Qnil);
2274		    if (EQ (window, selected_window))
2275		      Fset_buffer (w->buffer);
2276		  }
2277	      }
2278	    break;
2279
2280	  case REDISPLAY_BUFFER_WINDOWS:
2281	    if (EQ (w->buffer, obj))
2282	      {
2283		mark_window_display_accurate (window, 0);
2284		w->update_mode_line = Qt;
2285		XBUFFER (obj)->prevent_redisplay_optimizations_p = 1;
2286		++update_mode_lines;
2287		best_window = window;
2288	      }
2289	    break;
2290
2291	    /* Check for a window that has a killed buffer.  */
2292	  case CHECK_ALL_WINDOWS:
2293	    if (! NILP (w->buffer)
2294		&& NILP (XBUFFER (w->buffer)->name))
2295	      abort ();
2296	    break;
2297
2298	  case WINDOW_LOOP_UNUSED:
2299	    break;
2300	  }
2301    }
2302
2303  UNGCPRO;
2304  return best_window;
2305}
2306
2307/* Used for debugging.  Abort if any window has a dead buffer.  */
2308
2309void
2310check_all_windows ()
2311{
2312  window_loop (CHECK_ALL_WINDOWS, Qnil, 1, Qt);
2313}
2314
2315DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 2, 0,
2316       doc: /* Return the window least recently selected or used for display.
2317\(LRU means Least Recently Used.)
2318
2319Return a full-width window if possible.
2320A minibuffer window is never a candidate.
2321A dedicated window is never a candidate, unless DEDICATED is non-nil,
2322  so if all windows are dedicated, the value is nil.
2323If optional argument FRAME is `visible', search all visible frames.
2324If FRAME is 0, search all visible and iconified frames.
2325If FRAME is t, search all frames.
2326If FRAME is nil, search only the selected frame.
2327If FRAME is a frame, search only that frame.  */)
2328  (frame, dedicated)
2329     Lisp_Object frame, dedicated;
2330{
2331  register Lisp_Object w;
2332  /* First try for a window that is full-width */
2333  w = window_loop (GET_LRU_WINDOW,
2334		   NILP (dedicated) ? make_number (1) : make_number (3),
2335		   0, frame);
2336  if (!NILP (w) && !EQ (w, selected_window))
2337    return w;
2338  /* If none of them, try the rest */
2339  return window_loop (GET_LRU_WINDOW,
2340		      NILP (dedicated) ? make_number (0) : make_number (2),
2341		      0, frame);
2342}
2343
2344DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 2, 0,
2345       doc: /* Return the largest window in area.
2346A minibuffer window is never a candidate.
2347A dedicated window is never a candidate unless DEDICATED is non-nil,
2348  so if all windows are dedicated, the value is nil.
2349If optional argument FRAME is `visible', search all visible frames.
2350If FRAME is 0, search all visible and iconified frames.
2351If FRAME is t, search all frames.
2352If FRAME is nil, search only the selected frame.
2353If FRAME is a frame, search only that frame.  */)
2354    (frame, dedicated)
2355     Lisp_Object frame, dedicated;
2356{
2357  return window_loop (GET_LARGEST_WINDOW, dedicated, 0,
2358		      frame);
2359}
2360
2361DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 1, 2, 0,
2362       doc: /* Return a window currently displaying BUFFER, or nil if none.
2363BUFFER can be a buffer or a buffer name.
2364If optional argument FRAME is `visible', search all visible frames.
2365If optional argument FRAME is 0, search all visible and iconified frames.
2366If FRAME is t, search all frames.
2367If FRAME is nil, search only the selected frame.
2368If FRAME is a frame, search only that frame.  */)
2369     (buffer, frame)
2370     Lisp_Object buffer, frame;
2371{
2372  buffer = Fget_buffer (buffer);
2373  if (BUFFERP (buffer))
2374    return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame);
2375  else
2376    return Qnil;
2377}
2378
2379DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
2380       0, 1, "",
2381       doc: /* Make WINDOW (or the selected window) fill its frame.
2382Only the frame WINDOW is on is affected.
2383This function tries to reduce display jumps
2384by keeping the text previously visible in WINDOW
2385in the same place on the frame.  Doing this depends on
2386the value of (window-start WINDOW), so if calling this function
2387in a program gives strange scrolling, make sure the window-start
2388value is reasonable when this function is called.  */)
2389     (window)
2390     Lisp_Object window;
2391{
2392  struct window *w;
2393  int startpos;
2394  int top, new_top;
2395
2396  if (NILP (window))
2397    window = selected_window;
2398  else
2399    CHECK_LIVE_WINDOW (window);
2400  w = XWINDOW (window);
2401
2402  startpos = marker_position (w->start);
2403  top = WINDOW_TOP_EDGE_LINE (w) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
2404
2405  if (MINI_WINDOW_P (w) && top > 0)
2406    error ("Can't expand minibuffer to full frame");
2407
2408  window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_FRAME (w));
2409
2410  /* Try to minimize scrolling, by setting the window start to the point
2411     will cause the text at the old window start to be at the same place
2412     on the frame.  But don't try to do this if the window start is
2413     outside the visible portion (as might happen when the display is
2414     not current, due to typeahead).  */
2415  new_top = WINDOW_TOP_EDGE_LINE (w) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
2416  if (new_top != top
2417      && startpos >= BUF_BEGV (XBUFFER (w->buffer))
2418      && startpos <= BUF_ZV (XBUFFER (w->buffer)))
2419    {
2420      struct position pos;
2421      struct buffer *obuf = current_buffer;
2422
2423      Fset_buffer (w->buffer);
2424      /* This computation used to temporarily move point, but that can
2425	 have unwanted side effects due to text properties.  */
2426      pos = *vmotion (startpos, -top, w);
2427
2428      set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
2429      w->window_end_valid = Qnil;
2430      w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
2431			       || FETCH_BYTE (pos.bytepos - 1) == '\n') ? Qt
2432			      : Qnil);
2433      /* We need to do this, so that the window-scroll-functions
2434	 get called.  */
2435      w->optional_new_start = Qt;
2436
2437      set_buffer_internal (obuf);
2438    }
2439
2440  return Qnil;
2441}
2442
2443DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
2444       1, 2, "bDelete windows on (buffer): ",
2445       doc: /* Delete all windows showing BUFFER.
2446BUFFER must be a buffer or the name of an existing buffer.
2447Optional second argument FRAME controls which frames are affected.
2448If optional argument FRAME is `visible', search all visible frames.
2449If FRAME is 0, search all visible and iconified frames.
2450If FRAME is nil, search all frames.
2451If FRAME is t, search only the selected frame.
2452If FRAME is a frame, search only that frame.  */)
2453     (buffer, frame)
2454     Lisp_Object buffer, frame;
2455{
2456  /* FRAME uses t and nil to mean the opposite of what window_loop
2457     expects.  */
2458  if (NILP (frame))
2459    frame = Qt;
2460  else if (EQ (frame, Qt))
2461    frame = Qnil;
2462
2463  if (!NILP (buffer))
2464    {
2465      buffer = Fget_buffer (buffer);
2466      CHECK_BUFFER (buffer);
2467      window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
2468    }
2469
2470  return Qnil;
2471}
2472
2473DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
2474       Sreplace_buffer_in_windows,
2475       1, 1, "bReplace buffer in windows: ",
2476       doc: /* Replace BUFFER with some other buffer in all windows showing it.
2477BUFFER may be a buffer or the name of an existing buffer.  */)
2478     (buffer)
2479     Lisp_Object buffer;
2480{
2481  if (!NILP (buffer))
2482    {
2483      buffer = Fget_buffer (buffer);
2484      CHECK_BUFFER (buffer);
2485      window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
2486    }
2487  return Qnil;
2488}
2489
2490/* Replace BUFFER with some other buffer in all windows
2491   of all frames, even those on other keyboards.  */
2492
2493void
2494replace_buffer_in_all_windows (buffer)
2495     Lisp_Object buffer;
2496{
2497#ifdef MULTI_KBOARD
2498  Lisp_Object tail, frame;
2499
2500  /* A single call to window_loop won't do the job
2501     because it only considers frames on the current keyboard.
2502     So loop manually over frames, and handle each one.  */
2503  FOR_EACH_FRAME (tail, frame)
2504    window_loop (UNSHOW_BUFFER, buffer, 1, frame);
2505#else
2506  window_loop (UNSHOW_BUFFER, buffer, 1, Qt);
2507#endif
2508}
2509
2510/* Set the height of WINDOW and all its inferiors.  */
2511
2512/* The smallest acceptable dimensions for a window.  Anything smaller
2513   might crash Emacs.  */
2514
2515#define MIN_SAFE_WINDOW_WIDTH  (2)
2516#define MIN_SAFE_WINDOW_HEIGHT (1)
2517
2518/* Make sure that window_min_height and window_min_width are
2519   not too small; if they are, set them to safe minima.  */
2520
2521static void
2522check_min_window_sizes ()
2523{
2524  /* Smaller values might permit a crash.  */
2525  if (window_min_width < MIN_SAFE_WINDOW_WIDTH)
2526    window_min_width = MIN_SAFE_WINDOW_WIDTH;
2527  if (window_min_height < MIN_SAFE_WINDOW_HEIGHT)
2528    window_min_height = MIN_SAFE_WINDOW_HEIGHT;
2529}
2530
2531/* If *ROWS or *COLS are too small a size for FRAME, set them to the
2532   minimum allowable size.  */
2533
2534void
2535check_frame_size (frame, rows, cols)
2536     FRAME_PTR frame;
2537     int *rows, *cols;
2538{
2539  /* For height, we have to see:
2540     how many windows the frame has at minimum (one or two),
2541     and whether it has a menu bar or other special stuff at the top.  */
2542  int min_height
2543    = ((FRAME_MINIBUF_ONLY_P (frame) || ! FRAME_HAS_MINIBUF_P (frame))
2544       ? MIN_SAFE_WINDOW_HEIGHT
2545       : 2 * MIN_SAFE_WINDOW_HEIGHT);
2546
2547  if (FRAME_TOP_MARGIN (frame) > 0)
2548    min_height += FRAME_TOP_MARGIN (frame);
2549
2550  if (*rows < min_height)
2551    *rows = min_height;
2552  if (*cols  < MIN_SAFE_WINDOW_WIDTH)
2553    *cols = MIN_SAFE_WINDOW_WIDTH;
2554}
2555
2556
2557/* Value is non-zero if window W is fixed-size.  WIDTH_P non-zero means
2558   check if W's width can be changed, otherwise check W's height.
2559   CHECK_SIBLINGS_P non-zero means check resizablity of WINDOW's
2560   siblings, too.  If none of the siblings is resizable, WINDOW isn't
2561   either.  */
2562
2563static int
2564window_fixed_size_p (w, width_p, check_siblings_p)
2565     struct window *w;
2566     int width_p, check_siblings_p;
2567{
2568  int fixed_p;
2569  struct window *c;
2570
2571  if (!NILP (w->hchild))
2572    {
2573      c = XWINDOW (w->hchild);
2574
2575      if (width_p)
2576	{
2577	  /* A horiz. combination is fixed-width if all of if its
2578	     children are.  */
2579	  while (c && window_fixed_size_p (c, width_p, 0))
2580	    c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2581	  fixed_p = c == NULL;
2582	}
2583      else
2584	{
2585	  /* A horiz. combination is fixed-height if one of if its
2586	     children is.  */
2587	  while (c && !window_fixed_size_p (c, width_p, 0))
2588	    c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2589	  fixed_p = c != NULL;
2590	}
2591    }
2592  else if (!NILP (w->vchild))
2593    {
2594      c = XWINDOW (w->vchild);
2595
2596      if (width_p)
2597	{
2598	  /* A vert. combination is fixed-width if one of if its
2599	     children is.  */
2600	  while (c && !window_fixed_size_p (c, width_p, 0))
2601	    c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2602	  fixed_p = c != NULL;
2603	}
2604      else
2605	{
2606	  /* A vert. combination is fixed-height if all of if its
2607	     children are.  */
2608	  while (c && window_fixed_size_p (c, width_p, 0))
2609	    c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2610	  fixed_p = c == NULL;
2611	}
2612    }
2613  else if (BUFFERP (w->buffer))
2614    {
2615      struct buffer *old = current_buffer;
2616      Lisp_Object val;
2617
2618      current_buffer = XBUFFER (w->buffer);
2619      val = find_symbol_value (Qwindow_size_fixed);
2620      current_buffer = old;
2621
2622      fixed_p = 0;
2623      if (!EQ (val, Qunbound))
2624	{
2625	  fixed_p = !NILP (val);
2626
2627	  if (fixed_p
2628	      && ((EQ (val, Qheight) && width_p)
2629		  || (EQ (val, Qwidth) && !width_p)))
2630	    fixed_p = 0;
2631	}
2632
2633      /* Can't tell if this one is resizable without looking at
2634	 siblings.  If all siblings are fixed-size this one is too.  */
2635      if (!fixed_p && check_siblings_p && WINDOWP (w->parent))
2636	{
2637	  Lisp_Object child;
2638
2639	  for (child = w->prev; !NILP (child); child = XWINDOW (child)->prev)
2640	    if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
2641	      break;
2642
2643	  if (NILP (child))
2644	    for (child = w->next; !NILP (child); child = XWINDOW (child)->next)
2645	      if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
2646		break;
2647
2648	  if (NILP (child))
2649	    fixed_p = 1;
2650	}
2651    }
2652  else
2653    fixed_p = 1;
2654
2655  return fixed_p;
2656}
2657
2658
2659/* Return the minimum size of window W, not taking fixed-width windows
2660   into account.  WIDTH_P non-zero means return the minimum width,
2661   otherwise return the minimum height.  If W is a combination window,
2662   compute the minimum size from the minimum sizes of W's children.  */
2663
2664static int
2665window_min_size_1 (w, width_p)
2666     struct window *w;
2667     int width_p;
2668{
2669  struct window *c;
2670  int size;
2671
2672  if (!NILP (w->hchild))
2673    {
2674      c = XWINDOW (w->hchild);
2675      size = 0;
2676
2677      if (width_p)
2678	{
2679	  /* The min width of a horizontal combination is
2680	     the sum of the min widths of its children.  */
2681	  while (c)
2682	    {
2683	      size += window_min_size_1 (c, width_p);
2684	      c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2685	    }
2686	}
2687      else
2688	{
2689	  /* The min height a horizontal combination equals
2690	     the maximum of all min height of its children.  */
2691	  while (c)
2692	    {
2693	      int min_size = window_min_size_1 (c, width_p);
2694	      size = max (min_size, size);
2695	      c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2696	    }
2697	}
2698    }
2699  else if (!NILP (w->vchild))
2700    {
2701      c = XWINDOW (w->vchild);
2702      size = 0;
2703
2704      if (width_p)
2705	{
2706	  /* The min width of a vertical combination is
2707	     the maximum of the min widths of its children.  */
2708	  while (c)
2709	    {
2710	      int min_size = window_min_size_1 (c, width_p);
2711	      size = max (min_size, size);
2712	      c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2713	    }
2714	}
2715      else
2716	{
2717	  /* The min height of a vertical combination equals
2718	     the sum of the min height of its children.  */
2719	  while (c)
2720	    {
2721	      size += window_min_size_1 (c, width_p);
2722	      c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2723	    }
2724	}
2725    }
2726  else
2727    {
2728      if (width_p)
2729	size = max (window_min_width,
2730		    (MIN_SAFE_WINDOW_WIDTH
2731		     + WINDOW_FRINGE_COLS (w)
2732		     + WINDOW_SCROLL_BAR_COLS (w)));
2733      else
2734	{
2735	  if (MINI_WINDOW_P (w)
2736	      || (!WINDOW_WANTS_MODELINE_P (w)
2737		  && !WINDOW_WANTS_HEADER_LINE_P (w)))
2738	    size = 1;
2739	  else
2740	    size = window_min_height;
2741	}
2742    }
2743
2744  return size;
2745}
2746
2747
2748/* Return the minimum size of window W, taking fixed-size windows into
2749   account.  WIDTH_P non-zero means return the minimum width,
2750   otherwise return the minimum height.  IGNORE_FIXED_P non-zero means
2751   ignore if W is fixed-size.  Set *FIXED to 1 if W is fixed-size
2752   unless FIXED is null.  */
2753
2754static int
2755window_min_size (w, width_p, ignore_fixed_p, fixed)
2756     struct window *w;
2757     int width_p, ignore_fixed_p, *fixed;
2758{
2759  int size, fixed_p;
2760
2761  if (ignore_fixed_p)
2762    fixed_p = 0;
2763  else
2764    fixed_p = window_fixed_size_p (w, width_p, 1);
2765
2766  if (fixed)
2767    *fixed = fixed_p;
2768
2769  if (fixed_p)
2770    size = width_p ? XFASTINT (w->total_cols) : XFASTINT (w->total_lines);
2771  else
2772    size = window_min_size_1 (w, width_p);
2773
2774  return size;
2775}
2776
2777
2778/* Adjust the margins of window W if text area is too small.
2779   Return 1 if window width is ok after adjustment; 0 if window
2780   is still too narrow.  */
2781
2782static int
2783adjust_window_margins (w)
2784     struct window *w;
2785{
2786  int box_cols = (WINDOW_TOTAL_COLS (w)
2787		  - WINDOW_FRINGE_COLS (w)
2788		  - WINDOW_SCROLL_BAR_COLS (w));
2789  int margin_cols = (WINDOW_LEFT_MARGIN_COLS (w)
2790		     + WINDOW_RIGHT_MARGIN_COLS (w));
2791
2792  if (box_cols - margin_cols >= MIN_SAFE_WINDOW_WIDTH)
2793    return 1;
2794
2795  if (margin_cols < 0 || box_cols < MIN_SAFE_WINDOW_WIDTH)
2796    return 0;
2797
2798  /* Window's text area is too narrow, but reducing the window
2799     margins will fix that.  */
2800  margin_cols = box_cols - MIN_SAFE_WINDOW_WIDTH;
2801  if (WINDOW_RIGHT_MARGIN_COLS (w) > 0)
2802    {
2803      if (WINDOW_LEFT_MARGIN_COLS (w) > 0)
2804	w->left_margin_cols = w->right_margin_cols
2805	  = make_number (margin_cols/2);
2806      else
2807	w->right_margin_cols = make_number (margin_cols);
2808    }
2809  else
2810    w->left_margin_cols = make_number (margin_cols);
2811  return 1;
2812}
2813
2814/* Calculate new sizes for windows in the list FORWARD when the window size
2815   goes from TOTAL to SIZE.  TOTAL must be greater than SIZE.
2816   The number of windows in FORWARD is NCHILDREN, and the number that
2817   can shrink is SHRINKABLE.
2818   The minimum size a window can have is MIN_SIZE.
2819   If we are shrinking fixed windows, RESIZE_FIXED_P is non-zero.
2820   If we are shrinking columns, WIDTH_P is non-zero, otherwise we are
2821   shrinking rows.
2822
2823   This function returns an allocated array of new sizes that the caller
2824   must free.  The size -1 means the window is fixed and RESIZE_FIXED_P
2825   is zero.  Array index 0 refers to the first window in FORWARD, 1 to
2826   the second, and so on.
2827
2828   This function tries to keep windows at least at the minimum size
2829   and resize other windows before it resizes any window to zero (i.e.
2830   delete that window).
2831
2832   Windows are resized proportional to their size, so bigger windows
2833   shrink more than smaller windows.  */
2834static int *
2835shrink_windows (total, size, nchildren, shrinkable,
2836                min_size, resize_fixed_p, forward, width_p)
2837     int total, size, nchildren, shrinkable, min_size;
2838     int resize_fixed_p, width_p;
2839     Lisp_Object forward;
2840{
2841  int available_resize = 0;
2842  int *new_sizes;
2843  struct window *c;
2844  Lisp_Object child;
2845  int smallest = total;
2846  int total_removed = 0;
2847  int total_shrink = total - size;
2848  int i;
2849
2850  new_sizes = xmalloc (sizeof (*new_sizes) * nchildren);
2851
2852  for (i = 0, child = forward; !NILP (child); child = c->next, ++i)
2853    {
2854      int child_size;
2855
2856      c = XWINDOW (child);
2857      child_size = width_p ? XINT (c->total_cols) : XINT (c->total_lines);
2858
2859      if (! resize_fixed_p && window_fixed_size_p (c, width_p, 0))
2860        new_sizes[i] = -1;
2861      else
2862        {
2863          new_sizes[i] = child_size;
2864          if (child_size > min_size)
2865            available_resize += child_size - min_size;
2866        }
2867    }
2868  /* We might need to shrink some windows to zero.  Find the smallest
2869     windows and set them to 0 until we can fulfil the new size.  */
2870
2871  while (shrinkable > 1 && size + available_resize < total)
2872    {
2873      for (i = 0; i < nchildren; ++i)
2874        if (new_sizes[i] > 0 && smallest > new_sizes[i])
2875          smallest = new_sizes[i];
2876
2877      for (i = 0; i < nchildren; ++i)
2878        if (new_sizes[i] == smallest)
2879          {
2880            /* Resize this window down to zero.  */
2881            new_sizes[i] = 0;
2882            if (smallest > min_size)
2883              available_resize -= smallest - min_size;
2884            available_resize += smallest;
2885            --shrinkable;
2886            total_removed += smallest;
2887
2888            /* We don't know what the smallest is now.  */
2889            smallest = total;
2890
2891            /* Out of for, just remove one window at the time and
2892               check again if we have enough space.  */
2893            break;
2894          }
2895    }
2896
2897  /* Now, calculate the new sizes.  Try to shrink each window
2898     proportional to its size.  */
2899  for (i = 0; i < nchildren; ++i)
2900    {
2901      if (new_sizes[i] > min_size)
2902        {
2903          int to_shrink = total_shrink*new_sizes[i]/total;
2904          if (new_sizes[i] - to_shrink < min_size)
2905            to_shrink = new_sizes[i] - min_size;
2906          new_sizes[i] -= to_shrink;
2907          total_removed += to_shrink;
2908        }
2909    }
2910
2911  /* Any reminder due to rounding, we just subtract from windows
2912     that are left and still can be shrunk.  */
2913  while (total_shrink > total_removed)
2914    {
2915      int nonzero_sizes = 0;
2916      int nonzero_idx = -1;
2917
2918      for (i = 0; i < nchildren; ++i)
2919        if (new_sizes[i] > 0)
2920          {
2921            ++nonzero_sizes;
2922            nonzero_idx = i;
2923          }
2924
2925      for (i = 0; i < nchildren; ++i)
2926        if (new_sizes[i] > min_size)
2927          {
2928            --new_sizes[i];
2929            ++total_removed;
2930
2931            /* Out of for, just shrink one window at the time and
2932               check again if we have enough space.  */
2933            break;
2934          }
2935
2936
2937      /* Special case, only one window left.  */
2938      if (nonzero_sizes == 1)
2939        break;
2940    }
2941
2942  /* Any surplus due to rounding, we add to windows that are left.  */
2943  while (total_shrink < total_removed)
2944    {
2945      for (i = 0; i < nchildren; ++i)
2946        {
2947          if (new_sizes[i] != 0 && total_shrink < total_removed)
2948            {
2949              ++new_sizes[i];
2950              --total_removed;
2951              break;
2952            }
2953        }
2954    }
2955
2956  return new_sizes;
2957}
2958
2959/* Set WINDOW's height or width to SIZE.  WIDTH_P non-zero means set
2960   WINDOW's width.  Resize WINDOW's children, if any, so that they
2961   keep their proportionate size relative to WINDOW.
2962
2963   If FIRST_ONLY is 1, change only the first of WINDOW's children when
2964   they are in series.  If LAST_ONLY is 1, change only the last of
2965   WINDOW's children when they are in series.
2966
2967   Propagate WINDOW's top or left edge position to children.  Delete
2968   windows that become too small unless NODELETE_P is non-zero.
2969
2970   If NODELETE_P is 2, that means we do delete windows that are
2971   too small, even if they were too small before!  */
2972
2973static void
2974size_window (window, size, width_p, nodelete_p, first_only, last_only)
2975     Lisp_Object window;
2976     int size, width_p, nodelete_p;
2977     int first_only, last_only;
2978{
2979  struct window *w = XWINDOW (window);
2980  struct window *c;
2981  Lisp_Object child, *forward, *sideward;
2982  int old_size, min_size, safe_min_size;
2983
2984  /* We test nodelete_p != 2 and nodelete_p != 1 below, so it
2985     seems like it's too soon to do this here.  ++KFS.  */
2986  if (nodelete_p == 2)
2987    nodelete_p = 0;
2988
2989  check_min_window_sizes ();
2990  size = max (0, size);
2991
2992  /* If the window has been "too small" at one point,
2993     don't delete it for being "too small" in the future.
2994     Preserve it as long as that is at all possible.  */
2995  if (width_p)
2996    {
2997      old_size = WINDOW_TOTAL_COLS (w);
2998      min_size = window_min_width;
2999      /* Ensure that there is room for the scroll bar and fringes!
3000         We may reduce display margins though.  */
3001      safe_min_size = (MIN_SAFE_WINDOW_WIDTH
3002		       + WINDOW_FRINGE_COLS (w)
3003		       + WINDOW_SCROLL_BAR_COLS (w));
3004    }
3005  else
3006    {
3007      old_size = XINT (w->total_lines);
3008      min_size = window_min_height;
3009      safe_min_size = MIN_SAFE_WINDOW_HEIGHT;
3010    }
3011
3012  if (old_size < min_size && nodelete_p != 2)
3013    w->too_small_ok = Qt;
3014
3015  /* Maybe delete WINDOW if it's too small.  */
3016  if (nodelete_p != 1 && !NILP (w->parent))
3017    {
3018      if (!MINI_WINDOW_P (w) && !NILP (w->too_small_ok))
3019	min_size = width_p ? MIN_SAFE_WINDOW_WIDTH : MIN_SAFE_WINDOW_HEIGHT;
3020      if (min_size < safe_min_size)
3021	min_size = safe_min_size;
3022      if (size < min_size)
3023	{
3024	  delete_window (window);
3025	  return;
3026	}
3027    }
3028
3029  /* Set redisplay hints.  */
3030  w->last_modified = make_number (0);
3031  w->last_overlay_modified = make_number (0);
3032  windows_or_buffers_changed++;
3033  FRAME_WINDOW_SIZES_CHANGED (XFRAME (w->frame)) = 1;
3034
3035  if (width_p)
3036    {
3037      sideward = &w->vchild;
3038      forward = &w->hchild;
3039      w->total_cols = make_number (size);
3040      adjust_window_margins (w);
3041    }
3042  else
3043    {
3044      sideward = &w->hchild;
3045      forward = &w->vchild;
3046      w->total_lines = make_number (size);
3047      w->orig_total_lines = Qnil;
3048    }
3049
3050  if (!NILP (*sideward))
3051    {
3052      /* We have a chain of parallel siblings whose size should all change.  */
3053      for (child = *sideward; !NILP (child); child = c->next)
3054	{
3055	  c = XWINDOW (child);
3056	  if (width_p)
3057	    c->left_col = w->left_col;
3058	  else
3059	    c->top_line = w->top_line;
3060	  size_window (child, size, width_p, nodelete_p,
3061		       first_only, last_only);
3062	}
3063    }
3064  else if (!NILP (*forward) && last_only)
3065    {
3066      /* Change the last in a series of siblings.  */
3067      Lisp_Object last_child;
3068      int child_size;
3069
3070      for (child = *forward; !NILP (child); child = c->next)
3071	{
3072	  c = XWINDOW (child);
3073	  last_child = child;
3074	}
3075
3076      child_size = XINT (width_p ? c->total_cols : c->total_lines);
3077      size_window (last_child,
3078		   size - old_size + child_size,
3079		   width_p, nodelete_p, first_only, last_only);
3080    }
3081  else if (!NILP (*forward) && first_only)
3082    {
3083      /* Change the first in a series of siblings.  */
3084      int child_size;
3085
3086      child = *forward;
3087      c = XWINDOW (child);
3088
3089      if (width_p)
3090	c->left_col = w->left_col;
3091      else
3092	c->top_line = w->top_line;
3093
3094      child_size = XINT (width_p ? c->total_cols : c->total_lines);
3095      size_window (child,
3096		   size - old_size + child_size,
3097		   width_p, nodelete_p, first_only, last_only);
3098    }
3099  else if (!NILP (*forward))
3100    {
3101      int fixed_size, each, extra, n;
3102      int resize_fixed_p, nfixed;
3103      int last_pos, first_pos, nchildren, total;
3104      int *new_sizes = NULL;
3105
3106      /* Determine the fixed-size portion of this window, and the
3107	 number of child windows.  */
3108      fixed_size = nchildren = nfixed = total = 0;
3109      for (child = *forward; !NILP (child); child = c->next, ++nchildren)
3110	{
3111	  int child_size;
3112
3113	  c = XWINDOW (child);
3114	  child_size = width_p ? XINT (c->total_cols) : XINT (c->total_lines);
3115	  total += child_size;
3116
3117	  if (window_fixed_size_p (c, width_p, 0))
3118	    {
3119	      fixed_size += child_size;
3120	      ++nfixed;
3121	    }
3122	}
3123
3124      /* If the new size is smaller than fixed_size, or if there
3125	 aren't any resizable windows, allow resizing fixed-size
3126	 windows.  */
3127      resize_fixed_p = nfixed == nchildren || size < fixed_size;
3128
3129      /* Compute how many lines/columns to add/remove to each child.  The
3130	 value of extra takes care of rounding errors.  */
3131      n = resize_fixed_p ? nchildren : nchildren - nfixed;
3132      if (size < total && n > 1)
3133        new_sizes = shrink_windows (total, size, nchildren, n, min_size,
3134                                    resize_fixed_p, *forward, width_p);
3135      else
3136        {
3137          each = (size - total) / n;
3138          extra = (size - total) - n * each;
3139        }
3140
3141      /* Compute new children heights and edge positions.  */
3142      first_pos = width_p ? XINT (w->left_col) : XINT (w->top_line);
3143      last_pos = first_pos;
3144      for (n = 0, child = *forward; !NILP (child); child = c->next, ++n)
3145	{
3146	  int new_size, old_size;
3147
3148	  c = XWINDOW (child);
3149	  old_size = width_p ? XFASTINT (c->total_cols) : XFASTINT (c->total_lines);
3150	  new_size = old_size;
3151
3152	  /* The top or left edge position of this child equals the
3153	     bottom or right edge of its predecessor.  */
3154	  if (width_p)
3155	    c->left_col = make_number (last_pos);
3156	  else
3157	    c->top_line = make_number (last_pos);
3158
3159	  /* If this child can be resized, do it.  */
3160	  if (resize_fixed_p || !window_fixed_size_p (c, width_p, 0))
3161	    {
3162	      new_size = new_sizes ? new_sizes[n] : old_size + each + extra;
3163	      extra = 0;
3164	    }
3165
3166	  /* Set new height.  Note that size_window also propagates
3167	     edge positions to children, so it's not a no-op if we
3168	     didn't change the child's size.  */
3169	  size_window (child, new_size, width_p, 1, first_only, last_only);
3170
3171	  /* Remember the bottom/right edge position of this child; it
3172	     will be used to set the top/left edge of the next child.  */
3173          last_pos += new_size;
3174	}
3175
3176      if (new_sizes) xfree (new_sizes);
3177
3178      /* We should have covered the parent exactly with child windows.  */
3179      xassert (size == last_pos - first_pos);
3180
3181      /* Now delete any children that became too small.  */
3182      if (!nodelete_p)
3183	for (child = *forward; !NILP (child); child = c->next)
3184	  {
3185	    int child_size;
3186	    c = XWINDOW (child);
3187	    child_size = width_p ? XINT (c->total_cols) : XINT (c->total_lines);
3188	    size_window (child, child_size, width_p, 2, first_only, last_only);
3189	  }
3190    }
3191}
3192
3193/* Set WINDOW's height to HEIGHT, and recursively change the height of
3194   WINDOW's children.  NODELETE non-zero means don't delete windows
3195   that become too small in the process.  (The caller should check
3196   later and do so if appropriate.)  */
3197
3198void
3199set_window_height (window, height, nodelete)
3200     Lisp_Object window;
3201     int height;
3202     int nodelete;
3203{
3204  size_window (window, height, 0, nodelete, 0, 0);
3205}
3206
3207
3208/* Set WINDOW's width to WIDTH, and recursively change the width of
3209   WINDOW's children.  NODELETE non-zero means don't delete windows
3210   that become too small in the process.  (The caller should check
3211   later and do so if appropriate.)  */
3212
3213void
3214set_window_width (window, width, nodelete)
3215     Lisp_Object window;
3216     int width;
3217     int nodelete;
3218{
3219  size_window (window, width, 1, nodelete, 0, 0);
3220}
3221
3222/* Change window heights in windows rooted in WINDOW by N lines.  */
3223
3224void
3225change_window_heights (window, n)
3226     Lisp_Object window;
3227     int n;
3228{
3229  struct window *w = XWINDOW (window);
3230
3231  XSETFASTINT (w->top_line, XFASTINT (w->top_line) + n);
3232  XSETFASTINT (w->total_lines, XFASTINT (w->total_lines) - n);
3233
3234  if (INTEGERP (w->orig_top_line))
3235    XSETFASTINT (w->orig_top_line, XFASTINT (w->orig_top_line) + n);
3236  if (INTEGERP (w->orig_total_lines))
3237    XSETFASTINT (w->orig_total_lines, XFASTINT (w->orig_total_lines) - n);
3238
3239  /* Handle just the top child in a vertical split.  */
3240  if (!NILP (w->vchild))
3241    change_window_heights (w->vchild, n);
3242
3243  /* Adjust all children in a horizontal split.  */
3244  for (window = w->hchild; !NILP (window); window = w->next)
3245    {
3246      w = XWINDOW (window);
3247      change_window_heights (window, n);
3248    }
3249}
3250
3251
3252int window_select_count;
3253
3254Lisp_Object
3255Fset_window_buffer_unwind (obuf)
3256     Lisp_Object obuf;
3257{
3258  Fset_buffer (obuf);
3259  return Qnil;
3260}
3261
3262EXFUN (Fset_window_fringes, 4);
3263EXFUN (Fset_window_scroll_bars, 4);
3264
3265/* Make WINDOW display BUFFER as its contents.  RUN_HOOKS_P non-zero
3266   means it's allowed to run hooks.  See make_frame for a case where
3267   it's not allowed.  KEEP_MARGINS_P non-zero means that the current
3268   margins, fringes, and scroll-bar settings of the window are not
3269   reset from the buffer's local settings.  */
3270
3271void
3272set_window_buffer (window, buffer, run_hooks_p, keep_margins_p)
3273     Lisp_Object window, buffer;
3274     int run_hooks_p, keep_margins_p;
3275{
3276  struct window *w = XWINDOW (window);
3277  struct buffer *b = XBUFFER (buffer);
3278  int count = SPECPDL_INDEX ();
3279
3280  w->buffer = buffer;
3281
3282  if (EQ (window, selected_window))
3283    b->last_selected_window = window;
3284
3285  /* Let redisplay errors through.  */
3286  b->display_error_modiff = 0;
3287
3288  /* Update time stamps of buffer display.  */
3289  if (INTEGERP (b->display_count))
3290    XSETINT (b->display_count, XINT (b->display_count) + 1);
3291  b->display_time = Fcurrent_time ();
3292
3293  XSETFASTINT (w->window_end_pos, 0);
3294  XSETFASTINT (w->window_end_vpos, 0);
3295  bzero (&w->last_cursor, sizeof w->last_cursor);
3296  w->window_end_valid = Qnil;
3297  w->hscroll = w->min_hscroll = make_number (0);
3298  w->vscroll = 0;
3299  set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
3300  set_marker_restricted (w->start,
3301			 make_number (b->last_window_start),
3302			 buffer);
3303  w->start_at_line_beg = Qnil;
3304  w->force_start = Qnil;
3305  XSETFASTINT (w->last_modified, 0);
3306  XSETFASTINT (w->last_overlay_modified, 0);
3307  windows_or_buffers_changed++;
3308
3309  /* We must select BUFFER for running the window-scroll-functions.
3310     If WINDOW is selected, switch permanently.
3311     Otherwise, switch but go back to the ambient buffer afterward.  */
3312  if (EQ (window, selected_window))
3313    Fset_buffer (buffer);
3314  /* We can't check ! NILP (Vwindow_scroll_functions) here
3315     because that might itself be a local variable.  */
3316  else if (window_initialized)
3317    {
3318      record_unwind_protect (Fset_window_buffer_unwind, Fcurrent_buffer ());
3319      Fset_buffer (buffer);
3320    }
3321
3322  if (!keep_margins_p)
3323    {
3324      /* Set left and right marginal area width etc. from buffer.  */
3325
3326      /* This may call adjust_window_margins three times, so
3327	 temporarily disable window margins.  */
3328      Lisp_Object save_left = w->left_margin_cols;
3329      Lisp_Object save_right = w->right_margin_cols;
3330
3331      w->left_margin_cols = w->right_margin_cols = Qnil;
3332
3333      Fset_window_fringes (window,
3334			   b->left_fringe_width, b->right_fringe_width,
3335			   b->fringes_outside_margins);
3336
3337      Fset_window_scroll_bars (window,
3338			       b->scroll_bar_width,
3339			       b->vertical_scroll_bar_type, Qnil);
3340
3341      w->left_margin_cols = save_left;
3342      w->right_margin_cols = save_right;
3343
3344      Fset_window_margins (window,
3345			   b->left_margin_cols, b->right_margin_cols);
3346    }
3347
3348  if (run_hooks_p)
3349    {
3350      if (! NILP (Vwindow_scroll_functions))
3351	run_hook_with_args_2 (Qwindow_scroll_functions, window,
3352			      Fmarker_position (w->start));
3353
3354      if (! NILP (Vwindow_configuration_change_hook)
3355	  && ! NILP (Vrun_hooks))
3356	call1 (Vrun_hooks, Qwindow_configuration_change_hook);
3357    }
3358
3359  unbind_to (count, Qnil);
3360}
3361
3362
3363DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 3, 0,
3364       doc: /* Make WINDOW display BUFFER as its contents.
3365BUFFER can be a buffer or the name of an existing buffer.
3366Optional third arg KEEP-MARGINS non-nil means that WINDOW's current
3367display margins, fringe widths, and scroll bar settings are maintained;
3368the default is to reset these from BUFFER's local settings or the frame
3369defaults.
3370
3371This function runs the hook `window-scroll-functions'.  */)
3372     (window, buffer, keep_margins)
3373     register Lisp_Object window, buffer, keep_margins;
3374{
3375  register Lisp_Object tem;
3376  register struct window *w = decode_window (window);
3377
3378  XSETWINDOW (window, w);
3379  buffer = Fget_buffer (buffer);
3380  CHECK_BUFFER (buffer);
3381
3382  if (NILP (XBUFFER (buffer)->name))
3383    error ("Attempt to display deleted buffer");
3384
3385  tem = w->buffer;
3386  if (NILP (tem))
3387    error ("Window is deleted");
3388  else if (! EQ (tem, Qt))	/* w->buffer is t when the window
3389				   is first being set up.  */
3390    {
3391      if (!NILP (w->dedicated) && !EQ (tem, buffer))
3392	error ("Window is dedicated to `%s'",
3393	       SDATA (XBUFFER (tem)->name));
3394
3395      unshow_buffer (w);
3396    }
3397
3398  set_window_buffer (window, buffer, 1, !NILP (keep_margins));
3399  return Qnil;
3400}
3401
3402/* Note that selected_window can be nil
3403   when this is called from Fset_window_configuration.  */
3404
3405DEFUN ("select-window", Fselect_window, Sselect_window, 1, 2, 0,
3406       doc: /* Select WINDOW.  Most editing will apply to WINDOW's buffer.
3407If WINDOW is not already selected, make WINDOW's buffer current
3408and make WINDOW the frame's selected window.  Return WINDOW.
3409Optional second arg NORECORD non-nil means
3410do not put this buffer at the front of the list of recently selected ones.
3411
3412Note that the main editor command loop
3413selects the buffer of the selected window before each command.  */)
3414     (window, norecord)
3415     register Lisp_Object window, norecord;
3416{
3417  register struct window *w;
3418  register struct window *ow;
3419  struct frame *sf;
3420
3421  CHECK_LIVE_WINDOW (window);
3422
3423  w = XWINDOW (window);
3424  w->frozen_window_start_p = 0;
3425
3426  ++window_select_count;
3427  XSETFASTINT (w->use_time, window_select_count);
3428  if (EQ (window, selected_window))
3429    return window;
3430
3431  /* Store the current buffer's actual point into the
3432     old selected window.  It belongs to that window,
3433     and when the window is not selected, must be in the window.  */
3434  if (!NILP (selected_window))
3435    {
3436      ow = XWINDOW (selected_window);
3437      if (! NILP (ow->buffer))
3438	set_marker_both (ow->pointm, ow->buffer,
3439			 BUF_PT (XBUFFER (ow->buffer)),
3440			 BUF_PT_BYTE (XBUFFER (ow->buffer)));
3441    }
3442
3443  selected_window = window;
3444  sf = SELECTED_FRAME ();
3445  if (XFRAME (WINDOW_FRAME (w)) != sf)
3446    {
3447      XFRAME (WINDOW_FRAME (w))->selected_window = window;
3448      /* Use this rather than Fhandle_switch_frame
3449	 so that FRAME_FOCUS_FRAME is moved appropriately as we
3450	 move around in the state where a minibuffer in a separate
3451	 frame is active.  */
3452      Fselect_frame (WINDOW_FRAME (w));
3453    }
3454  else
3455    sf->selected_window = window;
3456
3457  if (NILP (norecord))
3458    record_buffer (w->buffer);
3459  Fset_buffer (w->buffer);
3460
3461  XBUFFER (w->buffer)->last_selected_window = window;
3462
3463  /* Go to the point recorded in the window.
3464     This is important when the buffer is in more
3465     than one window.  It also matters when
3466     redisplay_window has altered point after scrolling,
3467     because it makes the change only in the window.  */
3468  {
3469    register int new_point = marker_position (w->pointm);
3470    if (new_point < BEGV)
3471      SET_PT (BEGV);
3472    else if (new_point > ZV)
3473      SET_PT (ZV);
3474    else
3475      SET_PT (new_point);
3476  }
3477
3478  windows_or_buffers_changed++;
3479  return window;
3480}
3481
3482static Lisp_Object
3483select_window_norecord (window)
3484     Lisp_Object window;
3485{
3486  return Fselect_window (window, Qt);
3487}
3488
3489/* Deiconify the frame containing the window WINDOW,
3490   unless it is the selected frame;
3491   then return WINDOW.
3492
3493   The reason for the exception for the selected frame
3494   is that it seems better not to change the selected frames visibility
3495   merely because of displaying a different buffer in it.
3496   The deiconification is useful when a buffer gets shown in
3497   another frame that you were not using lately.  */
3498
3499static Lisp_Object
3500display_buffer_1 (window)
3501     Lisp_Object window;
3502{
3503  Lisp_Object frame = XWINDOW (window)->frame;
3504  FRAME_PTR f = XFRAME (frame);
3505
3506  FRAME_SAMPLE_VISIBILITY (f);
3507
3508  if (EQ (frame, selected_frame))
3509    ; /* Assume the selected frame is already visible enough.  */
3510  else if (minibuf_level > 0
3511	   && MINI_WINDOW_P (XWINDOW (selected_window))
3512	   && WINDOW_LIVE_P (minibuf_selected_window)
3513	   && EQ (frame, WINDOW_FRAME (XWINDOW (minibuf_selected_window))))
3514    ; /* Assume the frame from which we invoked the minibuffer is visible.  */
3515  else
3516    {
3517      if (FRAME_ICONIFIED_P (f))
3518	Fmake_frame_visible (frame);
3519      else if (FRAME_VISIBLE_P (f))
3520	Fraise_frame (frame);
3521    }
3522
3523  return window;
3524}
3525
3526DEFUN ("special-display-p", Fspecial_display_p, Sspecial_display_p, 1, 1, 0,
3527       doc: /* Returns non-nil if a buffer named BUFFER-NAME gets a special frame.
3528If the value is t, `display-buffer' or `pop-to-buffer' would create a
3529special frame for that buffer using the default frame parameters.
3530
3531If the value is a list, it is a list of frame parameters that would be used
3532to make a frame for that buffer.
3533The variables `special-display-buffer-names'
3534and `special-display-regexps' control this.  */)
3535     (buffer_name)
3536     Lisp_Object buffer_name;
3537{
3538  Lisp_Object tem;
3539
3540  CHECK_STRING (buffer_name);
3541
3542  tem = Fmember (buffer_name, Vspecial_display_buffer_names);
3543  if (!NILP (tem))
3544    return Qt;
3545
3546  tem = Fassoc (buffer_name, Vspecial_display_buffer_names);
3547  if (!NILP (tem))
3548    return XCDR (tem);
3549
3550  for (tem = Vspecial_display_regexps; CONSP (tem); tem = XCDR (tem))
3551    {
3552      Lisp_Object car = XCAR (tem);
3553      if (STRINGP (car)
3554	  && fast_string_match (car, buffer_name) >= 0)
3555	return Qt;
3556      else if (CONSP (car)
3557	       && STRINGP (XCAR (car))
3558	       && fast_string_match (XCAR (car), buffer_name) >= 0)
3559	return XCDR (car);
3560    }
3561  return Qnil;
3562}
3563
3564DEFUN ("same-window-p", Fsame_window_p, Ssame_window_p, 1, 1, 0,
3565       doc: /* Returns non-nil if a buffer named BUFFER-NAME would use the same window.
3566More precisely, if `display-buffer' or `pop-to-buffer' would display
3567that buffer in the selected window rather than (as usual) in some other window.
3568See `same-window-buffer-names' and `same-window-regexps'.  */)
3569     (buffer_name)
3570     Lisp_Object buffer_name;
3571{
3572  Lisp_Object tem;
3573
3574  CHECK_STRING (buffer_name);
3575
3576  tem = Fmember (buffer_name, Vsame_window_buffer_names);
3577  if (!NILP (tem))
3578    return Qt;
3579
3580  tem = Fassoc (buffer_name, Vsame_window_buffer_names);
3581  if (!NILP (tem))
3582    return Qt;
3583
3584  for (tem = Vsame_window_regexps; CONSP (tem); tem = XCDR (tem))
3585    {
3586      Lisp_Object car = XCAR (tem);
3587      if (STRINGP (car)
3588	  && fast_string_match (car, buffer_name) >= 0)
3589	return Qt;
3590      else if (CONSP (car)
3591	       && STRINGP (XCAR (car))
3592	       && fast_string_match (XCAR (car), buffer_name) >= 0)
3593	return Qt;
3594    }
3595  return Qnil;
3596}
3597
3598/* Use B so the default is (other-buffer).  */
3599DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 3,
3600       "BDisplay buffer: \nP",
3601       doc: /* Make BUFFER appear in some window but don't select it.
3602BUFFER must be the name of an existing buffer, or, when called from Lisp,
3603a buffer.
3604If BUFFER is shown already in some window, just use that one,
3605unless the window is the selected window and the optional second
3606argument NOT-THIS-WINDOW is non-nil (interactively, with prefix arg).
3607If `pop-up-frames' is non-nil, make a new frame if no window shows BUFFER.
3608Returns the window displaying BUFFER.
3609If `display-buffer-reuse-frames' is non-nil, and another frame is currently
3610displaying BUFFER, then simply raise that frame.
3611
3612The variables `special-display-buffer-names',
3613`special-display-regexps', `same-window-buffer-names', and
3614`same-window-regexps' customize how certain buffer names are handled.
3615The latter two take effect only if NOT-THIS-WINDOW is nil.
3616
3617If optional argument FRAME is `visible', check all visible frames
3618for a window to use.
3619If FRAME is 0, check all visible and iconified frames.
3620If FRAME is t, check all frames.
3621If FRAME is a frame, check only that frame.
3622If FRAME is nil, check only the selected frame
3623 (actually the last nonminibuffer frame),
3624 unless `pop-up-frames' or `display-buffer-reuse-frames' is non-nil,
3625 which means search visible and iconified frames.
3626
3627If a full-width window on a splittable frame is available to display
3628the buffer, it may be split, subject to the value of the variable
3629`split-height-threshold'.
3630
3631If `even-window-heights' is non-nil, window heights will be evened out
3632if displaying the buffer causes two vertically adjacent windows to be
3633displayed.  */)
3634     (buffer, not_this_window, frame)
3635     register Lisp_Object buffer, not_this_window, frame;
3636{
3637  register Lisp_Object window, tem, swp;
3638  struct frame *f;
3639
3640  swp = Qnil;
3641  buffer = Fget_buffer (buffer);
3642  CHECK_BUFFER (buffer);
3643
3644  if (!NILP (Vdisplay_buffer_function))
3645    return call2 (Vdisplay_buffer_function, buffer, not_this_window);
3646
3647  if (NILP (not_this_window)
3648      && XBUFFER (XWINDOW (selected_window)->buffer) == XBUFFER (buffer))
3649    return display_buffer_1 (selected_window);
3650
3651  /* See if the user has specified this buffer should appear
3652     in the selected window.  */
3653  if (NILP (not_this_window))
3654    {
3655      swp = Fsame_window_p (XBUFFER (buffer)->name);
3656      if (!NILP (swp) && !no_switch_window (selected_window))
3657	{
3658	  Fswitch_to_buffer (buffer, Qnil);
3659	  return display_buffer_1 (selected_window);
3660	}
3661    }
3662
3663  /* If the user wants pop-up-frames or display-buffer-reuse-frames,
3664     look for a window showing BUFFER on any visible or iconified frame.
3665     Otherwise search only the current frame.  */
3666  if (! NILP (frame))
3667    tem = frame;
3668  else if (pop_up_frames
3669	   || display_buffer_reuse_frames
3670	   || last_nonminibuf_frame == 0)
3671    XSETFASTINT (tem, 0);
3672  else
3673    XSETFRAME (tem, last_nonminibuf_frame);
3674
3675  window = Fget_buffer_window (buffer, tem);
3676  if (!NILP (window)
3677      && (NILP (not_this_window) || !EQ (window, selected_window)))
3678    return display_buffer_1 (window);
3679
3680  /* Certain buffer names get special handling.  */
3681  if (!NILP (Vspecial_display_function) && NILP (swp))
3682    {
3683      tem = Fspecial_display_p (XBUFFER (buffer)->name);
3684      if (EQ (tem, Qt))
3685	return call1 (Vspecial_display_function, buffer);
3686      if (CONSP (tem))
3687	return call2 (Vspecial_display_function, buffer, tem);
3688    }
3689
3690  /* If there are no frames open that have more than a minibuffer,
3691     we need to create a new frame.  */
3692  if (pop_up_frames || last_nonminibuf_frame == 0)
3693    {
3694      window = Fframe_selected_window (call0 (Vpop_up_frame_function));
3695      Fset_window_buffer (window, buffer, Qnil);
3696      return display_buffer_1 (window);
3697    }
3698
3699  f = SELECTED_FRAME ();
3700  if (pop_up_windows
3701      || FRAME_MINIBUF_ONLY_P (f)
3702      /* If the current frame is a special display frame,
3703	 don't try to reuse its windows.  */
3704      || !NILP (XWINDOW (FRAME_ROOT_WINDOW (f))->dedicated))
3705    {
3706      Lisp_Object frames;
3707
3708      frames = Qnil;
3709      if (FRAME_MINIBUF_ONLY_P (f))
3710	XSETFRAME (frames, last_nonminibuf_frame);
3711      /* Don't try to create a window if we would get an error.  */
3712      if (split_height_threshold < window_min_height << 1)
3713	split_height_threshold = window_min_height << 1;
3714
3715      /* Note that both Fget_largest_window and Fget_lru_window
3716	 ignore minibuffers and dedicated windows.
3717	 This means they can return nil.  */
3718
3719      /* If the frame we would try to split cannot be split,
3720	 try other frames.  */
3721      if (FRAME_NO_SPLIT_P (NILP (frames) ? f : last_nonminibuf_frame))
3722	{
3723	  /* Try visible frames first.  */
3724	  window = Fget_largest_window (Qvisible, Qt);
3725	  /* If that didn't work, try iconified frames.  */
3726	  if (NILP (window))
3727	    window = Fget_largest_window (make_number (0), Qt);
3728#if 0     /* Don't try windows on other displays.  */
3729	  if (NILP (window))
3730	    window = Fget_largest_window (Qt, Qt);
3731#endif
3732	}
3733      else
3734	window = Fget_largest_window (frames, Qt);
3735
3736      /* If we got a tall enough full-width window that can be split,
3737	 split it.  */
3738      if (!NILP (window)
3739	  && ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
3740	  && window_height (window) >= split_height_threshold
3741	  && WINDOW_FULL_WIDTH_P (XWINDOW (window)))
3742	window = Fsplit_window (window, Qnil, Qnil);
3743      else
3744	{
3745	  Lisp_Object upper, lower, other;
3746
3747	  window = Fget_lru_window (frames, Qt);
3748	  /* If the LRU window is selected, and big enough,
3749	     and can be split, split it.  */
3750	  if (!NILP (window)
3751	      && ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
3752	      && (EQ (window, selected_window)
3753		  || EQ (XWINDOW (window)->parent, Qnil))
3754	      && window_height (window) >= window_min_height << 1)
3755	    window = Fsplit_window (window, Qnil, Qnil);
3756	  else
3757	    window = Fget_lru_window (frames, Qnil);
3758	  /* If Fget_lru_window returned nil, try other approaches.  */
3759
3760	  /* Try visible frames first.  */
3761	  if (NILP (window))
3762	    window = Fget_buffer_window (buffer, Qvisible);
3763	  if (NILP (window))
3764	    window = Fget_largest_window (Qvisible, Qnil);
3765	  /* If that didn't work, try iconified frames.  */
3766	  if (NILP (window))
3767	    window = Fget_buffer_window (buffer, make_number (0));
3768	  if (NILP (window))
3769	    window = Fget_largest_window (make_number (0), Qnil);
3770
3771#if 0     /* Don't try frames on other displays.  */
3772	  if (NILP (window))
3773	    window = Fget_buffer_window (buffer, Qt);
3774	  if (NILP (window))
3775	    window = Fget_largest_window (Qt, Qnil);
3776#endif
3777	  /* As a last resort, make a new frame.  */
3778	  if (NILP (window))
3779	    window = Fframe_selected_window (call0 (Vpop_up_frame_function));
3780	  /* If window appears above or below another,
3781	     even out their heights.  */
3782	  other = upper = lower = Qnil;
3783	  if (!NILP (XWINDOW (window)->prev))
3784	    other = upper = XWINDOW (window)->prev, lower = window;
3785	  if (!NILP (XWINDOW (window)->next))
3786	    other = lower = XWINDOW (window)->next, upper = window;
3787	  if (!NILP (other)
3788	      && !NILP (Veven_window_heights)
3789	      /* Check that OTHER and WINDOW are vertically arrayed.  */
3790	      && !EQ (XWINDOW (other)->top_line, XWINDOW (window)->top_line)
3791	      && (XFASTINT (XWINDOW (other)->total_lines)
3792		  > XFASTINT (XWINDOW (window)->total_lines)))
3793	    {
3794	      int total = (XFASTINT (XWINDOW (other)->total_lines)
3795			   + XFASTINT (XWINDOW (window)->total_lines));
3796	      enlarge_window (upper,
3797			      total / 2 - XFASTINT (XWINDOW (upper)->total_lines),
3798			      0);
3799	    }
3800	}
3801    }
3802  else
3803    window = Fget_lru_window (Qnil, Qnil);
3804
3805  Fset_window_buffer (window, buffer, Qnil);
3806  return display_buffer_1 (window);
3807}
3808
3809
3810DEFUN ("force-window-update", Fforce_window_update, Sforce_window_update,
3811       0, 1, 0,
3812       doc: /* Force all windows to be updated on next redisplay.
3813If optional arg OBJECT is a window, force redisplay of that window only.
3814If OBJECT is a buffer or buffer name, force redisplay of all windows
3815displaying that buffer.  */)
3816     (object)
3817     Lisp_Object object;
3818{
3819  if (NILP (object))
3820    {
3821      windows_or_buffers_changed++;
3822      update_mode_lines++;
3823      return Qt;
3824    }
3825
3826  if (WINDOWP (object))
3827    {
3828      struct window *w = XWINDOW (object);
3829      mark_window_display_accurate (object, 0);
3830      w->update_mode_line = Qt;
3831      if (BUFFERP (w->buffer))
3832	XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
3833      ++update_mode_lines;
3834      return Qt;
3835    }
3836
3837  if (STRINGP (object))
3838    object = Fget_buffer (object);
3839  if (BUFFERP (object) && !NILP (XBUFFER (object)->name))
3840    {
3841      /* Walk all windows looking for buffer, and force update
3842	 of each of those windows.  */
3843
3844      object = window_loop (REDISPLAY_BUFFER_WINDOWS, object, 0, Qvisible);
3845      return NILP (object) ? Qnil : Qt;
3846    }
3847
3848  /* If nothing suitable was found, just return.
3849     We could signal an error, but this feature will typically be used
3850     asynchronously in timers or process sentinels, so we don't.  */
3851  return Qnil;
3852}
3853
3854
3855void
3856temp_output_buffer_show (buf)
3857     register Lisp_Object buf;
3858{
3859  register struct buffer *old = current_buffer;
3860  register Lisp_Object window;
3861  register struct window *w;
3862
3863  XBUFFER (buf)->directory = current_buffer->directory;
3864
3865  Fset_buffer (buf);
3866  BUF_SAVE_MODIFF (XBUFFER (buf)) = MODIFF;
3867  BEGV = BEG;
3868  ZV = Z;
3869  SET_PT (BEG);
3870#if 0  /* rms: there should be no reason for this.  */
3871  XBUFFER (buf)->prevent_redisplay_optimizations_p = 1;
3872#endif
3873  set_buffer_internal (old);
3874
3875  if (!NILP (Vtemp_buffer_show_function))
3876    call1 (Vtemp_buffer_show_function, buf);
3877  else
3878    {
3879      window = Fdisplay_buffer (buf, Qnil, Qnil);
3880
3881      if (!EQ (XWINDOW (window)->frame, selected_frame))
3882	Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
3883      Vminibuf_scroll_window = window;
3884      w = XWINDOW (window);
3885      XSETFASTINT (w->hscroll, 0);
3886      XSETFASTINT (w->min_hscroll, 0);
3887      set_marker_restricted_both (w->start, buf, BEG, BEG);
3888      set_marker_restricted_both (w->pointm, buf, BEG, BEG);
3889
3890      /* Run temp-buffer-show-hook, with the chosen window selected
3891	 and its buffer current.  */
3892
3893      if (!NILP (Vrun_hooks)
3894	  && !NILP (Fboundp (Qtemp_buffer_show_hook))
3895	  && !NILP (Fsymbol_value (Qtemp_buffer_show_hook)))
3896	{
3897	  int count = SPECPDL_INDEX ();
3898	  Lisp_Object prev_window, prev_buffer;
3899	  prev_window = selected_window;
3900	  XSETBUFFER (prev_buffer, old);
3901
3902	  /* Select the window that was chosen, for running the hook.
3903	     Note: Both Fselect_window and select_window_norecord may
3904	     set-buffer to the buffer displayed in the window,
3905	     so we need to save the current buffer.  --stef  */
3906	  record_unwind_protect (Fset_buffer, prev_buffer);
3907	  record_unwind_protect (select_window_norecord, prev_window);
3908	  Fselect_window (window, Qt);
3909	  Fset_buffer (w->buffer);
3910	  call1 (Vrun_hooks, Qtemp_buffer_show_hook);
3911	  unbind_to (count, Qnil);
3912	}
3913    }
3914}
3915
3916static void
3917make_dummy_parent (window)
3918     Lisp_Object window;
3919{
3920  Lisp_Object new;
3921  register struct window *o, *p;
3922  int i;
3923
3924  o = XWINDOW (window);
3925  p = allocate_window ();
3926  for (i = 0; i < VECSIZE (struct window); ++i)
3927    ((struct Lisp_Vector *) p)->contents[i]
3928      = ((struct Lisp_Vector *)o)->contents[i];
3929  XSETWINDOW (new, p);
3930
3931  ++sequence_number;
3932  XSETFASTINT (p->sequence_number, sequence_number);
3933
3934  /* Put new into window structure in place of window */
3935  replace_window (window, new);
3936
3937  o->next = Qnil;
3938  o->prev = Qnil;
3939  o->vchild = Qnil;
3940  o->hchild = Qnil;
3941  o->parent = new;
3942
3943  p->start = Qnil;
3944  p->pointm = Qnil;
3945  p->buffer = Qnil;
3946}
3947
3948DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
3949       doc: /* Split WINDOW, putting SIZE lines in the first of the pair.
3950WINDOW defaults to selected one and SIZE to half its size.
3951If optional third arg HORFLAG is non-nil, split side by side
3952and put SIZE columns in the first of the pair.  In that case,
3953SIZE includes that window's scroll bar, or the divider column to its right.
3954Interactively, all arguments are nil.
3955
3956Returns the newly created window (which is the lower or rightmost one).
3957The upper or leftmost window is the original one, and remains selected
3958if it was selected before.
3959
3960See Info node `(elisp)Splitting Windows' for more details and examples.*/)
3961     (window, size, horflag)
3962     Lisp_Object window, size, horflag;
3963{
3964  register Lisp_Object new;
3965  register struct window *o, *p;
3966  FRAME_PTR fo;
3967  register int size_int;
3968
3969  if (NILP (window))
3970    window = selected_window;
3971  else
3972    CHECK_LIVE_WINDOW (window);
3973
3974  o = XWINDOW (window);
3975  fo = XFRAME (WINDOW_FRAME (o));
3976
3977  if (NILP (size))
3978    {
3979      if (!NILP (horflag))
3980	/* Calculate the size of the left-hand window, by dividing
3981	   the usable space in columns by two.
3982	   We round up, since the left-hand window may include
3983	   a dividing line, while the right-hand may not.  */
3984	size_int = (XFASTINT (o->total_cols) + 1) >> 1;
3985      else
3986	size_int = XFASTINT (o->total_lines) >> 1;
3987    }
3988  else
3989    {
3990      CHECK_NUMBER (size);
3991      size_int = XINT (size);
3992    }
3993
3994  if (MINI_WINDOW_P (o))
3995    error ("Attempt to split minibuffer window");
3996  else if (window_fixed_size_p (o, !NILP (horflag), 0))
3997    error ("Attempt to split fixed-size window");
3998
3999  check_min_window_sizes ();
4000
4001  if (NILP (horflag))
4002    {
4003      if (size_int < window_min_height)
4004	error ("Window height %d too small (after splitting)", size_int);
4005      if (size_int + window_min_height > XFASTINT (o->total_lines))
4006	error ("Window height %d too small (after splitting)",
4007	       XFASTINT (o->total_lines) - size_int);
4008      if (NILP (o->parent)
4009	  || NILP (XWINDOW (o->parent)->vchild))
4010	{
4011	  make_dummy_parent (window);
4012	  new = o->parent;
4013	  XWINDOW (new)->vchild = window;
4014	}
4015    }
4016  else
4017    {
4018      if (size_int < window_min_width)
4019	error ("Window width %d too small (after splitting)", size_int);
4020
4021      if (size_int + window_min_width > XFASTINT (o->total_cols))
4022	error ("Window width %d too small (after splitting)",
4023	       XFASTINT (o->total_cols) - size_int);
4024      if (NILP (o->parent)
4025	  || NILP (XWINDOW (o->parent)->hchild))
4026	{
4027	  make_dummy_parent (window);
4028	  new = o->parent;
4029	  XWINDOW (new)->hchild = window;
4030	}
4031    }
4032
4033  /* Now we know that window's parent is a vertical combination
4034     if we are dividing vertically, or a horizontal combination
4035     if we are making side-by-side windows */
4036
4037  windows_or_buffers_changed++;
4038  FRAME_WINDOW_SIZES_CHANGED (fo) = 1;
4039  new = make_window ();
4040  p = XWINDOW (new);
4041
4042  p->frame = o->frame;
4043  p->next = o->next;
4044  if (!NILP (p->next))
4045    XWINDOW (p->next)->prev = new;
4046  p->prev = window;
4047  o->next = new;
4048  p->parent = o->parent;
4049  p->buffer = Qt;
4050  p->window_end_valid = Qnil;
4051  bzero (&p->last_cursor, sizeof p->last_cursor);
4052
4053  /* Duplicate special geometry settings.  */
4054
4055  p->left_margin_cols = o->left_margin_cols;
4056  p->right_margin_cols = o->right_margin_cols;
4057  p->left_fringe_width = o->left_fringe_width;
4058  p->right_fringe_width = o->right_fringe_width;
4059  p->fringes_outside_margins = o->fringes_outside_margins;
4060  p->scroll_bar_width = o->scroll_bar_width;
4061  p->vertical_scroll_bar_type = o->vertical_scroll_bar_type;
4062
4063  /* Apportion the available frame space among the two new windows */
4064
4065  if (!NILP (horflag))
4066    {
4067      p->total_lines = o->total_lines;
4068      p->top_line = o->top_line;
4069      XSETFASTINT (p->total_cols, XFASTINT (o->total_cols) - size_int);
4070      XSETFASTINT (o->total_cols, size_int);
4071      XSETFASTINT (p->left_col, XFASTINT (o->left_col) + size_int);
4072      adjust_window_margins (p);
4073      adjust_window_margins (o);
4074    }
4075  else
4076    {
4077      p->left_col = o->left_col;
4078      p->total_cols = o->total_cols;
4079      XSETFASTINT (p->total_lines, XFASTINT (o->total_lines) - size_int);
4080      XSETFASTINT (o->total_lines, size_int);
4081      XSETFASTINT (p->top_line, XFASTINT (o->top_line) + size_int);
4082    }
4083
4084  /* Adjust glyph matrices.  */
4085  adjust_glyphs (fo);
4086
4087  Fset_window_buffer (new, o->buffer, Qt);
4088  return new;
4089}
4090
4091DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
4092       doc: /* Make current window ARG lines bigger.
4093From program, optional second arg non-nil means grow sideways ARG columns.
4094Interactively, if an argument is not given, make the window one line bigger.
4095If HORIZONTAL is non-nil, enlarge horizontally instead of vertically.
4096This function can delete windows, even the second window, if they get
4097too small.  */)
4098     (arg, horizontal)
4099     Lisp_Object arg, horizontal;
4100{
4101  CHECK_NUMBER (arg);
4102  enlarge_window (selected_window, XINT (arg), !NILP (horizontal));
4103
4104  if (! NILP (Vwindow_configuration_change_hook))
4105    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
4106
4107  return Qnil;
4108}
4109
4110DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
4111       doc: /* Make current window ARG lines smaller.
4112From program, optional second arg non-nil means shrink sideways arg columns.
4113Interactively, if an argument is not given, make the window one line smaller.  Only
4114siblings to the right or below are changed.  */)
4115     (arg, side)
4116     Lisp_Object arg, side;
4117{
4118  CHECK_NUMBER (arg);
4119  enlarge_window (selected_window, -XINT (arg), !NILP (side));
4120
4121  if (! NILP (Vwindow_configuration_change_hook))
4122    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
4123
4124  return Qnil;
4125}
4126
4127int
4128window_height (window)
4129     Lisp_Object window;
4130{
4131  register struct window *p = XWINDOW (window);
4132  return WINDOW_TOTAL_LINES (p);
4133}
4134
4135int
4136window_width (window)
4137     Lisp_Object window;
4138{
4139  register struct window *p = XWINDOW (window);
4140  return WINDOW_TOTAL_COLS (p);
4141}
4142
4143
4144#define CURBEG(w) \
4145  *(horiz_flag ? &(XWINDOW (w)->left_col) : &(XWINDOW (w)->top_line))
4146
4147#define CURSIZE(w) \
4148  *(horiz_flag ? &(XWINDOW (w)->total_cols) : &(XWINDOW (w)->total_lines))
4149
4150
4151/* Enlarge WINDOW by DELTA.
4152   HORIZ_FLAG nonzero means enlarge it horizontally;
4153   zero means do it vertically.
4154
4155   Siblings of the selected window are resized to fulfill the size
4156   request.  If they become too small in the process, they will be
4157   deleted.  */
4158
4159static void
4160enlarge_window (window, delta, horiz_flag)
4161     Lisp_Object window;
4162     int delta, horiz_flag;
4163{
4164  Lisp_Object parent, next, prev;
4165  struct window *p;
4166  Lisp_Object *sizep;
4167  int maximum;
4168  int (*sizefun) P_ ((Lisp_Object))
4169    = horiz_flag ? window_width : window_height;
4170  void (*setsizefun) P_ ((Lisp_Object, int, int))
4171    = (horiz_flag ? set_window_width : set_window_height);
4172
4173  /* Check values of window_min_width and window_min_height for
4174     validity.  */
4175  check_min_window_sizes ();
4176
4177  /* Give up if this window cannot be resized.  */
4178  if (window_fixed_size_p (XWINDOW (window), horiz_flag, 1))
4179    error ("Window is not resizable");
4180
4181  /* Find the parent of the selected window.  */
4182  while (1)
4183    {
4184      p = XWINDOW (window);
4185      parent = p->parent;
4186
4187      if (NILP (parent))
4188	{
4189	  if (horiz_flag)
4190	    error ("No other window to side of this one");
4191	  break;
4192	}
4193
4194      if (horiz_flag
4195	  ? !NILP (XWINDOW (parent)->hchild)
4196	  : !NILP (XWINDOW (parent)->vchild))
4197	break;
4198
4199      window = parent;
4200    }
4201
4202  sizep = &CURSIZE (window);
4203
4204  {
4205    register int maxdelta;
4206
4207    /* Compute the maximum size increment this window can have.  */
4208
4209    maxdelta = (!NILP (parent) ? (*sizefun) (parent) - XINT (*sizep)
4210		/* This is a main window followed by a minibuffer.  */
4211		: !NILP (p->next) ? ((*sizefun) (p->next)
4212				     - window_min_size (XWINDOW (p->next),
4213							horiz_flag, 0, 0))
4214		/* This is a minibuffer following a main window.  */
4215		: !NILP (p->prev) ? ((*sizefun) (p->prev)
4216				     - window_min_size (XWINDOW (p->prev),
4217							horiz_flag, 0, 0))
4218		/* This is a frame with only one window, a minibuffer-only
4219		   or a minibufferless frame.  */
4220		: (delta = 0));
4221
4222    if (delta > maxdelta)
4223      /* This case traps trying to make the minibuffer
4224	 the full frame, or make the only window aside from the
4225	 minibuffer the full frame.  */
4226      delta = maxdelta;
4227  }
4228
4229  if (XINT (*sizep) + delta < window_min_size (XWINDOW (window), horiz_flag, 0, 0))
4230    {
4231      delete_window (window);
4232      return;
4233    }
4234
4235  if (delta == 0)
4236    return;
4237
4238  /* Find the total we can get from other siblings without deleting them.  */
4239  maximum = 0;
4240  for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
4241    maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
4242						    horiz_flag, 0, 0);
4243  for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
4244    maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
4245						    horiz_flag, 0, 0);
4246
4247  /* If we can get it all from them without deleting them, do so.  */
4248  if (delta <= maximum)
4249    {
4250      Lisp_Object first_unaffected;
4251      Lisp_Object first_affected;
4252      int fixed_p;
4253
4254      next = p->next;
4255      prev = p->prev;
4256      first_affected = window;
4257      /* Look at one sibling at a time,
4258	 moving away from this window in both directions alternately,
4259	 and take as much as we can get without deleting that sibling.  */
4260      while (delta != 0
4261	     && (!NILP (next) || !NILP (prev)))
4262	{
4263	  if (! NILP (next))
4264	    {
4265	      int this_one = ((*sizefun) (next)
4266			      - window_min_size (XWINDOW (next),
4267						 horiz_flag, 0, &fixed_p));
4268	      if (!fixed_p)
4269		{
4270		  if (this_one > delta)
4271		    this_one = delta;
4272
4273		  (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
4274		  (*setsizefun) (window, XINT (*sizep) + this_one, 0);
4275
4276		  delta -= this_one;
4277		}
4278
4279	      next = XWINDOW (next)->next;
4280	    }
4281
4282	  if (delta == 0)
4283	    break;
4284
4285	  if (! NILP (prev))
4286	    {
4287	      int this_one = ((*sizefun) (prev)
4288			      - window_min_size (XWINDOW (prev),
4289						 horiz_flag, 0, &fixed_p));
4290	      if (!fixed_p)
4291		{
4292		  if (this_one > delta)
4293		    this_one = delta;
4294
4295		  first_affected = prev;
4296
4297		  (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
4298		  (*setsizefun) (window, XINT (*sizep) + this_one, 0);
4299
4300		  delta -= this_one;
4301		}
4302
4303	      prev = XWINDOW (prev)->prev;
4304	    }
4305	}
4306
4307      xassert (delta == 0);
4308
4309      /* Now recalculate the edge positions of all the windows affected,
4310	 based on the new sizes.  */
4311      first_unaffected = next;
4312      prev = first_affected;
4313      for (next = XWINDOW (prev)->next; ! EQ (next, first_unaffected);
4314	   prev = next, next = XWINDOW (next)->next)
4315	{
4316	  XSETINT (CURBEG (next), XINT (CURBEG (prev)) + (*sizefun) (prev));
4317	  /* This does not change size of NEXT,
4318	     but it propagates the new top edge to its children */
4319	  (*setsizefun) (next, (*sizefun) (next), 0);
4320	}
4321    }
4322  else
4323    {
4324      register int delta1;
4325      register int opht = (*sizefun) (parent);
4326
4327      if (opht <= XINT (*sizep) + delta)
4328	{
4329	  /* If trying to grow this window to or beyond size of the parent,
4330	     just delete all the sibling windows.  */
4331	  Lisp_Object start, tem, next;
4332
4333	  start = XWINDOW (parent)->vchild;
4334	  if (NILP (start))
4335	    start = XWINDOW (parent)->hchild;
4336
4337	  /* Delete any siblings that come after WINDOW.  */
4338	  tem = XWINDOW (window)->next;
4339	  while (! NILP (tem))
4340	    {
4341	      next = XWINDOW (tem)->next;
4342	      delete_window (tem);
4343	      tem = next;
4344	    }
4345
4346	  /* Delete any siblings that come after WINDOW.
4347	     Note that if START is not WINDOW, then WINDOW still
4348	     Fhas siblings, so WINDOW has not yet replaced its parent.  */
4349	  tem = start;
4350	  while (! EQ (tem, window))
4351	    {
4352	      next = XWINDOW (tem)->next;
4353	      delete_window (tem);
4354	      tem = next;
4355	    }
4356	}
4357      else
4358	{
4359	  /* Otherwise, make delta1 just right so that if we add
4360	     delta1 lines to this window and to the parent, and then
4361	     shrink the parent back to its original size, the new
4362	     proportional size of this window will increase by delta.
4363
4364	     The function size_window will compute the new height h'
4365	     of the window from delta1 as:
4366
4367	     e = delta1/n
4368	     x = delta1 - delta1/n * n for the 1st resizable child
4369	     h' = h + e + x
4370
4371	     where n is the number of children that can be resized.
4372	     We can ignore x by choosing a delta1 that is a multiple of
4373	     n.  We want the height of this window to come out as
4374
4375	     h' = h + delta
4376
4377	     So, delta1 must be
4378
4379	     h + e = h + delta
4380	     delta1/n = delta
4381	     delta1 = n * delta.
4382
4383	     The number of children n equals the number of resizable
4384	     children of this window + 1 because we know window itself
4385	     is resizable (otherwise we would have signalled an error).  */
4386
4387	  struct window *w = XWINDOW (window);
4388	  Lisp_Object s;
4389	  int n = 1;
4390
4391	  for (s = w->next; !NILP (s); s = XWINDOW (s)->next)
4392	    if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
4393	      ++n;
4394	  for (s = w->prev; !NILP (s); s = XWINDOW (s)->prev)
4395	    if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
4396	      ++n;
4397
4398	  delta1 = n * delta;
4399
4400	  /* Add delta1 lines or columns to this window, and to the parent,
4401	     keeping things consistent while not affecting siblings.  */
4402	  XSETINT (CURSIZE (parent), opht + delta1);
4403	  (*setsizefun) (window, XINT (*sizep) + delta1, 0);
4404
4405	  /* Squeeze out delta1 lines or columns from our parent,
4406	     shriking this window and siblings proportionately.
4407	     This brings parent back to correct size.
4408	     Delta1 was calculated so this makes this window the desired size,
4409	     taking it all out of the siblings.  */
4410	  (*setsizefun) (parent, opht, 0);
4411
4412	}
4413    }
4414
4415  XSETFASTINT (p->last_modified, 0);
4416  XSETFASTINT (p->last_overlay_modified, 0);
4417
4418  /* Adjust glyph matrices. */
4419  adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
4420}
4421
4422
4423/* Adjust the size of WINDOW by DELTA, moving only its trailing edge.
4424   HORIZ_FLAG nonzero means adjust the width, moving the right edge.
4425   zero means adjust the height, moving the bottom edge.
4426
4427   Following siblings of the selected window are resized to fulfill
4428   the size request.  If they become too small in the process, they
4429   are not deleted; instead, we signal an error.  */
4430
4431static void
4432adjust_window_trailing_edge (window, delta, horiz_flag)
4433     Lisp_Object window;
4434     int delta, horiz_flag;
4435{
4436  Lisp_Object parent, child;
4437  struct window *p;
4438  Lisp_Object old_config = Fcurrent_window_configuration (Qnil);
4439  int delcount = window_deletion_count;
4440
4441  /* Check values of window_min_width and window_min_height for
4442     validity.  */
4443  check_min_window_sizes ();
4444
4445  if (NILP (window))
4446    window = Fselected_window ();
4447
4448  CHECK_WINDOW (window);
4449
4450  /* Give up if this window cannot be resized.  */
4451  if (window_fixed_size_p (XWINDOW (window), horiz_flag, 1))
4452    error ("Window is not resizable");
4453
4454  while (1)
4455    {
4456      Lisp_Object first_parallel = Qnil;
4457
4458      if (NILP (window))
4459	{
4460	  /* This happens if WINDOW on the previous iteration was
4461	     at top level of the window tree.  */
4462	  Fset_window_configuration (old_config);
4463	  error ("Specified window edge is fixed");
4464	}
4465
4466      p = XWINDOW (window);
4467      parent = p->parent;
4468
4469      /* See if this level has windows in parallel in the specified
4470	 direction.  If so, set FIRST_PARALLEL to the first one.  */
4471      if (horiz_flag)
4472	{
4473	  if (! NILP (parent) && !NILP (XWINDOW (parent)->vchild))
4474	    first_parallel = XWINDOW (parent)->vchild;
4475	  else if (NILP (parent) && !NILP (p->next))
4476	    {
4477	      /* Handle the vertical chain of main window and minibuffer
4478		 which has no parent.  */
4479	      first_parallel = window;
4480	      while (! NILP (XWINDOW (first_parallel)->prev))
4481		first_parallel = XWINDOW (first_parallel)->prev;
4482	    }
4483	}
4484      else
4485	{
4486	  if (! NILP (parent) && !NILP (XWINDOW (parent)->hchild))
4487	    first_parallel = XWINDOW (parent)->hchild;
4488	}
4489
4490      /* If this level's succession is in the desired dimension,
4491	 and this window is the last one, and there is no higher level,
4492	 its trailing edge is fixed.  */
4493      if (NILP (XWINDOW (window)->next) && NILP (first_parallel)
4494	  && NILP (parent))
4495	{
4496	  Fset_window_configuration (old_config);
4497	  error ("Specified window edge is fixed");
4498	}
4499
4500      /* Don't make this window too small.  */
4501      if (XINT (CURSIZE (window)) + delta
4502	  < (horiz_flag ? window_min_width : window_min_height))
4503	{
4504	  Fset_window_configuration (old_config);
4505	  error ("Cannot adjust window size as specified");
4506	}
4507
4508      /* Clear out some redisplay caches.  */
4509      XSETFASTINT (p->last_modified, 0);
4510      XSETFASTINT (p->last_overlay_modified, 0);
4511
4512      /* Adjust this window's edge.  */
4513      XSETINT (CURSIZE (window),
4514	       XINT (CURSIZE (window)) + delta);
4515
4516      /* If this window has following siblings in the desired dimension,
4517	 make them smaller, and exit the loop.
4518
4519	 (If we reach the top of the tree and can never do this,
4520	 we will fail and report an error, above.)  */
4521      if (NILP (first_parallel))
4522	{
4523	  if (!NILP (p->next))
4524	    {
4525              /* This may happen for the minibuffer.  In that case
4526                 the window_deletion_count check below does not work.  */
4527              if (XINT (CURSIZE (p->next)) - delta <= 0)
4528                {
4529                  Fset_window_configuration (old_config);
4530                  error ("Cannot adjust window size as specified");
4531                }
4532
4533	      XSETINT (CURBEG (p->next),
4534		       XINT (CURBEG (p->next)) + delta);
4535	      size_window (p->next, XINT (CURSIZE (p->next)) - delta,
4536			   horiz_flag, 0, 1, 0);
4537	      break;
4538	    }
4539	}
4540      else
4541	/* Here we have a chain of parallel siblings, in the other dimension.
4542	   Change the size of the other siblings.  */
4543	for (child = first_parallel;
4544	     ! NILP (child);
4545	     child = XWINDOW (child)->next)
4546	  if (! EQ (child, window))
4547	    size_window (child, XINT (CURSIZE (child)) + delta,
4548			 horiz_flag, 0, 0, 1);
4549
4550      window = parent;
4551    }
4552
4553  /* If we made a window so small it got deleted,
4554     we failed.  Report failure.  */
4555  if (delcount != window_deletion_count)
4556    {
4557      Fset_window_configuration (old_config);
4558      error ("Cannot adjust window size as specified");
4559    }
4560
4561  /* Adjust glyph matrices. */
4562  adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
4563}
4564
4565#undef CURBEG
4566#undef CURSIZE
4567
4568DEFUN ("adjust-window-trailing-edge", Fadjust_window_trailing_edge,
4569       Sadjust_window_trailing_edge, 3, 3, 0,
4570       doc: /* Adjust the bottom or right edge of WINDOW by DELTA.
4571If HORIZONTAL is non-nil, that means adjust the width, moving the right edge.
4572Otherwise, adjust the height, moving the bottom edge.
4573
4574Following siblings of the selected window are resized to fulfill
4575the size request.  If they become too small in the process, they
4576are not deleted; instead, we signal an error.  */)
4577  (window, delta, horizontal)
4578  Lisp_Object window, delta, horizontal;
4579{
4580  CHECK_NUMBER (delta);
4581  adjust_window_trailing_edge (window, XINT (delta), !NILP (horizontal));
4582
4583  if (! NILP (Vwindow_configuration_change_hook))
4584    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
4585
4586  return Qnil;
4587}
4588
4589
4590
4591/***********************************************************************
4592			Resizing Mini-Windows
4593 ***********************************************************************/
4594
4595static void shrink_window_lowest_first P_ ((struct window *, int));
4596
4597enum save_restore_action
4598{
4599    CHECK_ORIG_SIZES,
4600    SAVE_ORIG_SIZES,
4601    RESTORE_ORIG_SIZES
4602};
4603
4604static int save_restore_orig_size P_ ((struct window *,
4605                                       enum save_restore_action));
4606
4607/* Shrink windows rooted in window W to HEIGHT.  Take the space needed
4608   from lowest windows first.  */
4609
4610static void
4611shrink_window_lowest_first (w, height)
4612     struct window *w;
4613     int height;
4614{
4615  struct window *c;
4616  Lisp_Object child;
4617  int old_height;
4618
4619  xassert (!MINI_WINDOW_P (w));
4620
4621  /* Set redisplay hints.  */
4622  XSETFASTINT (w->last_modified, 0);
4623  XSETFASTINT (w->last_overlay_modified, 0);
4624  windows_or_buffers_changed++;
4625  FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
4626
4627  old_height = XFASTINT (w->total_lines);
4628  XSETFASTINT (w->total_lines, height);
4629
4630  if (!NILP (w->hchild))
4631    {
4632      for (child = w->hchild; !NILP (child); child = c->next)
4633	{
4634	  c = XWINDOW (child);
4635	  c->top_line = w->top_line;
4636	  shrink_window_lowest_first (c, height);
4637	}
4638    }
4639  else if (!NILP (w->vchild))
4640    {
4641      Lisp_Object last_child;
4642      int delta = old_height - height;
4643      int last_top;
4644
4645      last_child = Qnil;
4646
4647      /* Find the last child.  We are taking space from lowest windows
4648	 first, so we iterate over children from the last child
4649	 backwards.  */
4650      for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
4651	last_child = child;
4652
4653      /* Assign new heights.  We leave only MIN_SAFE_WINDOW_HEIGHT.  */
4654      for (child = last_child; delta && !NILP (child); child = c->prev)
4655	{
4656	  int this_one;
4657
4658	  c = XWINDOW (child);
4659	  this_one = XFASTINT (c->total_lines) - MIN_SAFE_WINDOW_HEIGHT;
4660
4661	  if (this_one > delta)
4662	    this_one = delta;
4663
4664	  shrink_window_lowest_first (c, XFASTINT (c->total_lines) - this_one);
4665	  delta -= this_one;
4666	}
4667
4668      /* Compute new positions.  */
4669      last_top = XINT (w->top_line);
4670      for (child = w->vchild; !NILP (child); child = c->next)
4671	{
4672	  c = XWINDOW (child);
4673	  c->top_line = make_number (last_top);
4674	  shrink_window_lowest_first (c, XFASTINT (c->total_lines));
4675	  last_top += XFASTINT (c->total_lines);
4676	}
4677    }
4678}
4679
4680
4681/* Save, restore, or check positions and sizes in the window tree
4682   rooted at W.  ACTION says what to do.
4683
4684   If ACTION is CHECK_ORIG_SIZES, check if orig_top_line and
4685   orig_total_lines members are valid for all windows in the window
4686   tree.  Value is non-zero if they are valid.
4687
4688   If ACTION is SAVE_ORIG_SIZES, save members top and height in
4689   orig_top_line and orig_total_lines for all windows in the tree.
4690
4691   If ACTION is RESTORE_ORIG_SIZES, restore top and height from values
4692   stored in orig_top_line and orig_total_lines for all windows.  */
4693
4694static int
4695save_restore_orig_size (w, action)
4696     struct window *w;
4697     enum save_restore_action action;
4698{
4699  int success_p = 1;
4700
4701  while (w)
4702    {
4703      if (!NILP (w->hchild))
4704	{
4705	  if (!save_restore_orig_size (XWINDOW (w->hchild), action))
4706	    success_p = 0;
4707	}
4708      else if (!NILP (w->vchild))
4709	{
4710	  if (!save_restore_orig_size (XWINDOW (w->vchild), action))
4711	    success_p = 0;
4712	}
4713
4714      switch (action)
4715	{
4716	case CHECK_ORIG_SIZES:
4717	  if (!INTEGERP (w->orig_top_line) || !INTEGERP (w->orig_total_lines))
4718	    return 0;
4719	  break;
4720
4721	case SAVE_ORIG_SIZES:
4722	  w->orig_top_line = w->top_line;
4723	  w->orig_total_lines = w->total_lines;
4724          XSETFASTINT (w->last_modified, 0);
4725          XSETFASTINT (w->last_overlay_modified, 0);
4726	  break;
4727
4728	case RESTORE_ORIG_SIZES:
4729	  xassert (INTEGERP (w->orig_top_line) && INTEGERP (w->orig_total_lines));
4730	  w->top_line = w->orig_top_line;
4731	  w->total_lines = w->orig_total_lines;
4732	  w->orig_total_lines = w->orig_top_line = Qnil;
4733          XSETFASTINT (w->last_modified, 0);
4734          XSETFASTINT (w->last_overlay_modified, 0);
4735	  break;
4736
4737	default:
4738	  abort ();
4739	}
4740
4741      w = NILP (w->next) ? NULL : XWINDOW (w->next);
4742    }
4743
4744  return success_p;
4745}
4746
4747
4748/* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we can
4749   without deleting other windows.  */
4750
4751void
4752grow_mini_window (w, delta)
4753     struct window *w;
4754     int delta;
4755{
4756  struct frame *f = XFRAME (w->frame);
4757  struct window *root;
4758
4759  xassert (MINI_WINDOW_P (w));
4760  xassert (delta >= 0);
4761
4762  /* Check values of window_min_width and window_min_height for
4763     validity.  */
4764  check_min_window_sizes ();
4765
4766  /* Compute how much we can enlarge the mini-window without deleting
4767     other windows.  */
4768  root = XWINDOW (FRAME_ROOT_WINDOW (f));
4769  if (delta)
4770    {
4771      int min_height = window_min_size (root, 0, 0, 0);
4772      if (XFASTINT (root->total_lines) - delta < min_height)
4773	/* Note that the root window may already be smaller than
4774	   min_height.  */
4775	delta = max (0, XFASTINT (root->total_lines) - min_height);
4776    }
4777
4778  if (delta)
4779    {
4780      /* Save original window sizes and positions, if not already done.  */
4781      if (!save_restore_orig_size (root, CHECK_ORIG_SIZES))
4782	save_restore_orig_size (root, SAVE_ORIG_SIZES);
4783
4784      /* Shrink other windows.  */
4785      shrink_window_lowest_first (root, XFASTINT (root->total_lines) - delta);
4786
4787      /* Grow the mini-window.  */
4788      w->top_line = make_number (XFASTINT (root->top_line) + XFASTINT (root->total_lines));
4789      w->total_lines = make_number (XFASTINT (w->total_lines) + delta);
4790      XSETFASTINT (w->last_modified, 0);
4791      XSETFASTINT (w->last_overlay_modified, 0);
4792
4793      adjust_glyphs (f);
4794    }
4795}
4796
4797
4798/* Shrink mini-window W.  If there is recorded info about window sizes
4799   before a call to grow_mini_window, restore recorded window sizes.
4800   Otherwise, if the mini-window is higher than 1 line, resize it to 1
4801   line.  */
4802
4803void
4804shrink_mini_window (w)
4805     struct window *w;
4806{
4807  struct frame *f = XFRAME (w->frame);
4808  struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
4809
4810  if (save_restore_orig_size (root, CHECK_ORIG_SIZES))
4811    {
4812      save_restore_orig_size (root, RESTORE_ORIG_SIZES);
4813      adjust_glyphs (f);
4814      FRAME_WINDOW_SIZES_CHANGED (f) = 1;
4815      windows_or_buffers_changed = 1;
4816    }
4817  else if (XFASTINT (w->total_lines) > 1)
4818    {
4819      /* Distribute the additional lines of the mini-window
4820	 among the other windows.  */
4821      Lisp_Object window;
4822      XSETWINDOW (window, w);
4823      enlarge_window (window, 1 - XFASTINT (w->total_lines), 0);
4824    }
4825}
4826
4827
4828
4829/* Mark window cursors off for all windows in the window tree rooted
4830   at W by setting their phys_cursor_on_p flag to zero.  Called from
4831   xterm.c, e.g. when a frame is cleared and thereby all cursors on
4832   the frame are cleared.  */
4833
4834void
4835mark_window_cursors_off (w)
4836     struct window *w;
4837{
4838  while (w)
4839    {
4840      if (!NILP (w->hchild))
4841	mark_window_cursors_off (XWINDOW (w->hchild));
4842      else if (!NILP (w->vchild))
4843	mark_window_cursors_off (XWINDOW (w->vchild));
4844      else
4845	w->phys_cursor_on_p = 0;
4846
4847      w = NILP (w->next) ? 0 : XWINDOW (w->next);
4848    }
4849}
4850
4851
4852/* Return number of lines of text (not counting mode lines) in W.  */
4853
4854int
4855window_internal_height (w)
4856     struct window *w;
4857{
4858  int ht = XFASTINT (w->total_lines);
4859
4860  if (!MINI_WINDOW_P (w))
4861    {
4862      if (!NILP (w->parent)
4863	  || !NILP (w->vchild)
4864	  || !NILP (w->hchild)
4865	  || !NILP (w->next)
4866	  || !NILP (w->prev)
4867	  || WINDOW_WANTS_MODELINE_P (w))
4868	--ht;
4869
4870      if (WINDOW_WANTS_HEADER_LINE_P (w))
4871	--ht;
4872    }
4873
4874  return ht;
4875}
4876
4877
4878/* Return the number of columns in W.
4879   Don't count columns occupied by scroll bars or the vertical bar
4880   separating W from the sibling to its right.  */
4881
4882int
4883window_box_text_cols (w)
4884     struct window *w;
4885{
4886  struct frame *f = XFRAME (WINDOW_FRAME (w));
4887  int width = XINT (w->total_cols);
4888
4889  if (WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
4890    /* Scroll bars occupy a few columns.  */
4891    width -= WINDOW_CONFIG_SCROLL_BAR_COLS (w);
4892  else if (!FRAME_WINDOW_P (f)
4893	   && !WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
4894    /* The column of `|' characters separating side-by-side windows
4895       occupies one column only.  */
4896    width -= 1;
4897
4898  if (FRAME_WINDOW_P (f))
4899    /* On window-systems, fringes and display margins cannot be
4900       used for normal text.  */
4901    width -= (WINDOW_FRINGE_COLS (w)
4902	      + WINDOW_LEFT_MARGIN_COLS (w)
4903	      + WINDOW_RIGHT_MARGIN_COLS (w));
4904
4905  return width;
4906}
4907
4908
4909/************************************************************************
4910			   Window Scrolling
4911 ***********************************************************************/
4912
4913/* Scroll contents of window WINDOW up.  If WHOLE is non-zero, scroll
4914   N screen-fulls, which is defined as the height of the window minus
4915   next_screen_context_lines.  If WHOLE is zero, scroll up N lines
4916   instead.  Negative values of N mean scroll down.  NOERROR non-zero
4917   means don't signal an error if we try to move over BEGV or ZV,
4918   respectively.  */
4919
4920static void
4921window_scroll (window, n, whole, noerror)
4922     Lisp_Object window;
4923     int n;
4924     int whole;
4925     int noerror;
4926{
4927  immediate_quit = 1;
4928
4929  /* If we must, use the pixel-based version which is much slower than
4930     the line-based one but can handle varying line heights.  */
4931  if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
4932    window_scroll_pixel_based (window, n, whole, noerror);
4933  else
4934    window_scroll_line_based (window, n, whole, noerror);
4935
4936  immediate_quit = 0;
4937}
4938
4939
4940/* Implementation of window_scroll that works based on pixel line
4941   heights.  See the comment of window_scroll for parameter
4942   descriptions.  */
4943
4944static void
4945window_scroll_pixel_based (window, n, whole, noerror)
4946     Lisp_Object window;
4947     int n;
4948     int whole;
4949     int noerror;
4950{
4951  struct it it;
4952  struct window *w = XWINDOW (window);
4953  struct text_pos start;
4954  int this_scroll_margin;
4955  /* True if we fiddled the window vscroll field without really scrolling.   */
4956  int vscrolled = 0;
4957  int x, y, rtop, rbot, rowh, vpos;
4958
4959  SET_TEXT_POS_FROM_MARKER (start, w->start);
4960
4961  /* If PT is not visible in WINDOW, move back one half of
4962     the screen.  Allow PT to be partially visible, otherwise
4963     something like (scroll-down 1) with PT in the line before
4964     the partially visible one would recenter. */
4965
4966  if (!pos_visible_p (w, PT, &x, &y, &rtop, &rbot, &rowh, &vpos))
4967    {
4968      /* Move backward half the height of the window.  Performance note:
4969	 vmotion used here is about 10% faster, but would give wrong
4970	 results for variable height lines.  */
4971      init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
4972      it.current_y = it.last_visible_y;
4973      move_it_vertically_backward (&it, window_box_height (w) / 2);
4974
4975      /* The function move_iterator_vertically may move over more than
4976	 the specified y-distance.  If it->w is small, e.g. a
4977	 mini-buffer window, we may end up in front of the window's
4978	 display area.  This is the case when Start displaying at the
4979	 start of the line containing PT in this case.  */
4980      if (it.current_y <= 0)
4981	{
4982	  init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
4983	  move_it_vertically_backward (&it, 0);
4984	  it.current_y = 0;
4985	}
4986
4987      start = it.current.pos;
4988    }
4989  else if (auto_window_vscroll_p)
4990    {
4991      if (rtop || rbot)		/* partially visible */
4992	{
4993	  int px;
4994	  int dy = WINDOW_FRAME_LINE_HEIGHT (w);
4995	  if (whole)
4996	    dy = max ((window_box_height (w)
4997		       - next_screen_context_lines * dy),
4998		      dy);
4999	  dy *= n;
5000
5001	  if (n < 0)
5002	    {
5003	      /* Only vscroll backwards if already vscrolled forwards.  */
5004	      if (w->vscroll < 0 && rtop > 0)
5005		{
5006		  px = max (0, -w->vscroll - min (rtop, -dy));
5007		  Fset_window_vscroll (window, make_number (px), Qt);
5008		  return;
5009		}
5010	    }
5011	  if (n > 0)
5012	    {
5013	      /* Do vscroll if already vscrolled or only display line.  */
5014	      if (rbot > 0 && (w->vscroll < 0 || vpos == 0))
5015		{
5016		  px = max (0, -w->vscroll + min (rbot, dy));
5017		  Fset_window_vscroll (window, make_number (px), Qt);
5018		  return;
5019		}
5020
5021	      /* Maybe modify window start instead of scrolling.  */
5022	      if (rbot > 0 || w->vscroll < 0)
5023		{
5024		  int spos;
5025
5026		  Fset_window_vscroll (window, make_number (0), Qt);
5027		  /* If there are other text lines above the current row,
5028		     move window start to current row.  Else to next row. */
5029		  if (rbot > 0)
5030		    spos = XINT (Fline_beginning_position (Qnil));
5031		  else
5032		    spos = min (XINT (Fline_end_position (Qnil)) + 1, ZV);
5033		  set_marker_restricted (w->start, make_number (spos),
5034					 w->buffer);
5035		  w->start_at_line_beg = Qt;
5036		  w->update_mode_line = Qt;
5037		  XSETFASTINT (w->last_modified, 0);
5038		  XSETFASTINT (w->last_overlay_modified, 0);
5039		  /* Set force_start so that redisplay_window will run the
5040		     window-scroll-functions.  */
5041		  w->force_start = Qt;
5042		  return;
5043		}
5044	    }
5045	}
5046      /* Cancel previous vscroll.  */
5047      Fset_window_vscroll (window, make_number (0), Qt);
5048    }
5049
5050  /* If scroll_preserve_screen_position is non-nil, we try to set
5051     point in the same window line as it is now, so get that line.  */
5052  if (!NILP (Vscroll_preserve_screen_position))
5053    {
5054      /* We preserve the goal pixel coordinate across consecutive
5055	 calls to scroll-up or scroll-down.  This avoids the
5056	 possibility of point becoming "stuck" on a tall line when
5057	 scrolling by one line.  */
5058      if (window_scroll_pixel_based_preserve_y < 0
5059	  || (!EQ (current_kboard->Vlast_command, Qscroll_up)
5060	      && !EQ (current_kboard->Vlast_command, Qscroll_down)))
5061	{
5062	  start_display (&it, w, start);
5063	  move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
5064	  window_scroll_pixel_based_preserve_y = it.current_y;
5065	}
5066    }
5067  else
5068    window_scroll_pixel_based_preserve_y = -1;
5069
5070  /* Move iterator it from start the specified distance forward or
5071     backward.  The result is the new window start.  */
5072  start_display (&it, w, start);
5073  if (whole)
5074    {
5075      int start_pos = IT_CHARPOS (it);
5076      int dy = WINDOW_FRAME_LINE_HEIGHT (w);
5077      dy = max ((window_box_height (w)
5078		 - next_screen_context_lines * dy),
5079		dy) * n;
5080
5081      /* Note that move_it_vertically always moves the iterator to the
5082         start of a line.  So, if the last line doesn't have a newline,
5083	 we would end up at the start of the line ending at ZV.  */
5084      if (dy <= 0)
5085	{
5086	  move_it_vertically_backward (&it, -dy);
5087	  /* Ensure we actually do move, e.g. in case we are currently
5088	     looking at an image that is taller that the window height.  */
5089	  while (start_pos == IT_CHARPOS (it)
5090		 && start_pos > BEGV)
5091	    move_it_by_lines (&it, -1, 1);
5092	}
5093      else if (dy > 0)
5094	{
5095	  move_it_to (&it, ZV, -1, it.current_y + dy, -1,
5096		      MOVE_TO_POS | MOVE_TO_Y);
5097	  /* Ensure we actually do move, e.g. in case we are currently
5098	     looking at an image that is taller that the window height.  */
5099	  while (start_pos == IT_CHARPOS (it)
5100		 && start_pos < ZV)
5101	    move_it_by_lines (&it, 1, 1);
5102	}
5103    }
5104  else
5105    move_it_by_lines (&it, n, 1);
5106
5107  /* We failed if we find ZV is already on the screen (scrolling up,
5108     means there's nothing past the end), or if we can't start any
5109     earlier (scrolling down, means there's nothing past the top).  */
5110  if ((n > 0 && IT_CHARPOS (it) == ZV)
5111      || (n < 0 && IT_CHARPOS (it) == CHARPOS (start)))
5112    {
5113      if (IT_CHARPOS (it) == ZV)
5114	{
5115	  if (it.current_y < it.last_visible_y
5116	      && (it.current_y + it.max_ascent + it.max_descent
5117		  > it.last_visible_y))
5118	    {
5119	      /* The last line was only partially visible, make it fully
5120		 visible.  */
5121	      w->vscroll = (it.last_visible_y
5122			    - it.current_y + it.max_ascent + it.max_descent);
5123	      adjust_glyphs (it.f);
5124	    }
5125	  else if (noerror)
5126	    return;
5127	  else if (n < 0)	/* could happen with empty buffers */
5128	    xsignal0 (Qbeginning_of_buffer);
5129	  else
5130	    xsignal0 (Qend_of_buffer);
5131	}
5132      else
5133	{
5134	  if (w->vscroll != 0)
5135	    /* The first line was only partially visible, make it fully
5136	       visible. */
5137	    w->vscroll = 0;
5138	  else if (noerror)
5139	    return;
5140	  else
5141	    xsignal0 (Qbeginning_of_buffer);
5142	}
5143
5144      /* If control gets here, then we vscrolled.  */
5145
5146      XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
5147
5148      /* Don't try to change the window start below.  */
5149      vscrolled = 1;
5150    }
5151
5152  if (! vscrolled)
5153    {
5154      int pos = IT_CHARPOS (it);
5155      int bytepos;
5156
5157      /* If in the middle of a multi-glyph character move forward to
5158	 the next character.  */
5159      if (in_display_vector_p (&it))
5160	{
5161	  ++pos;
5162	  move_it_to (&it, pos, -1, -1, -1, MOVE_TO_POS);
5163	}
5164
5165      /* Set the window start, and set up the window for redisplay.  */
5166      set_marker_restricted (w->start, make_number (pos),
5167			     w->buffer);
5168      bytepos = XMARKER (w->start)->bytepos;
5169      w->start_at_line_beg = ((pos == BEGV || FETCH_BYTE (bytepos - 1) == '\n')
5170			      ? Qt : Qnil);
5171      w->update_mode_line = Qt;
5172      XSETFASTINT (w->last_modified, 0);
5173      XSETFASTINT (w->last_overlay_modified, 0);
5174      /* Set force_start so that redisplay_window will run the
5175	 window-scroll-functions.  */
5176      w->force_start = Qt;
5177    }
5178
5179  /* The rest of this function uses current_y in a nonstandard way,
5180     not including the height of the header line if any.  */
5181  it.current_y = it.vpos = 0;
5182
5183  /* Move PT out of scroll margins.
5184     This code wants current_y to be zero at the window start position
5185     even if there is a header line.  */
5186  this_scroll_margin = max (0, scroll_margin);
5187  this_scroll_margin = min (this_scroll_margin, XFASTINT (w->total_lines) / 4);
5188  this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
5189
5190  if (n > 0)
5191    {
5192      /* We moved the window start towards ZV, so PT may be now
5193	 in the scroll margin at the top.  */
5194      move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
5195      if (IT_CHARPOS (it) == PT && it.current_y >= this_scroll_margin
5196          && (NILP (Vscroll_preserve_screen_position)
5197	      || EQ (Vscroll_preserve_screen_position, Qt)))
5198	/* We found PT at a legitimate height.  Leave it alone.  */
5199	;
5200      else if (window_scroll_pixel_based_preserve_y >= 0)
5201	{
5202	  /* If we have a header line, take account of it.
5203	     This is necessary because we set it.current_y to 0, above.  */
5204	  move_it_to (&it, -1, -1,
5205		      window_scroll_pixel_based_preserve_y
5206		      - (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0 ),
5207		      -1, MOVE_TO_Y);
5208	  SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5209	}
5210      else
5211	{
5212	  while (it.current_y < this_scroll_margin)
5213	    {
5214	      int prev = it.current_y;
5215	      move_it_by_lines (&it, 1, 1);
5216	      if (prev == it.current_y)
5217		break;
5218	    }
5219	  SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5220	}
5221    }
5222  else if (n < 0)
5223    {
5224      int charpos, bytepos;
5225      int partial_p;
5226
5227      /* Save our position, for the
5228	 window_scroll_pixel_based_preserve_y case.  */
5229      charpos = IT_CHARPOS (it);
5230      bytepos = IT_BYTEPOS (it);
5231
5232      /* We moved the window start towards BEGV, so PT may be now
5233	 in the scroll margin at the bottom.  */
5234      move_it_to (&it, PT, -1,
5235		  (it.last_visible_y - CURRENT_HEADER_LINE_HEIGHT (w)
5236		   - this_scroll_margin - 1),
5237		  -1,
5238		  MOVE_TO_POS | MOVE_TO_Y);
5239
5240      /* Save our position, in case it's correct.  */
5241      charpos = IT_CHARPOS (it);
5242      bytepos = IT_BYTEPOS (it);
5243
5244      /* See if point is on a partially visible line at the end.  */
5245      if (it.what == IT_EOB)
5246	partial_p = it.current_y + it.ascent + it.descent > it.last_visible_y;
5247      else
5248	{
5249	  move_it_by_lines (&it, 1, 1);
5250	  partial_p = it.current_y > it.last_visible_y;
5251	}
5252
5253      if (charpos == PT && !partial_p
5254          && (NILP (Vscroll_preserve_screen_position)
5255	      || EQ (Vscroll_preserve_screen_position, Qt)))
5256	/* We found PT before we found the display margin, so PT is ok.  */
5257	;
5258      else if (window_scroll_pixel_based_preserve_y >= 0)
5259	{
5260	  SET_TEXT_POS_FROM_MARKER (start, w->start);
5261	  start_display (&it, w, start);
5262	  /* It would be wrong to subtract CURRENT_HEADER_LINE_HEIGHT
5263	     here because we called start_display again and did not
5264	     alter it.current_y this time.  */
5265	  move_it_to (&it, -1, -1, window_scroll_pixel_based_preserve_y, -1,
5266		      MOVE_TO_Y);
5267	  SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5268	}
5269      else
5270	{
5271	  if (partial_p)
5272	    /* The last line was only partially visible, so back up two
5273	       lines to make sure we're on a fully visible line.  */
5274	    {
5275	      move_it_by_lines (&it, -2, 0);
5276	      SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5277	    }
5278	  else
5279	    /* No, the position we saved is OK, so use it.  */
5280	    SET_PT_BOTH (charpos, bytepos);
5281	}
5282    }
5283}
5284
5285
5286/* Implementation of window_scroll that works based on screen lines.
5287   See the comment of window_scroll for parameter descriptions.  */
5288
5289static void
5290window_scroll_line_based (window, n, whole, noerror)
5291     Lisp_Object window;
5292     int n;
5293     int whole;
5294     int noerror;
5295{
5296  register struct window *w = XWINDOW (window);
5297  register int opoint = PT, opoint_byte = PT_BYTE;
5298  register int pos, pos_byte;
5299  register int ht = window_internal_height (w);
5300  register Lisp_Object tem;
5301  int lose;
5302  Lisp_Object bolp;
5303  int startpos;
5304  struct position posit;
5305  int original_vpos;
5306
5307  /* If scrolling screen-fulls, compute the number of lines to
5308     scroll from the window's height.  */
5309  if (whole)
5310    n *= max (1, ht - next_screen_context_lines);
5311
5312  startpos = marker_position (w->start);
5313
5314  posit = *compute_motion (startpos, 0, 0, 0,
5315			   PT, ht, 0,
5316			   -1, XINT (w->hscroll),
5317			   0, w);
5318  original_vpos = posit.vpos;
5319
5320  XSETFASTINT (tem, PT);
5321  tem = Fpos_visible_in_window_p (tem, window, Qnil);
5322
5323  if (NILP (tem))
5324    {
5325      Fvertical_motion (make_number (- (ht / 2)), window);
5326      startpos = PT;
5327    }
5328
5329  SET_PT (startpos);
5330  lose = n < 0 && PT == BEGV;
5331  Fvertical_motion (make_number (n), window);
5332  pos = PT;
5333  pos_byte = PT_BYTE;
5334  bolp = Fbolp ();
5335  SET_PT_BOTH (opoint, opoint_byte);
5336
5337  if (lose)
5338    {
5339      if (noerror)
5340	return;
5341      else
5342	xsignal0 (Qbeginning_of_buffer);
5343    }
5344
5345  if (pos < ZV)
5346    {
5347      int this_scroll_margin = scroll_margin;
5348
5349      /* Don't use a scroll margin that is negative or too large.  */
5350      if (this_scroll_margin < 0)
5351	this_scroll_margin = 0;
5352
5353      if (XINT (w->total_lines) < 4 * scroll_margin)
5354	this_scroll_margin = XINT (w->total_lines) / 4;
5355
5356      set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
5357      w->start_at_line_beg = bolp;
5358      w->update_mode_line = Qt;
5359      XSETFASTINT (w->last_modified, 0);
5360      XSETFASTINT (w->last_overlay_modified, 0);
5361      /* Set force_start so that redisplay_window will run
5362	 the window-scroll-functions.  */
5363      w->force_start = Qt;
5364
5365      if (!NILP (Vscroll_preserve_screen_position)
5366	  && (whole || !EQ (Vscroll_preserve_screen_position, Qt)))
5367	{
5368	  SET_PT_BOTH (pos, pos_byte);
5369	  Fvertical_motion (make_number (original_vpos), window);
5370	}
5371      /* If we scrolled forward, put point enough lines down
5372	 that it is outside the scroll margin.  */
5373      else if (n > 0)
5374	{
5375	  int top_margin;
5376
5377	  if (this_scroll_margin > 0)
5378	    {
5379	      SET_PT_BOTH (pos, pos_byte);
5380	      Fvertical_motion (make_number (this_scroll_margin), window);
5381	      top_margin = PT;
5382	    }
5383	  else
5384	    top_margin = pos;
5385
5386	  if (top_margin <= opoint)
5387	    SET_PT_BOTH (opoint, opoint_byte);
5388	  else if (!NILP (Vscroll_preserve_screen_position))
5389	    {
5390	      SET_PT_BOTH (pos, pos_byte);
5391	      Fvertical_motion (make_number (original_vpos), window);
5392	    }
5393	  else
5394	    SET_PT (top_margin);
5395	}
5396      else if (n < 0)
5397	{
5398	  int bottom_margin;
5399
5400	  /* If we scrolled backward, put point near the end of the window
5401	     but not within the scroll margin.  */
5402	  SET_PT_BOTH (pos, pos_byte);
5403	  tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
5404	  if (XFASTINT (tem) == ht - this_scroll_margin)
5405	    bottom_margin = PT;
5406	  else
5407	    bottom_margin = PT + 1;
5408
5409	  if (bottom_margin > opoint)
5410	    SET_PT_BOTH (opoint, opoint_byte);
5411	  else
5412	    {
5413	      if (!NILP (Vscroll_preserve_screen_position))
5414		{
5415		  SET_PT_BOTH (pos, pos_byte);
5416		  Fvertical_motion (make_number (original_vpos), window);
5417		}
5418	      else
5419		Fvertical_motion (make_number (-1), window);
5420	    }
5421	}
5422    }
5423  else
5424    {
5425      if (noerror)
5426	return;
5427      else
5428	xsignal0 (Qend_of_buffer);
5429    }
5430}
5431
5432
5433/* Scroll selected_window up or down.  If N is nil, scroll a
5434   screen-full which is defined as the height of the window minus
5435   next_screen_context_lines.  If N is the symbol `-', scroll.
5436   DIRECTION may be 1 meaning to scroll down, or -1 meaning to scroll
5437   up.  This is the guts of Fscroll_up and Fscroll_down.  */
5438
5439static void
5440scroll_command (n, direction)
5441     Lisp_Object n;
5442     int direction;
5443{
5444  int count = SPECPDL_INDEX ();
5445
5446  xassert (abs (direction) == 1);
5447
5448  /* If selected window's buffer isn't current, make it current for
5449     the moment.  But don't screw up if window_scroll gets an error.  */
5450  if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
5451    {
5452      record_unwind_protect (save_excursion_restore, save_excursion_save ());
5453      Fset_buffer (XWINDOW (selected_window)->buffer);
5454
5455      /* Make redisplay consider other windows than just selected_window.  */
5456      ++windows_or_buffers_changed;
5457    }
5458
5459  if (NILP (n))
5460    window_scroll (selected_window, direction, 1, 0);
5461  else if (EQ (n, Qminus))
5462    window_scroll (selected_window, -direction, 1, 0);
5463  else
5464    {
5465      n = Fprefix_numeric_value (n);
5466      window_scroll (selected_window, XINT (n) * direction, 0, 0);
5467    }
5468
5469  unbind_to (count, Qnil);
5470}
5471
5472DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
5473       doc: /* Scroll text of current window upward ARG lines.
5474If ARG is omitted or nil, scroll upward by a near full screen.
5475A near full screen is `next-screen-context-lines' less than a full screen.
5476Negative ARG means scroll downward.
5477If ARG is the atom `-', scroll downward by nearly full screen.
5478When calling from a program, supply as argument a number, nil, or `-'.  */)
5479     (arg)
5480     Lisp_Object arg;
5481{
5482  scroll_command (arg, 1);
5483  return Qnil;
5484}
5485
5486DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
5487       doc: /* Scroll text of current window down ARG lines.
5488If ARG is omitted or nil, scroll down by a near full screen.
5489A near full screen is `next-screen-context-lines' less than a full screen.
5490Negative ARG means scroll upward.
5491If ARG is the atom `-', scroll upward by nearly full screen.
5492When calling from a program, supply as argument a number, nil, or `-'.  */)
5493     (arg)
5494     Lisp_Object arg;
5495{
5496  scroll_command (arg, -1);
5497  return Qnil;
5498}
5499
5500DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0,
5501       doc: /* Return the other window for \"other window scroll\" commands.
5502If `other-window-scroll-buffer' is non-nil, a window
5503showing that buffer is used.
5504If in the minibuffer, `minibuffer-scroll-window' if non-nil
5505specifies the window.  This takes precedence over
5506`other-window-scroll-buffer'.  */)
5507     ()
5508{
5509  Lisp_Object window;
5510
5511  if (MINI_WINDOW_P (XWINDOW (selected_window))
5512      && !NILP (Vminibuf_scroll_window))
5513    window = Vminibuf_scroll_window;
5514  /* If buffer is specified, scroll that buffer.  */
5515  else if (!NILP (Vother_window_scroll_buffer))
5516    {
5517      window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
5518      if (NILP (window))
5519	window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt, Qnil);
5520    }
5521  else
5522    {
5523      /* Nothing specified; look for a neighboring window on the same
5524	 frame.  */
5525      window = Fnext_window (selected_window, Qnil, Qnil);
5526
5527      if (EQ (window, selected_window))
5528	/* That didn't get us anywhere; look for a window on another
5529           visible frame.  */
5530	do
5531	  window = Fnext_window (window, Qnil, Qt);
5532	while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
5533	       && ! EQ (window, selected_window));
5534    }
5535
5536  CHECK_LIVE_WINDOW (window);
5537
5538  if (EQ (window, selected_window))
5539    error ("There is no other window");
5540
5541  return window;
5542}
5543
5544DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
5545       doc: /* Scroll next window upward ARG lines; or near full screen if no ARG.
5546A near full screen is `next-screen-context-lines' less than a full screen.
5547The next window is the one below the current one; or the one at the top
5548if the current one is at the bottom.  Negative ARG means scroll downward.
5549If ARG is the atom `-', scroll downward by nearly full screen.
5550When calling from a program, supply as argument a number, nil, or `-'.
5551
5552If `other-window-scroll-buffer' is non-nil, scroll the window
5553showing that buffer, popping the buffer up if necessary.
5554If in the minibuffer, `minibuffer-scroll-window' if non-nil
5555specifies the window to scroll.  This takes precedence over
5556`other-window-scroll-buffer'.  */)
5557     (arg)
5558     Lisp_Object arg;
5559{
5560  Lisp_Object window;
5561  struct window *w;
5562  int count = SPECPDL_INDEX ();
5563
5564  window = Fother_window_for_scrolling ();
5565  w = XWINDOW (window);
5566
5567  /* Don't screw up if window_scroll gets an error.  */
5568  record_unwind_protect (save_excursion_restore, save_excursion_save ());
5569  ++windows_or_buffers_changed;
5570
5571  Fset_buffer (w->buffer);
5572  SET_PT (marker_position (w->pointm));
5573
5574  if (NILP (arg))
5575    window_scroll (window, 1, 1, 1);
5576  else if (EQ (arg, Qminus))
5577    window_scroll (window, -1, 1, 1);
5578  else
5579    {
5580      if (CONSP (arg))
5581	arg = Fcar (arg);
5582      CHECK_NUMBER (arg);
5583      window_scroll (window, XINT (arg), 0, 1);
5584    }
5585
5586  set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
5587  unbind_to (count, Qnil);
5588
5589  return Qnil;
5590}
5591
5592DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 2, "P\np",
5593       doc: /* Scroll selected window display ARG columns left.
5594Default for ARG is window width minus 2.
5595Value is the total amount of leftward horizontal scrolling in
5596effect after the change.
5597If SET_MINIMUM is non-nil, the new scroll amount becomes the
5598lower bound for automatic scrolling, i.e. automatic scrolling
5599will not scroll a window to a column less than the value returned
5600by this function.  This happens in an interactive call.  */)
5601     (arg, set_minimum)
5602     register Lisp_Object arg, set_minimum;
5603{
5604  Lisp_Object result;
5605  int hscroll;
5606  struct window *w = XWINDOW (selected_window);
5607
5608  if (NILP (arg))
5609    XSETFASTINT (arg, window_box_text_cols (w) - 2);
5610  else
5611    arg = Fprefix_numeric_value (arg);
5612
5613  hscroll = XINT (w->hscroll) + XINT (arg);
5614  result = Fset_window_hscroll (selected_window, make_number (hscroll));
5615
5616  if (!NILP (set_minimum))
5617    w->min_hscroll = w->hscroll;
5618
5619  return result;
5620}
5621
5622DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 2, "P\np",
5623       doc: /* Scroll selected window display ARG columns right.
5624Default for ARG is window width minus 2.
5625Value is the total amount of leftward horizontal scrolling in
5626effect after the change.
5627If SET_MINIMUM is non-nil, the new scroll amount becomes the
5628lower bound for automatic scrolling, i.e. automatic scrolling
5629will not scroll a window to a column less than the value returned
5630by this function.  This happens in an interactive call.  */)
5631     (arg, set_minimum)
5632     register Lisp_Object arg, set_minimum;
5633{
5634  Lisp_Object result;
5635  int hscroll;
5636  struct window *w = XWINDOW (selected_window);
5637
5638  if (NILP (arg))
5639    XSETFASTINT (arg, window_box_text_cols (w) - 2);
5640  else
5641    arg = Fprefix_numeric_value (arg);
5642
5643  hscroll = XINT (w->hscroll) - XINT (arg);
5644  result = Fset_window_hscroll (selected_window, make_number (hscroll));
5645
5646  if (!NILP (set_minimum))
5647    w->min_hscroll = w->hscroll;
5648
5649  return result;
5650}
5651
5652DEFUN ("minibuffer-selected-window", Fminibuffer_selected_window, Sminibuffer_selected_window, 0, 0, 0,
5653       doc: /* Return the window which was selected when entering the minibuffer.
5654Returns nil, if current window is not a minibuffer window.  */)
5655     ()
5656{
5657  if (minibuf_level > 0
5658      && MINI_WINDOW_P (XWINDOW (selected_window))
5659      && WINDOW_LIVE_P (minibuf_selected_window))
5660    return minibuf_selected_window;
5661
5662  return Qnil;
5663}
5664
5665/* Value is the number of lines actually displayed in window W,
5666   as opposed to its height.  */
5667
5668static int
5669displayed_window_lines (w)
5670     struct window *w;
5671{
5672  struct it it;
5673  struct text_pos start;
5674  int height = window_box_height (w);
5675  struct buffer *old_buffer;
5676  int bottom_y;
5677
5678  if (XBUFFER (w->buffer) != current_buffer)
5679    {
5680      old_buffer = current_buffer;
5681      set_buffer_internal (XBUFFER (w->buffer));
5682    }
5683  else
5684    old_buffer = NULL;
5685
5686  /* In case W->start is out of the accessible range, do something
5687     reasonable.  This happens in Info mode when Info-scroll-down
5688     calls (recenter -1) while W->start is 1.  */
5689  if (XMARKER (w->start)->charpos < BEGV)
5690    SET_TEXT_POS (start, BEGV, BEGV_BYTE);
5691  else if (XMARKER (w->start)->charpos > ZV)
5692    SET_TEXT_POS (start, ZV, ZV_BYTE);
5693  else
5694    SET_TEXT_POS_FROM_MARKER (start, w->start);
5695
5696  start_display (&it, w, start);
5697  move_it_vertically (&it, height);
5698  bottom_y = line_bottom_y (&it);
5699
5700  /* rms: On a non-window display,
5701     the value of it.vpos at the bottom of the screen
5702     seems to be 1 larger than window_box_height (w).
5703     This kludge fixes a bug whereby (move-to-window-line -1)
5704     when ZV is on the last screen line
5705     moves to the previous screen line instead of the last one.  */
5706  if (! FRAME_WINDOW_P (XFRAME (w->frame)))
5707    height++;
5708
5709  /* Add in empty lines at the bottom of the window.  */
5710  if (bottom_y < height)
5711    {
5712      int uy = FRAME_LINE_HEIGHT (it.f);
5713      it.vpos += (height - bottom_y + uy - 1) / uy;
5714    }
5715
5716  if (old_buffer)
5717    set_buffer_internal (old_buffer);
5718
5719  return it.vpos;
5720}
5721
5722
5723DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
5724       doc: /* Center point in window and redisplay frame.
5725With prefix argument ARG, recenter putting point on screen line ARG
5726relative to the current window.  If ARG is negative, it counts up from the
5727bottom of the window.  (ARG should be less than the height of the window.)
5728
5729If ARG is omitted or nil, erase the entire frame and then redraw with point
5730in the center of the current window.  If `auto-resize-tool-bars' is set to
5731`grow-only', this resets the tool-bar's height to the minimum height needed.
5732
5733Just C-u as prefix means put point in the center of the window
5734and redisplay normally--don't erase and redraw the frame.  */)
5735     (arg)
5736     register Lisp_Object arg;
5737{
5738  struct window *w = XWINDOW (selected_window);
5739  struct buffer *buf = XBUFFER (w->buffer);
5740  struct buffer *obuf = current_buffer;
5741  int center_p = 0;
5742  int charpos, bytepos;
5743  int iarg;
5744  int this_scroll_margin;
5745
5746  /* If redisplay is suppressed due to an error, try again.  */
5747  obuf->display_error_modiff = 0;
5748
5749  if (NILP (arg))
5750    {
5751      int i;
5752
5753      /* Invalidate pixel data calculated for all compositions.  */
5754      for (i = 0; i < n_compositions; i++)
5755	composition_table[i]->font = NULL;
5756
5757      WINDOW_XFRAME (w)->minimize_tool_bar_window_p = 1;
5758
5759      Fredraw_frame (WINDOW_FRAME (w));
5760      SET_FRAME_GARBAGED (WINDOW_XFRAME (w));
5761      center_p = 1;
5762    }
5763  else if (CONSP (arg)) /* Just C-u. */
5764    center_p = 1;
5765  else
5766    {
5767      arg = Fprefix_numeric_value (arg);
5768      CHECK_NUMBER (arg);
5769      iarg = XINT (arg);
5770    }
5771
5772  set_buffer_internal (buf);
5773
5774  /* Do this after making BUF current
5775     in case scroll_margin is buffer-local.  */
5776  this_scroll_margin = max (0, scroll_margin);
5777  this_scroll_margin = min (this_scroll_margin,
5778			    XFASTINT (w->total_lines) / 4);
5779
5780  /* Handle centering on a graphical frame specially.  Such frames can
5781     have variable-height lines and centering point on the basis of
5782     line counts would lead to strange effects.  */
5783  if (FRAME_WINDOW_P (XFRAME (w->frame)))
5784    {
5785      if (center_p)
5786	{
5787	  struct it it;
5788	  struct text_pos pt;
5789
5790	  SET_TEXT_POS (pt, PT, PT_BYTE);
5791	  start_display (&it, w, pt);
5792	  move_it_vertically_backward (&it, window_box_height (w) / 2);
5793	  charpos = IT_CHARPOS (it);
5794	  bytepos = IT_BYTEPOS (it);
5795	}
5796      else if (iarg < 0)
5797	{
5798	  struct it it;
5799	  struct text_pos pt;
5800	  int nlines = -iarg;
5801	  int extra_line_spacing;
5802	  int h = window_box_height (w);
5803
5804	  iarg = - max (-iarg, this_scroll_margin);
5805
5806	  SET_TEXT_POS (pt, PT, PT_BYTE);
5807	  start_display (&it, w, pt);
5808
5809	  /* Be sure we have the exact height of the full line containing PT.  */
5810	  move_it_by_lines (&it, 0, 1);
5811
5812	  /* The amount of pixels we have to move back is the window
5813	     height minus what's displayed in the line containing PT,
5814	     and the lines below.  */
5815	  it.current_y = 0;
5816	  it.vpos = 0;
5817	  move_it_by_lines (&it, nlines, 1);
5818
5819	  if (it.vpos == nlines)
5820	    h -= it.current_y;
5821	  else
5822	    {
5823	      /* Last line has no newline */
5824	      h -= line_bottom_y (&it);
5825	      it.vpos++;
5826	    }
5827
5828	  /* Don't reserve space for extra line spacing of last line.  */
5829	  extra_line_spacing = it.max_extra_line_spacing;
5830
5831	  /* If we can't move down NLINES lines because we hit
5832	     the end of the buffer, count in some empty lines.  */
5833	  if (it.vpos < nlines)
5834	    {
5835	      nlines -= it.vpos;
5836	      extra_line_spacing = it.extra_line_spacing;
5837	      h -= nlines * (FRAME_LINE_HEIGHT (it.f) + extra_line_spacing);
5838	    }
5839	  if (h <= 0)
5840	    return Qnil;
5841
5842	  /* Now find the new top line (starting position) of the window.  */
5843	  start_display (&it, w, pt);
5844	  it.current_y = 0;
5845	  move_it_vertically_backward (&it, h);
5846
5847	  /* If extra line spacing is present, we may move too far
5848	     back.  This causes the last line to be only partially
5849	     visible (which triggers redisplay to recenter that line
5850	     in the middle), so move forward.
5851	     But ignore extra line spacing on last line, as it is not
5852	     considered to be part of the visible height of the line.
5853	  */
5854	  h += extra_line_spacing;
5855	  while (-it.current_y > h)
5856	    move_it_by_lines (&it, 1, 1);
5857
5858	  charpos = IT_CHARPOS (it);
5859	  bytepos = IT_BYTEPOS (it);
5860	}
5861      else
5862	{
5863	  struct position pos;
5864
5865	  iarg = max (iarg, this_scroll_margin);
5866
5867	  pos = *vmotion (PT, -iarg, w);
5868	  charpos = pos.bufpos;
5869	  bytepos = pos.bytepos;
5870	}
5871    }
5872  else
5873    {
5874      struct position pos;
5875      int ht = window_internal_height (w);
5876
5877      if (center_p)
5878	iarg = ht / 2;
5879      else if (iarg < 0)
5880	iarg += ht;
5881
5882      /* Don't let it get into the margin at either top or bottom.  */
5883      iarg = max (iarg, this_scroll_margin);
5884      iarg = min (iarg, ht - this_scroll_margin - 1);
5885
5886      pos = *vmotion (PT, - iarg, w);
5887      charpos = pos.bufpos;
5888      bytepos = pos.bytepos;
5889    }
5890
5891  /* Set the new window start.  */
5892  set_marker_both (w->start, w->buffer, charpos, bytepos);
5893  w->window_end_valid = Qnil;
5894
5895  w->optional_new_start = Qt;
5896
5897  if (bytepos == BEGV_BYTE || FETCH_BYTE (bytepos - 1) == '\n')
5898    w->start_at_line_beg = Qt;
5899  else
5900    w->start_at_line_beg = Qnil;
5901
5902  set_buffer_internal (obuf);
5903  return Qnil;
5904}
5905
5906
5907DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height,
5908       0, 1, 0,
5909       doc: /* Return the height in lines of the text display area of WINDOW.
5910WINDOW defaults to the selected window.
5911This doesn't include the mode-line (or header-line if any) or any
5912partial-height lines in the text display area.  */)
5913     (window)
5914     Lisp_Object window;
5915{
5916  struct window *w = decode_window (window);
5917  int pixel_height = window_box_height (w);
5918  int line_height = pixel_height / FRAME_LINE_HEIGHT (XFRAME (w->frame));
5919  return make_number (line_height);
5920}
5921
5922
5923
5924DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
5925       1, 1, "P",
5926       doc: /* Position point relative to window.
5927With no argument, position point at center of window.
5928An argument specifies vertical position within the window;
5929zero means top of window, negative means relative to bottom of window.  */)
5930     (arg)
5931     Lisp_Object arg;
5932{
5933  struct window *w = XWINDOW (selected_window);
5934  int lines, start;
5935  Lisp_Object window;
5936#if 0
5937  int this_scroll_margin;
5938#endif
5939
5940  window = selected_window;
5941  start = marker_position (w->start);
5942  if (start < BEGV || start > ZV)
5943    {
5944      int height = window_internal_height (w);
5945      Fvertical_motion (make_number (- (height / 2)), window);
5946      set_marker_both (w->start, w->buffer, PT, PT_BYTE);
5947      w->start_at_line_beg = Fbolp ();
5948      w->force_start = Qt;
5949    }
5950  else
5951    Fgoto_char (w->start);
5952
5953  lines = displayed_window_lines (w);
5954
5955#if 0
5956  this_scroll_margin = max (0, scroll_margin);
5957  this_scroll_margin = min (this_scroll_margin, lines / 4);
5958#endif
5959
5960  if (NILP (arg))
5961    XSETFASTINT (arg, lines / 2);
5962  else
5963    {
5964      int iarg = XINT (Fprefix_numeric_value (arg));
5965
5966      if (iarg < 0)
5967	iarg = iarg + lines;
5968
5969#if 0  /* This code would prevent move-to-window-line from moving point
5970	  to a place inside the scroll margins (which would cause the
5971	  next redisplay to scroll).  I wrote this code, but then concluded
5972	  it is probably better not to install it.  However, it is here
5973	  inside #if 0 so as not to lose it.  -- rms.  */
5974
5975      /* Don't let it get into the margin at either top or bottom.  */
5976      iarg = max (iarg, this_scroll_margin);
5977      iarg = min (iarg, lines - this_scroll_margin - 1);
5978#endif
5979
5980      arg = make_number (iarg);
5981    }
5982
5983  /* Skip past a partially visible first line.  */
5984  if (w->vscroll)
5985    XSETINT (arg, XINT (arg) + 1);
5986
5987  return Fvertical_motion (arg, window);
5988}
5989
5990
5991
5992/***********************************************************************
5993			 Window Configuration
5994 ***********************************************************************/
5995
5996struct save_window_data
5997  {
5998    EMACS_INT size_from_Lisp_Vector_struct;
5999    struct Lisp_Vector *next_from_Lisp_Vector_struct;
6000    Lisp_Object frame_cols, frame_lines, frame_menu_bar_lines;
6001    Lisp_Object frame_tool_bar_lines;
6002    Lisp_Object selected_frame;
6003    Lisp_Object current_window;
6004    Lisp_Object current_buffer;
6005    Lisp_Object minibuf_scroll_window;
6006    Lisp_Object minibuf_selected_window;
6007    Lisp_Object root_window;
6008    Lisp_Object focus_frame;
6009    /* Record the values of window-min-width and window-min-height
6010       so that window sizes remain consistent with them.  */
6011    Lisp_Object min_width, min_height;
6012    /* A vector, each of whose elements is a struct saved_window
6013       for one window.  */
6014    Lisp_Object saved_windows;
6015  };
6016
6017/* This is saved as a Lisp_Vector  */
6018struct saved_window
6019{
6020  /* these first two must agree with struct Lisp_Vector in lisp.h */
6021  EMACS_INT size_from_Lisp_Vector_struct;
6022  struct Lisp_Vector *next_from_Lisp_Vector_struct;
6023
6024  Lisp_Object window;
6025  Lisp_Object buffer, start, pointm, mark;
6026  Lisp_Object left_col, top_line, total_cols, total_lines;
6027  Lisp_Object hscroll, min_hscroll;
6028  Lisp_Object parent, prev;
6029  Lisp_Object start_at_line_beg;
6030  Lisp_Object display_table;
6031  Lisp_Object orig_top_line, orig_total_lines;
6032  Lisp_Object left_margin_cols, right_margin_cols;
6033  Lisp_Object left_fringe_width, right_fringe_width, fringes_outside_margins;
6034  Lisp_Object scroll_bar_width, vertical_scroll_bar_type;
6035  Lisp_Object dedicated;
6036};
6037
6038#define SAVED_WINDOW_N(swv,n) \
6039  ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
6040
6041DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
6042       doc: /* Return t if OBJECT is a window-configuration object.  */)
6043     (object)
6044     Lisp_Object object;
6045{
6046  return WINDOW_CONFIGURATIONP (object) ? Qt : Qnil;
6047}
6048
6049DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
6050       doc: /* Return the frame that CONFIG, a window-configuration object, is about.  */)
6051     (config)
6052     Lisp_Object config;
6053{
6054  register struct save_window_data *data;
6055  struct Lisp_Vector *saved_windows;
6056
6057  CHECK_WINDOW_CONFIGURATION (config);
6058
6059  data = (struct save_window_data *) XVECTOR (config);
6060  saved_windows = XVECTOR (data->saved_windows);
6061  return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
6062}
6063
6064DEFUN ("set-window-configuration", Fset_window_configuration,
6065       Sset_window_configuration, 1, 1, 0,
6066       doc: /* Set the configuration of windows and buffers as specified by CONFIGURATION.
6067CONFIGURATION must be a value previously returned
6068by `current-window-configuration' (which see).
6069If CONFIGURATION was made from a frame that is now deleted,
6070only frame-independent values can be restored.  In this case,
6071the return value is nil.  Otherwise the value is t.  */)
6072     (configuration)
6073     Lisp_Object configuration;
6074{
6075  register struct save_window_data *data;
6076  struct Lisp_Vector *saved_windows;
6077  Lisp_Object new_current_buffer;
6078  Lisp_Object frame;
6079  FRAME_PTR f;
6080  int old_point = -1;
6081
6082  CHECK_WINDOW_CONFIGURATION (configuration);
6083
6084  data = (struct save_window_data *) XVECTOR (configuration);
6085  saved_windows = XVECTOR (data->saved_windows);
6086
6087  new_current_buffer = data->current_buffer;
6088  if (NILP (XBUFFER (new_current_buffer)->name))
6089    new_current_buffer = Qnil;
6090  else
6091    {
6092      if (XBUFFER (new_current_buffer) == current_buffer)
6093	/* The code further down "preserves point" by saving here PT in
6094	   old_point and then setting it later back into PT.  When the
6095	   current-selected-window and the final-selected-window both show
6096	   the current buffer, this suffers from the problem that the
6097	   current PT is the window-point of the current-selected-window,
6098	   while the final PT is the point of the final-selected-window, so
6099	   this copy from one PT to the other would end up moving the
6100	   window-point of the final-selected-window to the window-point of
6101	   the current-selected-window.  So we have to be careful which
6102	   point of the current-buffer we copy into old_point.  */
6103	if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer)
6104	    && WINDOWP (selected_window)
6105	    && EQ (XWINDOW (selected_window)->buffer, new_current_buffer)
6106	    && !EQ (selected_window, data->current_window))
6107	  old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos;
6108	else
6109	  old_point = PT;
6110      else
6111	/* BUF_PT (XBUFFER (new_current_buffer)) gives us the position of
6112	   point in new_current_buffer as of the last time this buffer was
6113	   used.  This can be non-deterministic since it can be changed by
6114	   things like jit-lock by mere temporary selection of some random
6115	   window that happens to show this buffer.
6116	   So if possible we want this arbitrary choice of "which point" to
6117	   be the one from the to-be-selected-window so as to prevent this
6118	   window's cursor from being copied from another window.  */
6119	if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer)
6120	    /* If current_window = selected_window, its point is in BUF_PT.  */
6121	    && !EQ (selected_window, data->current_window))
6122	  old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos;
6123	else
6124	  old_point = BUF_PT (XBUFFER (new_current_buffer));
6125    }
6126
6127  frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
6128  f = XFRAME (frame);
6129
6130  /* If f is a dead frame, don't bother rebuilding its window tree.
6131     However, there is other stuff we should still try to do below.  */
6132  if (FRAME_LIVE_P (f))
6133    {
6134      register struct window *w;
6135      register struct saved_window *p;
6136      struct window *root_window;
6137      struct window **leaf_windows;
6138      int n_leaf_windows;
6139      int k, i, n;
6140
6141      /* If the frame has been resized since this window configuration was
6142	 made, we change the frame to the size specified in the
6143	 configuration, restore the configuration, and then resize it
6144	 back.  We keep track of the prevailing height in these variables.  */
6145      int previous_frame_lines = FRAME_LINES (f);
6146      int previous_frame_cols =  FRAME_COLS  (f);
6147      int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
6148      int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
6149
6150      /* The mouse highlighting code could get screwed up
6151	 if it runs during this.  */
6152      BLOCK_INPUT;
6153
6154      if (XFASTINT (data->frame_lines) != previous_frame_lines
6155	  || XFASTINT (data->frame_cols) != previous_frame_cols)
6156	change_frame_size (f, XFASTINT (data->frame_lines),
6157			   XFASTINT (data->frame_cols), 0, 0, 0);
6158#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
6159      if (XFASTINT (data->frame_menu_bar_lines)
6160	  != previous_frame_menu_bar_lines)
6161	x_set_menu_bar_lines (f, data->frame_menu_bar_lines, make_number (0));
6162#ifdef HAVE_WINDOW_SYSTEM
6163      if (XFASTINT (data->frame_tool_bar_lines)
6164	  != previous_frame_tool_bar_lines)
6165	x_set_tool_bar_lines (f, data->frame_tool_bar_lines, make_number (0));
6166#endif
6167#endif
6168
6169      /* "Swap out" point from the selected window's buffer
6170	 into the window itself.  (Normally the pointm of the selected
6171	 window holds garbage.)  We do this now, before
6172	 restoring the window contents, and prevent it from
6173	 being done later on when we select a new window.  */
6174      if (! NILP (XWINDOW (selected_window)->buffer))
6175	{
6176	  w = XWINDOW (selected_window);
6177	  set_marker_both (w->pointm,
6178			   w->buffer,
6179			   BUF_PT (XBUFFER (w->buffer)),
6180			   BUF_PT_BYTE (XBUFFER (w->buffer)));
6181	}
6182
6183      windows_or_buffers_changed++;
6184      FRAME_WINDOW_SIZES_CHANGED (f) = 1;
6185
6186      /* Problem: Freeing all matrices and later allocating them again
6187	 is a serious redisplay flickering problem.  What we would
6188	 really like to do is to free only those matrices not reused
6189	 below.   */
6190      root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
6191      leaf_windows
6192	= (struct window **) alloca (count_windows (root_window)
6193				     * sizeof (struct window *));
6194      n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
6195
6196      /* Temporarily avoid any problems with windows that are smaller
6197	 than they are supposed to be.  */
6198      window_min_height = 1;
6199      window_min_width = 1;
6200
6201      /* Kludge Alert!
6202	 Mark all windows now on frame as "deleted".
6203	 Restoring the new configuration "undeletes" any that are in it.
6204
6205	 Save their current buffers in their height fields, since we may
6206	 need it later, if a buffer saved in the configuration is now
6207	 dead.  */
6208      delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
6209
6210      for (k = 0; k < saved_windows->size; k++)
6211	{
6212	  p = SAVED_WINDOW_N (saved_windows, k);
6213	  w = XWINDOW (p->window);
6214	  w->next = Qnil;
6215
6216	  if (!NILP (p->parent))
6217	    w->parent = SAVED_WINDOW_N (saved_windows,
6218					XFASTINT (p->parent))->window;
6219	  else
6220	    w->parent = Qnil;
6221
6222	  if (!NILP (p->prev))
6223	    {
6224	      w->prev = SAVED_WINDOW_N (saved_windows,
6225					XFASTINT (p->prev))->window;
6226	      XWINDOW (w->prev)->next = p->window;
6227	    }
6228	  else
6229	    {
6230	      w->prev = Qnil;
6231	      if (!NILP (w->parent))
6232		{
6233		  if (EQ (p->total_cols, XWINDOW (w->parent)->total_cols))
6234		    {
6235		      XWINDOW (w->parent)->vchild = p->window;
6236		      XWINDOW (w->parent)->hchild = Qnil;
6237		    }
6238		  else
6239		    {
6240		      XWINDOW (w->parent)->hchild = p->window;
6241		      XWINDOW (w->parent)->vchild = Qnil;
6242		    }
6243		}
6244	    }
6245
6246	  /* If we squirreled away the buffer in the window's height,
6247	     restore it now.  */
6248	  if (BUFFERP (w->total_lines))
6249	    w->buffer = w->total_lines;
6250	  w->left_col = p->left_col;
6251	  w->top_line = p->top_line;
6252	  w->total_cols = p->total_cols;
6253	  w->total_lines = p->total_lines;
6254	  w->hscroll = p->hscroll;
6255	  w->min_hscroll = p->min_hscroll;
6256	  w->display_table = p->display_table;
6257	  w->orig_top_line = p->orig_top_line;
6258	  w->orig_total_lines = p->orig_total_lines;
6259	  w->left_margin_cols = p->left_margin_cols;
6260	  w->right_margin_cols = p->right_margin_cols;
6261	  w->left_fringe_width = p->left_fringe_width;
6262	  w->right_fringe_width = p->right_fringe_width;
6263	  w->fringes_outside_margins = p->fringes_outside_margins;
6264	  w->scroll_bar_width = p->scroll_bar_width;
6265	  w->vertical_scroll_bar_type = p->vertical_scroll_bar_type;
6266	  w->dedicated = p->dedicated;
6267	  XSETFASTINT (w->last_modified, 0);
6268	  XSETFASTINT (w->last_overlay_modified, 0);
6269
6270	  /* Reinstall the saved buffer and pointers into it.  */
6271	  if (NILP (p->buffer))
6272	    w->buffer = p->buffer;
6273	  else
6274	    {
6275	      if (!NILP (XBUFFER (p->buffer)->name))
6276		/* If saved buffer is alive, install it.  */
6277		{
6278		  w->buffer = p->buffer;
6279		  w->start_at_line_beg = p->start_at_line_beg;
6280		  set_marker_restricted (w->start, p->start, w->buffer);
6281		  set_marker_restricted (w->pointm, p->pointm, w->buffer);
6282		  Fset_marker (XBUFFER (w->buffer)->mark,
6283			       p->mark, w->buffer);
6284
6285		  /* As documented in Fcurrent_window_configuration, don't
6286		     restore the location of point in the buffer which was
6287		     current when the window configuration was recorded.  */
6288		  if (!EQ (p->buffer, new_current_buffer)
6289		      && XBUFFER (p->buffer) == current_buffer)
6290		    Fgoto_char (w->pointm);
6291		}
6292	      else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
6293		/* Else unless window has a live buffer, get one.  */
6294		{
6295		  w->buffer = Fcdr (Fcar (Vbuffer_alist));
6296		  /* This will set the markers to beginning of visible
6297		     range.  */
6298		  set_marker_restricted (w->start, make_number (0), w->buffer);
6299		  set_marker_restricted (w->pointm, make_number (0),w->buffer);
6300		  w->start_at_line_beg = Qt;
6301		}
6302	      else
6303		/* Keeping window's old buffer; make sure the markers
6304		   are real.  */
6305		{
6306		  /* Set window markers at start of visible range.  */
6307		  if (XMARKER (w->start)->buffer == 0)
6308		    set_marker_restricted (w->start, make_number (0),
6309					   w->buffer);
6310		  if (XMARKER (w->pointm)->buffer == 0)
6311		    set_marker_restricted_both (w->pointm, w->buffer,
6312						BUF_PT (XBUFFER (w->buffer)),
6313						BUF_PT_BYTE (XBUFFER (w->buffer)));
6314		  w->start_at_line_beg = Qt;
6315		}
6316	    }
6317	}
6318
6319      FRAME_ROOT_WINDOW (f) = data->root_window;
6320      /* Prevent "swapping out point" in the old selected window
6321	 using the buffer that has been restored into it.
6322	 We already swapped out point that from that window's old buffer.  */
6323      selected_window = Qnil;
6324
6325      /* Arrange *not* to restore point in the buffer that was
6326	 current when the window configuration was saved.  */
6327      if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer))
6328	set_marker_restricted (XWINDOW (data->current_window)->pointm,
6329			       make_number (old_point),
6330			       XWINDOW (data->current_window)->buffer);
6331
6332      Fselect_window (data->current_window, Qnil);
6333      XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
6334	= selected_window;
6335
6336      if (NILP (data->focus_frame)
6337	  || (FRAMEP (data->focus_frame)
6338	      && FRAME_LIVE_P (XFRAME (data->focus_frame))))
6339	Fredirect_frame_focus (frame, data->focus_frame);
6340
6341#if 0 /* I don't understand why this is needed, and it causes problems
6342         when the frame's old selected window has been deleted.  */
6343      if (f != selected_frame && FRAME_WINDOW_P (f))
6344	do_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)),
6345			 0, 0);
6346#endif
6347
6348      /* Set the screen height to the value it had before this function.  */
6349      if (previous_frame_lines != FRAME_LINES (f)
6350	  || previous_frame_cols != FRAME_COLS (f))
6351	change_frame_size (f, previous_frame_lines, previous_frame_cols,
6352			   0, 0, 0);
6353#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
6354      if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
6355	x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
6356			      make_number (0));
6357#ifdef HAVE_WINDOW_SYSTEM
6358      if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
6359	x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
6360			      make_number (0));
6361#endif
6362#endif
6363
6364      /* Now, free glyph matrices in windows that were not reused.  */
6365      for (i = n = 0; i < n_leaf_windows; ++i)
6366	{
6367	  if (NILP (leaf_windows[i]->buffer))
6368	    {
6369	      /* Assert it's not reused as a combination.  */
6370	      xassert (NILP (leaf_windows[i]->hchild)
6371		       && NILP (leaf_windows[i]->vchild));
6372	      free_window_matrices (leaf_windows[i]);
6373	    }
6374	  else if (EQ (leaf_windows[i]->buffer, new_current_buffer))
6375	    ++n;
6376	}
6377
6378      adjust_glyphs (f);
6379
6380      UNBLOCK_INPUT;
6381
6382      /* Fselect_window will have made f the selected frame, so we
6383	 reselect the proper frame here.  Fhandle_switch_frame will change the
6384	 selected window too, but that doesn't make the call to
6385	 Fselect_window above totally superfluous; it still sets f's
6386	 selected window.  */
6387      if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
6388	do_switch_frame (data->selected_frame, 0, 0);
6389
6390      if (! NILP (Vwindow_configuration_change_hook)
6391	  && ! NILP (Vrun_hooks))
6392	call1 (Vrun_hooks, Qwindow_configuration_change_hook);
6393    }
6394
6395  if (!NILP (new_current_buffer))
6396    Fset_buffer (new_current_buffer);
6397
6398  /* Restore the minimum heights recorded in the configuration.  */
6399  window_min_height = XINT (data->min_height);
6400  window_min_width = XINT (data->min_width);
6401
6402  Vminibuf_scroll_window = data->minibuf_scroll_window;
6403  minibuf_selected_window = data->minibuf_selected_window;
6404
6405  return (FRAME_LIVE_P (f) ? Qt : Qnil);
6406}
6407
6408/* Mark all windows now on frame as deleted
6409   by setting their buffers to nil.  */
6410
6411void
6412delete_all_subwindows (w)
6413     register struct window *w;
6414{
6415  if (!NILP (w->next))
6416    delete_all_subwindows (XWINDOW (w->next));
6417  if (!NILP (w->vchild))
6418    delete_all_subwindows (XWINDOW (w->vchild));
6419  if (!NILP (w->hchild))
6420    delete_all_subwindows (XWINDOW (w->hchild));
6421
6422  w->total_lines = w->buffer;       /* See Fset_window_configuration for excuse.  */
6423
6424  if (!NILP (w->buffer))
6425    unshow_buffer (w);
6426
6427  /* We set all three of these fields to nil, to make sure that we can
6428     distinguish this dead window from any live window.  Live leaf
6429     windows will have buffer set, and combination windows will have
6430     vchild or hchild set.  */
6431  w->buffer = Qnil;
6432  w->vchild = Qnil;
6433  w->hchild = Qnil;
6434
6435  Vwindow_list = Qnil;
6436}
6437
6438static int
6439count_windows (window)
6440     register struct window *window;
6441{
6442  register int count = 1;
6443  if (!NILP (window->next))
6444    count += count_windows (XWINDOW (window->next));
6445  if (!NILP (window->vchild))
6446    count += count_windows (XWINDOW (window->vchild));
6447  if (!NILP (window->hchild))
6448    count += count_windows (XWINDOW (window->hchild));
6449  return count;
6450}
6451
6452
6453/* Fill vector FLAT with leaf windows under W, starting at index I.
6454   Value is last index + 1.  */
6455
6456static int
6457get_leaf_windows (w, flat, i)
6458     struct window *w;
6459     struct window **flat;
6460     int i;
6461{
6462  while (w)
6463    {
6464      if (!NILP (w->hchild))
6465	i = get_leaf_windows (XWINDOW (w->hchild), flat, i);
6466      else if (!NILP (w->vchild))
6467	i = get_leaf_windows (XWINDOW (w->vchild), flat, i);
6468      else
6469	flat[i++] = w;
6470
6471      w = NILP (w->next) ? 0 : XWINDOW (w->next);
6472    }
6473
6474  return i;
6475}
6476
6477
6478/* Return a pointer to the glyph W's physical cursor is on.  Value is
6479   null if W's current matrix is invalid, so that no meaningfull glyph
6480   can be returned.  */
6481
6482struct glyph *
6483get_phys_cursor_glyph (w)
6484     struct window *w;
6485{
6486  struct glyph_row *row;
6487  struct glyph *glyph;
6488
6489  if (w->phys_cursor.vpos >= 0
6490      && w->phys_cursor.vpos < w->current_matrix->nrows
6491      && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
6492	  row->enabled_p)
6493      && row->used[TEXT_AREA] > w->phys_cursor.hpos)
6494    glyph = row->glyphs[TEXT_AREA] + w->phys_cursor.hpos;
6495  else
6496    glyph = NULL;
6497
6498  return glyph;
6499}
6500
6501
6502static int
6503save_window_save (window, vector, i)
6504     Lisp_Object window;
6505     struct Lisp_Vector *vector;
6506     int i;
6507{
6508  register struct saved_window *p;
6509  register struct window *w;
6510  register Lisp_Object tem;
6511
6512  for (;!NILP (window); window = w->next)
6513    {
6514      p = SAVED_WINDOW_N (vector, i);
6515      w = XWINDOW (window);
6516
6517      XSETFASTINT (w->temslot, i); i++;
6518      p->window = window;
6519      p->buffer = w->buffer;
6520      p->left_col = w->left_col;
6521      p->top_line = w->top_line;
6522      p->total_cols = w->total_cols;
6523      p->total_lines = w->total_lines;
6524      p->hscroll = w->hscroll;
6525      p->min_hscroll = w->min_hscroll;
6526      p->display_table = w->display_table;
6527      p->orig_top_line = w->orig_top_line;
6528      p->orig_total_lines = w->orig_total_lines;
6529      p->left_margin_cols = w->left_margin_cols;
6530      p->right_margin_cols = w->right_margin_cols;
6531      p->left_fringe_width = w->left_fringe_width;
6532      p->right_fringe_width = w->right_fringe_width;
6533      p->fringes_outside_margins = w->fringes_outside_margins;
6534      p->scroll_bar_width = w->scroll_bar_width;
6535      p->vertical_scroll_bar_type = w->vertical_scroll_bar_type;
6536      p->dedicated = w->dedicated;
6537      if (!NILP (w->buffer))
6538	{
6539	  /* Save w's value of point in the window configuration.
6540	     If w is the selected window, then get the value of point
6541	     from the buffer; pointm is garbage in the selected window.  */
6542	  if (EQ (window, selected_window))
6543	    {
6544	      p->pointm = Fmake_marker ();
6545	      set_marker_both (p->pointm, w->buffer,
6546			       BUF_PT (XBUFFER (w->buffer)),
6547			       BUF_PT_BYTE (XBUFFER (w->buffer)));
6548	    }
6549	  else
6550	    p->pointm = Fcopy_marker (w->pointm, Qnil);
6551
6552	  p->start = Fcopy_marker (w->start, Qnil);
6553	  p->start_at_line_beg = w->start_at_line_beg;
6554
6555	  tem = XBUFFER (w->buffer)->mark;
6556	  p->mark = Fcopy_marker (tem, Qnil);
6557	}
6558      else
6559	{
6560	  p->pointm = Qnil;
6561	  p->start = Qnil;
6562	  p->mark = Qnil;
6563	  p->start_at_line_beg = Qnil;
6564	}
6565
6566      if (NILP (w->parent))
6567	p->parent = Qnil;
6568      else
6569	p->parent = XWINDOW (w->parent)->temslot;
6570
6571      if (NILP (w->prev))
6572	p->prev = Qnil;
6573      else
6574	p->prev = XWINDOW (w->prev)->temslot;
6575
6576      if (!NILP (w->vchild))
6577	i = save_window_save (w->vchild, vector, i);
6578      if (!NILP (w->hchild))
6579	i = save_window_save (w->hchild, vector, i);
6580    }
6581
6582  return i;
6583}
6584
6585DEFUN ("current-window-configuration", Fcurrent_window_configuration,
6586       Scurrent_window_configuration, 0, 1, 0,
6587       doc: /* Return an object representing the current window configuration of FRAME.
6588If FRAME is nil or omitted, use the selected frame.
6589This describes the number of windows, their sizes and current buffers,
6590and for each displayed buffer, where display starts, and the positions of
6591point and mark.  An exception is made for point in the current buffer:
6592its value is -not- saved.
6593This also records the currently selected frame, and FRAME's focus
6594redirection (see `redirect-frame-focus').  */)
6595     (frame)
6596     Lisp_Object frame;
6597{
6598  register Lisp_Object tem;
6599  register int n_windows;
6600  register struct save_window_data *data;
6601  register struct Lisp_Vector *vec;
6602  register int i;
6603  FRAME_PTR f;
6604
6605  if (NILP (frame))
6606    frame = selected_frame;
6607  CHECK_LIVE_FRAME (frame);
6608  f = XFRAME (frame);
6609
6610  n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
6611  vec = allocate_other_vector (VECSIZE (struct save_window_data));
6612  data = (struct save_window_data *)vec;
6613
6614  XSETFASTINT (data->frame_cols, FRAME_COLS (f));
6615  XSETFASTINT (data->frame_lines, FRAME_LINES (f));
6616  XSETFASTINT (data->frame_menu_bar_lines, FRAME_MENU_BAR_LINES (f));
6617  XSETFASTINT (data->frame_tool_bar_lines, FRAME_TOOL_BAR_LINES (f));
6618  data->selected_frame = selected_frame;
6619  data->current_window = FRAME_SELECTED_WINDOW (f);
6620  XSETBUFFER (data->current_buffer, current_buffer);
6621  data->minibuf_scroll_window = minibuf_level > 0 ? Vminibuf_scroll_window : Qnil;
6622  data->minibuf_selected_window = minibuf_level > 0 ? minibuf_selected_window : Qnil;
6623  data->root_window = FRAME_ROOT_WINDOW (f);
6624  data->focus_frame = FRAME_FOCUS_FRAME (f);
6625  XSETINT (data->min_height, window_min_height);
6626  XSETINT (data->min_width, window_min_width);
6627  tem = Fmake_vector (make_number (n_windows), Qnil);
6628  data->saved_windows = tem;
6629  for (i = 0; i < n_windows; i++)
6630    XVECTOR (tem)->contents[i]
6631      = Fmake_vector (make_number (VECSIZE (struct saved_window)), Qnil);
6632  save_window_save (FRAME_ROOT_WINDOW (f), XVECTOR (tem), 0);
6633  XSETWINDOW_CONFIGURATION (tem, data);
6634  return (tem);
6635}
6636
6637DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
6638       0, UNEVALLED, 0,
6639       doc: /* Execute BODY, preserving window sizes and contents.
6640Return the value of the last form in BODY.
6641Restore which buffer appears in which window, where display starts,
6642and the value of point and mark for each window.
6643Also restore the choice of selected window.
6644Also restore which buffer is current.
6645Does not restore the value of point in current buffer.
6646usage: (save-window-excursion BODY ...)  */)
6647     (args)
6648     Lisp_Object args;
6649{
6650  register Lisp_Object val;
6651  register int count = SPECPDL_INDEX ();
6652
6653  record_unwind_protect (Fset_window_configuration,
6654			 Fcurrent_window_configuration (Qnil));
6655  val = Fprogn (args);
6656  return unbind_to (count, val);
6657}
6658
6659
6660
6661/***********************************************************************
6662			    Window Split Tree
6663 ***********************************************************************/
6664
6665static Lisp_Object
6666window_tree (w)
6667     struct window *w;
6668{
6669  Lisp_Object tail = Qnil;
6670  Lisp_Object result = Qnil;
6671
6672  while (w)
6673    {
6674      Lisp_Object wn;
6675
6676      XSETWINDOW (wn, w);
6677      if (!NILP (w->hchild))
6678	wn = Fcons (Qnil, Fcons (Fwindow_edges (wn),
6679				 window_tree (XWINDOW (w->hchild))));
6680      else if (!NILP (w->vchild))
6681	wn = Fcons (Qt, Fcons (Fwindow_edges (wn),
6682			       window_tree (XWINDOW (w->vchild))));
6683
6684      if (NILP (result))
6685	{
6686	  result = tail = Fcons (wn, Qnil);
6687	}
6688      else
6689	{
6690	  XSETCDR (tail, Fcons (wn, Qnil));
6691	  tail = XCDR (tail);
6692	}
6693
6694      w = NILP (w->next) ? 0 : XWINDOW (w->next);
6695    }
6696
6697  return result;
6698}
6699
6700
6701
6702DEFUN ("window-tree", Fwindow_tree, Swindow_tree,
6703       0, 1, 0,
6704       doc: /* Return the window tree for frame FRAME.
6705
6706The return value is a list of the form (ROOT MINI), where ROOT
6707represents the window tree of the frame's root window, and MINI
6708is the frame's minibuffer window.
6709
6710If the root window is not split, ROOT is the root window itself.
6711Otherwise, ROOT is a list (DIR EDGES W1 W2 ...) where DIR is nil for a
6712horizontal split, and t for a vertical split, EDGES gives the combined
6713size and position of the subwindows in the split, and the rest of the
6714elements are the subwindows in the split.  Each of the subwindows may
6715again be a window or a list representing a window split, and so on.
6716EDGES is a list \(LEFT TOP RIGHT BOTTOM) as returned by `window-edges'.
6717
6718If FRAME is nil or omitted, return information on the currently
6719selected frame.  */)
6720     (frame)
6721     Lisp_Object frame;
6722{
6723  FRAME_PTR f;
6724
6725  if (NILP (frame))
6726    frame = selected_frame;
6727
6728  CHECK_FRAME (frame);
6729  f = XFRAME (frame);
6730
6731  if (!FRAME_LIVE_P (f))
6732    return Qnil;
6733
6734  return window_tree (XWINDOW (FRAME_ROOT_WINDOW (f)));
6735}
6736
6737
6738/***********************************************************************
6739			    Marginal Areas
6740 ***********************************************************************/
6741
6742DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
6743       2, 3, 0,
6744       doc: /* Set width of marginal areas of window WINDOW.
6745If WINDOW is nil, set margins of the currently selected window.
6746Second arg LEFT-WIDTH specifies the number of character cells to
6747reserve for the left marginal area.  Optional third arg RIGHT-WIDTH
6748does the same for the right marginal area.  A nil width parameter
6749means no margin.  */)
6750     (window, left_width, right_width)
6751     Lisp_Object window, left_width, right_width;
6752{
6753  struct window *w = decode_window (window);
6754
6755  /* Translate negative or zero widths to nil.
6756     Margins that are too wide have to be checked elsewhere.  */
6757
6758  if (!NILP (left_width))
6759    {
6760      CHECK_NUMBER (left_width);
6761      if (XINT (left_width) <= 0)
6762	left_width = Qnil;
6763    }
6764
6765  if (!NILP (right_width))
6766    {
6767      CHECK_NUMBER (right_width);
6768      if (XINT (right_width) <= 0)
6769	right_width = Qnil;
6770    }
6771
6772  if (!EQ (w->left_margin_cols, left_width)
6773      || !EQ (w->right_margin_cols, right_width))
6774    {
6775      w->left_margin_cols = left_width;
6776      w->right_margin_cols = right_width;
6777
6778      adjust_window_margins (w);
6779
6780      ++windows_or_buffers_changed;
6781      adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6782    }
6783
6784  return Qnil;
6785}
6786
6787
6788DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
6789       0, 1, 0,
6790       doc: /* Get width of marginal areas of window WINDOW.
6791If WINDOW is omitted or nil, use the currently selected window.
6792Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).
6793If a marginal area does not exist, its width will be returned
6794as nil.  */)
6795     (window)
6796     Lisp_Object window;
6797{
6798  struct window *w = decode_window (window);
6799  return Fcons (w->left_margin_cols, w->right_margin_cols);
6800}
6801
6802
6803
6804/***********************************************************************
6805			    Fringes
6806 ***********************************************************************/
6807
6808DEFUN ("set-window-fringes", Fset_window_fringes, Sset_window_fringes,
6809       2, 4, 0,
6810       doc: /* Set the fringe widths of window WINDOW.
6811If WINDOW is nil, set the fringe widths of the currently selected
6812window.
6813Second arg LEFT-WIDTH specifies the number of pixels to reserve for
6814the left fringe.  Optional third arg RIGHT-WIDTH specifies the right
6815fringe width.  If a fringe width arg is nil, that means to use the
6816frame's default fringe width.  Default fringe widths can be set with
6817the command `set-fringe-style'.
6818If optional fourth arg OUTSIDE-MARGINS is non-nil, draw the fringes
6819outside of the display margins.  By default, fringes are drawn between
6820display marginal areas and the text area.  */)
6821     (window, left_width, right_width, outside_margins)
6822     Lisp_Object window, left_width, right_width, outside_margins;
6823{
6824  struct window *w = decode_window (window);
6825
6826  if (!NILP (left_width))
6827    CHECK_NATNUM (left_width);
6828  if (!NILP (right_width))
6829    CHECK_NATNUM (right_width);
6830
6831  /* Do nothing on a tty.  */
6832  if (FRAME_WINDOW_P (WINDOW_XFRAME (w))
6833      && (!EQ (w->left_fringe_width, left_width)
6834	  || !EQ (w->right_fringe_width, right_width)
6835	  || !EQ (w->fringes_outside_margins, outside_margins)))
6836    {
6837      w->left_fringe_width = left_width;
6838      w->right_fringe_width = right_width;
6839      w->fringes_outside_margins = outside_margins;
6840
6841      adjust_window_margins (w);
6842
6843      clear_glyph_matrix (w->current_matrix);
6844      w->window_end_valid = Qnil;
6845
6846      ++windows_or_buffers_changed;
6847      adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6848    }
6849
6850  return Qnil;
6851}
6852
6853
6854DEFUN ("window-fringes", Fwindow_fringes, Swindow_fringes,
6855       0, 1, 0,
6856       doc: /* Get width of fringes of window WINDOW.
6857If WINDOW is omitted or nil, use the currently selected window.
6858Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS).  */)
6859     (window)
6860     Lisp_Object window;
6861{
6862  struct window *w = decode_window (window);
6863
6864  return Fcons (make_number (WINDOW_LEFT_FRINGE_WIDTH (w)),
6865		Fcons (make_number (WINDOW_RIGHT_FRINGE_WIDTH (w)),
6866		       Fcons ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
6867			       ? Qt : Qnil), Qnil)));
6868}
6869
6870
6871
6872/***********************************************************************
6873			    Scroll bars
6874 ***********************************************************************/
6875
6876DEFUN ("set-window-scroll-bars", Fset_window_scroll_bars, Sset_window_scroll_bars,
6877       2, 4, 0,
6878       doc: /* Set width and type of scroll bars of window WINDOW.
6879If window is nil, set scroll bars of the currently selected window.
6880Second parameter WIDTH specifies the pixel width for the scroll bar;
6881this is automatically adjusted to a multiple of the frame column width.
6882Third parameter VERTICAL-TYPE specifies the type of the vertical scroll
6883bar: left, right, or nil.
6884If WIDTH is nil, use the frame's scroll-bar width.
6885If VERTICAL-TYPE is t, use the frame's scroll-bar type.
6886Fourth parameter HORIZONTAL-TYPE is currently unused.  */)
6887     (window, width, vertical_type, horizontal_type)
6888     Lisp_Object window, width, vertical_type, horizontal_type;
6889{
6890  struct window *w = decode_window (window);
6891
6892  if (!NILP (width))
6893    {
6894      CHECK_NATNUM (width);
6895
6896      if (XINT (width) == 0)
6897	vertical_type = Qnil;
6898    }
6899
6900  if (!(EQ (vertical_type, Qnil)
6901	|| EQ (vertical_type, Qleft)
6902	|| EQ (vertical_type, Qright)
6903	|| EQ (vertical_type, Qt)))
6904    error ("Invalid type of vertical scroll bar");
6905
6906  if (!EQ (w->scroll_bar_width, width)
6907      || !EQ (w->vertical_scroll_bar_type, vertical_type))
6908    {
6909      w->scroll_bar_width = width;
6910      w->vertical_scroll_bar_type = vertical_type;
6911
6912      adjust_window_margins (w);
6913
6914      clear_glyph_matrix (w->current_matrix);
6915      w->window_end_valid = Qnil;
6916
6917      ++windows_or_buffers_changed;
6918      adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6919    }
6920
6921  return Qnil;
6922}
6923
6924
6925DEFUN ("window-scroll-bars", Fwindow_scroll_bars, Swindow_scroll_bars,
6926       0, 1, 0,
6927       doc: /* Get width and type of scroll bars of window WINDOW.
6928If WINDOW is omitted or nil, use the currently selected window.
6929Value is a list of the form (WIDTH COLS VERTICAL-TYPE HORIZONTAL-TYPE).
6930If WIDTH is nil or TYPE is t, the window is using the frame's corresponding
6931value.  */)
6932     (window)
6933     Lisp_Object window;
6934{
6935  struct window *w = decode_window (window);
6936  return Fcons (make_number ((WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
6937			      ? WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
6938			      : WINDOW_SCROLL_BAR_AREA_WIDTH (w))),
6939		Fcons (make_number (WINDOW_SCROLL_BAR_COLS (w)),
6940		       Fcons (w->vertical_scroll_bar_type,
6941			      Fcons (Qnil, Qnil))));
6942}
6943
6944
6945
6946/***********************************************************************
6947			   Smooth scrolling
6948 ***********************************************************************/
6949
6950DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 2, 0,
6951       doc: /* Return the amount by which WINDOW is scrolled vertically.
6952Use the selected window if WINDOW is nil or omitted.
6953Normally, value is a multiple of the canonical character height of WINDOW;
6954optional second arg PIXELS-P means value is measured in pixels.  */)
6955  (window, pixels_p)
6956     Lisp_Object window, pixels_p;
6957{
6958  Lisp_Object result;
6959  struct frame *f;
6960  struct window *w;
6961
6962  if (NILP (window))
6963    window = selected_window;
6964  else
6965    CHECK_WINDOW (window);
6966  w = XWINDOW (window);
6967  f = XFRAME (w->frame);
6968
6969  if (FRAME_WINDOW_P (f))
6970    result = (NILP (pixels_p)
6971	      ? FRAME_CANON_Y_FROM_PIXEL_Y (f, -w->vscroll)
6972	      : make_number (-w->vscroll));
6973  else
6974    result = make_number (0);
6975  return result;
6976}
6977
6978
6979DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
6980       2, 3, 0,
6981       doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL.
6982WINDOW nil means use the selected window.  Normally, VSCROLL is a
6983non-negative multiple of the canonical character height of WINDOW;
6984optional third arg PIXELS-P non-nil means that VSCROLL is in pixels.
6985If PIXELS-P is nil, VSCROLL may have to be rounded so that it
6986corresponds to an integral number of pixels.  The return value is the
6987result of this rounding.
6988If PIXELS-P is non-nil, the return value is VSCROLL.  */)
6989  (window, vscroll, pixels_p)
6990     Lisp_Object window, vscroll, pixels_p;
6991{
6992  struct window *w;
6993  struct frame *f;
6994
6995  if (NILP (window))
6996    window = selected_window;
6997  else
6998    CHECK_WINDOW (window);
6999  CHECK_NUMBER_OR_FLOAT (vscroll);
7000
7001  w = XWINDOW (window);
7002  f = XFRAME (w->frame);
7003
7004  if (FRAME_WINDOW_P (f))
7005    {
7006      int old_dy = w->vscroll;
7007
7008      w->vscroll = - (NILP (pixels_p)
7009		      ? FRAME_LINE_HEIGHT (f) * XFLOATINT (vscroll)
7010		      : XFLOATINT (vscroll));
7011      w->vscroll = min (w->vscroll, 0);
7012
7013      if (w->vscroll != old_dy)
7014	{
7015	  /* Adjust glyph matrix of the frame if the virtual display
7016	     area becomes larger than before.  */
7017	  if (w->vscroll < 0 && w->vscroll < old_dy)
7018	    adjust_glyphs (f);
7019
7020	  /* Prevent redisplay shortcuts.  */
7021	  XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
7022	}
7023    }
7024
7025  return Fwindow_vscroll (window, pixels_p);
7026}
7027
7028
7029/* Call FN for all leaf windows on frame F.  FN is called with the
7030   first argument being a pointer to the leaf window, and with
7031   additional argument USER_DATA.  Stops when FN returns 0.  */
7032
7033void
7034foreach_window (f, fn, user_data)
7035     struct frame *f;
7036     int (* fn) P_ ((struct window *, void *));
7037     void *user_data;
7038{
7039  /* Fdelete_frame may set FRAME_ROOT_WINDOW (f) to Qnil.  */
7040  if (WINDOWP (FRAME_ROOT_WINDOW (f)))
7041    foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data);
7042}
7043
7044
7045/* Helper function for foreach_window.  Call FN for all leaf windows
7046   reachable from W.  FN is called with the first argument being a
7047   pointer to the leaf window, and with additional argument USER_DATA.
7048   Stop when FN returns 0.  Value is 0 if stopped by FN.  */
7049
7050static int
7051foreach_window_1 (w, fn, user_data)
7052     struct window *w;
7053     int (* fn) P_ ((struct window *, void *));
7054     void *user_data;
7055{
7056  int cont;
7057
7058  for (cont = 1; w && cont;)
7059    {
7060      if (!NILP (w->hchild))
7061 	cont = foreach_window_1 (XWINDOW (w->hchild), fn, user_data);
7062      else if (!NILP (w->vchild))
7063 	cont = foreach_window_1 (XWINDOW (w->vchild), fn, user_data);
7064      else
7065	cont = fn (w, user_data);
7066
7067      w = NILP (w->next) ? 0 : XWINDOW (w->next);
7068    }
7069
7070  return cont;
7071}
7072
7073
7074/* Freeze or unfreeze the window start of W unless it is a
7075   mini-window or the selected window.  FREEZE_P non-null means freeze
7076   the window start.  */
7077
7078static int
7079freeze_window_start (w, freeze_p)
7080     struct window *w;
7081     void *freeze_p;
7082{
7083  if (w == XWINDOW (selected_window)
7084      || MINI_WINDOW_P (w)
7085      || (MINI_WINDOW_P (XWINDOW (selected_window))
7086	  && ! NILP (Vminibuf_scroll_window)
7087	  && w == XWINDOW (Vminibuf_scroll_window)))
7088    freeze_p = NULL;
7089
7090  w->frozen_window_start_p = freeze_p != NULL;
7091  return 1;
7092}
7093
7094
7095/* Freeze or unfreeze the window starts of all leaf windows on frame
7096   F, except the selected window and a mini-window.  FREEZE_P non-zero
7097   means freeze the window start.  */
7098
7099void
7100freeze_window_starts (f, freeze_p)
7101     struct frame *f;
7102     int freeze_p;
7103{
7104  foreach_window (f, freeze_window_start, (void *) (freeze_p ? f : 0));
7105}
7106
7107
7108/***********************************************************************
7109			    Initialization
7110 ***********************************************************************/
7111
7112/* Return 1 if window configurations C1 and C2
7113   describe the same state of affairs.  This is used by Fequal.   */
7114
7115int
7116compare_window_configurations (c1, c2, ignore_positions)
7117     Lisp_Object c1, c2;
7118     int ignore_positions;
7119{
7120  register struct save_window_data *d1, *d2;
7121  struct Lisp_Vector *sw1, *sw2;
7122  int i;
7123
7124  CHECK_WINDOW_CONFIGURATION (c1);
7125  CHECK_WINDOW_CONFIGURATION (c2);
7126
7127  d1 = (struct save_window_data *) XVECTOR (c1);
7128  d2 = (struct save_window_data *) XVECTOR (c2);
7129  sw1 = XVECTOR (d1->saved_windows);
7130  sw2 = XVECTOR (d2->saved_windows);
7131
7132  if (! EQ (d1->frame_cols, d2->frame_cols))
7133    return 0;
7134  if (! EQ (d1->frame_lines, d2->frame_lines))
7135    return 0;
7136  if (! EQ (d1->frame_menu_bar_lines, d2->frame_menu_bar_lines))
7137    return 0;
7138  if (! EQ (d1->selected_frame, d2->selected_frame))
7139    return 0;
7140  /* Don't compare the current_window field directly.
7141     Instead see w1_is_current and w2_is_current, below.  */
7142  if (! EQ (d1->current_buffer, d2->current_buffer))
7143    return 0;
7144  if (! ignore_positions)
7145    {
7146      if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
7147	return 0;
7148      if (! EQ (d1->minibuf_selected_window, d2->minibuf_selected_window))
7149	return 0;
7150    }
7151  /* Don't compare the root_window field.
7152     We don't require the two configurations
7153     to use the same window object,
7154     and the two root windows must be equivalent
7155     if everything else compares equal.  */
7156  if (! EQ (d1->focus_frame, d2->focus_frame))
7157    return 0;
7158  if (! EQ (d1->min_width, d2->min_width))
7159    return 0;
7160  if (! EQ (d1->min_height, d2->min_height))
7161    return 0;
7162
7163  /* Verify that the two confis have the same number of windows.  */
7164  if (sw1->size != sw2->size)
7165    return 0;
7166
7167  for (i = 0; i < sw1->size; i++)
7168    {
7169      struct saved_window *p1, *p2;
7170      int w1_is_current, w2_is_current;
7171
7172      p1 = SAVED_WINDOW_N (sw1, i);
7173      p2 = SAVED_WINDOW_N (sw2, i);
7174
7175      /* Verify that the current windows in the two
7176	 configurations correspond to each other.  */
7177      w1_is_current = EQ (d1->current_window, p1->window);
7178      w2_is_current = EQ (d2->current_window, p2->window);
7179
7180      if (w1_is_current != w2_is_current)
7181	return 0;
7182
7183      /* Verify that the corresponding windows do match.  */
7184      if (! EQ (p1->buffer, p2->buffer))
7185	return 0;
7186      if (! EQ (p1->left_col, p2->left_col))
7187	return 0;
7188      if (! EQ (p1->top_line, p2->top_line))
7189	return 0;
7190      if (! EQ (p1->total_cols, p2->total_cols))
7191	return 0;
7192      if (! EQ (p1->total_lines, p2->total_lines))
7193	return 0;
7194      if (! EQ (p1->display_table, p2->display_table))
7195	return 0;
7196      if (! EQ (p1->parent, p2->parent))
7197	return 0;
7198      if (! EQ (p1->prev, p2->prev))
7199	return 0;
7200      if (! ignore_positions)
7201	{
7202	  if (! EQ (p1->hscroll, p2->hscroll))
7203	    return 0;
7204	  if (!EQ (p1->min_hscroll, p2->min_hscroll))
7205	    return 0;
7206	  if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
7207	    return 0;
7208	  if (NILP (Fequal (p1->start, p2->start)))
7209	    return 0;
7210	  if (NILP (Fequal (p1->pointm, p2->pointm)))
7211	    return 0;
7212	  if (NILP (Fequal (p1->mark, p2->mark)))
7213	    return 0;
7214	}
7215      if (! EQ (p1->left_margin_cols, p2->left_margin_cols))
7216	return 0;
7217      if (! EQ (p1->right_margin_cols, p2->right_margin_cols))
7218	return 0;
7219      if (! EQ (p1->left_fringe_width, p2->left_fringe_width))
7220	return 0;
7221      if (! EQ (p1->right_fringe_width, p2->right_fringe_width))
7222	return 0;
7223      if (! EQ (p1->fringes_outside_margins, p2->fringes_outside_margins))
7224	return 0;
7225      if (! EQ (p1->scroll_bar_width, p2->scroll_bar_width))
7226	return 0;
7227      if (! EQ (p1->vertical_scroll_bar_type, p2->vertical_scroll_bar_type))
7228	return 0;
7229    }
7230
7231  return 1;
7232}
7233
7234DEFUN ("compare-window-configurations", Fcompare_window_configurations,
7235       Scompare_window_configurations, 2, 2, 0,
7236       doc: /* Compare two window configurations as regards the structure of windows.
7237This function ignores details such as the values of point and mark
7238and scrolling positions.  */)
7239     (x, y)
7240     Lisp_Object x, y;
7241{
7242  if (compare_window_configurations (x, y, 1))
7243    return Qt;
7244  return Qnil;
7245}
7246
7247void
7248init_window_once ()
7249{
7250  struct frame *f = make_terminal_frame ();
7251  XSETFRAME (selected_frame, f);
7252  Vterminal_frame = selected_frame;
7253  minibuf_window = f->minibuffer_window;
7254  selected_window = f->selected_window;
7255  last_nonminibuf_frame = f;
7256
7257  window_initialized = 1;
7258}
7259
7260void
7261init_window ()
7262{
7263  Vwindow_list = Qnil;
7264}
7265
7266void
7267syms_of_window ()
7268{
7269  Qscroll_up = intern ("scroll-up");
7270  staticpro (&Qscroll_up);
7271
7272  Qscroll_down = intern ("scroll-down");
7273  staticpro (&Qscroll_down);
7274
7275  Qwindow_size_fixed = intern ("window-size-fixed");
7276  staticpro (&Qwindow_size_fixed);
7277  Fset (Qwindow_size_fixed, Qnil);
7278
7279  staticpro (&Qwindow_configuration_change_hook);
7280  Qwindow_configuration_change_hook
7281    = intern ("window-configuration-change-hook");
7282
7283  Qwindowp = intern ("windowp");
7284  staticpro (&Qwindowp);
7285
7286  Qwindow_configuration_p = intern ("window-configuration-p");
7287  staticpro (&Qwindow_configuration_p);
7288
7289  Qwindow_live_p = intern ("window-live-p");
7290  staticpro (&Qwindow_live_p);
7291
7292  Qtemp_buffer_show_hook = intern ("temp-buffer-show-hook");
7293  staticpro (&Qtemp_buffer_show_hook);
7294
7295  staticpro (&Vwindow_list);
7296
7297  minibuf_selected_window = Qnil;
7298  staticpro (&minibuf_selected_window);
7299
7300  window_scroll_pixel_based_preserve_y = -1;
7301
7302  DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
7303	       doc: /* Non-nil means call as function to display a help buffer.
7304The function is called with one argument, the buffer to be displayed.
7305Used by `with-output-to-temp-buffer'.
7306If this function is used, then it must do the entire job of showing
7307the buffer; `temp-buffer-show-hook' is not run unless this function runs it.  */);
7308  Vtemp_buffer_show_function = Qnil;
7309
7310  DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
7311	       doc: /* If non-nil, function to call to handle `display-buffer'.
7312It will receive two args, the buffer and a flag which if non-nil means
7313that the currently selected window is not acceptable.
7314It should choose or create a window, display the specified buffer in it,
7315and return the window.
7316Commands such as `switch-to-buffer-other-window' and `find-file-other-window'
7317work using this function.  */);
7318  Vdisplay_buffer_function = Qnil;
7319
7320  DEFVAR_LISP ("even-window-heights", &Veven_window_heights,
7321	       doc: /* *If non-nil, `display-buffer' should even the window heights.
7322If nil, `display-buffer' will leave the window configuration alone.  */);
7323  Veven_window_heights = Qt;
7324
7325  DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
7326	       doc: /* Non-nil means it is the window that C-M-v in minibuffer should scroll.  */);
7327  Vminibuf_scroll_window = Qnil;
7328
7329  DEFVAR_BOOL ("mode-line-in-non-selected-windows", &mode_line_in_non_selected_windows,
7330	       doc: /* Non-nil means to use `mode-line-inactive' face in non-selected windows.
7331If the minibuffer is active, the `minibuffer-scroll-window' mode line
7332is displayed in the `mode-line' face.  */);
7333  mode_line_in_non_selected_windows = 1;
7334
7335  DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
7336	       doc: /* If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.  */);
7337  Vother_window_scroll_buffer = Qnil;
7338
7339  DEFVAR_BOOL ("pop-up-frames", &pop_up_frames,
7340	       doc: /* *Non-nil means `display-buffer' should make a separate frame.  */);
7341  pop_up_frames = 0;
7342
7343  DEFVAR_BOOL ("auto-window-vscroll", &auto_window_vscroll_p,
7344	       doc: /* *Non-nil means to automatically adjust `window-vscroll' to view tall lines.  */);
7345  auto_window_vscroll_p = 1;
7346
7347  DEFVAR_BOOL ("display-buffer-reuse-frames", &display_buffer_reuse_frames,
7348	       doc: /* *Non-nil means `display-buffer' should reuse frames.
7349If the buffer in question is already displayed in a frame, raise that frame.  */);
7350  display_buffer_reuse_frames = 0;
7351
7352  DEFVAR_LISP ("pop-up-frame-function", &Vpop_up_frame_function,
7353	       doc: /* Function to call to handle automatic new frame creation.
7354It is called with no arguments and should return a newly created frame.
7355
7356A typical value might be `(lambda () (new-frame pop-up-frame-alist))'
7357where `pop-up-frame-alist' would hold the default frame parameters.  */);
7358  Vpop_up_frame_function = Qnil;
7359
7360  DEFVAR_LISP ("special-display-buffer-names", &Vspecial_display_buffer_names,
7361	       doc: /* *List of buffer names that should have their own special frames.
7362Displaying a buffer with `display-buffer' or `pop-to-buffer',
7363if its name is in this list, makes a special frame for it
7364using `special-display-function'.  See also `special-display-regexps'.
7365
7366An element of the list can be a list instead of just a string.
7367There are two ways to use a list as an element:
7368  (BUFFER FRAME-PARAMETERS...)   (BUFFER FUNCTION OTHER-ARGS...)
7369In the first case, the FRAME-PARAMETERS are pairs of the form
7370\(PARAMETER . VALUE); these parameter values are used to create the frame.
7371In the second case, FUNCTION is called with BUFFER as the first argument,
7372followed by the OTHER-ARGS--it can display BUFFER in any way it likes.
7373All this is done by the function found in `special-display-function'.
7374
7375If the specified frame parameters include (same-buffer . t), the
7376buffer is displayed in the currently selected window.  Otherwise, if
7377they include (same-frame . t), the buffer is displayed in a new window
7378in the currently selected frame.
7379
7380If this variable appears \"not to work\", because you add a name to it
7381but that buffer still appears in the selected window, look at the
7382values of `same-window-buffer-names' and `same-window-regexps'.
7383Those variables take precedence over this one.  */);
7384  Vspecial_display_buffer_names = Qnil;
7385
7386  DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
7387	       doc: /* *List of regexps saying which buffers should have their own special frames.
7388When displaying a buffer with `display-buffer' or `pop-to-buffer',
7389if any regexp in this list matches the buffer name, it makes a
7390special frame for the buffer by calling `special-display-function'.
7391
7392An element of the list can be a list instead of just a string.
7393There are two ways to use a list as an element:
7394  (REGEXP FRAME-PARAMETERS...)   (REGEXP FUNCTION OTHER-ARGS...)
7395In the first case, the FRAME-PARAMETERS are pairs of the form
7396\(PARAMETER . VALUE); these parameter values are used to create the frame.
7397In the second case, FUNCTION is called with BUFFER as the first argument,
7398followed by the OTHER-ARGS--it can display the buffer in any way it likes.
7399All this is done by the function found in `special-display-function'.
7400
7401If the specified frame parameters include (same-buffer . t), the
7402buffer is displayed in the currently selected window.  Otherwise, if
7403they include (same-frame . t), the buffer is displayed in a new window
7404in the currently selected frame.
7405
7406If this variable appears \"not to work\", because you add a regexp to it
7407but the matching buffers still appear in the selected window, look at the
7408values of `same-window-buffer-names' and `same-window-regexps'.
7409Those variables take precedence over this one.  */);
7410  Vspecial_display_regexps = Qnil;
7411
7412  DEFVAR_LISP ("special-display-function", &Vspecial_display_function,
7413	       doc: /* Function to call to make a new frame for a special buffer.
7414It is called with two arguments, the buffer and optional buffer specific
7415data, and should return a window displaying that buffer.
7416The default value normally makes a separate frame for the buffer,
7417  using `special-display-frame-alist' to specify the frame parameters.
7418But if the buffer specific data includes (same-buffer . t) then the
7419  buffer is displayed in the current selected window.
7420Otherwise if it includes (same-frame . t) then the buffer is displayed in
7421  a new window in the currently selected frame.
7422
7423A buffer is special if it is listed in `special-display-buffer-names'
7424or matches a regexp in `special-display-regexps'.  */);
7425  Vspecial_display_function = Qnil;
7426
7427  DEFVAR_LISP ("same-window-buffer-names", &Vsame_window_buffer_names,
7428	       doc: /* *List of buffer names that should appear in the selected window.
7429Displaying one of these buffers using `display-buffer' or `pop-to-buffer'
7430switches to it in the selected window, rather than making it appear
7431in some other window.
7432
7433An element of the list can be a cons cell instead of just a string.
7434Then the car must be a string, which specifies the buffer name.
7435This is for compatibility with `special-display-buffer-names';
7436the cdr of the cons cell is ignored.
7437
7438See also `same-window-regexps'.  */);
7439  Vsame_window_buffer_names = Qnil;
7440
7441  DEFVAR_LISP ("same-window-regexps", &Vsame_window_regexps,
7442	       doc: /* *List of regexps saying which buffers should appear in the selected window.
7443If a buffer name matches one of these regexps, then displaying it
7444using `display-buffer' or `pop-to-buffer' switches to it
7445in the selected window, rather than making it appear in some other window.
7446
7447An element of the list can be a cons cell instead of just a string.
7448Then the car must be a string, which specifies the buffer name.
7449This is for compatibility with `special-display-buffer-names';
7450the cdr of the cons cell is ignored.
7451
7452See also `same-window-buffer-names'.  */);
7453  Vsame_window_regexps = Qnil;
7454
7455  DEFVAR_BOOL ("pop-up-windows", &pop_up_windows,
7456	       doc: /* *Non-nil means display-buffer should make new windows.  */);
7457  pop_up_windows = 1;
7458
7459  DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
7460	      doc: /* *Number of lines of continuity when scrolling by screenfuls.  */);
7461  next_screen_context_lines = 2;
7462
7463  DEFVAR_INT ("split-height-threshold", &split_height_threshold,
7464	      doc: /* *A window must be at least this tall to be eligible for splitting
7465by `display-buffer'.  The value is in line units.
7466If there is only one window, it is split regardless of this value.  */);
7467  split_height_threshold = 500;
7468
7469  DEFVAR_INT ("window-min-height", &window_min_height,
7470	      doc: /* *Delete any window less than this tall (including its mode line).
7471The value is in line units. */);
7472  window_min_height = 4;
7473
7474  DEFVAR_INT ("window-min-width", &window_min_width,
7475	      doc: /* *Delete any window less than this wide (measured in characters).  */);
7476  window_min_width = 10;
7477
7478  DEFVAR_LISP ("scroll-preserve-screen-position",
7479	       &Vscroll_preserve_screen_position,
7480	       doc: /* *Controls if scroll commands move point to keep its screen line unchanged.
7481A value of nil means point does not keep its screen position except
7482at the scroll margin or window boundary respectively.
7483A value of t means point keeps its screen position if the scroll
7484command moved it vertically out of the window, e.g. when scrolling
7485by full screens.
7486Any other value means point always keeps its screen position.  */);
7487  Vscroll_preserve_screen_position = Qnil;
7488
7489  DEFVAR_LISP ("window-configuration-change-hook",
7490	       &Vwindow_configuration_change_hook,
7491	       doc: /* Functions to call when window configuration changes.
7492The selected frame is the one whose configuration has changed.  */);
7493  Vwindow_configuration_change_hook = Qnil;
7494
7495  defsubr (&Sselected_window);
7496  defsubr (&Sminibuffer_window);
7497  defsubr (&Swindow_minibuffer_p);
7498  defsubr (&Swindowp);
7499  defsubr (&Swindow_live_p);
7500  defsubr (&Spos_visible_in_window_p);
7501  defsubr (&Swindow_line_height);
7502  defsubr (&Swindow_buffer);
7503  defsubr (&Swindow_height);
7504  defsubr (&Swindow_width);
7505  defsubr (&Swindow_hscroll);
7506  defsubr (&Sset_window_hscroll);
7507  defsubr (&Swindow_redisplay_end_trigger);
7508  defsubr (&Sset_window_redisplay_end_trigger);
7509  defsubr (&Swindow_edges);
7510  defsubr (&Swindow_pixel_edges);
7511  defsubr (&Swindow_inside_edges);
7512  defsubr (&Swindow_inside_pixel_edges);
7513  defsubr (&Scoordinates_in_window_p);
7514  defsubr (&Swindow_at);
7515  defsubr (&Swindow_point);
7516  defsubr (&Swindow_start);
7517  defsubr (&Swindow_end);
7518  defsubr (&Sset_window_point);
7519  defsubr (&Sset_window_start);
7520  defsubr (&Swindow_dedicated_p);
7521  defsubr (&Sset_window_dedicated_p);
7522  defsubr (&Swindow_display_table);
7523  defsubr (&Sset_window_display_table);
7524  defsubr (&Snext_window);
7525  defsubr (&Sprevious_window);
7526  defsubr (&Sother_window);
7527  defsubr (&Sget_lru_window);
7528  defsubr (&Sget_largest_window);
7529  defsubr (&Sget_buffer_window);
7530  defsubr (&Sdelete_other_windows);
7531  defsubr (&Sdelete_windows_on);
7532  defsubr (&Sreplace_buffer_in_windows);
7533  defsubr (&Sdelete_window);
7534  defsubr (&Sset_window_buffer);
7535  defsubr (&Sselect_window);
7536  defsubr (&Sspecial_display_p);
7537  defsubr (&Ssame_window_p);
7538  defsubr (&Sdisplay_buffer);
7539  defsubr (&Sforce_window_update);
7540  defsubr (&Ssplit_window);
7541  defsubr (&Senlarge_window);
7542  defsubr (&Sshrink_window);
7543  defsubr (&Sadjust_window_trailing_edge);
7544  defsubr (&Sscroll_up);
7545  defsubr (&Sscroll_down);
7546  defsubr (&Sscroll_left);
7547  defsubr (&Sscroll_right);
7548  defsubr (&Sother_window_for_scrolling);
7549  defsubr (&Sscroll_other_window);
7550  defsubr (&Sminibuffer_selected_window);
7551  defsubr (&Srecenter);
7552  defsubr (&Swindow_text_height);
7553  defsubr (&Smove_to_window_line);
7554  defsubr (&Swindow_configuration_p);
7555  defsubr (&Swindow_configuration_frame);
7556  defsubr (&Sset_window_configuration);
7557  defsubr (&Scurrent_window_configuration);
7558  defsubr (&Ssave_window_excursion);
7559  defsubr (&Swindow_tree);
7560  defsubr (&Sset_window_margins);
7561  defsubr (&Swindow_margins);
7562  defsubr (&Sset_window_fringes);
7563  defsubr (&Swindow_fringes);
7564  defsubr (&Sset_window_scroll_bars);
7565  defsubr (&Swindow_scroll_bars);
7566  defsubr (&Swindow_vscroll);
7567  defsubr (&Sset_window_vscroll);
7568  defsubr (&Scompare_window_configurations);
7569  defsubr (&Swindow_list);
7570}
7571
7572void
7573keys_of_window ()
7574{
7575  initial_define_key (control_x_map, '1', "delete-other-windows");
7576  initial_define_key (control_x_map, '2', "split-window");
7577  initial_define_key (control_x_map, '0', "delete-window");
7578  initial_define_key (control_x_map, 'o', "other-window");
7579  initial_define_key (control_x_map, '^', "enlarge-window");
7580  initial_define_key (control_x_map, '<', "scroll-left");
7581  initial_define_key (control_x_map, '>', "scroll-right");
7582
7583  initial_define_key (global_map, Ctl ('V'), "scroll-up");
7584  initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
7585  initial_define_key (meta_map, 'v', "scroll-down");
7586
7587  initial_define_key (global_map, Ctl('L'), "recenter");
7588  initial_define_key (meta_map, 'r', "move-to-window-line");
7589}
7590
7591/* arch-tag: 90a9c576-0590-48f1-a5f1-6c96a0452d9f
7592   (do not change this comment) */
7593