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