*** empty log message ***
[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);
cee67da9 3538 /* If Fget_lru_window returned nil, try other approaches. */
48d9379d 3539
cee67da9 3540 /* Try visible frames first. */
48d9379d
RS
3541 if (NILP (window))
3542 window = Fget_buffer_window (buffer, Qvisible);
cee67da9 3543 if (NILP (window))
3cbb13c8 3544 window = Fget_largest_window (Qvisible, Qnil);
cee67da9 3545 /* If that didn't work, try iconified frames. */
48d9379d
RS
3546 if (NILP (window))
3547 window = Fget_buffer_window (buffer, make_number (0));
cee67da9 3548 if (NILP (window))
3cbb13c8
SM
3549 window = Fget_largest_window (make_number (0), Qnil);
3550
3551#if 0 /* Don't try frames on other displays. */
48d9379d
RS
3552 if (NILP (window))
3553 window = Fget_buffer_window (buffer, Qt);
cee67da9 3554 if (NILP (window))
3cbb13c8
SM
3555 window = Fget_largest_window (Qt, Qnil);
3556#endif
cee67da9
RS
3557 /* As a last resort, make a new frame. */
3558 if (NILP (window))
3559 window = Fframe_selected_window (call0 (Vpop_up_frame_function));
1942f68f
RS
3560 /* If window appears above or below another,
3561 even out their heights. */
cac66e4f 3562 other = upper = lower = Qnil;
1942f68f
RS
3563 if (!NILP (XWINDOW (window)->prev))
3564 other = upper = XWINDOW (window)->prev, lower = window;
3565 if (!NILP (XWINDOW (window)->next))
3566 other = lower = XWINDOW (window)->next, upper = window;
3567 if (!NILP (other)
6529ed87 3568 && !NILP (Veven_window_heights)
1942f68f 3569 /* Check that OTHER and WINDOW are vertically arrayed. */
949cf20f
KS
3570 && !EQ (XWINDOW (other)->top_line, XWINDOW (window)->top_line)
3571 && (XFASTINT (XWINDOW (other)->total_lines)
3572 > XFASTINT (XWINDOW (window)->total_lines)))
1942f68f 3573 {
949cf20f
KS
3574 int total = (XFASTINT (XWINDOW (other)->total_lines)
3575 + XFASTINT (XWINDOW (window)->total_lines));
86c8e823 3576 enlarge_window (upper,
949cf20f 3577 total / 2 - XFASTINT (XWINDOW (upper)->total_lines),
f95284d2 3578 0, 0);
1942f68f 3579 }
7ab12479
JB
3580 }
3581 }
3582 else
3cbb13c8 3583 window = Fget_lru_window (Qnil, Qnil);
7ab12479 3584
949cf20f 3585 Fset_window_buffer (window, buffer, Qnil);
d07f802a 3586 return display_buffer_1 (window);
7ab12479
JB
3587}
3588
e661376d
KS
3589
3590DEFUN ("force-window-update", Fforce_window_update, Sforce_window_update,
3591 0, 1, 0,
3592 doc: /* Force redisplay of all windows.
3593If optional arg OBJECT is a window, force redisplay of that window only.
0cc1039f 3594If OBJECT is a buffer or buffer name, force redisplay of all windows
e661376d
KS
3595displaying that buffer. */)
3596 (object)
3597 Lisp_Object object;
3598{
3599 if (NILP (object))
3600 {
3601 windows_or_buffers_changed++;
40c6ee74 3602 update_mode_lines++;
e661376d
KS
3603 return Qt;
3604 }
3605
3606 if (WINDOWP (object))
3607 {
40c6ee74 3608 struct window *w = XWINDOW (object);
e661376d 3609 mark_window_display_accurate (object, 0);
40c6ee74
KS
3610 w->update_mode_line = Qt;
3611 if (BUFFERP (w->buffer))
3612 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
3613 ++update_mode_lines;
e661376d
KS
3614 return Qt;
3615 }
0cc1039f 3616
e661376d
KS
3617 if (STRINGP (object))
3618 object = Fget_buffer (object);
3619 if (BUFFERP (object) && !NILP (XBUFFER (object)->name))
3620 {
3621 /* Walk all windows looking for buffer, and force update
3622 of each of those windows. */
3623
3624 object = window_loop (REDISPLAY_BUFFER_WINDOWS, object, 0, Qvisible);
3625 return NILP (object) ? Qnil : Qt;
3626 }
3627
3628 /* If nothing suitable was found, just return.
3629 We could signal an error, but this feature will typically be used
3630 asynchronously in timers or process sentinels, so we don't. */
3631 return Qnil;
3632}
3633
3634
7ab12479
JB
3635void
3636temp_output_buffer_show (buf)
3637 register Lisp_Object buf;
3638{
3639 register struct buffer *old = current_buffer;
3640 register Lisp_Object window;
3641 register struct window *w;
3642
bccd3dd1
RS
3643 XBUFFER (buf)->directory = current_buffer->directory;
3644
7ab12479 3645 Fset_buffer (buf);
c6367666 3646 BUF_SAVE_MODIFF (XBUFFER (buf)) = MODIFF;
7ab12479
JB
3647 BEGV = BEG;
3648 ZV = Z;
3649 SET_PT (BEG);
06be4f85 3650#if 0 /* rms: there should be no reason for this. */
b1599b4c 3651 XBUFFER (buf)->prevent_redisplay_optimizations_p = 1;
06be4f85 3652#endif
7ab12479
JB
3653 set_buffer_internal (old);
3654
3655 if (!EQ (Vtemp_buffer_show_function, Qnil))
3656 call1 (Vtemp_buffer_show_function, buf);
3657 else
3658 {
53f76081 3659 window = Fdisplay_buffer (buf, Qnil, Qnil);
7ab12479 3660
1ae1a37d 3661 if (!EQ (XWINDOW (window)->frame, selected_frame))
44fa5b1e 3662 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
7ab12479
JB
3663 Vminibuf_scroll_window = window;
3664 w = XWINDOW (window);
d834a2e9 3665 XSETFASTINT (w->hscroll, 0);
ea68264b 3666 XSETFASTINT (w->min_hscroll, 0);
2d0834cc
SM
3667 set_marker_restricted_both (w->start, buf, BEG, BEG);
3668 set_marker_restricted_both (w->pointm, buf, BEG, BEG);
a58ec57d 3669
beb4e312 3670 /* Run temp-buffer-show-hook, with the chosen window selected
a5731348 3671 and its buffer current. */
2d0834cc
SM
3672
3673 if (!NILP (Vrun_hooks)
3674 && !NILP (Fboundp (Qtemp_buffer_show_hook))
3675 && !NILP (Fsymbol_value (Qtemp_buffer_show_hook)))
2cccc823 3676 {
2d0834cc
SM
3677 int count = SPECPDL_INDEX ();
3678 Lisp_Object prev_window, prev_buffer;
3679 prev_window = selected_window;
3680 XSETBUFFER (prev_buffer, old);
0cc1039f 3681
2d0834cc
SM
3682 /* Select the window that was chosen, for running the hook.
3683 Note: Both Fselect_window and select_window_norecord may
3684 set-buffer to the buffer displayed in the window,
3685 so we need to save the current buffer. --stef */
3686 record_unwind_protect (Fset_buffer, prev_buffer);
3687 record_unwind_protect (select_window_norecord, prev_window);
3688 Fselect_window (window, Qt);
3689 Fset_buffer (w->buffer);
3690 call1 (Vrun_hooks, Qtemp_buffer_show_hook);
3691 unbind_to (count, Qnil);
2cccc823
RS
3692 }
3693 }
7ab12479
JB
3694}
3695\f
dfcf069d 3696static void
7ab12479
JB
3697make_dummy_parent (window)
3698 Lisp_Object window;
3699{
cffec418 3700 Lisp_Object new;
7ab12479 3701 register struct window *o, *p;
cffec418 3702 int i;
7ab12479 3703
cffec418 3704 o = XWINDOW (window);
26605be9 3705 p = allocate_window ();
cffec418 3706 for (i = 0; i < VECSIZE (struct window); ++i)
26605be9
GM
3707 ((struct Lisp_Vector *) p)->contents[i]
3708 = ((struct Lisp_Vector *)o)->contents[i];
cffec418 3709 XSETWINDOW (new, p);
7ab12479 3710
2a1893f4
SM
3711 ++sequence_number;
3712 XSETFASTINT (p->sequence_number, sequence_number);
7ab12479
JB
3713
3714 /* Put new into window structure in place of window */
3715 replace_window (window, new);
3716
3717 o->next = Qnil;
3718 o->prev = Qnil;
3719 o->vchild = Qnil;
3720 o->hchild = Qnil;
3721 o->parent = new;
3722
3723 p->start = Qnil;
3724 p->pointm = Qnil;
3725 p->buffer = Qnil;
3726}
3727
3728DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
fdb82f93
PJ
3729 doc: /* Split WINDOW, putting SIZE lines in the first of the pair.
3730WINDOW defaults to selected one and SIZE to half its size.
3731If optional third arg HORFLAG is non-nil, split side by side
3732and put SIZE columns in the first of the pair. In that case,
876e2665 3733SIZE includes that window's scroll bar, or the divider column to its right.
c2755926
LT
3734Interactively, all arguments are nil.
3735
3736Returns the newly created window (which is the lower or rightmost one).
3737The upper or leftmost window is the original one and remains selected.
3738See Info node `(elisp)Splitting Windows' for more details and examples.*/)
fdb82f93 3739 (window, size, horflag)
77ae0fe3 3740 Lisp_Object window, size, horflag;
7ab12479
JB
3741{
3742 register Lisp_Object new;
3743 register struct window *o, *p;
c0807608 3744 FRAME_PTR fo;
77ae0fe3 3745 register int size_int;
7ab12479 3746
265a9e55 3747 if (NILP (window))
7ab12479
JB
3748 window = selected_window;
3749 else
b7826503 3750 CHECK_LIVE_WINDOW (window);
7ab12479
JB
3751
3752 o = XWINDOW (window);
c0807608 3753 fo = XFRAME (WINDOW_FRAME (o));
7ab12479 3754
77ae0fe3 3755 if (NILP (size))
7ab12479 3756 {
265a9e55 3757 if (!NILP (horflag))
c0807608 3758 /* Calculate the size of the left-hand window, by dividing
25b33244
KH
3759 the usable space in columns by two.
3760 We round up, since the left-hand window may include
3761 a dividing line, while the right-hand may not. */
949cf20f 3762 size_int = (XFASTINT (o->total_cols) + 1) >> 1;
7ab12479 3763 else
949cf20f 3764 size_int = XFASTINT (o->total_lines) >> 1;
7ab12479
JB
3765 }
3766 else
3767 {
b7826503 3768 CHECK_NUMBER (size);
77ae0fe3 3769 size_int = XINT (size);
7ab12479
JB
3770 }
3771
3772 if (MINI_WINDOW_P (o))
3773 error ("Attempt to split minibuffer window");
233a4a2c
GM
3774 else if (window_fixed_size_p (o, !NILP (horflag), 0))
3775 error ("Attempt to split fixed-size window");
7ab12479 3776
a481b3ea 3777 check_min_window_sizes ();
7ab12479 3778
265a9e55 3779 if (NILP (horflag))
7ab12479 3780 {
77ae0fe3
KH
3781 if (size_int < window_min_height)
3782 error ("Window height %d too small (after splitting)", size_int);
949cf20f 3783 if (size_int + window_min_height > XFASTINT (o->total_lines))
37962e60 3784 error ("Window height %d too small (after splitting)",
949cf20f 3785 XFASTINT (o->total_lines) - size_int);
265a9e55
JB
3786 if (NILP (o->parent)
3787 || NILP (XWINDOW (o->parent)->vchild))
7ab12479
JB
3788 {
3789 make_dummy_parent (window);
3790 new = o->parent;
3791 XWINDOW (new)->vchild = window;
3792 }
3793 }
3794 else
3795 {
77ae0fe3
KH
3796 if (size_int < window_min_width)
3797 error ("Window width %d too small (after splitting)", size_int);
a59fed7e 3798
949cf20f 3799 if (size_int + window_min_width > XFASTINT (o->total_cols))
37962e60 3800 error ("Window width %d too small (after splitting)",
949cf20f 3801 XFASTINT (o->total_cols) - size_int);
265a9e55
JB
3802 if (NILP (o->parent)
3803 || NILP (XWINDOW (o->parent)->hchild))
7ab12479
JB
3804 {
3805 make_dummy_parent (window);
3806 new = o->parent;
3807 XWINDOW (new)->hchild = window;
3808 }
3809 }
3810
3811 /* Now we know that window's parent is a vertical combination
3812 if we are dividing vertically, or a horizontal combination
3813 if we are making side-by-side windows */
3814
3815 windows_or_buffers_changed++;
c0807608 3816 FRAME_WINDOW_SIZES_CHANGED (fo) = 1;
7ab12479
JB
3817 new = make_window ();
3818 p = XWINDOW (new);
3819
44fa5b1e 3820 p->frame = o->frame;
7ab12479 3821 p->next = o->next;
265a9e55 3822 if (!NILP (p->next))
7ab12479
JB
3823 XWINDOW (p->next)->prev = new;
3824 p->prev = window;
3825 o->next = new;
3826 p->parent = o->parent;
3827 p->buffer = Qt;
5500c422
GM
3828 p->window_end_valid = Qnil;
3829 bzero (&p->last_cursor, sizeof p->last_cursor);
7ab12479 3830
949cf20f
KS
3831 /* Duplicate special geometry settings. */
3832
3833 p->left_margin_cols = o->left_margin_cols;
3834 p->right_margin_cols = o->right_margin_cols;
3835 p->left_fringe_width = o->left_fringe_width;
3836 p->right_fringe_width = o->right_fringe_width;
3837 p->fringes_outside_margins = o->fringes_outside_margins;
3838 p->scroll_bar_width = o->scroll_bar_width;
3839 p->vertical_scroll_bar_type = o->vertical_scroll_bar_type;
3840
44fa5b1e 3841 /* Apportion the available frame space among the two new windows */
7ab12479 3842
265a9e55 3843 if (!NILP (horflag))
7ab12479 3844 {
949cf20f
KS
3845 p->total_lines = o->total_lines;
3846 p->top_line = o->top_line;
3847 XSETFASTINT (p->total_cols, XFASTINT (o->total_cols) - size_int);
3848 XSETFASTINT (o->total_cols, size_int);
3849 XSETFASTINT (p->left_col, XFASTINT (o->left_col) + size_int);
3850 adjust_window_margins (p);
3851 adjust_window_margins (o);
7ab12479
JB
3852 }
3853 else
3854 {
949cf20f
KS
3855 p->left_col = o->left_col;
3856 p->total_cols = o->total_cols;
3857 XSETFASTINT (p->total_lines, XFASTINT (o->total_lines) - size_int);
3858 XSETFASTINT (o->total_lines, size_int);
3859 XSETFASTINT (p->top_line, XFASTINT (o->top_line) + size_int);
7ab12479
JB
3860 }
3861
5500c422
GM
3862 /* Adjust glyph matrices. */
3863 adjust_glyphs (fo);
949cf20f
KS
3864
3865 Fset_window_buffer (new, o->buffer, Qt);
7ab12479
JB
3866 return new;
3867}
3868\f
f95284d2 3869DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 3, "p",
fdb82f93
PJ
3870 doc: /* Make current window ARG lines bigger.
3871From program, optional second arg non-nil means grow sideways ARG columns.
f95284d2
RS
3872Interactively, if an argument is not given, make the window one line bigger.
3873
3874Optional third arg PRESERVE-BEFORE, if non-nil, means do not change the size
3875of the siblings above or to the left of the selected window. Only
3876siblings to the right or below are changed. */)
3877 (arg, side, preserve_before)
3878 register Lisp_Object arg, side, preserve_before;
7ab12479 3879{
b7826503 3880 CHECK_NUMBER (arg);
f95284d2
RS
3881 enlarge_window (selected_window, XINT (arg), !NILP (side),
3882 !NILP (preserve_before));
543f5fb1
RS
3883
3884 if (! NILP (Vwindow_configuration_change_hook))
3885 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
3886
7ab12479
JB
3887 return Qnil;
3888}
3889
a5731348 3890DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 3, "p",
fdb82f93
PJ
3891 doc: /* Make current window ARG lines smaller.
3892From program, optional second arg non-nil means shrink sideways arg columns.
a5731348
SM
3893Interactively, if an argument is not given, make the window one line smaller.
3894
3895Optional third arg PRESERVE-BEFORE, if non-nil, means do not change the size
3896of the siblings above or to the left of the selected window. Only
3897siblings to the right or below are changed. */)
3898 (arg, side, preserve_before)
3899 register Lisp_Object arg, side, preserve_before;
7ab12479 3900{
b7826503 3901 CHECK_NUMBER (arg);
a5731348
SM
3902 enlarge_window (selected_window, -XINT (arg), !NILP (side),
3903 !NILP (preserve_before));
543f5fb1
RS
3904
3905 if (! NILP (Vwindow_configuration_change_hook))
3906 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
3907
7ab12479
JB
3908 return Qnil;
3909}
3910
3911int
3912window_height (window)
3913 Lisp_Object window;
3914{
3915 register struct window *p = XWINDOW (window);
949cf20f 3916 return WINDOW_TOTAL_LINES (p);
7ab12479
JB
3917}
3918
3919int
3920window_width (window)
3921 Lisp_Object window;
3922{
3923 register struct window *p = XWINDOW (window);
949cf20f 3924 return WINDOW_TOTAL_COLS (p);
7ab12479
JB
3925}
3926
177c0ea7 3927
7ab12479 3928#define CURBEG(w) \
949cf20f 3929 *(widthflag ? &(XWINDOW (w)->left_col) : &(XWINDOW (w)->top_line))
7ab12479
JB
3930
3931#define CURSIZE(w) \
949cf20f 3932 *(widthflag ? &(XWINDOW (w)->total_cols) : &(XWINDOW (w)->total_lines))
7ab12479 3933
233a4a2c 3934
f95284d2 3935/* Enlarge WINDOW by DELTA. WIDTHFLAG non-zero means
233a4a2c 3936 increase its width. Siblings of the selected window are resized to
f95284d2
RS
3937 fulfill the size request. If they become too small in the process,
3938 they will be deleted.
3939
3940 If PRESERVE_BEFORE is nonzero, that means don't alter
3941 the siblings to the left or above WINDOW. */
7ab12479 3942
f984d4fc 3943static void
f95284d2 3944enlarge_window (window, delta, widthflag, preserve_before)
86c8e823 3945 Lisp_Object window;
f95284d2 3946 int delta, widthflag, preserve_before;
7ab12479 3947{
86c8e823 3948 Lisp_Object parent, next, prev;
233a4a2c 3949 struct window *p;
3578db3c
KR
3950 Lisp_Object *sizep;
3951 int maximum;
5e14b1fc
AS
3952 int (*sizefun) P_ ((Lisp_Object))
3953 = widthflag ? window_width : window_height;
233a4a2c 3954 void (*setsizefun) P_ ((Lisp_Object, int, int))
5e14b1fc 3955 = (widthflag ? set_window_width : set_window_height);
7ab12479 3956
233a4a2c
GM
3957 /* Check values of window_min_width and window_min_height for
3958 validity. */
a481b3ea 3959 check_min_window_sizes ();
7ab12479 3960
233a4a2c 3961 /* Give up if this window cannot be resized. */
233a4a2c
GM
3962 if (window_fixed_size_p (XWINDOW (window), widthflag, 1))
3963 error ("Window is not resizable");
3964
3965 /* Find the parent of the selected window. */
7ab12479
JB
3966 while (1)
3967 {
3968 p = XWINDOW (window);
3969 parent = p->parent;
177c0ea7 3970
265a9e55 3971 if (NILP (parent))
7ab12479
JB
3972 {
3973 if (widthflag)
3974 error ("No other window to side of this one");
3975 break;
3976 }
177c0ea7 3977
233a4a2c
GM
3978 if (widthflag
3979 ? !NILP (XWINDOW (parent)->hchild)
265a9e55 3980 : !NILP (XWINDOW (parent)->vchild))
7ab12479 3981 break;
177c0ea7 3982
7ab12479
JB
3983 window = parent;
3984 }
3985
05c2896a 3986 sizep = &CURSIZE (window);
7ab12479 3987
7ab12479
JB
3988 {
3989 register int maxdelta;
7ab12479 3990
f95284d2
RS
3991 /* Compute the maximum size increment this window can have. */
3992
3993 if (preserve_before)
3994 {
3995 if (!NILP (parent))
3996 {
3997 maxdelta = (*sizefun) (parent) - XINT (*sizep);
3998 /* Subtract size of siblings before, since we can't take that. */
1ab964d7 3999 maxdelta -= XINT (CURBEG (window)) - XINT (CURBEG (parent));
f95284d2
RS
4000 }
4001 else
4002 maxdelta = (!NILP (p->next) ? ((*sizefun) (p->next)
4003 - window_min_size (XWINDOW (p->next),
4004 widthflag, 0, 0))
4005 : (delta = 0));
4006 }
4007 else
4008 maxdelta = (!NILP (parent) ? (*sizefun) (parent) - XINT (*sizep)
4009 /* This is a main window followed by a minibuffer. */
4010 : !NILP (p->next) ? ((*sizefun) (p->next)
4011 - window_min_size (XWINDOW (p->next),
4012 widthflag, 0, 0))
4013 /* This is a minibuffer following a main window. */
4014 : !NILP (p->prev) ? ((*sizefun) (p->prev)
4015 - window_min_size (XWINDOW (p->prev),
4016 widthflag, 0, 0))
4017 /* This is a frame with only one window, a minibuffer-only
4018 or a minibufferless frame. */
4019 : (delta = 0));
7ab12479
JB
4020
4021 if (delta > maxdelta)
4022 /* This case traps trying to make the minibuffer
44fa5b1e
JB
4023 the full frame, or make the only window aside from the
4024 minibuffer the full frame. */
7ab12479 4025 delta = maxdelta;
6b54027b 4026 }
d5783c40 4027
3578db3c 4028 if (XINT (*sizep) + delta < window_min_size (XWINDOW (window), widthflag, 0, 0))
6b54027b 4029 {
543f5fb1 4030 delete_window (window);
d5783c40 4031 return;
6b54027b
RS
4032 }
4033
4034 if (delta == 0)
4035 return;
7ab12479 4036
f95284d2 4037 /* Find the total we can get from other siblings without deleting them. */
db98a733
RS
4038 maximum = 0;
4039 for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
c1636aa6 4040 maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
f984d4fc 4041 widthflag, 0, 0);
f95284d2
RS
4042 if (! preserve_before)
4043 for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
4044 maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
4045 widthflag, 0, 0);
db98a733 4046
f95284d2 4047 /* If we can get it all from them without deleting them, do so. */
c6b530ed 4048 if (delta <= maximum)
7ab12479 4049 {
db98a733
RS
4050 Lisp_Object first_unaffected;
4051 Lisp_Object first_affected;
233a4a2c 4052 int fixed_p;
db98a733
RS
4053
4054 next = p->next;
4055 prev = p->prev;
4056 first_affected = window;
4057 /* Look at one sibling at a time,
4058 moving away from this window in both directions alternately,
4059 and take as much as we can get without deleting that sibling. */
f95284d2
RS
4060 while (delta != 0
4061 && (!NILP (next) || (!preserve_before && !NILP (prev))))
db98a733 4062 {
db98a733
RS
4063 if (! NILP (next))
4064 {
c1636aa6 4065 int this_one = ((*sizefun) (next)
233a4a2c 4066 - window_min_size (XWINDOW (next),
f984d4fc 4067 widthflag, 0, &fixed_p));
233a4a2c
GM
4068 if (!fixed_p)
4069 {
4070 if (this_one > delta)
4071 this_one = delta;
177c0ea7 4072
233a4a2c 4073 (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
3578db3c 4074 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
db98a733 4075
233a4a2c
GM
4076 delta -= this_one;
4077 }
177c0ea7 4078
db98a733
RS
4079 next = XWINDOW (next)->next;
4080 }
177c0ea7 4081
db98a733
RS
4082 if (delta == 0)
4083 break;
177c0ea7 4084
f95284d2 4085 if (!preserve_before && ! NILP (prev))
db98a733 4086 {
c1636aa6 4087 int this_one = ((*sizefun) (prev)
233a4a2c 4088 - window_min_size (XWINDOW (prev),
f984d4fc 4089 widthflag, 0, &fixed_p));
233a4a2c
GM
4090 if (!fixed_p)
4091 {
4092 if (this_one > delta)
4093 this_one = delta;
177c0ea7 4094
233a4a2c 4095 first_affected = prev;
177c0ea7 4096
233a4a2c 4097 (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
3578db3c 4098 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
233a4a2c
GM
4099
4100 delta -= this_one;
4101 }
177c0ea7 4102
db98a733
RS
4103 prev = XWINDOW (prev)->prev;
4104 }
4105 }
4106
233a4a2c
GM
4107 xassert (delta == 0);
4108
db98a733
RS
4109 /* Now recalculate the edge positions of all the windows affected,
4110 based on the new sizes. */
4111 first_unaffected = next;
4112 prev = first_affected;
4113 for (next = XWINDOW (prev)->next; ! EQ (next, first_unaffected);
4114 prev = next, next = XWINDOW (next)->next)
4115 {
3578db3c 4116 XSETINT (CURBEG (next), XINT (CURBEG (prev)) + (*sizefun) (prev));
db98a733
RS
4117 /* This does not change size of NEXT,
4118 but it propagates the new top edge to its children */
4119 (*setsizefun) (next, (*sizefun) (next), 0);
4120 }
7ab12479
JB
4121 }
4122 else
4123 {
4124 register int delta1;
4125 register int opht = (*sizefun) (parent);
4126
3578db3c 4127 if (opht <= XINT (*sizep) + delta)
daf516d3
RS
4128 {
4129 /* If trying to grow this window to or beyond size of the parent,
4130 just delete all the sibling windows. */
dc1ab1ee 4131 Lisp_Object start, tem, next;
daf516d3 4132
dc1ab1ee
RS
4133 start = XWINDOW (parent)->vchild;
4134 if (NILP (start))
4135 start = XWINDOW (parent)->hchild;
daf516d3 4136
dc1ab1ee
RS
4137 /* Delete any siblings that come after WINDOW. */
4138 tem = XWINDOW (window)->next;
daf516d3
RS
4139 while (! NILP (tem))
4140 {
4141 next = XWINDOW (tem)->next;
dc1ab1ee
RS
4142 delete_window (tem);
4143 tem = next;
4144 }
4145
4146 /* Delete any siblings that come after WINDOW.
4147 Note that if START is not WINDOW, then WINDOW still
4148 Fhas siblings, so WINDOW has not yet replaced its parent. */
4149 tem = start;
4150 while (! EQ (tem, window))
4151 {
4152 next = XWINDOW (tem)->next;
4153 delete_window (tem);
daf516d3
RS
4154 tem = next;
4155 }
4156 }
7ab12479 4157 else
233a4a2c
GM
4158 {
4159 /* Otherwise, make delta1 just right so that if we add
4160 delta1 lines to this window and to the parent, and then
4161 shrink the parent back to its original size, the new
4162 proportional size of this window will increase by delta.
4163
4164 The function size_window will compute the new height h'
4165 of the window from delta1 as:
177c0ea7 4166
233a4a2c
GM
4167 e = delta1/n
4168 x = delta1 - delta1/n * n for the 1st resizable child
4169 h' = h + e + x
4170
4171 where n is the number of children that can be resized.
4172 We can ignore x by choosing a delta1 that is a multiple of
4173 n. We want the height of this window to come out as
177c0ea7 4174
233a4a2c
GM
4175 h' = h + delta
4176
4177 So, delta1 must be
177c0ea7 4178
233a4a2c
GM
4179 h + e = h + delta
4180 delta1/n = delta
4181 delta1 = n * delta.
4182
a5731348 4183 The number of children n equals the number of resizable
233a4a2c 4184 children of this window + 1 because we know window itself
6e0dca3d 4185 is resizable (otherwise we would have signalled an error). */
233a4a2c
GM
4186
4187 struct window *w = XWINDOW (window);
4188 Lisp_Object s;
4189 int n = 1;
4190
4191 for (s = w->next; !NILP (s); s = XWINDOW (s)->next)
4192 if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
4193 ++n;
4194 for (s = w->prev; !NILP (s); s = XWINDOW (s)->prev)
4195 if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
4196 ++n;
4197
4198 delta1 = n * delta;
7ab12479 4199
daf516d3
RS
4200 /* Add delta1 lines or columns to this window, and to the parent,
4201 keeping things consistent while not affecting siblings. */
4202 XSETINT (CURSIZE (parent), opht + delta1);
4203 (*setsizefun) (window, XINT (*sizep) + delta1, 0);
4204
4205 /* Squeeze out delta1 lines or columns from our parent,
4206 shriking this window and siblings proportionately.
4207 This brings parent back to correct size.
4208 Delta1 was calculated so this makes this window the desired size,
4209 taking it all out of the siblings. */
4210 (*setsizefun) (parent, opht, 0);
4211
4212 }
7ab12479
JB
4213 }
4214
d834a2e9 4215 XSETFASTINT (p->last_modified, 0);
3cd21523 4216 XSETFASTINT (p->last_overlay_modified, 0);
5500c422
GM
4217
4218 /* Adjust glyph matrices. */
4219 adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
7ab12479 4220}
c1636aa6 4221
7ab12479
JB
4222#undef CURBEG
4223#undef CURSIZE
4224
5500c422 4225
f984d4fc
GM
4226\f
4227/***********************************************************************
4228 Resizing Mini-Windows
4229 ***********************************************************************/
4230
4231static void shrink_window_lowest_first P_ ((struct window *, int));
f984d4fc 4232
43b4a21f
GM
4233enum save_restore_action
4234{
4235 CHECK_ORIG_SIZES,
4236 SAVE_ORIG_SIZES,
4237 RESTORE_ORIG_SIZES
4238};
4239
177c0ea7 4240static int save_restore_orig_size P_ ((struct window *,
43b4a21f 4241 enum save_restore_action));
f984d4fc
GM
4242
4243/* Shrink windows rooted in window W to HEIGHT. Take the space needed
4244 from lowest windows first. */
4245
4246static void
4247shrink_window_lowest_first (w, height)
4248 struct window *w;
4249 int height;
4250{
4251 struct window *c;
4252 Lisp_Object child;
4253 int old_height;
4254
4255 xassert (!MINI_WINDOW_P (w));
4256
4257 /* Set redisplay hints. */
4258 XSETFASTINT (w->last_modified, 0);
4259 XSETFASTINT (w->last_overlay_modified, 0);
4260 windows_or_buffers_changed++;
4261 FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
4262
949cf20f
KS
4263 old_height = XFASTINT (w->total_lines);
4264 XSETFASTINT (w->total_lines, height);
f984d4fc
GM
4265
4266 if (!NILP (w->hchild))
4267 {
4268 for (child = w->hchild; !NILP (child); child = c->next)
4269 {
4270 c = XWINDOW (child);
949cf20f 4271 c->top_line = w->top_line;
f984d4fc
GM
4272 shrink_window_lowest_first (c, height);
4273 }
4274 }
4275 else if (!NILP (w->vchild))
4276 {
4277 Lisp_Object last_child;
4278 int delta = old_height - height;
4279 int last_top;
6bbd7a29
GM
4280
4281 last_child = Qnil;
177c0ea7 4282
f984d4fc
GM
4283 /* Find the last child. We are taking space from lowest windows
4284 first, so we iterate over children from the last child
4285 backwards. */
4286 for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
4287 last_child = child;
4288
4289 /* Assign new heights. We leave only MIN_SAFE_WINDOW_HEIGHT. */
4290 for (child = last_child; delta && !NILP (child); child = c->prev)
4291 {
4292 int this_one;
177c0ea7 4293
f984d4fc 4294 c = XWINDOW (child);
949cf20f 4295 this_one = XFASTINT (c->total_lines) - MIN_SAFE_WINDOW_HEIGHT;
f984d4fc
GM
4296
4297 if (this_one > delta)
4298 this_one = delta;
4299
949cf20f 4300 shrink_window_lowest_first (c, XFASTINT (c->total_lines) - this_one);
f984d4fc
GM
4301 delta -= this_one;
4302 }
4303
4304 /* Compute new positions. */
949cf20f 4305 last_top = XINT (w->top_line);
f984d4fc
GM
4306 for (child = w->vchild; !NILP (child); child = c->next)
4307 {
4308 c = XWINDOW (child);
949cf20f
KS
4309 c->top_line = make_number (last_top);
4310 shrink_window_lowest_first (c, XFASTINT (c->total_lines));
4311 last_top += XFASTINT (c->total_lines);
f984d4fc
GM
4312 }
4313 }
4314}
4315
4316
43b4a21f
GM
4317/* Save, restore, or check positions and sizes in the window tree
4318 rooted at W. ACTION says what to do.
f984d4fc 4319
949cf20f
KS
4320 If ACTION is CHECK_ORIG_SIZES, check if orig_top_line and
4321 orig_total_lines members are valid for all windows in the window
4322 tree. Value is non-zero if they are valid.
177c0ea7 4323
43b4a21f 4324 If ACTION is SAVE_ORIG_SIZES, save members top and height in
949cf20f 4325 orig_top_line and orig_total_lines for all windows in the tree.
43b4a21f 4326
949cf20f
KS
4327 If ACTION is RESTORE_ORIG_SIZES, restore top and height from values
4328 stored in orig_top_line and orig_total_lines for all windows. */
43b4a21f
GM
4329
4330static int
4331save_restore_orig_size (w, action)
f984d4fc 4332 struct window *w;
43b4a21f 4333 enum save_restore_action action;
f984d4fc 4334{
43b4a21f
GM
4335 int success_p = 1;
4336
f984d4fc
GM
4337 while (w)
4338 {
4339 if (!NILP (w->hchild))
43b4a21f
GM
4340 {
4341 if (!save_restore_orig_size (XWINDOW (w->hchild), action))
4342 success_p = 0;
4343 }
f984d4fc 4344 else if (!NILP (w->vchild))
43b4a21f
GM
4345 {
4346 if (!save_restore_orig_size (XWINDOW (w->vchild), action))
4347 success_p = 0;
4348 }
177c0ea7 4349
43b4a21f 4350 switch (action)
f984d4fc 4351 {
43b4a21f 4352 case CHECK_ORIG_SIZES:
949cf20f 4353 if (!INTEGERP (w->orig_top_line) || !INTEGERP (w->orig_total_lines))
43b4a21f
GM
4354 return 0;
4355 break;
4356
4357 case SAVE_ORIG_SIZES:
949cf20f
KS
4358 w->orig_top_line = w->top_line;
4359 w->orig_total_lines = w->total_lines;
43b4a21f
GM
4360 XSETFASTINT (w->last_modified, 0);
4361 XSETFASTINT (w->last_overlay_modified, 0);
4362 break;
4363
4364 case RESTORE_ORIG_SIZES:
949cf20f
KS
4365 xassert (INTEGERP (w->orig_top_line) && INTEGERP (w->orig_total_lines));
4366 w->top_line = w->orig_top_line;
4367 w->total_lines = w->orig_total_lines;
4368 w->orig_total_lines = w->orig_top_line = Qnil;
43b4a21f
GM
4369 XSETFASTINT (w->last_modified, 0);
4370 XSETFASTINT (w->last_overlay_modified, 0);
4371 break;
4372
4373 default:
4374 abort ();
f984d4fc 4375 }
43b4a21f 4376
f984d4fc
GM
4377 w = NILP (w->next) ? NULL : XWINDOW (w->next);
4378 }
43b4a21f
GM
4379
4380 return success_p;
f984d4fc
GM
4381}
4382
4383
4384/* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we can
4385 without deleting other windows. */
4386
4387void
4388grow_mini_window (w, delta)
4389 struct window *w;
4390 int delta;
4391{
4392 struct frame *f = XFRAME (w->frame);
4393 struct window *root;
177c0ea7 4394
f984d4fc
GM
4395 xassert (MINI_WINDOW_P (w));
4396 xassert (delta >= 0);
177c0ea7 4397
f984d4fc
GM
4398 /* Check values of window_min_width and window_min_height for
4399 validity. */
4400 check_min_window_sizes ();
4401
4402 /* Compute how much we can enlarge the mini-window without deleting
4403 other windows. */
4404 root = XWINDOW (FRAME_ROOT_WINDOW (f));
4405 if (delta)
4406 {
4407 int min_height = window_min_size (root, 0, 0, 0);
949cf20f 4408 if (XFASTINT (root->total_lines) - delta < min_height)
8b8bd9c6 4409 /* Note that the root window may already be smaller than
eafa3196 4410 min_height. */
949cf20f 4411 delta = max (0, XFASTINT (root->total_lines) - min_height);
f984d4fc 4412 }
177c0ea7 4413
f984d4fc
GM
4414 if (delta)
4415 {
4416 /* Save original window sizes and positions, if not already done. */
43b4a21f
GM
4417 if (!save_restore_orig_size (root, CHECK_ORIG_SIZES))
4418 save_restore_orig_size (root, SAVE_ORIG_SIZES);
f984d4fc
GM
4419
4420 /* Shrink other windows. */
949cf20f 4421 shrink_window_lowest_first (root, XFASTINT (root->total_lines) - delta);
f984d4fc
GM
4422
4423 /* Grow the mini-window. */
949cf20f
KS
4424 w->top_line = make_number (XFASTINT (root->top_line) + XFASTINT (root->total_lines));
4425 w->total_lines = make_number (XFASTINT (w->total_lines) + delta);
f984d4fc
GM
4426 XSETFASTINT (w->last_modified, 0);
4427 XSETFASTINT (w->last_overlay_modified, 0);
177c0ea7 4428
f984d4fc
GM
4429 adjust_glyphs (f);
4430 }
4431}
4432
4433
86c8e823
GM
4434/* Shrink mini-window W. If there is recorded info about window sizes
4435 before a call to grow_mini_window, restore recorded window sizes.
4436 Otherwise, if the mini-window is higher than 1 line, resize it to 1
4437 line. */
f984d4fc
GM
4438
4439void
4440shrink_mini_window (w)
4441 struct window *w;
4442{
4443 struct frame *f = XFRAME (w->frame);
4444 struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
4445
43b4a21f 4446 if (save_restore_orig_size (root, CHECK_ORIG_SIZES))
f984d4fc 4447 {
43b4a21f 4448 save_restore_orig_size (root, RESTORE_ORIG_SIZES);
f984d4fc
GM
4449 adjust_glyphs (f);
4450 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
4451 windows_or_buffers_changed = 1;
4452 }
949cf20f 4453 else if (XFASTINT (w->total_lines) > 1)
86c8e823 4454 {
0130fe1a
GM
4455 /* Distribute the additional lines of the mini-window
4456 among the other windows. */
86c8e823
GM
4457 Lisp_Object window;
4458 XSETWINDOW (window, w);
949cf20f 4459 enlarge_window (window, 1 - XFASTINT (w->total_lines), 0, 0);
86c8e823 4460 }
f984d4fc
GM
4461}
4462
4463
4464\f
5500c422
GM
4465/* Mark window cursors off for all windows in the window tree rooted
4466 at W by setting their phys_cursor_on_p flag to zero. Called from
4467 xterm.c, e.g. when a frame is cleared and thereby all cursors on
4468 the frame are cleared. */
4469
4470void
4471mark_window_cursors_off (w)
4472 struct window *w;
4473{
4474 while (w)
4475 {
4476 if (!NILP (w->hchild))
4477 mark_window_cursors_off (XWINDOW (w->hchild));
4478 else if (!NILP (w->vchild))
4479 mark_window_cursors_off (XWINDOW (w->vchild));
4480 else
4481 w->phys_cursor_on_p = 0;
4482
4483 w = NILP (w->next) ? 0 : XWINDOW (w->next);
4484 }
4485}
4486
4487
e9c195b1 4488/* Return number of lines of text (not counting mode lines) in W. */
7ab12479
JB
4489
4490int
4491window_internal_height (w)
4492 struct window *w;
4493{
949cf20f 4494 int ht = XFASTINT (w->total_lines);
7ab12479 4495
e9c195b1
GM
4496 if (!MINI_WINDOW_P (w))
4497 {
4498 if (!NILP (w->parent)
4499 || !NILP (w->vchild)
4500 || !NILP (w->hchild)
4501 || !NILP (w->next)
4502 || !NILP (w->prev)
4503 || WINDOW_WANTS_MODELINE_P (w))
4504 --ht;
7ab12479 4505
e9c195b1
GM
4506 if (WINDOW_WANTS_HEADER_LINE_P (w))
4507 --ht;
4508 }
7ab12479
JB
4509
4510 return ht;
4511}
4512
535e0b8e
JB
4513
4514/* Return the number of columns in W.
a3c87d4e 4515 Don't count columns occupied by scroll bars or the vertical bar
535e0b8e 4516 separating W from the sibling to its right. */
5500c422 4517
535e0b8e 4518int
949cf20f 4519window_box_text_cols (w)
535e0b8e
JB
4520 struct window *w;
4521{
5500c422 4522 struct frame *f = XFRAME (WINDOW_FRAME (w));
949cf20f 4523 int width = XINT (w->total_cols);
535e0b8e 4524
949cf20f 4525 if (WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
5500c422 4526 /* Scroll bars occupy a few columns. */
949cf20f
KS
4527 width -= WINDOW_CONFIG_SCROLL_BAR_COLS (w);
4528 else if (!FRAME_WINDOW_P (f)
4529 && !WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
5500c422
GM
4530 /* The column of `|' characters separating side-by-side windows
4531 occupies one column only. */
4532 width -= 1;
4533
5500c422 4534 if (FRAME_WINDOW_P (f))
949cf20f
KS
4535 /* On window-systems, fringes and display margins cannot be
4536 used for normal text. */
4537 width -= (WINDOW_FRINGE_COLS (w)
4538 + WINDOW_LEFT_MARGIN_COLS (w)
4539 + WINDOW_RIGHT_MARGIN_COLS (w));
111e5992
RS
4540
4541 return width;
535e0b8e
JB
4542}
4543
5500c422
GM
4544\f
4545/************************************************************************
4546 Window Scrolling
4547 ***********************************************************************/
535e0b8e 4548
5500c422 4549/* Scroll contents of window WINDOW up. If WHOLE is non-zero, scroll
d4e7cf01 4550 N screen-fulls, which is defined as the height of the window minus
5500c422
GM
4551 next_screen_context_lines. If WHOLE is zero, scroll up N lines
4552 instead. Negative values of N mean scroll down. NOERROR non-zero
4553 means don't signal an error if we try to move over BEGV or ZV,
4554 respectively. */
7ab12479 4555
101d1605
RS
4556static void
4557window_scroll (window, n, whole, noerror)
7ab12479
JB
4558 Lisp_Object window;
4559 int n;
101d1605 4560 int whole;
f8026fd8 4561 int noerror;
5500c422 4562{
cba59f77
RS
4563 immediate_quit = 1;
4564
5500c422
GM
4565 /* If we must, use the pixel-based version which is much slower than
4566 the line-based one but can handle varying line heights. */
4567 if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
4568 window_scroll_pixel_based (window, n, whole, noerror);
4569 else
4570 window_scroll_line_based (window, n, whole, noerror);
cba59f77
RS
4571
4572 immediate_quit = 0;
5500c422
GM
4573}
4574
4575
4576/* Implementation of window_scroll that works based on pixel line
4577 heights. See the comment of window_scroll for parameter
4578 descriptions. */
4579
4580static void
4581window_scroll_pixel_based (window, n, whole, noerror)
4582 Lisp_Object window;
4583 int n;
4584 int whole;
4585 int noerror;
4586{
4587 struct it it;
4588 struct window *w = XWINDOW (window);
4589 struct text_pos start;
4590 Lisp_Object tem;
4591 int this_scroll_margin;
4592 int preserve_y;
5cdb3cf3
MB
4593 /* True if we fiddled the window vscroll field without really scrolling. */
4594 int vscrolled = 0;
5500c422
GM
4595
4596 SET_TEXT_POS_FROM_MARKER (start, w->start);
177c0ea7 4597
5500c422 4598 /* If PT is not visible in WINDOW, move back one half of
288d4e06
GM
4599 the screen. Allow PT to be partially visible, otherwise
4600 something like (scroll-down 1) with PT in the line before
4601 the partially visible one would recenter. */
4602 tem = Fpos_visible_in_window_p (make_number (PT), window, Qt);
5500c422
GM
4603 if (NILP (tem))
4604 {
4605 /* Move backward half the height of the window. Performance note:
4606 vmotion used here is about 10% faster, but would give wrong
4607 results for variable height lines. */
4608 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
4609 it.current_y = it.last_visible_y;
f204989e 4610 move_it_vertically_backward (&it, window_box_height (w) / 2);
177c0ea7 4611
5500c422
GM
4612 /* The function move_iterator_vertically may move over more than
4613 the specified y-distance. If it->w is small, e.g. a
4614 mini-buffer window, we may end up in front of the window's
4615 display area. This is the case when Start displaying at the
4616 start of the line containing PT in this case. */
4617 if (it.current_y <= 0)
4618 {
4619 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
f204989e 4620 move_it_vertically_backward (&it, 0);
5500c422
GM
4621 it.current_y = 0;
4622 }
4623
4624 start = it.current.pos;
4625 }
e56263e5
KS
4626 else if (auto_window_vscroll_p)
4627 {
5b1ba1e3 4628 if (tem = XCAR (XCDR (XCDR (tem))), CONSP (tem))
e56263e5
KS
4629 {
4630 int px;
4631 int dy = WINDOW_FRAME_LINE_HEIGHT (w);
4632 if (whole)
e856c216
KS
4633 dy = max ((window_box_height (w)
4634 - next_screen_context_lines * dy),
4635 dy);
e56263e5
KS
4636 dy *= n;
4637
5b1ba1e3 4638 if (n < 0 && (px = XINT (XCAR (tem))) > 0)
e56263e5
KS
4639 {
4640 px = max (0, -w->vscroll - min (px, -dy));
4641 Fset_window_vscroll (window, make_number (px), Qt);
4642 return;
4643 }
5b1ba1e3 4644 if (n > 0 && (px = XINT (XCDR (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 }
4650 }
4651 Fset_window_vscroll (window, make_number (0), Qt);
4652 }
5500c422 4653
d0c38d63 4654 /* If scroll_preserve_screen_position is non-nil, we try to set
5500c422
GM
4655 point in the same window line as it is now, so get that line. */
4656 if (!NILP (Vscroll_preserve_screen_position))
4657 {
4658 start_display (&it, w, start);
4659 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
4660 preserve_y = it.current_y;
4661 }
4662 else
4663 preserve_y = -1;
4664
4665 /* Move iterator it from start the specified distance forward or
4666 backward. The result is the new window start. */
4667 start_display (&it, w, start);
4668 if (whole)
4669 {
e856c216
KS
4670 int start_pos = IT_CHARPOS (it);
4671 int dy = WINDOW_FRAME_LINE_HEIGHT (w);
4672 dy = max ((window_box_height (w)
4673 - next_screen_context_lines * dy),
4674 dy) * n;
d72340d4
GM
4675
4676 /* Note that move_it_vertically always moves the iterator to the
4677 start of a line. So, if the last line doesn't have a newline,
4678 we would end up at the start of the line ending at ZV. */
4679 if (dy <= 0)
e856c216
KS
4680 {
4681 move_it_vertically_backward (&it, -dy);
4682 /* Ensure we actually does move, e.g. in case we are currently
4683 looking at an image that is taller that the window height. */
4684 while (start_pos == IT_CHARPOS (it)
4685 && start_pos > BEGV)
4686 move_it_by_lines (&it, -1, 1);
4687 }
d72340d4 4688 else if (dy > 0)
bed83ee4 4689 {
bed83ee4
KS
4690 move_it_to (&it, ZV, -1, it.current_y + dy, -1,
4691 MOVE_TO_POS | MOVE_TO_Y);
4692 /* Ensure we actually does move, e.g. in case we are currently
4693 looking at an image that is taller that the window height. */
4694 while (start_pos == IT_CHARPOS (it)
4695 && start_pos < ZV)
4696 move_it_by_lines (&it, 1, 1);
4697 }
5500c422
GM
4698 }
4699 else
4700 move_it_by_lines (&it, n, 1);
4701
96ae58c8
RS
4702 /* We failed if we find ZV is already on the screen (scrolling up,
4703 means there's nothing past the end), or if we can't start any
4704 earlier (scrolling down, means there's nothing past the top). */
5500c422 4705 if ((n > 0 && IT_CHARPOS (it) == ZV)
96ae58c8 4706 || (n < 0 && IT_CHARPOS (it) == CHARPOS (start)))
5500c422 4707 {
5cdb3cf3
MB
4708 if (IT_CHARPOS (it) == ZV)
4709 {
07ce8b53
RS
4710 if (it.current_y < it.last_visible_y
4711 && (it.current_y + it.max_ascent + it.max_descent
4712 >= it.last_visible_y))
a74eca50
GM
4713 {
4714 /* The last line was only partially visible, make it fully
4715 visible. */
4716 w->vscroll = (it.last_visible_y
4717 - it.current_y + it.max_ascent + it.max_descent);
4718 adjust_glyphs (it.f);
4719 }
5cdb3cf3
MB
4720 else if (noerror)
4721 return;
4722 else
4723 Fsignal (Qend_of_buffer, Qnil);
4724 }
5500c422 4725 else
5cdb3cf3
MB
4726 {
4727 if (w->vscroll != 0)
4728 /* The first line was only partially visible, make it fully
4729 visible. */
4730 w->vscroll = 0;
4731 else if (noerror)
4732 return;
4733 else
4734 Fsignal (Qbeginning_of_buffer, Qnil);
4735 }
4736
4737 /* If control gets here, then we vscrolled. */
4738
4739 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
4740
4741 /* Don't try to change the window start below. */
4742 vscrolled = 1;
5500c422
GM
4743 }
4744
5cdb3cf3
MB
4745 if (! vscrolled)
4746 {
dad67609
RS
4747 int pos = IT_CHARPOS (it);
4748 int bytepos;
e68def1e
AS
4749
4750 /* If in the middle of a multi-glyph character move forward to
4751 the next character. */
4752 if (in_display_vector_p (&it))
4753 {
4754 ++pos;
4755 move_it_to (&it, pos, -1, -1, -1, MOVE_TO_POS);
4756 }
4757
5cdb3cf3 4758 /* Set the window start, and set up the window for redisplay. */
dad67609 4759 set_marker_restricted (w->start, make_number (pos),
5cdb3cf3 4760 w->buffer);
dad67609
RS
4761 bytepos = XMARKER (w->start)->bytepos;
4762 w->start_at_line_beg = ((pos == BEGV || FETCH_BYTE (bytepos - 1) == '\n')
4763 ? Qt : Qnil);
5cdb3cf3
MB
4764 w->update_mode_line = Qt;
4765 XSETFASTINT (w->last_modified, 0);
4766 XSETFASTINT (w->last_overlay_modified, 0);
4767 /* Set force_start so that redisplay_window will run the
4768 window-scroll-functions. */
4769 w->force_start = Qt;
4770 }
177c0ea7 4771
dc297565
RS
4772 /* The rest of this function uses current_y in a nonstandard way,
4773 not including the height of the header line if any. */
5500c422 4774 it.current_y = it.vpos = 0;
177c0ea7 4775
940f53e5
RS
4776 /* Move PT out of scroll margins.
4777 This code wants current_y to be zero at the window start position
4778 even if there is a header line. */
4779 this_scroll_margin = max (0, scroll_margin);
4780 this_scroll_margin = min (this_scroll_margin, XFASTINT (w->total_lines) / 4);
4781 this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
4782
4783 if (n > 0)
5500c422 4784 {
940f53e5
RS
4785 /* We moved the window start towards ZV, so PT may be now
4786 in the scroll margin at the top. */
4787 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
bdf4ec93
RS
4788 if (IT_CHARPOS (it) == PT && it.current_y >= this_scroll_margin
4789 && (NILP (Vscroll_preserve_screen_position)
4790 || EQ (Vscroll_preserve_screen_position, Qt)))
940f53e5
RS
4791 /* We found PT at a legitimate height. Leave it alone. */
4792 ;
4793 else if (preserve_y >= 0)
4794 {
fa3c3426
RS
4795 /* If we have a header line, take account of it.
4796 This is necessary because we set it.current_y to 0, above. */
940f53e5
RS
4797 if (WINDOW_WANTS_HEADER_LINE_P (w))
4798 preserve_y -= CURRENT_HEADER_LINE_HEIGHT (w);
dc297565 4799
940f53e5
RS
4800 move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
4801 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
4802 }
4803 else
5500c422 4804 {
5500c422 4805 while (it.current_y < this_scroll_margin)
e9b2c961
RS
4806 {
4807 int prev = it.current_y;
4808 move_it_by_lines (&it, 1, 1);
4809 if (prev == it.current_y)
4810 break;
4811 }
5500c422
GM
4812 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
4813 }
940f53e5
RS
4814 }
4815 else if (n < 0)
4816 {
4817 int charpos, bytepos;
aed328bf 4818 int partial_p;
940f53e5
RS
4819
4820 /* Save our position, for the preserve_y case. */
4821 charpos = IT_CHARPOS (it);
4822 bytepos = IT_BYTEPOS (it);
5cdb3cf3 4823
940f53e5
RS
4824 /* We moved the window start towards BEGV, so PT may be now
4825 in the scroll margin at the bottom. */
4826 move_it_to (&it, PT, -1,
7ad53239
RS
4827 (it.last_visible_y - CURRENT_HEADER_LINE_HEIGHT (w)
4828 - this_scroll_margin - 1),
4829 -1,
940f53e5
RS
4830 MOVE_TO_POS | MOVE_TO_Y);
4831
aed328bf
KS
4832 /* Save our position, in case it's correct. */
4833 charpos = IT_CHARPOS (it);
4834 bytepos = IT_BYTEPOS (it);
4835
4836 /* See if point is on a partially visible line at the end. */
4837 if (it.what == IT_EOB)
4838 partial_p = it.current_y + it.ascent + it.descent > it.last_visible_y;
4839 else
4840 {
4841 move_it_by_lines (&it, 1, 1);
4842 partial_p = it.current_y > it.last_visible_y;
4843 }
4844
bdf4ec93
RS
4845 if (charpos == PT && !partial_p
4846 && (NILP (Vscroll_preserve_screen_position)
4847 || EQ (Vscroll_preserve_screen_position, Qt)))
940f53e5
RS
4848 /* We found PT before we found the display margin, so PT is ok. */
4849 ;
4850 else if (preserve_y >= 0)
4851 {
4852 SET_TEXT_POS_FROM_MARKER (start, w->start);
4853 start_display (&it, w, start);
fa3c3426
RS
4854#if 0 /* It's wrong to subtract this here
4855 because we called start_display again
4856 and did not alter it.current_y this time. */
4857
940f53e5
RS
4858 /* If we have a header line, take account of it. */
4859 if (WINDOW_WANTS_HEADER_LINE_P (w))
4860 preserve_y -= CURRENT_HEADER_LINE_HEIGHT (w);
fa3c3426 4861#endif
5cdb3cf3 4862
940f53e5
RS
4863 move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
4864 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
4865 }
4866 else
4867 {
aed328bf 4868 if (partial_p)
5cdb3cf3
MB
4869 /* The last line was only partially visible, so back up two
4870 lines to make sure we're on a fully visible line. */
4871 {
4872 move_it_by_lines (&it, -2, 0);
4873 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
4874 }
4875 else
4876 /* No, the position we saved is OK, so use it. */
4877 SET_PT_BOTH (charpos, bytepos);
5500c422
GM
4878 }
4879 }
4880}
4881
4882
4883/* Implementation of window_scroll that works based on screen lines.
4884 See the comment of window_scroll for parameter descriptions. */
4885
4886static void
4887window_scroll_line_based (window, n, whole, noerror)
4888 Lisp_Object window;
4889 int n;
4890 int whole;
4891 int noerror;
7ab12479
JB
4892{
4893 register struct window *w = XWINDOW (window);
5500c422 4894 register int opoint = PT, opoint_byte = PT_BYTE;
b73ea88e 4895 register int pos, pos_byte;
7ab12479
JB
4896 register int ht = window_internal_height (w);
4897 register Lisp_Object tem;
4898 int lose;
5500c422 4899 Lisp_Object bolp;
345d45b2 4900 int startpos;
101d1605
RS
4901 struct position posit;
4902 int original_vpos;
4903
d4e7cf01
GM
4904 /* If scrolling screen-fulls, compute the number of lines to
4905 scroll from the window's height. */
4906 if (whole)
4907 n *= max (1, ht - next_screen_context_lines);
4908
101d1605
RS
4909 startpos = marker_position (w->start);
4910
4911 posit = *compute_motion (startpos, 0, 0, 0,
4912 PT, ht, 0,
ec2b66c4 4913 -1, XINT (w->hscroll),
101d1605
RS
4914 0, w);
4915 original_vpos = posit.vpos;
0a1f771a 4916
d834a2e9 4917 XSETFASTINT (tem, PT);
6ffdb539 4918 tem = Fpos_visible_in_window_p (tem, window, Qnil);
7ab12479 4919
265a9e55 4920 if (NILP (tem))
7ab12479 4921 {
cd2be1dd 4922 Fvertical_motion (make_number (- (ht / 2)), window);
345d45b2 4923 startpos = PT;
7ab12479
JB
4924 }
4925
345d45b2 4926 SET_PT (startpos);
5ce7b543 4927 lose = n < 0 && PT == BEGV;
540b6aa0 4928 Fvertical_motion (make_number (n), window);
5ce7b543 4929 pos = PT;
b73ea88e 4930 pos_byte = PT_BYTE;
7ab12479 4931 bolp = Fbolp ();
b73ea88e 4932 SET_PT_BOTH (opoint, opoint_byte);
7ab12479
JB
4933
4934 if (lose)
f8026fd8
JB
4935 {
4936 if (noerror)
4937 return;
4938 else
4939 Fsignal (Qbeginning_of_buffer, Qnil);
4940 }
7ab12479
JB
4941
4942 if (pos < ZV)
7ab12479 4943 {
0c7da84e
RS
4944 int this_scroll_margin = scroll_margin;
4945
4946 /* Don't use a scroll margin that is negative or too large. */
4947 if (this_scroll_margin < 0)
4948 this_scroll_margin = 0;
4949
949cf20f
KS
4950 if (XINT (w->total_lines) < 4 * scroll_margin)
4951 this_scroll_margin = XINT (w->total_lines) / 4;
0c7da84e 4952
b73ea88e 4953 set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
7ab12479
JB
4954 w->start_at_line_beg = bolp;
4955 w->update_mode_line = Qt;
d834a2e9 4956 XSETFASTINT (w->last_modified, 0);
3cd21523 4957 XSETFASTINT (w->last_overlay_modified, 0);
345d45b2
RS
4958 /* Set force_start so that redisplay_window will run
4959 the window-scroll-functions. */
4960 w->force_start = Qt;
0c7da84e 4961
bdf4ec93
RS
4962 if (!NILP (Vscroll_preserve_screen_position)
4963 && (whole || !EQ (Vscroll_preserve_screen_position, Qt)))
0c7da84e 4964 {
b73ea88e 4965 SET_PT_BOTH (pos, pos_byte);
101d1605 4966 Fvertical_motion (make_number (original_vpos), window);
0c7da84e 4967 }
101d1605
RS
4968 /* If we scrolled forward, put point enough lines down
4969 that it is outside the scroll margin. */
4970 else if (n > 0)
0c7da84e 4971 {
101d1605
RS
4972 int top_margin;
4973
4974 if (this_scroll_margin > 0)
4975 {
b73ea88e 4976 SET_PT_BOTH (pos, pos_byte);
101d1605
RS
4977 Fvertical_motion (make_number (this_scroll_margin), window);
4978 top_margin = PT;
4979 }
4980 else
4981 top_margin = pos;
4982
4983 if (top_margin <= opoint)
b73ea88e 4984 SET_PT_BOTH (opoint, opoint_byte);
5500c422 4985 else if (!NILP (Vscroll_preserve_screen_position))
101d1605 4986 {
b73ea88e 4987 SET_PT_BOTH (pos, pos_byte);
101d1605
RS
4988 Fvertical_motion (make_number (original_vpos), window);
4989 }
9317a85d 4990 else
335406fc 4991 SET_PT (top_margin);
0c7da84e 4992 }
101d1605 4993 else if (n < 0)
7ab12479 4994 {
101d1605
RS
4995 int bottom_margin;
4996
0c7da84e
RS
4997 /* If we scrolled backward, put point near the end of the window
4998 but not within the scroll margin. */
b73ea88e 4999 SET_PT_BOTH (pos, pos_byte);
0c7da84e 5000 tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
101d1605
RS
5001 if (XFASTINT (tem) == ht - this_scroll_margin)
5002 bottom_margin = PT;
5003 else
5004 bottom_margin = PT + 1;
5005
5006 if (bottom_margin > opoint)
b73ea88e 5007 SET_PT_BOTH (opoint, opoint_byte);
7ab12479 5008 else
101d1605 5009 {
5500c422 5010 if (!NILP (Vscroll_preserve_screen_position))
9317a85d 5011 {
b73ea88e 5012 SET_PT_BOTH (pos, pos_byte);
9317a85d
RS
5013 Fvertical_motion (make_number (original_vpos), window);
5014 }
5015 else
5016 Fvertical_motion (make_number (-1), window);
101d1605 5017 }
7ab12479
JB
5018 }
5019 }
5020 else
f8026fd8
JB
5021 {
5022 if (noerror)
5023 return;
5024 else
5025 Fsignal (Qend_of_buffer, Qnil);
5026 }
7ab12479 5027}
5500c422
GM
5028
5029
5030/* Scroll selected_window up or down. If N is nil, scroll a
5031 screen-full which is defined as the height of the window minus
5032 next_screen_context_lines. If N is the symbol `-', scroll.
5033 DIRECTION may be 1 meaning to scroll down, or -1 meaning to scroll
5034 up. This is the guts of Fscroll_up and Fscroll_down. */
7ab12479
JB
5035
5036static void
5037scroll_command (n, direction)
5500c422 5038 Lisp_Object n;
7ab12479
JB
5039 int direction;
5040{
331379bf 5041 int count = SPECPDL_INDEX ();
7ab12479 5042
5500c422
GM
5043 xassert (abs (direction) == 1);
5044
5045 /* If selected window's buffer isn't current, make it current for
5046 the moment. But don't screw up if window_scroll gets an error. */
7ab12479 5047 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
95605e15
JB
5048 {
5049 record_unwind_protect (save_excursion_restore, save_excursion_save ());
5050 Fset_buffer (XWINDOW (selected_window)->buffer);
5500c422
GM
5051
5052 /* Make redisplay consider other windows than just selected_window. */
5053 ++windows_or_buffers_changed;
95605e15 5054 }
7ab12479 5055
265a9e55 5056 if (NILP (n))
d4e7cf01 5057 window_scroll (selected_window, direction, 1, 0);
7ab12479 5058 else if (EQ (n, Qminus))
d4e7cf01 5059 window_scroll (selected_window, -direction, 1, 0);
7ab12479
JB
5060 else
5061 {
5062 n = Fprefix_numeric_value (n);
101d1605 5063 window_scroll (selected_window, XINT (n) * direction, 0, 0);
7ab12479 5064 }
95605e15
JB
5065
5066 unbind_to (count, Qnil);
7ab12479
JB
5067}
5068
5069DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
a0a37a6f
LT
5070 doc: /* Scroll text of current window upward ARG lines.
5071If ARG is omitted or nil, scroll upward by a near full screen.
fdb82f93
PJ
5072A near full screen is `next-screen-context-lines' less than a full screen.
5073Negative ARG means scroll downward.
5074If ARG is the atom `-', scroll downward by nearly full screen.
5075When calling from a program, supply as argument a number, nil, or `-'. */)
5076 (arg)
413430c5 5077 Lisp_Object arg;
7ab12479 5078{
413430c5 5079 scroll_command (arg, 1);
7ab12479
JB
5080 return Qnil;
5081}
5082
5083DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
a0a37a6f
LT
5084 doc: /* Scroll text of current window down ARG lines.
5085If ARG is omitted or nil, scroll down by a near full screen.
fdb82f93
PJ
5086A near full screen is `next-screen-context-lines' less than a full screen.
5087Negative ARG means scroll upward.
5088If ARG is the atom `-', scroll upward by nearly full screen.
5089When calling from a program, supply as argument a number, nil, or `-'. */)
5090 (arg)
413430c5 5091 Lisp_Object arg;
7ab12479 5092{
413430c5 5093 scroll_command (arg, -1);
7ab12479
JB
5094 return Qnil;
5095}
ccd0664b
RS
5096\f
5097DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0,
fdb82f93 5098 doc: /* Return the other window for \"other window scroll\" commands.
fdb82f93 5099If `other-window-scroll-buffer' is non-nil, a window
a0a37a6f
LT
5100showing that buffer is used.
5101If in the minibuffer, `minibuffer-scroll-window' if non-nil
5102specifies the window. This takes precedence over
5103`other-window-scroll-buffer'. */)
fdb82f93 5104 ()
7ab12479 5105{
ccd0664b 5106 Lisp_Object window;
7ab12479
JB
5107
5108 if (MINI_WINDOW_P (XWINDOW (selected_window))
265a9e55 5109 && !NILP (Vminibuf_scroll_window))
7ab12479
JB
5110 window = Vminibuf_scroll_window;
5111 /* If buffer is specified, scroll that buffer. */
265a9e55 5112 else if (!NILP (Vother_window_scroll_buffer))
7ab12479
JB
5113 {
5114 window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
265a9e55 5115 if (NILP (window))
53f76081 5116 window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt, Qnil);
7ab12479
JB
5117 }
5118 else
dbc4e1c1
JB
5119 {
5120 /* Nothing specified; look for a neighboring window on the same
5121 frame. */
5122 window = Fnext_window (selected_window, Qnil, Qnil);
5123
5124 if (EQ (window, selected_window))
5125 /* That didn't get us anywhere; look for a window on another
5126 visible frame. */
5127 do
5128 window = Fnext_window (window, Qnil, Qt);
5129 while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
5130 && ! EQ (window, selected_window));
5131 }
5132
b7826503 5133 CHECK_LIVE_WINDOW (window);
7ab12479
JB
5134
5135 if (EQ (window, selected_window))
5136 error ("There is no other window");
5137
ccd0664b
RS
5138 return window;
5139}
5140
5141DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
fdb82f93
PJ
5142 doc: /* Scroll next window upward ARG lines; or near full screen if no ARG.
5143A near full screen is `next-screen-context-lines' less than a full screen.
5144The next window is the one below the current one; or the one at the top
5145if the current one is at the bottom. Negative ARG means scroll downward.
5146If ARG is the atom `-', scroll downward by nearly full screen.
5147When calling from a program, supply as argument a number, nil, or `-'.
5148
fdb82f93 5149If `other-window-scroll-buffer' is non-nil, scroll the window
a0a37a6f
LT
5150showing that buffer, popping the buffer up if necessary.
5151If in the minibuffer, `minibuffer-scroll-window' if non-nil
5152specifies the window to scroll. This takes precedence over
5153`other-window-scroll-buffer'. */)
fdb82f93 5154 (arg)
d4e7cf01 5155 Lisp_Object arg;
ccd0664b 5156{
d4e7cf01
GM
5157 Lisp_Object window;
5158 struct window *w;
331379bf 5159 int count = SPECPDL_INDEX ();
ccd0664b
RS
5160
5161 window = Fother_window_for_scrolling ();
7ab12479 5162 w = XWINDOW (window);
7ab12479
JB
5163
5164 /* Don't screw up if window_scroll gets an error. */
5165 record_unwind_protect (save_excursion_restore, save_excursion_save ());
5500c422 5166 ++windows_or_buffers_changed;
7ab12479
JB
5167
5168 Fset_buffer (w->buffer);
5169 SET_PT (marker_position (w->pointm));
5170
413430c5 5171 if (NILP (arg))
d4e7cf01 5172 window_scroll (window, 1, 1, 1);
413430c5 5173 else if (EQ (arg, Qminus))
d4e7cf01 5174 window_scroll (window, -1, 1, 1);
7ab12479
JB
5175 else
5176 {
413430c5
EN
5177 if (CONSP (arg))
5178 arg = Fcar (arg);
b7826503 5179 CHECK_NUMBER (arg);
101d1605 5180 window_scroll (window, XINT (arg), 0, 1);
7ab12479
JB
5181 }
5182
b73ea88e 5183 set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
f4e7b2c2 5184 unbind_to (count, Qnil);
7ab12479
JB
5185
5186 return Qnil;
5187}
5188\f
dc297565 5189DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 2, "P\np",
fdb82f93 5190 doc: /* Scroll selected window display ARG columns left.
2fe41216
EZ
5191Default for ARG is window width minus 2.
5192Value is the total amount of leftward horizontal scrolling in
5193effect after the change.
dc297565
RS
5194If SET_MINIMUM is non-nil, the new scroll amount becomes the
5195lower bound for automatic scrolling, i.e. automatic scrolling
2fe41216 5196will not scroll a window to a column less than the value returned
dc297565
RS
5197by this function. This happens in an interactive call. */)
5198 (arg, set_minimum)
5199 register Lisp_Object arg, set_minimum;
7ab12479 5200{
c67fa410
GM
5201 Lisp_Object result;
5202 int hscroll;
5203 struct window *w = XWINDOW (selected_window);
177c0ea7 5204
265a9e55 5205 if (NILP (arg))
949cf20f 5206 XSETFASTINT (arg, window_box_text_cols (w) - 2);
7ab12479
JB
5207 else
5208 arg = Fprefix_numeric_value (arg);
5209
c67fa410
GM
5210 hscroll = XINT (w->hscroll) + XINT (arg);
5211 result = Fset_window_hscroll (selected_window, make_number (hscroll));
5212
dc297565 5213 if (!NILP (set_minimum))
c67fa410
GM
5214 w->min_hscroll = w->hscroll;
5215
5216 return result;
7ab12479
JB
5217}
5218
dc297565 5219DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 2, "P\np",
fdb82f93 5220 doc: /* Scroll selected window display ARG columns right.
2fe41216
EZ
5221Default for ARG is window width minus 2.
5222Value is the total amount of leftward horizontal scrolling in
5223effect after the change.
dc297565
RS
5224If SET_MINIMUM is non-nil, the new scroll amount becomes the
5225lower bound for automatic scrolling, i.e. automatic scrolling
2fe41216 5226will not scroll a window to a column less than the value returned
dc297565
RS
5227by this function. This happens in an interactive call. */)
5228 (arg, set_minimum)
a93563fd 5229 register Lisp_Object arg, set_minimum;
7ab12479 5230{
c67fa410
GM
5231 Lisp_Object result;
5232 int hscroll;
5233 struct window *w = XWINDOW (selected_window);
177c0ea7 5234
265a9e55 5235 if (NILP (arg))
949cf20f 5236 XSETFASTINT (arg, window_box_text_cols (w) - 2);
7ab12479
JB
5237 else
5238 arg = Fprefix_numeric_value (arg);
5239
c67fa410
GM
5240 hscroll = XINT (w->hscroll) - XINT (arg);
5241 result = Fset_window_hscroll (selected_window, make_number (hscroll));
177c0ea7 5242
dc297565 5243 if (!NILP (set_minimum))
c67fa410
GM
5244 w->min_hscroll = w->hscroll;
5245
5246 return result;
7ab12479
JB
5247}
5248
fa832261
KS
5249DEFUN ("minibuffer-selected-window", Fminibuffer_selected_window, Sminibuffer_selected_window, 0, 0, 0,
5250 doc: /* Return the window which was selected when entering the minibuffer.
5251Returns nil, if current window is not a minibuffer window. */)
5252 ()
5253{
5254 if (minibuf_level > 0
5255 && MINI_WINDOW_P (XWINDOW (selected_window))
fa832261
KS
5256 && WINDOW_LIVE_P (minibuf_selected_window))
5257 return minibuf_selected_window;
5258
5259 return Qnil;
5260}
5261
12c8b416
GM
5262/* Value is the number of lines actually displayed in window W,
5263 as opposed to its height. */
5264
5265static int
5266displayed_window_lines (w)
5267 struct window *w;
5268{
5269 struct it it;
5270 struct text_pos start;
5271 int height = window_box_height (w);
5272 struct buffer *old_buffer;
5273 int bottom_y;
5274
5275 if (XBUFFER (w->buffer) != current_buffer)
5276 {
5277 old_buffer = current_buffer;
5278 set_buffer_internal (XBUFFER (w->buffer));
5279 }
5280 else
5281 old_buffer = NULL;
5282
521b203e
GM
5283 /* In case W->start is out of the accessible range, do something
5284 reasonable. This happens in Info mode when Info-scroll-down
5285 calls (recenter -1) while W->start is 1. */
5286 if (XMARKER (w->start)->charpos < BEGV)
5287 SET_TEXT_POS (start, BEGV, BEGV_BYTE);
5288 else if (XMARKER (w->start)->charpos > ZV)
5289 SET_TEXT_POS (start, ZV, ZV_BYTE);
5290 else
5291 SET_TEXT_POS_FROM_MARKER (start, w->start);
5292
12c8b416
GM
5293 start_display (&it, w, start);
5294 move_it_vertically (&it, height);
c8bc6f65 5295 bottom_y = line_bottom_y (&it);
12c8b416 5296
1de65f51
RS
5297 /* rms: On a non-window display,
5298 the value of it.vpos at the bottom of the screen
5299 seems to be 1 larger than window_box_height (w).
5300 This kludge fixes a bug whereby (move-to-window-line -1)
5301 when ZV is on the last screen line
5302 moves to the previous screen line instead of the last one. */
5303 if (! FRAME_WINDOW_P (XFRAME (w->frame)))
5304 height++;
5305
12c8b416
GM
5306 /* Add in empty lines at the bottom of the window. */
5307 if (bottom_y < height)
5308 {
949cf20f 5309 int uy = FRAME_LINE_HEIGHT (it.f);
c8bc6f65 5310 it.vpos += (height - bottom_y + uy - 1) / uy;
12c8b416
GM
5311 }
5312
c8bc6f65
GM
5313 if (old_buffer)
5314 set_buffer_internal (old_buffer);
5315
12c8b416
GM
5316 return it.vpos;
5317}
5318
5319
7ab12479 5320DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
fdb82f93
PJ
5321 doc: /* Center point in window and redisplay frame.
5322With prefix argument ARG, recenter putting point on screen line ARG
5323relative to the current window. If ARG is negative, it counts up from the
5324bottom of the window. (ARG should be less than the height of the window.)
5325
5326If ARG is omitted or nil, erase the entire frame and then
5327redraw with point in the center of the current window.
5328Just C-u as prefix means put point in the center of the window
5329and redisplay normally--don't erase and redraw the frame. */)
5330 (arg)
413430c5 5331 register Lisp_Object arg;
7ab12479 5332{
6df47b59 5333 struct window *w = XWINDOW (selected_window);
478292ed
RS
5334 struct buffer *buf = XBUFFER (w->buffer);
5335 struct buffer *obuf = current_buffer;
6df47b59
GM
5336 int center_p = 0;
5337 int charpos, bytepos;
f6b43440
RS
5338 int iarg;
5339 int this_scroll_margin;
7ab12479 5340
0fa5d25b
RS
5341 /* If redisplay is suppressed due to an error, try again. */
5342 obuf->display_error_modiff = 0;
5343
413430c5 5344 if (NILP (arg))
7ab12479 5345 {
f02d6d5c
KH
5346 int i;
5347
5348 /* Invalidate pixel data calculated for all compositions. */
5349 for (i = 0; i < n_compositions; i++)
5350 composition_table[i]->font = NULL;
7ab12479 5351
527b6458 5352 Fredraw_frame (w->frame);
44fa5b1e 5353 SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
6df47b59 5354 center_p = 1;
7ab12479 5355 }
413430c5 5356 else if (CONSP (arg)) /* Just C-u. */
6df47b59 5357 center_p = 1;
7ab12479
JB
5358 else
5359 {
413430c5 5360 arg = Fprefix_numeric_value (arg);
b7826503 5361 CHECK_NUMBER (arg);
ae12ecd7 5362 iarg = XINT (arg);
7ab12479
JB
5363 }
5364
478292ed 5365 set_buffer_internal (buf);
7ab12479 5366
f6b43440
RS
5367 /* Do this after making BUF current
5368 in case scroll_margin is buffer-local. */
5369 this_scroll_margin = max (0, scroll_margin);
5370 this_scroll_margin = min (this_scroll_margin,
5371 XFASTINT (w->total_lines) / 4);
5372
521b203e 5373 /* Handle centering on a graphical frame specially. Such frames can
6df47b59
GM
5374 have variable-height lines and centering point on the basis of
5375 line counts would lead to strange effects. */
521b203e 5376 if (FRAME_WINDOW_P (XFRAME (w->frame)))
6df47b59 5377 {
6df47b59
GM
5378 if (center_p)
5379 {
521b203e
GM
5380 struct it it;
5381 struct text_pos pt;
177c0ea7 5382
521b203e
GM
5383 SET_TEXT_POS (pt, PT, PT_BYTE);
5384 start_display (&it, w, pt);
f204989e 5385 move_it_vertically_backward (&it, window_box_height (w) / 2);
521b203e
GM
5386 charpos = IT_CHARPOS (it);
5387 bytepos = IT_BYTEPOS (it);
6df47b59 5388 }
f6b43440 5389 else if (iarg < 0)
6df47b59 5390 {
521b203e
GM
5391 struct it it;
5392 struct text_pos pt;
f6b43440 5393 int nlines = -iarg;
f204989e
KS
5394 int extra_line_spacing;
5395 int h = window_box_height (w);
177c0ea7 5396
f6b43440
RS
5397 iarg = - max (-iarg, this_scroll_margin);
5398
521b203e
GM
5399 SET_TEXT_POS (pt, PT, PT_BYTE);
5400 start_display (&it, w, pt);
f204989e
KS
5401
5402 /* Be sure we have the exact height of the full line containing PT. */
5403 move_it_by_lines (&it, 0, 1);
521b203e 5404
d466fa4d 5405 /* The amount of pixels we have to move back is the window
521b203e
GM
5406 height minus what's displayed in the line containing PT,
5407 and the lines below. */
f204989e
KS
5408 it.current_y = 0;
5409 it.vpos = 0;
d466fa4d
GM
5410 move_it_by_lines (&it, nlines, 1);
5411
f204989e
KS
5412 if (it.vpos == nlines)
5413 h -= it.current_y;
5414 else
5415 {
5416 /* Last line has no newline */
5417 h -= line_bottom_y (&it);
5418 it.vpos++;
5419 }
5420
5421 /* Don't reserve space for extra line spacing of last line. */
5422 extra_line_spacing = it.max_extra_line_spacing;
d466fa4d
GM
5423
5424 /* If we can't move down NLINES lines because we hit
5425 the end of the buffer, count in some empty lines. */
5426 if (it.vpos < nlines)
f204989e
KS
5427 {
5428 nlines -= it.vpos;
5429 extra_line_spacing = it.extra_line_spacing;
5430 h -= nlines * (FRAME_LINE_HEIGHT (it.f) + extra_line_spacing);
5431 }
5432 if (h <= 0)
5433 return Qnil;
201c831a 5434
f204989e 5435 /* Now find the new top line (starting position) of the window. */
521b203e 5436 start_display (&it, w, pt);
f204989e
KS
5437 it.current_y = 0;
5438 move_it_vertically_backward (&it, h);
5439
5440 /* If extra line spacing is present, we may move too far
5441 back. This causes the last line to be only partially
5442 visible (which triggers redisplay to recenter that line
5443 in the middle), so move forward.
5444 But ignore extra line spacing on last line, as it is not
5445 considered to be part of the visible height of the line.
5446 */
5447 h += extra_line_spacing;
5448 while (-it.current_y > h)
5449 move_it_by_lines (&it, 1, 1);
5450
521b203e
GM
5451 charpos = IT_CHARPOS (it);
5452 bytepos = IT_BYTEPOS (it);
6df47b59 5453 }
521b203e
GM
5454 else
5455 {
5456 struct position pos;
f6b43440 5457
f6b43440
RS
5458 iarg = max (iarg, this_scroll_margin);
5459
5460 pos = *vmotion (PT, -iarg, w);
521b203e
GM
5461 charpos = pos.bufpos;
5462 bytepos = pos.bytepos;
5463 }
5464 }
5465 else
5466 {
5467 struct position pos;
5468 int ht = window_internal_height (w);
5469
5470 if (center_p)
a4429c5b 5471 iarg = ht / 2;
f567c488
KS
5472 else if (iarg < 0)
5473 iarg += ht;
f6b43440
RS
5474
5475 /* Don't let it get into the margin at either top or bottom. */
5476 iarg = max (iarg, this_scroll_margin);
5477 iarg = min (iarg, ht - this_scroll_margin - 1);
177c0ea7 5478
f6b43440 5479 pos = *vmotion (PT, - iarg, w);
6df47b59
GM
5480 charpos = pos.bufpos;
5481 bytepos = pos.bytepos;
5482 }
5483
5484 /* Set the new window start. */
5485 set_marker_both (w->start, w->buffer, charpos, bytepos);
2f3cad6c 5486 w->window_end_valid = Qnil;
177c0ea7 5487
95605b1b
RS
5488 w->optional_new_start = Qt;
5489
6df47b59
GM
5490 if (bytepos == BEGV_BYTE || FETCH_BYTE (bytepos - 1) == '\n')
5491 w->start_at_line_beg = Qt;
5492 else
5493 w->start_at_line_beg = Qnil;
177c0ea7 5494
478292ed 5495 set_buffer_internal (obuf);
7ab12479
JB
5496 return Qnil;
5497}
b7617575
GM
5498
5499
81fe0836 5500DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height,
fdb82f93
PJ
5501 0, 1, 0,
5502 doc: /* Return the height in lines of the text display area of WINDOW.
5503This doesn't include the mode-line (or header-line if any) or any
5504partial-height lines in the text display area. */)
5505 (window)
81fe0836
MB
5506 Lisp_Object window;
5507{
5508 struct window *w = decode_window (window);
5509 int pixel_height = window_box_height (w);
949cf20f 5510 int line_height = pixel_height / FRAME_LINE_HEIGHT (XFRAME (w->frame));
81fe0836
MB
5511 return make_number (line_height);
5512}
5513
5514
7ab12479
JB
5515\f
5516DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
fdb82f93
PJ
5517 1, 1, "P",
5518 doc: /* Position point relative to window.
5519With no argument, position point at center of window.
5520An argument specifies vertical position within the window;
5521zero means top of window, negative means relative to bottom of window. */)
5522 (arg)
b7617575 5523 Lisp_Object arg;
7ab12479 5524{
b7617575
GM
5525 struct window *w = XWINDOW (selected_window);
5526 int lines, start;
540b6aa0 5527 Lisp_Object window;
f6b43440
RS
5528#if 0
5529 int this_scroll_margin;
5530#endif
7ab12479 5531
b7617575 5532 window = selected_window;
7ab12479
JB
5533 start = marker_position (w->start);
5534 if (start < BEGV || start > ZV)
5535 {
b7617575 5536 int height = window_internal_height (w);
cd2be1dd 5537 Fvertical_motion (make_number (- (height / 2)), window);
b73ea88e 5538 set_marker_both (w->start, w->buffer, PT, PT_BYTE);
7ab12479
JB
5539 w->start_at_line_beg = Fbolp ();
5540 w->force_start = Qt;
5541 }
5542 else
b73ea88e 5543 Fgoto_char (w->start);
7ab12479 5544
b7617575 5545 lines = displayed_window_lines (w);
f6b43440
RS
5546
5547#if 0
5548 this_scroll_margin = max (0, scroll_margin);
5549 this_scroll_margin = min (this_scroll_margin, lines / 4);
5550#endif
5551
b7617575
GM
5552 if (NILP (arg))
5553 XSETFASTINT (arg, lines / 2);
5554 else
5555 {
f6b43440
RS
5556 int iarg = XINT (Fprefix_numeric_value (arg));
5557
5558 if (iarg < 0)
5559 iarg = iarg + lines;
5560
5561#if 0 /* This code would prevent move-to-window-line from moving point
5562 to a place inside the scroll margins (which would cause the
5563 next redisplay to scroll). I wrote this code, but then concluded
5564 it is probably better not to install it. However, it is here
5565 inside #if 0 so as not to lose it. -- rms. */
5566
5567 /* Don't let it get into the margin at either top or bottom. */
5568 iarg = max (iarg, this_scroll_margin);
5569 iarg = min (iarg, lines - this_scroll_margin - 1);
5570#endif
5571
5572 arg = make_number (iarg);
b7617575
GM
5573 }
5574
c8bc6f65 5575 /* Skip past a partially visible first line. */
163784df 5576 if (w->vscroll)
163784df
MB
5577 XSETINT (arg, XINT (arg) + 1);
5578
540b6aa0 5579 return Fvertical_motion (arg, window);
7ab12479 5580}
5500c422
GM
5581
5582
7ab12479 5583\f
5500c422
GM
5584/***********************************************************************
5585 Window Configuration
5586 ***********************************************************************/
5587
7ab12479
JB
5588struct save_window_data
5589 {
f5ccc0cc 5590 EMACS_INT size_from_Lisp_Vector_struct;
7ab12479 5591 struct Lisp_Vector *next_from_Lisp_Vector_struct;
949cf20f 5592 Lisp_Object frame_cols, frame_lines, frame_menu_bar_lines;
9ea173e8 5593 Lisp_Object frame_tool_bar_lines;
bdc727bf 5594 Lisp_Object selected_frame;
7ab12479
JB
5595 Lisp_Object current_window;
5596 Lisp_Object current_buffer;
5597 Lisp_Object minibuf_scroll_window;
3f49fddc 5598 Lisp_Object minibuf_selected_window;
7ab12479 5599 Lisp_Object root_window;
bdc727bf 5600 Lisp_Object focus_frame;
756b6edc
RS
5601 /* Record the values of window-min-width and window-min-height
5602 so that window sizes remain consistent with them. */
5603 Lisp_Object min_width, min_height;
cbff28e8
RS
5604 /* A vector, each of whose elements is a struct saved_window
5605 for one window. */
7ab12479
JB
5606 Lisp_Object saved_windows;
5607 };
ff06df24 5608
cbff28e8 5609/* This is saved as a Lisp_Vector */
7ab12479 5610struct saved_window
ea68264b
GM
5611{
5612 /* these first two must agree with struct Lisp_Vector in lisp.h */
5613 EMACS_INT size_from_Lisp_Vector_struct;
5614 struct Lisp_Vector *next_from_Lisp_Vector_struct;
7ab12479 5615
ea68264b
GM
5616 Lisp_Object window;
5617 Lisp_Object buffer, start, pointm, mark;
949cf20f
KS
5618 Lisp_Object left_col, top_line, total_cols, total_lines;
5619 Lisp_Object hscroll, min_hscroll;
ea68264b
GM
5620 Lisp_Object parent, prev;
5621 Lisp_Object start_at_line_beg;
5622 Lisp_Object display_table;
949cf20f
KS
5623 Lisp_Object orig_top_line, orig_total_lines;
5624 Lisp_Object left_margin_cols, right_margin_cols;
5625 Lisp_Object left_fringe_width, right_fringe_width, fringes_outside_margins;
5626 Lisp_Object scroll_bar_width, vertical_scroll_bar_type;
ea68264b
GM
5627};
5628
7ab12479
JB
5629#define SAVED_WINDOW_N(swv,n) \
5630 ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
5631
5632DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
fdb82f93
PJ
5633 doc: /* Return t if OBJECT is a window-configuration object. */)
5634 (object)
413430c5 5635 Lisp_Object object;
7ab12479 5636{
413430c5 5637 if (WINDOW_CONFIGURATIONP (object))
7ab12479
JB
5638 return Qt;
5639 return Qnil;
5640}
5641
3f8ab7bd 5642DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
fdb82f93
PJ
5643 doc: /* Return the frame that CONFIG, a window-configuration object, is about. */)
5644 (config)
3f8ab7bd
RS
5645 Lisp_Object config;
5646{
5647 register struct save_window_data *data;
5648 struct Lisp_Vector *saved_windows;
5649
5650 if (! WINDOW_CONFIGURATIONP (config))
5651 wrong_type_argument (Qwindow_configuration_p, config);
5652
5653 data = (struct save_window_data *) XVECTOR (config);
5654 saved_windows = XVECTOR (data->saved_windows);
5655 return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
5656}
5657
d5b2799e 5658DEFUN ("set-window-configuration", Fset_window_configuration,
fdb82f93
PJ
5659 Sset_window_configuration, 1, 1, 0,
5660 doc: /* Set the configuration of windows and buffers as specified by CONFIGURATION.
5661CONFIGURATION must be a value previously returned
5662by `current-window-configuration' (which see).
5663If CONFIGURATION was made from a frame that is now deleted,
5664only frame-independent values can be restored. In this case,
5665the return value is nil. Otherwise the value is t. */)
5666 (configuration)
2f83aebe 5667 Lisp_Object configuration;
7ab12479 5668{
7ab12479
JB
5669 register struct save_window_data *data;
5670 struct Lisp_Vector *saved_windows;
7ab12479 5671 Lisp_Object new_current_buffer;
fd482be5 5672 Lisp_Object frame;
44fa5b1e 5673 FRAME_PTR f;
72695e47 5674 int old_point = -1;
7ab12479 5675
017b2bad 5676 while (!WINDOW_CONFIGURATIONP (configuration))
3f8ab7bd 5677 wrong_type_argument (Qwindow_configuration_p, configuration);
7ab12479 5678
2f83aebe 5679 data = (struct save_window_data *) XVECTOR (configuration);
7ab12479
JB
5680 saved_windows = XVECTOR (data->saved_windows);
5681
7ab12479 5682 new_current_buffer = data->current_buffer;
265a9e55 5683 if (NILP (XBUFFER (new_current_buffer)->name))
7ab12479 5684 new_current_buffer = Qnil;
72695e47 5685 else
73cadfc1
DK
5686 {
5687 if (XBUFFER (new_current_buffer) == current_buffer)
5688 old_point = PT;
5689 else
203eb0aa
SM
5690 /* BUF_PT (XBUFFER (new_current_buffer)) gives us the position of
5691 point in new_current_buffer as of the last time this buffer was
5692 used. This can be non-deterministic since it can be changed by
5693 things like jit-lock by mere temporary selection of some random
5694 window that happens to show this buffer.
5695 So if possible we want this arbitrary choice of "which point" to
5696 be the one from the to-be-selected-window so as to prevent this
5697 window's cursor from being copied from another window. */
5698 if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer)
5699 /* If current_window = selected_window, its point is in BUF_PT. */
5700 && !EQ (selected_window, data->current_window))
5701 old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos;
5702 else
5703 old_point = BUF_PT (XBUFFER (new_current_buffer));
73cadfc1 5704 }
7ab12479 5705
fd482be5
JB
5706 frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
5707 f = XFRAME (frame);
177c0ea7 5708
fd482be5
JB
5709 /* If f is a dead frame, don't bother rebuilding its window tree.
5710 However, there is other stuff we should still try to do below. */
5711 if (FRAME_LIVE_P (f))
7ab12479 5712 {
fd482be5
JB
5713 register struct window *w;
5714 register struct saved_window *p;
5500c422
GM
5715 struct window *root_window;
5716 struct window **leaf_windows;
5717 int n_leaf_windows;
c4280705 5718 int k, i, n;
fd482be5
JB
5719
5720 /* If the frame has been resized since this window configuration was
5721 made, we change the frame to the size specified in the
5722 configuration, restore the configuration, and then resize it
5723 back. We keep track of the prevailing height in these variables. */
949cf20f
KS
5724 int previous_frame_lines = FRAME_LINES (f);
5725 int previous_frame_cols = FRAME_COLS (f);
8f6ea2e9 5726 int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
9ea173e8 5727 int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
fd482be5 5728
d2b35234
RS
5729 /* The mouse highlighting code could get screwed up
5730 if it runs during this. */
5731 BLOCK_INPUT;
5732
949cf20f
KS
5733 if (XFASTINT (data->frame_lines) != previous_frame_lines
5734 || XFASTINT (data->frame_cols) != previous_frame_cols)
5735 change_frame_size (f, XFASTINT (data->frame_lines),
5736 XFASTINT (data->frame_cols), 0, 0, 0);
e3678b64 5737#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
8f6ea2e9
KH
5738 if (XFASTINT (data->frame_menu_bar_lines)
5739 != previous_frame_menu_bar_lines)
f8ad443a 5740 x_set_menu_bar_lines (f, data->frame_menu_bar_lines, make_number (0));
4314246f 5741#ifdef HAVE_WINDOW_SYSTEM
9ea173e8
GM
5742 if (XFASTINT (data->frame_tool_bar_lines)
5743 != previous_frame_tool_bar_lines)
5744 x_set_tool_bar_lines (f, data->frame_tool_bar_lines, make_number (0));
4314246f 5745#endif
217f2871 5746#endif
fd482be5 5747
a46c0153
RS
5748 /* "Swap out" point from the selected window's buffer
5749 into the window itself. (Normally the pointm of the selected
5750 window holds garbage.) We do this now, before
719eaeb1
GM
5751 restoring the window contents, and prevent it from
5752 being done later on when we select a new window. */
596ae0cf
RS
5753 if (! NILP (XWINDOW (selected_window)->buffer))
5754 {
5755 w = XWINDOW (selected_window);
5756 set_marker_both (w->pointm,
5757 w->buffer,
5758 BUF_PT (XBUFFER (w->buffer)),
5759 BUF_PT_BYTE (XBUFFER (w->buffer)));
5760 }
5761
fd482be5 5762 windows_or_buffers_changed++;
29aeee73 5763 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
fd482be5 5764
5500c422 5765 /* Problem: Freeing all matrices and later allocating them again
177c0ea7 5766 is a serious redisplay flickering problem. What we would
5500c422
GM
5767 really like to do is to free only those matrices not reused
5768 below. */
5769 root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
5770 leaf_windows
5771 = (struct window **) alloca (count_windows (root_window)
5772 * sizeof (struct window *));
5773 n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
5774
756b6edc
RS
5775 /* Temporarily avoid any problems with windows that are smaller
5776 than they are supposed to be. */
5777 window_min_height = 1;
5778 window_min_width = 1;
5779
fd482be5
JB
5780 /* Kludge Alert!
5781 Mark all windows now on frame as "deleted".
5782 Restoring the new configuration "undeletes" any that are in it.
37962e60 5783
fd482be5
JB
5784 Save their current buffers in their height fields, since we may
5785 need it later, if a buffer saved in the configuration is now
5786 dead. */
5787 delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
5788
5789 for (k = 0; k < saved_windows->size; k++)
5790 {
5791 p = SAVED_WINDOW_N (saved_windows, k);
5792 w = XWINDOW (p->window);
5793 w->next = Qnil;
7ab12479 5794
fd482be5
JB
5795 if (!NILP (p->parent))
5796 w->parent = SAVED_WINDOW_N (saved_windows,
5797 XFASTINT (p->parent))->window;
5798 else
5799 w->parent = Qnil;
7ab12479 5800
fd482be5 5801 if (!NILP (p->prev))
7ab12479 5802 {
fd482be5
JB
5803 w->prev = SAVED_WINDOW_N (saved_windows,
5804 XFASTINT (p->prev))->window;
5805 XWINDOW (w->prev)->next = p->window;
5806 }
5807 else
5808 {
5809 w->prev = Qnil;
5810 if (!NILP (w->parent))
5811 {
949cf20f 5812 if (EQ (p->total_cols, XWINDOW (w->parent)->total_cols))
fd482be5
JB
5813 {
5814 XWINDOW (w->parent)->vchild = p->window;
5815 XWINDOW (w->parent)->hchild = Qnil;
5816 }
5817 else
5818 {
5819 XWINDOW (w->parent)->hchild = p->window;
5820 XWINDOW (w->parent)->vchild = Qnil;
5821 }
5822 }
5823 }
5824
5825 /* If we squirreled away the buffer in the window's height,
5826 restore it now. */
949cf20f
KS
5827 if (BUFFERP (w->total_lines))
5828 w->buffer = w->total_lines;
5829 w->left_col = p->left_col;
5830 w->top_line = p->top_line;
5831 w->total_cols = p->total_cols;
5832 w->total_lines = p->total_lines;
fd482be5 5833 w->hscroll = p->hscroll;
ea68264b 5834 w->min_hscroll = p->min_hscroll;
fd482be5 5835 w->display_table = p->display_table;
949cf20f
KS
5836 w->orig_top_line = p->orig_top_line;
5837 w->orig_total_lines = p->orig_total_lines;
5838 w->left_margin_cols = p->left_margin_cols;
5839 w->right_margin_cols = p->right_margin_cols;
5840 w->left_fringe_width = p->left_fringe_width;
5841 w->right_fringe_width = p->right_fringe_width;
5842 w->fringes_outside_margins = p->fringes_outside_margins;
5843 w->scroll_bar_width = p->scroll_bar_width;
5844 w->vertical_scroll_bar_type = p->vertical_scroll_bar_type;
d834a2e9 5845 XSETFASTINT (w->last_modified, 0);
3cd21523 5846 XSETFASTINT (w->last_overlay_modified, 0);
fd482be5
JB
5847
5848 /* Reinstall the saved buffer and pointers into it. */
5849 if (NILP (p->buffer))
5850 w->buffer = p->buffer;
5851 else
5852 {
5853 if (!NILP (XBUFFER (p->buffer)->name))
5854 /* If saved buffer is alive, install it. */
5855 {
5856 w->buffer = p->buffer;
5857 w->start_at_line_beg = p->start_at_line_beg;
b73ea88e
RS
5858 set_marker_restricted (w->start, p->start, w->buffer);
5859 set_marker_restricted (w->pointm, p->pointm, w->buffer);
fd482be5 5860 Fset_marker (XBUFFER (w->buffer)->mark,
b73ea88e 5861 p->mark, w->buffer);
fd482be5
JB
5862
5863 /* As documented in Fcurrent_window_configuration, don't
243a5ce6
RS
5864 restore the location of point in the buffer which was
5865 current when the window configuration was recorded. */
6b54027b
RS
5866 if (!EQ (p->buffer, new_current_buffer)
5867 && XBUFFER (p->buffer) == current_buffer)
fd482be5
JB
5868 Fgoto_char (w->pointm);
5869 }
52a68e98
RS
5870 else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
5871 /* Else unless window has a live buffer, get one. */
7ab12479 5872 {
fd482be5
JB
5873 w->buffer = Fcdr (Fcar (Vbuffer_alist));
5874 /* This will set the markers to beginning of visible
5875 range. */
5876 set_marker_restricted (w->start, make_number (0), w->buffer);
5877 set_marker_restricted (w->pointm, make_number (0),w->buffer);
5878 w->start_at_line_beg = Qt;
7ab12479
JB
5879 }
5880 else
fd482be5 5881 /* Keeping window's old buffer; make sure the markers
52a68e98 5882 are real. */
7ab12479 5883 {
fd482be5
JB
5884 /* Set window markers at start of visible range. */
5885 if (XMARKER (w->start)->buffer == 0)
5886 set_marker_restricted (w->start, make_number (0),
5887 w->buffer);
5888 if (XMARKER (w->pointm)->buffer == 0)
b73ea88e
RS
5889 set_marker_restricted_both (w->pointm, w->buffer,
5890 BUF_PT (XBUFFER (w->buffer)),
5891 BUF_PT_BYTE (XBUFFER (w->buffer)));
fd482be5 5892 w->start_at_line_beg = Qt;
7ab12479
JB
5893 }
5894 }
5895 }
9ace597f 5896
fd482be5 5897 FRAME_ROOT_WINDOW (f) = data->root_window;
719eaeb1
GM
5898 /* Prevent "swapping out point" in the old selected window
5899 using the buffer that has been restored into it.
a46c0153 5900 We already swapped out point that from that window's old buffer. */
719eaeb1 5901 selected_window = Qnil;
a46c0153
RS
5902
5903 /* Arrange *not* to restore point in the buffer that was
5904 current when the window configuration was saved. */
243a5ce6
RS
5905 if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer))
5906 set_marker_restricted (XWINDOW (data->current_window)->pointm,
18787f5e 5907 make_number (old_point),
243a5ce6 5908 XWINDOW (data->current_window)->buffer);
177c0ea7 5909
14d87dc9 5910 Fselect_window (data->current_window, Qnil);
396a830c
RS
5911 XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
5912 = selected_window;
7ab12479 5913
db269683 5914 if (NILP (data->focus_frame)
017b2bad 5915 || (FRAMEP (data->focus_frame)
db269683
JB
5916 && FRAME_LIVE_P (XFRAME (data->focus_frame))))
5917 Fredirect_frame_focus (frame, data->focus_frame);
7ab12479 5918
fd482be5
JB
5919#if 0 /* I don't understand why this is needed, and it causes problems
5920 when the frame's old selected window has been deleted. */
e4e59717 5921 if (f != selected_frame && FRAME_WINDOW_P (f))
9a7c6fc3 5922 do_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)),
d12f6f83 5923 0, 0);
fd482be5
JB
5924#endif
5925
5926 /* Set the screen height to the value it had before this function. */
949cf20f
KS
5927 if (previous_frame_lines != FRAME_LINES (f)
5928 || previous_frame_cols != FRAME_COLS (f))
5929 change_frame_size (f, previous_frame_lines, previous_frame_cols,
2b653806 5930 0, 0, 0);
e3678b64 5931#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
8f6ea2e9 5932 if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
f8ad443a
AS
5933 x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
5934 make_number (0));
4314246f 5935#ifdef HAVE_WINDOW_SYSTEM
9ea173e8
GM
5936 if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
5937 x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
5938 make_number (0));
4314246f 5939#endif
217f2871 5940#endif
d2b35234 5941
5500c422 5942 /* Now, free glyph matrices in windows that were not reused. */
c4280705
GM
5943 for (i = n = 0; i < n_leaf_windows; ++i)
5944 {
5945 if (NILP (leaf_windows[i]->buffer))
5946 {
5947 /* Assert it's not reused as a combination. */
177c0ea7 5948 xassert (NILP (leaf_windows[i]->hchild)
c4280705
GM
5949 && NILP (leaf_windows[i]->vchild));
5950 free_window_matrices (leaf_windows[i]);
c4280705
GM
5951 }
5952 else if (EQ (leaf_windows[i]->buffer, new_current_buffer))
5953 ++n;
5954 }
177c0ea7 5955
5500c422
GM
5956 adjust_glyphs (f);
5957
d2b35234 5958 UNBLOCK_INPUT;
756b6edc 5959
478292ed
RS
5960 /* Fselect_window will have made f the selected frame, so we
5961 reselect the proper frame here. Fhandle_switch_frame will change the
5962 selected window too, but that doesn't make the call to
5963 Fselect_window above totally superfluous; it still sets f's
5964 selected window. */
5965 if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
d12f6f83 5966 do_switch_frame (data->selected_frame, 0, 0);
478292ed
RS
5967
5968 if (! NILP (Vwindow_configuration_change_hook)
5969 && ! NILP (Vrun_hooks))
5970 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
5971 }
bdc727bf
JB
5972
5973 if (!NILP (new_current_buffer))
243a5ce6 5974 Fset_buffer (new_current_buffer);
bdc727bf 5975
478292ed
RS
5976 /* Restore the minimum heights recorded in the configuration. */
5977 window_min_height = XINT (data->min_height);
5978 window_min_width = XINT (data->min_width);
543f5fb1 5979
478292ed 5980 Vminibuf_scroll_window = data->minibuf_scroll_window;
3dbab091 5981 minibuf_selected_window = data->minibuf_selected_window;
543f5fb1 5982
3f8ab7bd 5983 return (FRAME_LIVE_P (f) ? Qt : Qnil);
7ab12479
JB
5984}
5985
44fa5b1e 5986/* Mark all windows now on frame as deleted
7ab12479
JB
5987 by setting their buffers to nil. */
5988
fd482be5 5989void
7ab12479
JB
5990delete_all_subwindows (w)
5991 register struct window *w;
5992{
265a9e55 5993 if (!NILP (w->next))
7ab12479 5994 delete_all_subwindows (XWINDOW (w->next));
265a9e55 5995 if (!NILP (w->vchild))
7ab12479 5996 delete_all_subwindows (XWINDOW (w->vchild));
265a9e55 5997 if (!NILP (w->hchild))
7ab12479 5998 delete_all_subwindows (XWINDOW (w->hchild));
605be8af 5999
949cf20f 6000 w->total_lines = w->buffer; /* See Fset_window_configuration for excuse. */
605be8af 6001
86e48436
RS
6002 if (!NILP (w->buffer))
6003 unshow_buffer (w);
6004
605be8af
JB
6005 /* We set all three of these fields to nil, to make sure that we can
6006 distinguish this dead window from any live window. Live leaf
6007 windows will have buffer set, and combination windows will have
6008 vchild or hchild set. */
6009 w->buffer = Qnil;
6010 w->vchild = Qnil;
6011 w->hchild = Qnil;
acf70840
GM
6012
6013 Vwindow_list = Qnil;
7ab12479
JB
6014}
6015\f
6016static int
6017count_windows (window)
6018 register struct window *window;
6019{
6020 register int count = 1;
265a9e55 6021 if (!NILP (window->next))
7ab12479 6022 count += count_windows (XWINDOW (window->next));
265a9e55 6023 if (!NILP (window->vchild))
7ab12479 6024 count += count_windows (XWINDOW (window->vchild));
265a9e55 6025 if (!NILP (window->hchild))
7ab12479
JB
6026 count += count_windows (XWINDOW (window->hchild));
6027 return count;
6028}
6029
5500c422 6030
177c0ea7 6031/* Fill vector FLAT with leaf windows under W, starting at index I.
5500c422
GM
6032 Value is last index + 1. */
6033
6034static int
6035get_leaf_windows (w, flat, i)
6036 struct window *w;
6037 struct window **flat;
6038 int i;
6039{
6040 while (w)
6041 {
6042 if (!NILP (w->hchild))
6043 i = get_leaf_windows (XWINDOW (w->hchild), flat, i);
6044 else if (!NILP (w->vchild))
6045 i = get_leaf_windows (XWINDOW (w->vchild), flat, i);
177c0ea7 6046 else
5500c422
GM
6047 flat[i++] = w;
6048
6049 w = NILP (w->next) ? 0 : XWINDOW (w->next);
6050 }
6051
6052 return i;
6053}
6054
6055
6056/* Return a pointer to the glyph W's physical cursor is on. Value is
6057 null if W's current matrix is invalid, so that no meaningfull glyph
6058 can be returned. */
6059
6060struct glyph *
6061get_phys_cursor_glyph (w)
6062 struct window *w;
6063{
6064 struct glyph_row *row;
6065 struct glyph *glyph;
6066
6067 if (w->phys_cursor.vpos >= 0
6068 && w->phys_cursor.vpos < w->current_matrix->nrows
6069 && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
6070 row->enabled_p)
6071 && row->used[TEXT_AREA] > w->phys_cursor.hpos)
6072 glyph = row->glyphs[TEXT_AREA] + w->phys_cursor.hpos;
6073 else
6074 glyph = NULL;
6075
6076 return glyph;
6077}
6078
6079
7ab12479
JB
6080static int
6081save_window_save (window, vector, i)
6082 Lisp_Object window;
6083 struct Lisp_Vector *vector;
6084 int i;
6085{
6086 register struct saved_window *p;
6087 register struct window *w;
6088 register Lisp_Object tem;
6089
265a9e55 6090 for (;!NILP (window); window = w->next)
7ab12479
JB
6091 {
6092 p = SAVED_WINDOW_N (vector, i);
6093 w = XWINDOW (window);
6094
2a1893f4 6095 XSETFASTINT (w->temslot, i); i++;
7ab12479
JB
6096 p->window = window;
6097 p->buffer = w->buffer;
949cf20f
KS
6098 p->left_col = w->left_col;
6099 p->top_line = w->top_line;
6100 p->total_cols = w->total_cols;
6101 p->total_lines = w->total_lines;
7ab12479 6102 p->hscroll = w->hscroll;
ea68264b 6103 p->min_hscroll = w->min_hscroll;
7ab12479 6104 p->display_table = w->display_table;
949cf20f
KS
6105 p->orig_top_line = w->orig_top_line;
6106 p->orig_total_lines = w->orig_total_lines;
6107 p->left_margin_cols = w->left_margin_cols;
6108 p->right_margin_cols = w->right_margin_cols;
6109 p->left_fringe_width = w->left_fringe_width;
6110 p->right_fringe_width = w->right_fringe_width;
6111 p->fringes_outside_margins = w->fringes_outside_margins;
6112 p->scroll_bar_width = w->scroll_bar_width;
6113 p->vertical_scroll_bar_type = w->vertical_scroll_bar_type;
265a9e55 6114 if (!NILP (w->buffer))
7ab12479
JB
6115 {
6116 /* Save w's value of point in the window configuration.
6117 If w is the selected window, then get the value of point
6118 from the buffer; pointm is garbage in the selected window. */
6119 if (EQ (window, selected_window))
6120 {
6121 p->pointm = Fmake_marker ();
b73ea88e
RS
6122 set_marker_both (p->pointm, w->buffer,
6123 BUF_PT (XBUFFER (w->buffer)),
6124 BUF_PT_BYTE (XBUFFER (w->buffer)));
7ab12479
JB
6125 }
6126 else
eeb82665 6127 p->pointm = Fcopy_marker (w->pointm, Qnil);
7ab12479 6128
eeb82665 6129 p->start = Fcopy_marker (w->start, Qnil);
7ab12479
JB
6130 p->start_at_line_beg = w->start_at_line_beg;
6131
6132 tem = XBUFFER (w->buffer)->mark;
eeb82665 6133 p->mark = Fcopy_marker (tem, Qnil);
7ab12479
JB
6134 }
6135 else
6136 {
6137 p->pointm = Qnil;
6138 p->start = Qnil;
6139 p->mark = Qnil;
6140 p->start_at_line_beg = Qnil;
6141 }
6142
265a9e55 6143 if (NILP (w->parent))
7ab12479
JB
6144 p->parent = Qnil;
6145 else
6146 p->parent = XWINDOW (w->parent)->temslot;
6147
265a9e55 6148 if (NILP (w->prev))
7ab12479
JB
6149 p->prev = Qnil;
6150 else
6151 p->prev = XWINDOW (w->prev)->temslot;
6152
265a9e55 6153 if (!NILP (w->vchild))
7ab12479 6154 i = save_window_save (w->vchild, vector, i);
265a9e55 6155 if (!NILP (w->hchild))
7ab12479
JB
6156 i = save_window_save (w->hchild, vector, i);
6157 }
6158
6159 return i;
6160}
6161
a0d76c27 6162DEFUN ("current-window-configuration", Fcurrent_window_configuration,
fdb82f93
PJ
6163 Scurrent_window_configuration, 0, 1, 0,
6164 doc: /* Return an object representing the current window configuration of FRAME.
6165If FRAME is nil or omitted, use the selected frame.
6166This describes the number of windows, their sizes and current buffers,
6167and for each displayed buffer, where display starts, and the positions of
6168point and mark. An exception is made for point in the current buffer:
6169its value is -not- saved.
6170This also records the currently selected frame, and FRAME's focus
6171redirection (see `redirect-frame-focus'). */)
6172 (frame)
44fa5b1e 6173 Lisp_Object frame;
7ab12479
JB
6174{
6175 register Lisp_Object tem;
6176 register int n_windows;
6177 register struct save_window_data *data;
da2792e0 6178 register struct Lisp_Vector *vec;
7ab12479 6179 register int i;
44fa5b1e 6180 FRAME_PTR f;
43bad991 6181
44fa5b1e 6182 if (NILP (frame))
1ae1a37d 6183 frame = selected_frame;
b7826503 6184 CHECK_LIVE_FRAME (frame);
1ae1a37d 6185 f = XFRAME (frame);
7ab12479 6186
44fa5b1e 6187 n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
26605be9 6188 vec = allocate_other_vector (VECSIZE (struct save_window_data));
da2792e0
KH
6189 data = (struct save_window_data *)vec;
6190
949cf20f
KS
6191 XSETFASTINT (data->frame_cols, FRAME_COLS (f));
6192 XSETFASTINT (data->frame_lines, FRAME_LINES (f));
d834a2e9 6193 XSETFASTINT (data->frame_menu_bar_lines, FRAME_MENU_BAR_LINES (f));
9ea173e8 6194 XSETFASTINT (data->frame_tool_bar_lines, FRAME_TOOL_BAR_LINES (f));
1ae1a37d 6195 data->selected_frame = selected_frame;
44fa5b1e 6196 data->current_window = FRAME_SELECTED_WINDOW (f);
74112613 6197 XSETBUFFER (data->current_buffer, current_buffer);
3f49fddc 6198 data->minibuf_scroll_window = minibuf_level > 0 ? Vminibuf_scroll_window : Qnil;
3dbab091 6199 data->minibuf_selected_window = minibuf_level > 0 ? minibuf_selected_window : Qnil;
44fa5b1e 6200 data->root_window = FRAME_ROOT_WINDOW (f);
bdc727bf 6201 data->focus_frame = FRAME_FOCUS_FRAME (f);
74112613
KH
6202 XSETINT (data->min_height, window_min_height);
6203 XSETINT (data->min_width, window_min_width);
7ab12479
JB
6204 tem = Fmake_vector (make_number (n_windows), Qnil);
6205 data->saved_windows = tem;
6206 for (i = 0; i < n_windows; i++)
6207 XVECTOR (tem)->contents[i]
8a450f0a 6208 = Fmake_vector (make_number (VECSIZE (struct saved_window)), Qnil);
a1d58e5b 6209 save_window_save (FRAME_ROOT_WINDOW (f), XVECTOR (tem), 0);
74112613 6210 XSETWINDOW_CONFIGURATION (tem, data);
7ab12479
JB
6211 return (tem);
6212}
6213
6214DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
fdb82f93 6215 0, UNEVALLED, 0,
a0a37a6f
LT
6216 doc: /* Execute BODY, preserving window sizes and contents.
6217Return the value of the last form in BODY.
fdb82f93
PJ
6218Restore which buffer appears in which window, where display starts,
6219and the value of point and mark for each window.
6220Also restore the choice of selected window.
6221Also restore which buffer is current.
6924dda6
MB
6222Does not restore the value of point in current buffer.
6223usage: (save-window-excursion BODY ...) */)
fdb82f93 6224 (args)
7ab12479
JB
6225 Lisp_Object args;
6226{
6227 register Lisp_Object val;
aed13378 6228 register int count = SPECPDL_INDEX ();
7ab12479
JB
6229
6230 record_unwind_protect (Fset_window_configuration,
43bad991 6231 Fcurrent_window_configuration (Qnil));
7ab12479
JB
6232 val = Fprogn (args);
6233 return unbind_to (count, val);
6234}
5500c422 6235
94e16dd5
KS
6236
6237\f
6238/***********************************************************************
6239 Window Split Tree
6240 ***********************************************************************/
6241
6242static Lisp_Object
c16e1cc3 6243window_tree (w)
94e16dd5
KS
6244 struct window *w;
6245{
6246 Lisp_Object tail = Qnil;
6247 Lisp_Object result = Qnil;
6248
6249 while (w)
6250 {
6251 Lisp_Object wn;
6252
6253 XSETWINDOW (wn, w);
6254 if (!NILP (w->hchild))
6255 wn = Fcons (Qnil, Fcons (Fwindow_edges (wn),
c16e1cc3 6256 window_tree (XWINDOW (w->hchild))));
94e16dd5
KS
6257 else if (!NILP (w->vchild))
6258 wn = Fcons (Qt, Fcons (Fwindow_edges (wn),
c16e1cc3 6259 window_tree (XWINDOW (w->vchild))));
94e16dd5
KS
6260
6261 if (NILP (result))
6262 {
6263 result = tail = Fcons (wn, Qnil);
6264 }
6265 else
6266 {
6267 XSETCDR (tail, Fcons (wn, Qnil));
6268 tail = XCDR (tail);
6269 }
6270
6271 w = NILP (w->next) ? 0 : XWINDOW (w->next);
6272 }
6273
6274 return result;
6275}
6276
6277
6278
c16e1cc3 6279DEFUN ("window-tree", Fwindow_tree, Swindow_tree,
94e16dd5 6280 0, 1, 0,
c16e1cc3 6281 doc: /* Return the window tree for frame FRAME.
94e16dd5
KS
6282
6283The return value is a list of the form (ROOT MINI), where ROOT
c16e1cc3 6284represents the window tree of the frame's root window, and MINI
94e16dd5
KS
6285is the frame's minibuffer window.
6286
6287If the root window is not split, ROOT is the root window itself.
6288Otherwise, ROOT is a list (DIR EDGES W1 W2 ...) where DIR is nil for a
008171a4 6289horizontal split, and t for a vertical split, EDGES gives the combined
94e16dd5
KS
6290size and position of the subwindows in the split, and the rest of the
6291elements are the subwindows in the split. Each of the subwindows may
6292again be a window or a list representing a window split, and so on.
6293EDGES is a list \(LEFT TOP RIGHT BOTTOM) as returned by `window-edges'.
6294
6295If FRAME is nil or omitted, return information on the currently
6296selected frame. */)
6297 (frame)
6298 Lisp_Object frame;
6299{
94e16dd5
KS
6300 FRAME_PTR f;
6301
6302 if (NILP (frame))
6303 frame = selected_frame;
6304
6305 CHECK_FRAME (frame);
6306 f = XFRAME (frame);
6307
6308 if (!FRAME_LIVE_P (f))
6309 return Qnil;
6310
c16e1cc3 6311 return window_tree (XWINDOW (FRAME_ROOT_WINDOW (f)));
94e16dd5
KS
6312}
6313
5500c422
GM
6314\f
6315/***********************************************************************
6316 Marginal Areas
6317 ***********************************************************************/
6318
6319DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
a7bdfc08 6320 2, 3, 0,
fdb82f93 6321 doc: /* Set width of marginal areas of window WINDOW.
e661376d
KS
6322If WINDOW is nil, set margins of the currently selected window.
6323Second arg LEFT-WIDTH specifies the number of character cells to
6324reserve for the left marginal area. Optional third arg RIGHT-WIDTH
6325does the same for the right marginal area. A nil width parameter
6326means no margin. */)
c10ce82e
JB
6327 (window, left_width, right_width)
6328 Lisp_Object window, left_width, right_width;
5500c422
GM
6329{
6330 struct window *w = decode_window (window);
5500c422 6331
c2c3f202
KS
6332 /* Translate negative or zero widths to nil.
6333 Margins that are too wide have to be checked elsewhere. */
6334
c10ce82e 6335 if (!NILP (left_width))
c2c3f202 6336 {
c10ce82e
JB
6337 CHECK_NUMBER (left_width);
6338 if (XINT (left_width) <= 0)
6339 left_width = Qnil;
c2c3f202 6340 }
5500c422 6341
c10ce82e 6342 if (!NILP (right_width))
c2c3f202 6343 {
c10ce82e
JB
6344 CHECK_NUMBER (right_width);
6345 if (XINT (right_width) <= 0)
6346 right_width = Qnil;
c2c3f202 6347 }
5500c422 6348
c10ce82e
JB
6349 if (!EQ (w->left_margin_cols, left_width)
6350 || !EQ (w->right_margin_cols, right_width))
949cf20f 6351 {
c10ce82e
JB
6352 w->left_margin_cols = left_width;
6353 w->right_margin_cols = right_width;
949cf20f
KS
6354
6355 adjust_window_margins (w);
6356
6357 ++windows_or_buffers_changed;
6358 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6359 }
5500c422 6360
5500c422
GM
6361 return Qnil;
6362}
6363
6364
6365DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
6366 0, 1, 0,
fdb82f93
PJ
6367 doc: /* Get width of marginal areas of window WINDOW.
6368If WINDOW is omitted or nil, use the currently selected window.
6369Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).
6370If a marginal area does not exist, its width will be returned
6371as nil. */)
6372 (window)
5500c422
GM
6373 Lisp_Object window;
6374{
6375 struct window *w = decode_window (window);
949cf20f
KS
6376 return Fcons (w->left_margin_cols, w->right_margin_cols);
6377}
6378
6379
6380\f
6381/***********************************************************************
6382 Fringes
6383 ***********************************************************************/
6384
6385DEFUN ("set-window-fringes", Fset_window_fringes, Sset_window_fringes,
6386 2, 4, 0,
62c2f759 6387 doc: /* Set the fringe widths of window WINDOW.
62c2f759
LK
6388If WINDOW is nil, set the fringe widths of the currently selected
6389window.
e661376d
KS
6390Second arg LEFT-WIDTH specifies the number of pixels to reserve for
6391the left fringe. Optional third arg RIGHT-WIDTH specifies the right
6392fringe width. If a fringe width arg is nil, that means to use the
6393frame's default fringe width. Default fringe widths can be set with
6394the command `set-fringe-style'.
6395If optional fourth arg OUTSIDE-MARGINS is non-nil, draw the fringes
62c2f759
LK
6396outside of the display margins. By default, fringes are drawn between
6397display marginal areas and the text area. */)
c10ce82e
JB
6398 (window, left_width, right_width, outside_margins)
6399 Lisp_Object window, left_width, right_width, outside_margins;
949cf20f
KS
6400{
6401 struct window *w = decode_window (window);
6402
c10ce82e
JB
6403 if (!NILP (left_width))
6404 CHECK_NATNUM (left_width);
6405 if (!NILP (right_width))
6406 CHECK_NATNUM (right_width);
949cf20f 6407
c10ce82e
JB
6408 if (!EQ (w->left_fringe_width, left_width)
6409 || !EQ (w->right_fringe_width, right_width)
949cf20f
KS
6410 || !EQ (w->fringes_outside_margins, outside_margins))
6411 {
c10ce82e
JB
6412 w->left_fringe_width = left_width;
6413 w->right_fringe_width = right_width;
949cf20f
KS
6414 w->fringes_outside_margins = outside_margins;
6415
6416 adjust_window_margins (w);
6417
6418 clear_glyph_matrix (w->current_matrix);
6419 w->window_end_valid = Qnil;
6420
6421 ++windows_or_buffers_changed;
6422 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6423 }
6424
6425 return Qnil;
6426}
6427
6428
6429DEFUN ("window-fringes", Fwindow_fringes, Swindow_fringes,
6430 0, 1, 0,
6431 doc: /* Get width of fringes of window WINDOW.
6432If WINDOW is omitted or nil, use the currently selected window.
467e281a 6433Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS). */)
949cf20f
KS
6434 (window)
6435 Lisp_Object window;
6436{
6437 struct window *w = decode_window (window);
6438 return Fcons (make_number (WINDOW_LEFT_FRINGE_WIDTH (w)),
6439 Fcons (make_number (WINDOW_RIGHT_FRINGE_WIDTH (w)),
6440 Fcons ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) ?
6441 Qt : Qnil), Qnil)));
6442}
6443
6444
6445\f
6446/***********************************************************************
6447 Scroll bars
6448 ***********************************************************************/
6449
6450DEFUN ("set-window-scroll-bars", Fset_window_scroll_bars, Sset_window_scroll_bars,
6451 2, 4, 0,
6452 doc: /* Set width and type of scroll bars of window WINDOW.
6453If window is nil, set scroll bars of the currently selected window.
6454Second parameter WIDTH specifies the pixel width for the scroll bar;
6455this is automatically adjusted to a multiple of the frame column width.
6456Third parameter VERTICAL-TYPE specifies the type of the vertical scroll
6457bar: left, right, or nil.
2f71b5ea
MY
6458If WIDTH is nil, use the frame's scroll-bar width.
6459If TYPE is t, use the frame's scroll-bar type. */)
79fd290e
JB
6460 (window, width, vertical_type, horizontal_type)
6461 Lisp_Object window, width, vertical_type, horizontal_type;
949cf20f
KS
6462{
6463 struct window *w = decode_window (window);
6464
6465 if (!NILP (width))
0f8fe9a2
SM
6466 {
6467 CHECK_NATNUM (width);
949cf20f 6468
0f8fe9a2
SM
6469 if (XINT (width) == 0)
6470 vertical_type = Qnil;
6471 }
949cf20f 6472
2f71b5ea 6473 if (!(EQ (vertical_type, Qnil)
0cc1039f 6474 || EQ (vertical_type, Qleft)
2f71b5ea
MY
6475 || EQ (vertical_type, Qright)
6476 || EQ (vertical_type, Qt)))
6477 error ("Invalid type of vertical scroll bar");
6478
949cf20f
KS
6479 if (!EQ (w->scroll_bar_width, width)
6480 || !EQ (w->vertical_scroll_bar_type, vertical_type))
6481 {
6482 w->scroll_bar_width = width;
6483 w->vertical_scroll_bar_type = vertical_type;
6484
6485 adjust_window_margins (w);
6486
6487 clear_glyph_matrix (w->current_matrix);
6488 w->window_end_valid = Qnil;
6489
6490 ++windows_or_buffers_changed;
6491 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6492 }
6493
6494 return Qnil;
6495}
6496
6497
6498DEFUN ("window-scroll-bars", Fwindow_scroll_bars, Swindow_scroll_bars,
6499 0, 1, 0,
6500 doc: /* Get width and type of scroll bars of window WINDOW.
6501If WINDOW is omitted or nil, use the currently selected window.
12853c58
KS
6502Value is a list of the form (WIDTH COLS VERTICAL-TYPE HORIZONTAL-TYPE).
6503If WIDTH is nil or TYPE is t, the window is using the frame's corresponding
6504value. */)
949cf20f
KS
6505 (window)
6506 Lisp_Object window;
6507{
6508 struct window *w = decode_window (window);
6509 return Fcons (make_number ((WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
6510 ? WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
6511 : WINDOW_SCROLL_BAR_AREA_WIDTH (w))),
6512 Fcons (make_number (WINDOW_SCROLL_BAR_COLS (w)),
6513 Fcons (w->vertical_scroll_bar_type,
6514 Fcons (Qnil, Qnil))));
5500c422
GM
6515}
6516
6517
7ab12479 6518\f
5500c422
GM
6519/***********************************************************************
6520 Smooth scrolling
6521 ***********************************************************************/
6522
0cc1039f 6523DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 2, 0,
fdb82f93
PJ
6524 doc: /* Return the amount by which WINDOW is scrolled vertically.
6525Use the selected window if WINDOW is nil or omitted.
0cc1039f
KS
6526Normally, value is a multiple of the canonical character height of WINDOW;
6527optional second arg PIXELS_P means value is measured in pixels. */)
6528 (window, pixels_p)
6529 Lisp_Object window, pixels_p;
5500c422 6530{
47004952 6531 Lisp_Object result;
5500c422
GM
6532 struct frame *f;
6533 struct window *w;
177c0ea7 6534
5500c422
GM
6535 if (NILP (window))
6536 window = selected_window;
47004952 6537 else
b7826503 6538 CHECK_WINDOW (window);
5500c422
GM
6539 w = XWINDOW (window);
6540 f = XFRAME (w->frame);
177c0ea7 6541
5500c422 6542 if (FRAME_WINDOW_P (f))
0cc1039f
KS
6543 result = (NILP (pixels_p)
6544 ? FRAME_CANON_Y_FROM_PIXEL_Y (f, -w->vscroll)
6545 : make_number (-w->vscroll));
5500c422 6546 else
47004952
GM
6547 result = make_number (0);
6548 return result;
5500c422
GM
6549}
6550
6551
6552DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
0cc1039f 6553 2, 3, 0,
fdb82f93 6554 doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL.
0cc1039f
KS
6555WINDOW nil means use the selected window. Normally, VSCROLL is a
6556non-negative multiple of the canonical character height of WINDOW;
a0a37a6f
LT
6557optional third arg PIXELS_P non-nil means that VSCROLL is in pixels.
6558If PIXELS-P is nil, VSCROLL may have to be rounded so that it
6559corresponds to an integral number of pixels. The return value is the
6560result of this rounding.
6561If PIXELS-P is non-nil, the return value is VSCROLL. */)
0cc1039f
KS
6562 (window, vscroll, pixels_p)
6563 Lisp_Object window, vscroll, pixels_p;
5500c422
GM
6564{
6565 struct window *w;
6566 struct frame *f;
177c0ea7 6567
5500c422
GM
6568 if (NILP (window))
6569 window = selected_window;
47004952 6570 else
b7826503
PJ
6571 CHECK_WINDOW (window);
6572 CHECK_NUMBER_OR_FLOAT (vscroll);
177c0ea7 6573
5500c422
GM
6574 w = XWINDOW (window);
6575 f = XFRAME (w->frame);
6576
6577 if (FRAME_WINDOW_P (f))
6578 {
6579 int old_dy = w->vscroll;
177c0ea7 6580
0cc1039f
KS
6581 w->vscroll = - (NILP (pixels_p)
6582 ? FRAME_LINE_HEIGHT (f) * XFLOATINT (vscroll)
6583 : XFLOATINT (vscroll));
47004952 6584 w->vscroll = min (w->vscroll, 0);
5500c422 6585
e56263e5
KS
6586 if (w->vscroll != old_dy)
6587 {
6588 /* Adjust glyph matrix of the frame if the virtual display
6589 area becomes larger than before. */
6590 if (w->vscroll < 0 && w->vscroll < old_dy)
6591 adjust_glyphs (f);
177c0ea7 6592
e56263e5
KS
6593 /* Prevent redisplay shortcuts. */
6594 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
6595 }
5500c422 6596 }
177c0ea7 6597
0cc1039f 6598 return Fwindow_vscroll (window, pixels_p);
5500c422 6599}
177c0ea7 6600
7bbb5782
GM
6601\f
6602/* Call FN for all leaf windows on frame F. FN is called with the
6603 first argument being a pointer to the leaf window, and with
f95464e4 6604 additional argument USER_DATA. Stops when FN returns 0. */
7bbb5782
GM
6605
6606void
f95464e4 6607foreach_window (f, fn, user_data)
7bbb5782 6608 struct frame *f;
f95464e4
GM
6609 int (* fn) P_ ((struct window *, void *));
6610 void *user_data;
7bbb5782 6611{
f95464e4 6612 foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data);
7bbb5782
GM
6613}
6614
6615
6616/* Helper function for foreach_window. Call FN for all leaf windows
6617 reachable from W. FN is called with the first argument being a
f95464e4 6618 pointer to the leaf window, and with additional argument USER_DATA.
67492200 6619 Stop when FN returns 0. Value is 0 if stopped by FN. */
7bbb5782 6620
67492200 6621static int
f95464e4 6622foreach_window_1 (w, fn, user_data)
7bbb5782 6623 struct window *w;
f95464e4
GM
6624 int (* fn) P_ ((struct window *, void *));
6625 void *user_data;
7bbb5782 6626{
67492200 6627 int cont;
177c0ea7 6628
67492200 6629 for (cont = 1; w && cont;)
7bbb5782
GM
6630 {
6631 if (!NILP (w->hchild))
f95464e4 6632 cont = foreach_window_1 (XWINDOW (w->hchild), fn, user_data);
7bbb5782 6633 else if (!NILP (w->vchild))
f95464e4 6634 cont = foreach_window_1 (XWINDOW (w->vchild), fn, user_data);
177c0ea7 6635 else
0f532a9a 6636 cont = fn (w, user_data);
177c0ea7 6637
7bbb5782
GM
6638 w = NILP (w->next) ? 0 : XWINDOW (w->next);
6639 }
67492200
GM
6640
6641 return cont;
7bbb5782
GM
6642}
6643
6644
6d194a45 6645/* Freeze or unfreeze the window start of W unless it is a
f95464e4 6646 mini-window or the selected window. FREEZE_P non-null means freeze
7bbb5782
GM
6647 the window start. */
6648
67492200 6649static int
7bbb5782
GM
6650freeze_window_start (w, freeze_p)
6651 struct window *w;
f95464e4 6652 void *freeze_p;
7bbb5782
GM
6653{
6654 if (w == XWINDOW (selected_window)
6655 || MINI_WINDOW_P (w)
6656 || (MINI_WINDOW_P (XWINDOW (selected_window))
24d744ac 6657 && ! NILP (Vminibuf_scroll_window)
7bbb5782 6658 && w == XWINDOW (Vminibuf_scroll_window)))
f95464e4 6659 freeze_p = NULL;
177c0ea7 6660
f95464e4 6661 w->frozen_window_start_p = freeze_p != NULL;
67492200 6662 return 1;
7bbb5782
GM
6663}
6664
6665
6666/* Freeze or unfreeze the window starts of all leaf windows on frame
6667 F, except the selected window and a mini-window. FREEZE_P non-zero
6668 means freeze the window start. */
6669
6670void
6671freeze_window_starts (f, freeze_p)
6672 struct frame *f;
6673 int freeze_p;
6674{
cbccabec 6675 foreach_window (f, freeze_window_start, (void *) (freeze_p ? f : 0));
7bbb5782 6676}
5500c422
GM
6677
6678\f
6679/***********************************************************************
6680 Initialization
6681 ***********************************************************************/
6682
cbff28e8
RS
6683/* Return 1 if window configurations C1 and C2
6684 describe the same state of affairs. This is used by Fequal. */
6685
6686int
2f8274be 6687compare_window_configurations (c1, c2, ignore_positions)
cbff28e8 6688 Lisp_Object c1, c2;
2f8274be 6689 int ignore_positions;
cbff28e8
RS
6690{
6691 register struct save_window_data *d1, *d2;
6692 struct Lisp_Vector *sw1, *sw2;
6693 int i;
6694
4d3edcb4
GM
6695 if (!WINDOW_CONFIGURATIONP (c1))
6696 wrong_type_argument (Qwindow_configuration_p, c1);
6697 if (!WINDOW_CONFIGURATIONP (c2))
6698 wrong_type_argument (Qwindow_configuration_p, c2);
177c0ea7 6699
cbff28e8
RS
6700 d1 = (struct save_window_data *) XVECTOR (c1);
6701 d2 = (struct save_window_data *) XVECTOR (c2);
6702 sw1 = XVECTOR (d1->saved_windows);
6703 sw2 = XVECTOR (d2->saved_windows);
6704
949cf20f 6705 if (! EQ (d1->frame_cols, d2->frame_cols))
cbff28e8 6706 return 0;
949cf20f 6707 if (! EQ (d1->frame_lines, d2->frame_lines))
cbff28e8
RS
6708 return 0;
6709 if (! EQ (d1->frame_menu_bar_lines, d2->frame_menu_bar_lines))
6710 return 0;
6711 if (! EQ (d1->selected_frame, d2->selected_frame))
6712 return 0;
6713 /* Don't compare the current_window field directly.
6714 Instead see w1_is_current and w2_is_current, below. */
6715 if (! EQ (d1->current_buffer, d2->current_buffer))
6716 return 0;
2f8274be 6717 if (! ignore_positions)
3f49fddc
KS
6718 {
6719 if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
6720 return 0;
6721 if (! EQ (d1->minibuf_selected_window, d2->minibuf_selected_window))
6722 return 0;
6723 }
cbff28e8
RS
6724 /* Don't compare the root_window field.
6725 We don't require the two configurations
6726 to use the same window object,
6727 and the two root windows must be equivalent
6728 if everything else compares equal. */
6729 if (! EQ (d1->focus_frame, d2->focus_frame))
6730 return 0;
6731 if (! EQ (d1->min_width, d2->min_width))
6732 return 0;
6733 if (! EQ (d1->min_height, d2->min_height))
6734 return 0;
6735
6736 /* Verify that the two confis have the same number of windows. */
6737 if (sw1->size != sw2->size)
6738 return 0;
6739
6740 for (i = 0; i < sw1->size; i++)
6741 {
6742 struct saved_window *p1, *p2;
6743 int w1_is_current, w2_is_current;
6744
6745 p1 = SAVED_WINDOW_N (sw1, i);
6746 p2 = SAVED_WINDOW_N (sw2, i);
6747
6748 /* Verify that the current windows in the two
6749 configurations correspond to each other. */
6750 w1_is_current = EQ (d1->current_window, p1->window);
6751 w2_is_current = EQ (d2->current_window, p2->window);
6752
6753 if (w1_is_current != w2_is_current)
6754 return 0;
6755
6756 /* Verify that the corresponding windows do match. */
6757 if (! EQ (p1->buffer, p2->buffer))
6758 return 0;
949cf20f 6759 if (! EQ (p1->left_col, p2->left_col))
cbff28e8 6760 return 0;
949cf20f 6761 if (! EQ (p1->top_line, p2->top_line))
cbff28e8 6762 return 0;
949cf20f 6763 if (! EQ (p1->total_cols, p2->total_cols))
cbff28e8 6764 return 0;
949cf20f 6765 if (! EQ (p1->total_lines, p2->total_lines))
cbff28e8 6766 return 0;
cbff28e8
RS
6767 if (! EQ (p1->display_table, p2->display_table))
6768 return 0;
6769 if (! EQ (p1->parent, p2->parent))
6770 return 0;
6771 if (! EQ (p1->prev, p2->prev))
6772 return 0;
2f8274be
RS
6773 if (! ignore_positions)
6774 {
6775 if (! EQ (p1->hscroll, p2->hscroll))
6776 return 0;
ea68264b
GM
6777 if (!EQ (p1->min_hscroll, p2->min_hscroll))
6778 return 0;
2f8274be
RS
6779 if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
6780 return 0;
6781 if (NILP (Fequal (p1->start, p2->start)))
6782 return 0;
6783 if (NILP (Fequal (p1->pointm, p2->pointm)))
6784 return 0;
6785 if (NILP (Fequal (p1->mark, p2->mark)))
6786 return 0;
6787 }
949cf20f
KS
6788 if (! EQ (p1->left_margin_cols, p2->left_margin_cols))
6789 return 0;
6790 if (! EQ (p1->right_margin_cols, p2->right_margin_cols))
6791 return 0;
6792 if (! EQ (p1->left_fringe_width, p2->left_fringe_width))
6793 return 0;
6794 if (! EQ (p1->right_fringe_width, p2->right_fringe_width))
6795 return 0;
6796 if (! EQ (p1->fringes_outside_margins, p2->fringes_outside_margins))
6797 return 0;
6798 if (! EQ (p1->scroll_bar_width, p2->scroll_bar_width))
6799 return 0;
6800 if (! EQ (p1->vertical_scroll_bar_type, p2->vertical_scroll_bar_type))
6801 return 0;
cbff28e8
RS
6802 }
6803
6804 return 1;
6805}
2f8274be
RS
6806
6807DEFUN ("compare-window-configurations", Fcompare_window_configurations,
6808 Scompare_window_configurations, 2, 2, 0,
fdb82f93
PJ
6809 doc: /* Compare two window configurations as regards the structure of windows.
6810This function ignores details such as the values of point and mark
6811and scrolling positions. */)
6812 (x, y)
2f8274be
RS
6813 Lisp_Object x, y;
6814{
6815 if (compare_window_configurations (x, y, 1))
6816 return Qt;
6817 return Qnil;
6818}
cbff28e8 6819\f
dfcf069d 6820void
7ab12479
JB
6821init_window_once ()
6822{
1ae1a37d
GM
6823 struct frame *f = make_terminal_frame ();
6824 XSETFRAME (selected_frame, f);
6825 Vterminal_frame = selected_frame;
6826 minibuf_window = f->minibuffer_window;
6827 selected_window = f->selected_window;
6828 last_nonminibuf_frame = f;
5b03d3c0
RS
6829
6830 window_initialized = 1;
7ab12479
JB
6831}
6832
67492200
GM
6833void
6834init_window ()
6835{
6836 Vwindow_list = Qnil;
6837}
6838
dfcf069d 6839void
7ab12479
JB
6840syms_of_window ()
6841{
8a37516b
GM
6842 Qwindow_size_fixed = intern ("window-size-fixed");
6843 staticpro (&Qwindow_size_fixed);
c0e7ccd3 6844 Fset (Qwindow_size_fixed, Qnil);
177c0ea7 6845
543f5fb1
RS
6846 staticpro (&Qwindow_configuration_change_hook);
6847 Qwindow_configuration_change_hook
6848 = intern ("window-configuration-change-hook");
6849
7ab12479
JB
6850 Qwindowp = intern ("windowp");
6851 staticpro (&Qwindowp);
6852
3f8ab7bd
RS
6853 Qwindow_configuration_p = intern ("window-configuration-p");
6854 staticpro (&Qwindow_configuration_p);
6855
806b4d9b
JB
6856 Qwindow_live_p = intern ("window-live-p");
6857 staticpro (&Qwindow_live_p);
605be8af 6858
2cccc823 6859 Qtemp_buffer_show_hook = intern ("temp-buffer-show-hook");
a58ec57d
RS
6860 staticpro (&Qtemp_buffer_show_hook);
6861
67492200 6862 staticpro (&Vwindow_list);
8bfb170b
KS
6863
6864 minibuf_selected_window = Qnil;
3dbab091 6865 staticpro (&minibuf_selected_window);
67492200 6866
7ab12479 6867 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
fdb82f93
PJ
6868 doc: /* Non-nil means call as function to display a help buffer.
6869The function is called with one argument, the buffer to be displayed.
6870Used by `with-output-to-temp-buffer'.
6871If this function is used, then it must do the entire job of showing
6872the buffer; `temp-buffer-show-hook' is not run unless this function runs it. */);
7ab12479
JB
6873 Vtemp_buffer_show_function = Qnil;
6874
6875 DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
fdb82f93
PJ
6876 doc: /* If non-nil, function to call to handle `display-buffer'.
6877It will receive two args, the buffer and a flag which if non-nil means
c2755926
LT
6878that the currently selected window is not acceptable.
6879It should choose or create a window, display the specified buffer in it,
6880and return the window.
fdb82f93
PJ
6881Commands such as `switch-to-buffer-other-window' and `find-file-other-window'
6882work using this function. */);
7ab12479
JB
6883 Vdisplay_buffer_function = Qnil;
6884
6529ed87 6885 DEFVAR_LISP ("even-window-heights", &Veven_window_heights,
fdb82f93
PJ
6886 doc: /* *If non-nil, `display-buffer' should even the window heights.
6887If nil, `display-buffer' will leave the window configuration alone. */);
6529ed87
GM
6888 Veven_window_heights = Qt;
6889
7ab12479 6890 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
fdb82f93 6891 doc: /* Non-nil means it is the window that C-M-v in minibuffer should scroll. */);
7ab12479
JB
6892 Vminibuf_scroll_window = Qnil;
6893
cc91894c 6894 DEFVAR_BOOL ("mode-line-in-non-selected-windows", &mode_line_in_non_selected_windows,
26124d5e 6895 doc: /* Non-nil means to use `mode-line-inactive' face in non-selected windows.
cc91894c
KS
6896If the minibuffer is active, the `minibuffer-scroll-window' mode line
6897is displayed in the `mode-line' face. */);
6898 mode_line_in_non_selected_windows = 1;
26124d5e 6899
7ab12479 6900 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
fdb82f93 6901 doc: /* If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window. */);
7ab12479
JB
6902 Vother_window_scroll_buffer = Qnil;
6903
44fa5b1e 6904 DEFVAR_BOOL ("pop-up-frames", &pop_up_frames,
fdb82f93 6905 doc: /* *Non-nil means `display-buffer' should make a separate frame. */);
44fa5b1e 6906 pop_up_frames = 0;
7ab12479 6907
e56263e5
KS
6908 DEFVAR_BOOL ("auto-window-vscroll", &auto_window_vscroll_p,
6909 doc: /* *Non-nil means to automatically adjust `window-vscroll' to view tall lines. */);
6910 auto_window_vscroll_p = 1;
6911
9c3da604 6912 DEFVAR_BOOL ("display-buffer-reuse-frames", &display_buffer_reuse_frames,
fdb82f93
PJ
6913 doc: /* *Non-nil means `display-buffer' should reuse frames.
6914If the buffer in question is already displayed in a frame, raise that frame. */);
9c3da604
GM
6915 display_buffer_reuse_frames = 0;
6916
44fa5b1e 6917 DEFVAR_LISP ("pop-up-frame-function", &Vpop_up_frame_function,
fdb82f93
PJ
6918 doc: /* Function to call to handle automatic new frame creation.
6919It is called with no arguments and should return a newly created frame.
6920
6921A typical value might be `(lambda () (new-frame pop-up-frame-alist))'
6922where `pop-up-frame-alist' would hold the default frame parameters. */);
44fa5b1e 6923 Vpop_up_frame_function = Qnil;
7ab12479 6924
a90712c2 6925 DEFVAR_LISP ("special-display-buffer-names", &Vspecial_display_buffer_names,
fdb82f93 6926 doc: /* *List of buffer names that should have their own special frames.
c019856e
RS
6927Displaying a buffer with `display-buffer' or `pop-to-buffer',
6928if its name is in this list, makes a special frame for it
fdb82f93
PJ
6929using `special-display-function'. See also `special-display-regexps'.
6930
6931An element of the list can be a list instead of just a string.
6932There are two ways to use a list as an element:
6933 (BUFFER FRAME-PARAMETERS...) (BUFFER FUNCTION OTHER-ARGS...)
3cb7143c
RS
6934In the first case, the FRAME-PARAMETERS are pairs of the form
6935\(PARAMETER . VALUE); these parameter values are used to create the frame.
6936In the second case, FUNCTION is called with BUFFER as the first argument,
6937followed by the OTHER-ARGS--it can display BUFFER in any way it likes.
fdb82f93
PJ
6938All this is done by the function found in `special-display-function'.
6939
499858c5
RS
6940If the specified frame parameters include (same-buffer . t), the
6941buffer is displayed in the currently selected window. Otherwise, if
6942they include (same-frame . t), the buffer is displayed in a new window
6943in the currently selected frame.
6944
fdb82f93
PJ
6945If this variable appears \"not to work\", because you add a name to it
6946but that buffer still appears in the selected window, look at the
6947values of `same-window-buffer-names' and `same-window-regexps'.
6948Those variables take precedence over this one. */);
a90712c2
RS
6949 Vspecial_display_buffer_names = Qnil;
6950
6951 DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
fdb82f93 6952 doc: /* *List of regexps saying which buffers should have their own special frames.
c019856e
RS
6953When displaying a buffer with `display-buffer' or `pop-to-buffer',
6954if any regexp in this list matches the buffer name, it makes a
6955special frame for the buffer by calling `special-display-function'.
fdb82f93
PJ
6956
6957An element of the list can be a list instead of just a string.
6958There are two ways to use a list as an element:
6959 (REGEXP FRAME-PARAMETERS...) (REGEXP FUNCTION OTHER-ARGS...)
3cb7143c
RS
6960In the first case, the FRAME-PARAMETERS are pairs of the form
6961\(PARAMETER . VALUE); these parameter values are used to create the frame.
6962In the second case, FUNCTION is called with BUFFER as the first argument,
6963followed by the OTHER-ARGS--it can display the buffer in any way it likes.
fdb82f93
PJ
6964All this is done by the function found in `special-display-function'.
6965
499858c5
RS
6966If the specified frame parameters include (same-buffer . t), the
6967buffer is displayed in the currently selected window. Otherwise, if
6968they include (same-frame . t), the buffer is displayed in a new window
6969in the currently selected frame.
6970
fdb82f93
PJ
6971If this variable appears \"not to work\", because you add a regexp to it
6972but the matching buffers still appear in the selected window, look at the
6973values of `same-window-buffer-names' and `same-window-regexps'.
6974Those variables take precedence over this one. */);
a90712c2
RS
6975 Vspecial_display_regexps = Qnil;
6976
6977 DEFVAR_LISP ("special-display-function", &Vspecial_display_function,
fdb82f93
PJ
6978 doc: /* Function to call to make a new frame for a special buffer.
6979It is called with two arguments, the buffer and optional buffer specific
6980data, and should return a window displaying that buffer.
a5731348
SM
6981The default value normally makes a separate frame for the buffer,
6982 using `special-display-frame-alist' to specify the frame parameters.
6983But if the buffer specific data includes (same-buffer . t) then the
6984 buffer is displayed in the current selected window.
6985Otherwise if it includes (same-frame . t) then the buffer is displayed in
6986 a new window in the currently selected frame.
6987
6988A buffer is special if it is listed in `special-display-buffer-names'
fdb82f93 6989or matches a regexp in `special-display-regexps'. */);
a90712c2
RS
6990 Vspecial_display_function = Qnil;
6991
855d8627 6992 DEFVAR_LISP ("same-window-buffer-names", &Vsame_window_buffer_names,
fdb82f93
PJ
6993 doc: /* *List of buffer names that should appear in the selected window.
6994Displaying one of these buffers using `display-buffer' or `pop-to-buffer'
6995switches to it in the selected window, rather than making it appear
6996in some other window.
6997
6998An element of the list can be a cons cell instead of just a string.
6999Then the car must be a string, which specifies the buffer name.
7000This is for compatibility with `special-display-buffer-names';
7001the cdr of the cons cell is ignored.
7002
7003See also `same-window-regexps'. */);
855d8627
RS
7004 Vsame_window_buffer_names = Qnil;
7005
7006 DEFVAR_LISP ("same-window-regexps", &Vsame_window_regexps,
fdb82f93
PJ
7007 doc: /* *List of regexps saying which buffers should appear in the selected window.
7008If a buffer name matches one of these regexps, then displaying it
7009using `display-buffer' or `pop-to-buffer' switches to it
7010in the selected window, rather than making it appear in some other window.
7011
7012An element of the list can be a cons cell instead of just a string.
7013Then the car must be a string, which specifies the buffer name.
7014This is for compatibility with `special-display-buffer-names';
7015the cdr of the cons cell is ignored.
7016
7017See also `same-window-buffer-names'. */);
855d8627
RS
7018 Vsame_window_regexps = Qnil;
7019
7ab12479 7020 DEFVAR_BOOL ("pop-up-windows", &pop_up_windows,
fdb82f93 7021 doc: /* *Non-nil means display-buffer should make new windows. */);
7ab12479
JB
7022 pop_up_windows = 1;
7023
7024 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
fdb82f93 7025 doc: /* *Number of lines of continuity when scrolling by screenfuls. */);
7ab12479
JB
7026 next_screen_context_lines = 2;
7027
7028 DEFVAR_INT ("split-height-threshold", &split_height_threshold,
876e2665 7029 doc: /* *A window must be at least this tall to be eligible for splitting by `display-buffer'.
fdb82f93 7030If there is only one window, it is split regardless of this value. */);
7ab12479
JB
7031 split_height_threshold = 500;
7032
7033 DEFVAR_INT ("window-min-height", &window_min_height,
fdb82f93 7034 doc: /* *Delete any window less than this tall (including its mode line). */);
7ab12479
JB
7035 window_min_height = 4;
7036
7037 DEFVAR_INT ("window-min-width", &window_min_width,
fdb82f93 7038 doc: /* *Delete any window less than this wide. */);
7ab12479
JB
7039 window_min_width = 10;
7040
5500c422
GM
7041 DEFVAR_LISP ("scroll-preserve-screen-position",
7042 &Vscroll_preserve_screen_position,
bdf4ec93
RS
7043 doc: /* *Controls if scroll commands move point to keep its screen line unchanged.
7044A value of nil means point does not keep its screen position except
7045at the scroll margin or window boundary respectively.
7046A value of t means point keeps its screen position if the scroll
7047command moved it vertically out of the window, e.g. when scrolling
7048by full screens.
7049Any other value means point always keeps its screen position. */);
5500c422 7050 Vscroll_preserve_screen_position = Qnil;
9317a85d 7051
543f5fb1
RS
7052 DEFVAR_LISP ("window-configuration-change-hook",
7053 &Vwindow_configuration_change_hook,
fdb82f93
PJ
7054 doc: /* Functions to call when window configuration changes.
7055The selected frame is the one whose configuration has changed. */);
543f5fb1
RS
7056 Vwindow_configuration_change_hook = Qnil;
7057
7ab12479
JB
7058 defsubr (&Sselected_window);
7059 defsubr (&Sminibuffer_window);
7060 defsubr (&Swindow_minibuffer_p);
7061 defsubr (&Swindowp);
806b4d9b 7062 defsubr (&Swindow_live_p);
7ab12479
JB
7063 defsubr (&Spos_visible_in_window_p);
7064 defsubr (&Swindow_buffer);
7065 defsubr (&Swindow_height);
7066 defsubr (&Swindow_width);
7067 defsubr (&Swindow_hscroll);
7068 defsubr (&Sset_window_hscroll);
190eb263
RS
7069 defsubr (&Swindow_redisplay_end_trigger);
7070 defsubr (&Sset_window_redisplay_end_trigger);
7ab12479 7071 defsubr (&Swindow_edges);
c99a9eb3
RS
7072 defsubr (&Swindow_pixel_edges);
7073 defsubr (&Swindow_inside_edges);
7074 defsubr (&Swindow_inside_pixel_edges);
d5783c40
JB
7075 defsubr (&Scoordinates_in_window_p);
7076 defsubr (&Swindow_at);
7ab12479
JB
7077 defsubr (&Swindow_point);
7078 defsubr (&Swindow_start);
7079 defsubr (&Swindow_end);
7080 defsubr (&Sset_window_point);
7081 defsubr (&Sset_window_start);
7082 defsubr (&Swindow_dedicated_p);
d207b766 7083 defsubr (&Sset_window_dedicated_p);
7ab12479
JB
7084 defsubr (&Swindow_display_table);
7085 defsubr (&Sset_window_display_table);
7086 defsubr (&Snext_window);
7087 defsubr (&Sprevious_window);
7088 defsubr (&Sother_window);
7089 defsubr (&Sget_lru_window);
7090 defsubr (&Sget_largest_window);
7091 defsubr (&Sget_buffer_window);
7092 defsubr (&Sdelete_other_windows);
7093 defsubr (&Sdelete_windows_on);
7094 defsubr (&Sreplace_buffer_in_windows);
7095 defsubr (&Sdelete_window);
7096 defsubr (&Sset_window_buffer);
7097 defsubr (&Sselect_window);
4628f7a4
EN
7098 defsubr (&Sspecial_display_p);
7099 defsubr (&Ssame_window_p);
7ab12479 7100 defsubr (&Sdisplay_buffer);
e661376d 7101 defsubr (&Sforce_window_update);
7ab12479
JB
7102 defsubr (&Ssplit_window);
7103 defsubr (&Senlarge_window);
7104 defsubr (&Sshrink_window);
7105 defsubr (&Sscroll_up);
7106 defsubr (&Sscroll_down);
7107 defsubr (&Sscroll_left);
7108 defsubr (&Sscroll_right);
ccd0664b 7109 defsubr (&Sother_window_for_scrolling);
7ab12479 7110 defsubr (&Sscroll_other_window);
fa832261 7111 defsubr (&Sminibuffer_selected_window);
7ab12479 7112 defsubr (&Srecenter);
81fe0836 7113 defsubr (&Swindow_text_height);
7ab12479
JB
7114 defsubr (&Smove_to_window_line);
7115 defsubr (&Swindow_configuration_p);
3f8ab7bd 7116 defsubr (&Swindow_configuration_frame);
7ab12479
JB
7117 defsubr (&Sset_window_configuration);
7118 defsubr (&Scurrent_window_configuration);
7119 defsubr (&Ssave_window_excursion);
c16e1cc3 7120 defsubr (&Swindow_tree);
5500c422
GM
7121 defsubr (&Sset_window_margins);
7122 defsubr (&Swindow_margins);
949cf20f
KS
7123 defsubr (&Sset_window_fringes);
7124 defsubr (&Swindow_fringes);
7125 defsubr (&Sset_window_scroll_bars);
7126 defsubr (&Swindow_scroll_bars);
5500c422
GM
7127 defsubr (&Swindow_vscroll);
7128 defsubr (&Sset_window_vscroll);
2f8274be 7129 defsubr (&Scompare_window_configurations);
67492200 7130 defsubr (&Swindow_list);
7ab12479
JB
7131}
7132
dfcf069d 7133void
7ab12479
JB
7134keys_of_window ()
7135{
7136 initial_define_key (control_x_map, '1', "delete-other-windows");
7137 initial_define_key (control_x_map, '2', "split-window");
7138 initial_define_key (control_x_map, '0', "delete-window");
7139 initial_define_key (control_x_map, 'o', "other-window");
7140 initial_define_key (control_x_map, '^', "enlarge-window");
7141 initial_define_key (control_x_map, '<', "scroll-left");
7142 initial_define_key (control_x_map, '>', "scroll-right");
7143
7144 initial_define_key (global_map, Ctl ('V'), "scroll-up");
7145 initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
7146 initial_define_key (meta_map, 'v', "scroll-down");
7147
7148 initial_define_key (global_map, Ctl('L'), "recenter");
7149 initial_define_key (meta_map, 'r', "move-to-window-line");
7150}
ab5796a9
MB
7151
7152/* arch-tag: 90a9c576-0590-48f1-a5f1-6c96a0452d9f
7153 (do not change this comment) */