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