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