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