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