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