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