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