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