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