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