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