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