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