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