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