(expose_window_tree, expose_window, expose_line): Return
[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
3963 the screen. */
d72340d4 3964 tem = Fpos_visible_in_window_p (make_number (PT), window, Qnil);
5500c422
GM
3965 if (NILP (tem))
3966 {
3967 /* Move backward half the height of the window. Performance note:
3968 vmotion used here is about 10% faster, but would give wrong
3969 results for variable height lines. */
3970 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
3971 it.current_y = it.last_visible_y;
202379cf 3972 move_it_vertically (&it, - window_box_height (w) / 2);
5500c422
GM
3973
3974 /* The function move_iterator_vertically may move over more than
3975 the specified y-distance. If it->w is small, e.g. a
3976 mini-buffer window, we may end up in front of the window's
3977 display area. This is the case when Start displaying at the
3978 start of the line containing PT in this case. */
3979 if (it.current_y <= 0)
3980 {
3981 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
3982 move_it_vertically (&it, 0);
3983 it.current_y = 0;
3984 }
3985
3986 start = it.current.pos;
3987 }
3988
3989 /* If scroll_preserve_screen_position is non-zero, we try to set
3990 point in the same window line as it is now, so get that line. */
3991 if (!NILP (Vscroll_preserve_screen_position))
3992 {
3993 start_display (&it, w, start);
3994 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
3995 preserve_y = it.current_y;
3996 }
3997 else
3998 preserve_y = -1;
3999
4000 /* Move iterator it from start the specified distance forward or
4001 backward. The result is the new window start. */
4002 start_display (&it, w, start);
4003 if (whole)
4004 {
202379cf 4005 int screen_full = (window_box_height (w)
5500c422 4006 - next_screen_context_lines * CANON_Y_UNIT (it.f));
d4e7cf01 4007 int dy = n * screen_full;
d72340d4
GM
4008
4009 /* Note that move_it_vertically always moves the iterator to the
4010 start of a line. So, if the last line doesn't have a newline,
4011 we would end up at the start of the line ending at ZV. */
4012 if (dy <= 0)
4013 move_it_vertically_backward (&it, -dy);
4014 else if (dy > 0)
4015 move_it_to (&it, ZV, -1, it.current_y + dy, -1,
4016 MOVE_TO_POS | MOVE_TO_Y);
5500c422
GM
4017 }
4018 else
4019 move_it_by_lines (&it, n, 1);
4020
4021 /* End if we end up at ZV or BEGV. */
4022 if ((n > 0 && IT_CHARPOS (it) == ZV)
4023 || (n < 0 && IT_CHARPOS (it) == CHARPOS (start)))
4024 {
5cdb3cf3
MB
4025 if (IT_CHARPOS (it) == ZV)
4026 {
4027 if (it.current_y + it.max_ascent + it.max_descent
4028 > it.last_visible_y)
a74eca50
GM
4029 {
4030 /* The last line was only partially visible, make it fully
4031 visible. */
4032 w->vscroll = (it.last_visible_y
4033 - it.current_y + it.max_ascent + it.max_descent);
4034 adjust_glyphs (it.f);
4035 }
5cdb3cf3
MB
4036 else if (noerror)
4037 return;
4038 else
4039 Fsignal (Qend_of_buffer, Qnil);
4040 }
5500c422 4041 else
5cdb3cf3
MB
4042 {
4043 if (w->vscroll != 0)
4044 /* The first line was only partially visible, make it fully
4045 visible. */
4046 w->vscroll = 0;
4047 else if (noerror)
4048 return;
4049 else
4050 Fsignal (Qbeginning_of_buffer, Qnil);
4051 }
4052
4053 /* If control gets here, then we vscrolled. */
4054
4055 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
4056
4057 /* Don't try to change the window start below. */
4058 vscrolled = 1;
5500c422
GM
4059 }
4060
5cdb3cf3
MB
4061 if (! vscrolled)
4062 {
4063 /* Set the window start, and set up the window for redisplay. */
4064 set_marker_restricted (w->start, make_number (IT_CHARPOS (it)),
4065 w->buffer);
4066 w->start_at_line_beg = Fbolp ();
4067 w->update_mode_line = Qt;
4068 XSETFASTINT (w->last_modified, 0);
4069 XSETFASTINT (w->last_overlay_modified, 0);
4070 /* Set force_start so that redisplay_window will run the
4071 window-scroll-functions. */
4072 w->force_start = Qt;
4073 }
5500c422
GM
4074
4075 it.current_y = it.vpos = 0;
4076
4077 /* Preserve the screen position if we must. */
4078 if (preserve_y >= 0)
4079 {
4080 move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
4081 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
4082 }
4083 else
4084 {
4085 /* Move PT out of scroll margins. */
4086 this_scroll_margin = max (0, scroll_margin);
4087 this_scroll_margin = min (this_scroll_margin, XFASTINT (w->height) / 4);
4088 this_scroll_margin *= CANON_Y_UNIT (it.f);
4089
4090 if (n > 0)
4091 {
4092 /* We moved the window start towards ZV, so PT may be now
4093 in the scroll margin at the top. */
4094 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
4095 while (it.current_y < this_scroll_margin)
4096 move_it_by_lines (&it, 1, 1);
4097 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
4098 }
4099 else if (n < 0)
4100 {
5cdb3cf3
MB
4101 int charpos, bytepos;
4102
5500c422
GM
4103 /* We moved the window start towards BEGV, so PT may be now
4104 in the scroll margin at the bottom. */
4105 move_it_to (&it, PT, -1,
4106 it.last_visible_y - this_scroll_margin - 1, -1,
4107 MOVE_TO_POS | MOVE_TO_Y);
5cdb3cf3
MB
4108
4109 /* Save our position, in case it's correct. */
4110 charpos = IT_CHARPOS (it);
4111 bytepos = IT_BYTEPOS (it);
5500c422 4112
5cdb3cf3
MB
4113 /* See if point is on a partially visible line at the end. */
4114 move_it_by_lines (&it, 1, 1);
4115 if (it.current_y > it.last_visible_y)
4116 /* The last line was only partially visible, so back up two
4117 lines to make sure we're on a fully visible line. */
4118 {
4119 move_it_by_lines (&it, -2, 0);
4120 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
4121 }
4122 else
4123 /* No, the position we saved is OK, so use it. */
4124 SET_PT_BOTH (charpos, bytepos);
5500c422
GM
4125 }
4126 }
4127}
4128
4129
4130/* Implementation of window_scroll that works based on screen lines.
4131 See the comment of window_scroll for parameter descriptions. */
4132
4133static void
4134window_scroll_line_based (window, n, whole, noerror)
4135 Lisp_Object window;
4136 int n;
4137 int whole;
4138 int noerror;
7ab12479
JB
4139{
4140 register struct window *w = XWINDOW (window);
5500c422 4141 register int opoint = PT, opoint_byte = PT_BYTE;
b73ea88e 4142 register int pos, pos_byte;
7ab12479
JB
4143 register int ht = window_internal_height (w);
4144 register Lisp_Object tem;
4145 int lose;
5500c422 4146 Lisp_Object bolp;
345d45b2 4147 int startpos;
101d1605
RS
4148 struct position posit;
4149 int original_vpos;
4150
d4e7cf01
GM
4151 /* If scrolling screen-fulls, compute the number of lines to
4152 scroll from the window's height. */
4153 if (whole)
4154 n *= max (1, ht - next_screen_context_lines);
4155
101d1605
RS
4156 startpos = marker_position (w->start);
4157
4158 posit = *compute_motion (startpos, 0, 0, 0,
4159 PT, ht, 0,
4160 window_internal_width (w), XINT (w->hscroll),
4161 0, w);
4162 original_vpos = posit.vpos;
0a1f771a 4163
d834a2e9 4164 XSETFASTINT (tem, PT);
6ffdb539 4165 tem = Fpos_visible_in_window_p (tem, window, Qnil);
7ab12479 4166
265a9e55 4167 if (NILP (tem))
7ab12479 4168 {
cd2be1dd 4169 Fvertical_motion (make_number (- (ht / 2)), window);
345d45b2 4170 startpos = PT;
7ab12479
JB
4171 }
4172
345d45b2 4173 SET_PT (startpos);
5ce7b543 4174 lose = n < 0 && PT == BEGV;
540b6aa0 4175 Fvertical_motion (make_number (n), window);
5ce7b543 4176 pos = PT;
b73ea88e 4177 pos_byte = PT_BYTE;
7ab12479 4178 bolp = Fbolp ();
b73ea88e 4179 SET_PT_BOTH (opoint, opoint_byte);
7ab12479
JB
4180
4181 if (lose)
f8026fd8
JB
4182 {
4183 if (noerror)
4184 return;
4185 else
4186 Fsignal (Qbeginning_of_buffer, Qnil);
4187 }
7ab12479
JB
4188
4189 if (pos < ZV)
7ab12479 4190 {
0c7da84e
RS
4191 int this_scroll_margin = scroll_margin;
4192
4193 /* Don't use a scroll margin that is negative or too large. */
4194 if (this_scroll_margin < 0)
4195 this_scroll_margin = 0;
4196
4197 if (XINT (w->height) < 4 * scroll_margin)
4198 this_scroll_margin = XINT (w->height) / 4;
4199
b73ea88e 4200 set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
7ab12479
JB
4201 w->start_at_line_beg = bolp;
4202 w->update_mode_line = Qt;
d834a2e9 4203 XSETFASTINT (w->last_modified, 0);
3cd21523 4204 XSETFASTINT (w->last_overlay_modified, 0);
345d45b2
RS
4205 /* Set force_start so that redisplay_window will run
4206 the window-scroll-functions. */
4207 w->force_start = Qt;
0c7da84e 4208
5500c422 4209 if (whole && !NILP (Vscroll_preserve_screen_position))
0c7da84e 4210 {
b73ea88e 4211 SET_PT_BOTH (pos, pos_byte);
101d1605 4212 Fvertical_motion (make_number (original_vpos), window);
0c7da84e 4213 }
101d1605
RS
4214 /* If we scrolled forward, put point enough lines down
4215 that it is outside the scroll margin. */
4216 else if (n > 0)
0c7da84e 4217 {
101d1605
RS
4218 int top_margin;
4219
4220 if (this_scroll_margin > 0)
4221 {
b73ea88e 4222 SET_PT_BOTH (pos, pos_byte);
101d1605
RS
4223 Fvertical_motion (make_number (this_scroll_margin), window);
4224 top_margin = PT;
4225 }
4226 else
4227 top_margin = pos;
4228
4229 if (top_margin <= opoint)
b73ea88e 4230 SET_PT_BOTH (opoint, opoint_byte);
5500c422 4231 else if (!NILP (Vscroll_preserve_screen_position))
101d1605 4232 {
b73ea88e 4233 SET_PT_BOTH (pos, pos_byte);
101d1605
RS
4234 Fvertical_motion (make_number (original_vpos), window);
4235 }
9317a85d 4236 else
335406fc 4237 SET_PT (top_margin);
0c7da84e 4238 }
101d1605 4239 else if (n < 0)
7ab12479 4240 {
101d1605
RS
4241 int bottom_margin;
4242
0c7da84e
RS
4243 /* If we scrolled backward, put point near the end of the window
4244 but not within the scroll margin. */
b73ea88e 4245 SET_PT_BOTH (pos, pos_byte);
0c7da84e 4246 tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
101d1605
RS
4247 if (XFASTINT (tem) == ht - this_scroll_margin)
4248 bottom_margin = PT;
4249 else
4250 bottom_margin = PT + 1;
4251
4252 if (bottom_margin > opoint)
b73ea88e 4253 SET_PT_BOTH (opoint, opoint_byte);
7ab12479 4254 else
101d1605 4255 {
5500c422 4256 if (!NILP (Vscroll_preserve_screen_position))
9317a85d 4257 {
b73ea88e 4258 SET_PT_BOTH (pos, pos_byte);
9317a85d
RS
4259 Fvertical_motion (make_number (original_vpos), window);
4260 }
4261 else
4262 Fvertical_motion (make_number (-1), window);
101d1605 4263 }
7ab12479
JB
4264 }
4265 }
4266 else
f8026fd8
JB
4267 {
4268 if (noerror)
4269 return;
4270 else
4271 Fsignal (Qend_of_buffer, Qnil);
4272 }
7ab12479 4273}
5500c422
GM
4274
4275
4276/* Scroll selected_window up or down. If N is nil, scroll a
4277 screen-full which is defined as the height of the window minus
4278 next_screen_context_lines. If N is the symbol `-', scroll.
4279 DIRECTION may be 1 meaning to scroll down, or -1 meaning to scroll
4280 up. This is the guts of Fscroll_up and Fscroll_down. */
7ab12479
JB
4281
4282static void
4283scroll_command (n, direction)
5500c422 4284 Lisp_Object n;
7ab12479
JB
4285 int direction;
4286{
d4e7cf01 4287 int count = BINDING_STACK_SIZE ();
7ab12479 4288
5500c422
GM
4289 xassert (abs (direction) == 1);
4290
4291 /* If selected window's buffer isn't current, make it current for
4292 the moment. But don't screw up if window_scroll gets an error. */
7ab12479 4293 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
95605e15
JB
4294 {
4295 record_unwind_protect (save_excursion_restore, save_excursion_save ());
4296 Fset_buffer (XWINDOW (selected_window)->buffer);
5500c422
GM
4297
4298 /* Make redisplay consider other windows than just selected_window. */
4299 ++windows_or_buffers_changed;
95605e15 4300 }
7ab12479 4301
265a9e55 4302 if (NILP (n))
d4e7cf01 4303 window_scroll (selected_window, direction, 1, 0);
7ab12479 4304 else if (EQ (n, Qminus))
d4e7cf01 4305 window_scroll (selected_window, -direction, 1, 0);
7ab12479
JB
4306 else
4307 {
4308 n = Fprefix_numeric_value (n);
101d1605 4309 window_scroll (selected_window, XINT (n) * direction, 0, 0);
7ab12479 4310 }
95605e15
JB
4311
4312 unbind_to (count, Qnil);
7ab12479
JB
4313}
4314
4315DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
4316 "Scroll text of current window upward ARG lines; or near full screen if no ARG.\n\
4317A near full screen is `next-screen-context-lines' less than a full screen.\n\
279e0e0c 4318Negative ARG means scroll downward.\n\
dd394ff9
KH
4319If ARG is the atom `-', scroll downward by nearly full screen.\n\
4320When calling from a program, supply as argument a number, nil, or `-'.")
413430c5
EN
4321 (arg)
4322 Lisp_Object arg;
7ab12479 4323{
413430c5 4324 scroll_command (arg, 1);
7ab12479
JB
4325 return Qnil;
4326}
4327
4328DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
a5fcbc4e 4329 "Scroll text of current window down ARG lines; or near full screen if no ARG.\n\
7ab12479 4330A near full screen is `next-screen-context-lines' less than a full screen.\n\
279e0e0c 4331Negative ARG means scroll upward.\n\
dd394ff9
KH
4332If ARG is the atom `-', scroll upward by nearly full screen.\n\
4333When calling from a program, supply as argument a number, nil, or `-'.")
413430c5
EN
4334 (arg)
4335 Lisp_Object arg;
7ab12479 4336{
413430c5 4337 scroll_command (arg, -1);
7ab12479
JB
4338 return Qnil;
4339}
ccd0664b
RS
4340\f
4341DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0,
4342 "Return the other window for \"other window scroll\" commands.\n\
77b24de6 4343If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
ccd0664b
RS
4344specifies the window.\n\
4345If `other-window-scroll-buffer' is non-nil, a window\n\
4346showing that buffer is used.")
eb16ec06 4347 ()
7ab12479 4348{
ccd0664b 4349 Lisp_Object window;
7ab12479
JB
4350
4351 if (MINI_WINDOW_P (XWINDOW (selected_window))
265a9e55 4352 && !NILP (Vminibuf_scroll_window))
7ab12479
JB
4353 window = Vminibuf_scroll_window;
4354 /* If buffer is specified, scroll that buffer. */
265a9e55 4355 else if (!NILP (Vother_window_scroll_buffer))
7ab12479
JB
4356 {
4357 window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
265a9e55 4358 if (NILP (window))
53f76081 4359 window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt, Qnil);
7ab12479
JB
4360 }
4361 else
dbc4e1c1
JB
4362 {
4363 /* Nothing specified; look for a neighboring window on the same
4364 frame. */
4365 window = Fnext_window (selected_window, Qnil, Qnil);
4366
4367 if (EQ (window, selected_window))
4368 /* That didn't get us anywhere; look for a window on another
4369 visible frame. */
4370 do
4371 window = Fnext_window (window, Qnil, Qt);
4372 while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
4373 && ! EQ (window, selected_window));
4374 }
4375
605be8af 4376 CHECK_LIVE_WINDOW (window, 0);
7ab12479
JB
4377
4378 if (EQ (window, selected_window))
4379 error ("There is no other window");
4380
ccd0664b
RS
4381 return window;
4382}
4383
4384DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
4385 "Scroll next window upward ARG lines; or near full screen if no ARG.\n\
dd394ff9 4386A near full screen is `next-screen-context-lines' less than a full screen.\n\
ccd0664b
RS
4387The next window is the one below the current one; or the one at the top\n\
4388if the current one is at the bottom. Negative ARG means scroll downward.\n\
dd394ff9
KH
4389If ARG is the atom `-', scroll downward by nearly full screen.\n\
4390When calling from a program, supply as argument a number, nil, or `-'.\n\
ccd0664b
RS
4391\n\
4392If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
4393specifies the window to scroll.\n\
4394If `other-window-scroll-buffer' is non-nil, scroll the window\n\
4395showing that buffer, popping the buffer up if necessary.")
413430c5 4396 (arg)
d4e7cf01 4397 Lisp_Object arg;
ccd0664b 4398{
d4e7cf01
GM
4399 Lisp_Object window;
4400 struct window *w;
4401 int count = BINDING_STACK_SIZE ();
ccd0664b
RS
4402
4403 window = Fother_window_for_scrolling ();
7ab12479 4404 w = XWINDOW (window);
7ab12479
JB
4405
4406 /* Don't screw up if window_scroll gets an error. */
4407 record_unwind_protect (save_excursion_restore, save_excursion_save ());
5500c422 4408 ++windows_or_buffers_changed;
7ab12479
JB
4409
4410 Fset_buffer (w->buffer);
4411 SET_PT (marker_position (w->pointm));
4412
413430c5 4413 if (NILP (arg))
d4e7cf01 4414 window_scroll (window, 1, 1, 1);
413430c5 4415 else if (EQ (arg, Qminus))
d4e7cf01 4416 window_scroll (window, -1, 1, 1);
7ab12479
JB
4417 else
4418 {
413430c5
EN
4419 if (CONSP (arg))
4420 arg = Fcar (arg);
4421 CHECK_NUMBER (arg, 0);
101d1605 4422 window_scroll (window, XINT (arg), 0, 1);
7ab12479
JB
4423 }
4424
b73ea88e 4425 set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
f4e7b2c2 4426 unbind_to (count, Qnil);
7ab12479
JB
4427
4428 return Qnil;
4429}
4430\f
644b477c 4431DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 1, "P",
7ab12479
JB
4432 "Scroll selected window display ARG columns left.\n\
4433Default for ARG is window width minus 2.")
4434 (arg)
4435 register Lisp_Object arg;
4436{
c67fa410
GM
4437 Lisp_Object result;
4438 int hscroll;
4439 struct window *w = XWINDOW (selected_window);
4440
265a9e55 4441 if (NILP (arg))
c67fa410 4442 XSETFASTINT (arg, window_internal_width (w) - 2);
7ab12479
JB
4443 else
4444 arg = Fprefix_numeric_value (arg);
4445
c67fa410
GM
4446 hscroll = XINT (w->hscroll) + XINT (arg);
4447 result = Fset_window_hscroll (selected_window, make_number (hscroll));
4448
f5686fbd 4449 if (interactive_p (0))
c67fa410
GM
4450 w->min_hscroll = w->hscroll;
4451
4452 return result;
7ab12479
JB
4453}
4454
644b477c 4455DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 1, "P",
7ab12479
JB
4456 "Scroll selected window display ARG columns right.\n\
4457Default for ARG is window width minus 2.")
4458 (arg)
4459 register Lisp_Object arg;
4460{
c67fa410
GM
4461 Lisp_Object result;
4462 int hscroll;
4463 struct window *w = XWINDOW (selected_window);
4464
265a9e55 4465 if (NILP (arg))
c67fa410 4466 XSETFASTINT (arg, window_internal_width (w) - 2);
7ab12479
JB
4467 else
4468 arg = Fprefix_numeric_value (arg);
4469
c67fa410
GM
4470 hscroll = XINT (w->hscroll) - XINT (arg);
4471 result = Fset_window_hscroll (selected_window, make_number (hscroll));
4472
f5686fbd 4473 if (interactive_p (0))
c67fa410
GM
4474 w->min_hscroll = w->hscroll;
4475
4476 return result;
7ab12479
JB
4477}
4478
12c8b416
GM
4479/* Value is the number of lines actually displayed in window W,
4480 as opposed to its height. */
4481
4482static int
4483displayed_window_lines (w)
4484 struct window *w;
4485{
4486 struct it it;
4487 struct text_pos start;
4488 int height = window_box_height (w);
4489 struct buffer *old_buffer;
4490 int bottom_y;
4491
4492 if (XBUFFER (w->buffer) != current_buffer)
4493 {
4494 old_buffer = current_buffer;
4495 set_buffer_internal (XBUFFER (w->buffer));
4496 }
4497 else
4498 old_buffer = NULL;
4499
521b203e
GM
4500 /* In case W->start is out of the accessible range, do something
4501 reasonable. This happens in Info mode when Info-scroll-down
4502 calls (recenter -1) while W->start is 1. */
4503 if (XMARKER (w->start)->charpos < BEGV)
4504 SET_TEXT_POS (start, BEGV, BEGV_BYTE);
4505 else if (XMARKER (w->start)->charpos > ZV)
4506 SET_TEXT_POS (start, ZV, ZV_BYTE);
4507 else
4508 SET_TEXT_POS_FROM_MARKER (start, w->start);
4509
12c8b416
GM
4510 start_display (&it, w, start);
4511 move_it_vertically (&it, height);
c8bc6f65 4512 bottom_y = line_bottom_y (&it);
12c8b416
GM
4513
4514 /* Add in empty lines at the bottom of the window. */
4515 if (bottom_y < height)
4516 {
c8bc6f65
GM
4517 int uy = CANON_Y_UNIT (it.f);
4518 it.vpos += (height - bottom_y + uy - 1) / uy;
12c8b416
GM
4519 }
4520
c8bc6f65
GM
4521 if (old_buffer)
4522 set_buffer_internal (old_buffer);
4523
12c8b416
GM
4524 return it.vpos;
4525}
4526
4527
7ab12479 4528DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
04212fcb
RS
4529 "Center point in window and redisplay frame.\n\
4530With prefix argument ARG, recenter putting point on screen line ARG\n\
4531relative to the current window. If ARG is negative, it counts up from the\n\
4532bottom of the window. (ARG should be less than the height of the window.)\n\
4533\n\
4534If ARG is omitted or nil, erase the entire frame and then\n\
4535redraw with point in the center of the current window.\n\
4536Just C-u as prefix means put point in the center of the window\n\
4537and redisplay normally--don't erase and redraw the frame.")
413430c5
EN
4538 (arg)
4539 register Lisp_Object arg;
7ab12479 4540{
6df47b59 4541 struct window *w = XWINDOW (selected_window);
478292ed
RS
4542 struct buffer *buf = XBUFFER (w->buffer);
4543 struct buffer *obuf = current_buffer;
6df47b59
GM
4544 int center_p = 0;
4545 int charpos, bytepos;
7ab12479 4546
413430c5 4547 if (NILP (arg))
7ab12479 4548 {
f02d6d5c
KH
4549 int i;
4550
4551 /* Invalidate pixel data calculated for all compositions. */
4552 for (i = 0; i < n_compositions; i++)
4553 composition_table[i]->font = NULL;
7ab12479 4554
527b6458 4555 Fredraw_frame (w->frame);
44fa5b1e 4556 SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
6df47b59 4557 center_p = 1;
7ab12479 4558 }
413430c5 4559 else if (CONSP (arg)) /* Just C-u. */
6df47b59 4560 center_p = 1;
7ab12479
JB
4561 else
4562 {
413430c5
EN
4563 arg = Fprefix_numeric_value (arg);
4564 CHECK_NUMBER (arg, 0);
7ab12479
JB
4565 }
4566
478292ed 4567 set_buffer_internal (buf);
7ab12479 4568
521b203e 4569 /* Handle centering on a graphical frame specially. Such frames can
6df47b59
GM
4570 have variable-height lines and centering point on the basis of
4571 line counts would lead to strange effects. */
521b203e 4572 if (FRAME_WINDOW_P (XFRAME (w->frame)))
6df47b59 4573 {
6df47b59
GM
4574 if (center_p)
4575 {
521b203e
GM
4576 struct it it;
4577 struct text_pos pt;
4578
4579 SET_TEXT_POS (pt, PT, PT_BYTE);
4580 start_display (&it, w, pt);
202379cf 4581 move_it_vertically (&it, - window_box_height (w) / 2);
521b203e
GM
4582 charpos = IT_CHARPOS (it);
4583 bytepos = IT_BYTEPOS (it);
6df47b59
GM
4584 }
4585 else if (XINT (arg) < 0)
4586 {
521b203e
GM
4587 struct it it;
4588 struct text_pos pt;
d466fa4d 4589 int y0, y1, h, nlines;
521b203e
GM
4590
4591 SET_TEXT_POS (pt, PT, PT_BYTE);
4592 start_display (&it, w, pt);
4593 y0 = it.current_y;
4594
d466fa4d 4595 /* The amount of pixels we have to move back is the window
521b203e
GM
4596 height minus what's displayed in the line containing PT,
4597 and the lines below. */
d466fa4d
GM
4598 nlines = - XINT (arg) - 1;
4599 move_it_by_lines (&it, nlines, 1);
4600
521b203e
GM
4601 y1 = it.current_y - y0;
4602 h = line_bottom_y (&it) - y1;
d466fa4d
GM
4603
4604 /* If we can't move down NLINES lines because we hit
4605 the end of the buffer, count in some empty lines. */
4606 if (it.vpos < nlines)
4607 y1 += (nlines - it.vpos) * CANON_Y_UNIT (it.f);
4608
521b203e
GM
4609 y0 = it.last_visible_y - y1 - h;
4610
4611 start_display (&it, w, pt);
4612 move_it_vertically (&it, - y0);
4613 charpos = IT_CHARPOS (it);
4614 bytepos = IT_BYTEPOS (it);
6df47b59 4615 }
521b203e
GM
4616 else
4617 {
4618 struct position pos;
4619 pos = *vmotion (PT, - XINT (arg), w);
4620 charpos = pos.bufpos;
4621 bytepos = pos.bytepos;
4622 }
4623 }
4624 else
4625 {
4626 struct position pos;
4627 int ht = window_internal_height (w);
4628
4629 if (center_p)
4630 arg = make_number (ht / 2);
4631 else if (XINT (arg) < 0)
4632 arg = make_number (XINT (arg) + ht);
6df47b59
GM
4633
4634 pos = *vmotion (PT, - XINT (arg), w);
4635 charpos = pos.bufpos;
4636 bytepos = pos.bytepos;
4637 }
4638
4639 /* Set the new window start. */
4640 set_marker_both (w->start, w->buffer, charpos, bytepos);
2f3cad6c 4641 w->window_end_valid = Qnil;
7ab12479 4642 w->force_start = Qt;
6df47b59
GM
4643 if (bytepos == BEGV_BYTE || FETCH_BYTE (bytepos - 1) == '\n')
4644 w->start_at_line_beg = Qt;
4645 else
4646 w->start_at_line_beg = Qnil;
4647
478292ed 4648 set_buffer_internal (obuf);
7ab12479
JB
4649 return Qnil;
4650}
b7617575
GM
4651
4652
81fe0836
MB
4653DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height,
4654 0, 1, 0,
4655 "Return the height in lines of the text display area of WINDOW.\n\
4656This doesn't include the mode-line (or header-line if any) or any\n\
4657partial-height lines in the text display area.")
4658 (window)
4659 Lisp_Object window;
4660{
4661 struct window *w = decode_window (window);
4662 int pixel_height = window_box_height (w);
4663 int line_height = pixel_height / CANON_Y_UNIT (XFRAME (w->frame));
4664 return make_number (line_height);
4665}
4666
4667
7ab12479
JB
4668\f
4669DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
4670 1, 1, "P",
4671 "Position point relative to window.\n\
19e3bf0a 4672With no argument, position point at center of window.\n\
d81724c7
RS
4673An argument specifies vertical position within the window;\n\
4674zero means top of window, negative means relative to bottom of window.")
7ab12479 4675 (arg)
b7617575 4676 Lisp_Object arg;
7ab12479 4677{
b7617575
GM
4678 struct window *w = XWINDOW (selected_window);
4679 int lines, start;
540b6aa0 4680 Lisp_Object window;
7ab12479 4681
b7617575 4682 window = selected_window;
7ab12479
JB
4683 start = marker_position (w->start);
4684 if (start < BEGV || start > ZV)
4685 {
b7617575 4686 int height = window_internal_height (w);
cd2be1dd 4687 Fvertical_motion (make_number (- (height / 2)), window);
b73ea88e 4688 set_marker_both (w->start, w->buffer, PT, PT_BYTE);
7ab12479
JB
4689 w->start_at_line_beg = Fbolp ();
4690 w->force_start = Qt;
4691 }
4692 else
b73ea88e 4693 Fgoto_char (w->start);
7ab12479 4694
b7617575
GM
4695 lines = displayed_window_lines (w);
4696 if (NILP (arg))
4697 XSETFASTINT (arg, lines / 2);
4698 else
4699 {
4700 arg = Fprefix_numeric_value (arg);
4701 if (XINT (arg) < 0)
4702 XSETINT (arg, XINT (arg) + lines);
4703 }
4704
c8bc6f65 4705 /* Skip past a partially visible first line. */
163784df 4706 if (w->vscroll)
163784df
MB
4707 XSETINT (arg, XINT (arg) + 1);
4708
540b6aa0 4709 return Fvertical_motion (arg, window);
7ab12479 4710}
5500c422
GM
4711
4712
7ab12479 4713\f
5500c422
GM
4714/***********************************************************************
4715 Window Configuration
4716 ***********************************************************************/
4717
7ab12479
JB
4718struct save_window_data
4719 {
f5ccc0cc 4720 EMACS_INT size_from_Lisp_Vector_struct;
7ab12479 4721 struct Lisp_Vector *next_from_Lisp_Vector_struct;
8f6ea2e9 4722 Lisp_Object frame_width, frame_height, frame_menu_bar_lines;
9ea173e8 4723 Lisp_Object frame_tool_bar_lines;
bdc727bf 4724 Lisp_Object selected_frame;
7ab12479
JB
4725 Lisp_Object current_window;
4726 Lisp_Object current_buffer;
4727 Lisp_Object minibuf_scroll_window;
4728 Lisp_Object root_window;
bdc727bf 4729 Lisp_Object focus_frame;
756b6edc
RS
4730 /* Record the values of window-min-width and window-min-height
4731 so that window sizes remain consistent with them. */
4732 Lisp_Object min_width, min_height;
cbff28e8
RS
4733 /* A vector, each of whose elements is a struct saved_window
4734 for one window. */
7ab12479
JB
4735 Lisp_Object saved_windows;
4736 };
ff06df24 4737
cbff28e8 4738/* This is saved as a Lisp_Vector */
7ab12479 4739struct saved_window
ea68264b
GM
4740{
4741 /* these first two must agree with struct Lisp_Vector in lisp.h */
4742 EMACS_INT size_from_Lisp_Vector_struct;
4743 struct Lisp_Vector *next_from_Lisp_Vector_struct;
7ab12479 4744
ea68264b
GM
4745 Lisp_Object window;
4746 Lisp_Object buffer, start, pointm, mark;
4747 Lisp_Object left, top, width, height, hscroll, min_hscroll;
4748 Lisp_Object parent, prev;
4749 Lisp_Object start_at_line_beg;
4750 Lisp_Object display_table;
4751 Lisp_Object orig_top, orig_height;
4752};
4753
4754#define SAVED_WINDOW_VECTOR_SIZE 17 /* Arg to Fmake_vector */
7ab12479
JB
4755
4756#define SAVED_WINDOW_N(swv,n) \
4757 ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
4758
4759DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
cbff28e8 4760 "Return t if OBJECT is a window-configuration object.")
413430c5
EN
4761 (object)
4762 Lisp_Object object;
7ab12479 4763{
413430c5 4764 if (WINDOW_CONFIGURATIONP (object))
7ab12479
JB
4765 return Qt;
4766 return Qnil;
4767}
4768
3f8ab7bd
RS
4769DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
4770 "Return the frame that CONFIG, a window-configuration object, is about.")
4771 (config)
4772 Lisp_Object config;
4773{
4774 register struct save_window_data *data;
4775 struct Lisp_Vector *saved_windows;
4776
4777 if (! WINDOW_CONFIGURATIONP (config))
4778 wrong_type_argument (Qwindow_configuration_p, config);
4779
4780 data = (struct save_window_data *) XVECTOR (config);
4781 saved_windows = XVECTOR (data->saved_windows);
4782 return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
4783}
4784
d5b2799e
RS
4785DEFUN ("set-window-configuration", Fset_window_configuration,
4786 Sset_window_configuration, 1, 1, 0,
7ab12479
JB
4787 "Set the configuration of windows and buffers as specified by CONFIGURATION.\n\
4788CONFIGURATION must be a value previously returned\n\
3f8ab7bd
RS
4789by `current-window-configuration' (which see).\n\
4790If CONFIGURATION was made from a frame that is now deleted,\n\
4791only frame-independent values can be restored. In this case,\n\
4792the return value is nil. Otherwise the value is t.")
4793 (configuration)
2f83aebe 4794 Lisp_Object configuration;
7ab12479 4795{
7ab12479
JB
4796 register struct save_window_data *data;
4797 struct Lisp_Vector *saved_windows;
7ab12479 4798 Lisp_Object new_current_buffer;
fd482be5 4799 Lisp_Object frame;
44fa5b1e 4800 FRAME_PTR f;
d2b35234 4801 int old_point = -1;
7ab12479 4802
017b2bad 4803 while (!WINDOW_CONFIGURATIONP (configuration))
3f8ab7bd 4804 wrong_type_argument (Qwindow_configuration_p, configuration);
7ab12479 4805
2f83aebe 4806 data = (struct save_window_data *) XVECTOR (configuration);
7ab12479
JB
4807 saved_windows = XVECTOR (data->saved_windows);
4808
7ab12479 4809 new_current_buffer = data->current_buffer;
265a9e55 4810 if (NILP (XBUFFER (new_current_buffer)->name))
7ab12479 4811 new_current_buffer = Qnil;
d2b35234
RS
4812 else
4813 {
4814 if (XBUFFER (new_current_buffer) == current_buffer)
4815 old_point = PT;
4816 }
7ab12479 4817
fd482be5
JB
4818 frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
4819 f = XFRAME (frame);
aa35ba9e 4820
fd482be5
JB
4821 /* If f is a dead frame, don't bother rebuilding its window tree.
4822 However, there is other stuff we should still try to do below. */
4823 if (FRAME_LIVE_P (f))
7ab12479 4824 {
fd482be5
JB
4825 register struct window *w;
4826 register struct saved_window *p;
5500c422
GM
4827 struct window *root_window;
4828 struct window **leaf_windows;
4829 int n_leaf_windows;
c4280705 4830 int k, i, n;
fd482be5
JB
4831
4832 /* If the frame has been resized since this window configuration was
4833 made, we change the frame to the size specified in the
4834 configuration, restore the configuration, and then resize it
4835 back. We keep track of the prevailing height in these variables. */
4836 int previous_frame_height = FRAME_HEIGHT (f);
4837 int previous_frame_width = FRAME_WIDTH (f);
8f6ea2e9 4838 int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
9ea173e8 4839 int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
fd482be5 4840
d2b35234
RS
4841 /* The mouse highlighting code could get screwed up
4842 if it runs during this. */
4843 BLOCK_INPUT;
4844
fd482be5
JB
4845 if (XFASTINT (data->frame_height) != previous_frame_height
4846 || XFASTINT (data->frame_width) != previous_frame_width)
f8ad443a 4847 change_frame_size (f, XFASTINT (data->frame_height),
2b653806 4848 XFASTINT (data->frame_width), 0, 0, 0);
e3678b64 4849#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
8f6ea2e9
KH
4850 if (XFASTINT (data->frame_menu_bar_lines)
4851 != previous_frame_menu_bar_lines)
f8ad443a 4852 x_set_menu_bar_lines (f, data->frame_menu_bar_lines, make_number (0));
4314246f 4853#ifdef HAVE_WINDOW_SYSTEM
9ea173e8
GM
4854 if (XFASTINT (data->frame_tool_bar_lines)
4855 != previous_frame_tool_bar_lines)
4856 x_set_tool_bar_lines (f, data->frame_tool_bar_lines, make_number (0));
4314246f 4857#endif
217f2871 4858#endif
fd482be5 4859
719eaeb1
GM
4860 /* "Swap out" point from the selected window
4861 into its buffer. We do this now, before
4862 restoring the window contents, and prevent it from
4863 being done later on when we select a new window. */
596ae0cf
RS
4864 if (! NILP (XWINDOW (selected_window)->buffer))
4865 {
4866 w = XWINDOW (selected_window);
4867 set_marker_both (w->pointm,
4868 w->buffer,
4869 BUF_PT (XBUFFER (w->buffer)),
4870 BUF_PT_BYTE (XBUFFER (w->buffer)));
4871 }
4872
fd482be5 4873 windows_or_buffers_changed++;
29aeee73 4874 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
fd482be5 4875
5500c422
GM
4876 /* Problem: Freeing all matrices and later allocating them again
4877 is a serious redisplay flickering problem. What we would
4878 really like to do is to free only those matrices not reused
4879 below. */
4880 root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
4881 leaf_windows
4882 = (struct window **) alloca (count_windows (root_window)
4883 * sizeof (struct window *));
4884 n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
4885
756b6edc
RS
4886 /* Temporarily avoid any problems with windows that are smaller
4887 than they are supposed to be. */
4888 window_min_height = 1;
4889 window_min_width = 1;
4890
fd482be5
JB
4891 /* Kludge Alert!
4892 Mark all windows now on frame as "deleted".
4893 Restoring the new configuration "undeletes" any that are in it.
37962e60 4894
fd482be5
JB
4895 Save their current buffers in their height fields, since we may
4896 need it later, if a buffer saved in the configuration is now
4897 dead. */
4898 delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
4899
4900 for (k = 0; k < saved_windows->size; k++)
4901 {
4902 p = SAVED_WINDOW_N (saved_windows, k);
4903 w = XWINDOW (p->window);
4904 w->next = Qnil;
7ab12479 4905
fd482be5
JB
4906 if (!NILP (p->parent))
4907 w->parent = SAVED_WINDOW_N (saved_windows,
4908 XFASTINT (p->parent))->window;
4909 else
4910 w->parent = Qnil;
7ab12479 4911
fd482be5 4912 if (!NILP (p->prev))
7ab12479 4913 {
fd482be5
JB
4914 w->prev = SAVED_WINDOW_N (saved_windows,
4915 XFASTINT (p->prev))->window;
4916 XWINDOW (w->prev)->next = p->window;
4917 }
4918 else
4919 {
4920 w->prev = Qnil;
4921 if (!NILP (w->parent))
4922 {
4923 if (EQ (p->width, XWINDOW (w->parent)->width))
4924 {
4925 XWINDOW (w->parent)->vchild = p->window;
4926 XWINDOW (w->parent)->hchild = Qnil;
4927 }
4928 else
4929 {
4930 XWINDOW (w->parent)->hchild = p->window;
4931 XWINDOW (w->parent)->vchild = Qnil;
4932 }
4933 }
4934 }
4935
4936 /* If we squirreled away the buffer in the window's height,
4937 restore it now. */
017b2bad 4938 if (BUFFERP (w->height))
fd482be5
JB
4939 w->buffer = w->height;
4940 w->left = p->left;
4941 w->top = p->top;
4942 w->width = p->width;
4943 w->height = p->height;
4944 w->hscroll = p->hscroll;
ea68264b 4945 w->min_hscroll = p->min_hscroll;
fd482be5 4946 w->display_table = p->display_table;
a1d58e5b
GM
4947 w->orig_top = p->orig_top;
4948 w->orig_height = p->orig_height;
d834a2e9 4949 XSETFASTINT (w->last_modified, 0);
3cd21523 4950 XSETFASTINT (w->last_overlay_modified, 0);
fd482be5
JB
4951
4952 /* Reinstall the saved buffer and pointers into it. */
4953 if (NILP (p->buffer))
4954 w->buffer = p->buffer;
4955 else
4956 {
4957 if (!NILP (XBUFFER (p->buffer)->name))
4958 /* If saved buffer is alive, install it. */
4959 {
4960 w->buffer = p->buffer;
4961 w->start_at_line_beg = p->start_at_line_beg;
b73ea88e
RS
4962 set_marker_restricted (w->start, p->start, w->buffer);
4963 set_marker_restricted (w->pointm, p->pointm, w->buffer);
fd482be5 4964 Fset_marker (XBUFFER (w->buffer)->mark,
b73ea88e 4965 p->mark, w->buffer);
fd482be5
JB
4966
4967 /* As documented in Fcurrent_window_configuration, don't
4968 save the location of point in the buffer which was current
4969 when the window configuration was recorded. */
6b54027b
RS
4970 if (!EQ (p->buffer, new_current_buffer)
4971 && XBUFFER (p->buffer) == current_buffer)
fd482be5
JB
4972 Fgoto_char (w->pointm);
4973 }
52a68e98
RS
4974 else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
4975 /* Else unless window has a live buffer, get one. */
7ab12479 4976 {
fd482be5
JB
4977 w->buffer = Fcdr (Fcar (Vbuffer_alist));
4978 /* This will set the markers to beginning of visible
4979 range. */
4980 set_marker_restricted (w->start, make_number (0), w->buffer);
4981 set_marker_restricted (w->pointm, make_number (0),w->buffer);
4982 w->start_at_line_beg = Qt;
7ab12479
JB
4983 }
4984 else
fd482be5 4985 /* Keeping window's old buffer; make sure the markers
52a68e98 4986 are real. */
7ab12479 4987 {
fd482be5
JB
4988 /* Set window markers at start of visible range. */
4989 if (XMARKER (w->start)->buffer == 0)
4990 set_marker_restricted (w->start, make_number (0),
4991 w->buffer);
4992 if (XMARKER (w->pointm)->buffer == 0)
b73ea88e
RS
4993 set_marker_restricted_both (w->pointm, w->buffer,
4994 BUF_PT (XBUFFER (w->buffer)),
4995 BUF_PT_BYTE (XBUFFER (w->buffer)));
fd482be5 4996 w->start_at_line_beg = Qt;
7ab12479
JB
4997 }
4998 }
4999 }
9ace597f 5000
fd482be5 5001 FRAME_ROOT_WINDOW (f) = data->root_window;
719eaeb1
GM
5002 /* Prevent "swapping out point" in the old selected window
5003 using the buffer that has been restored into it.
5004 That swapping out has already been done,
5005 near the beginning of this function. */
5006 selected_window = Qnil;
fd482be5 5007 Fselect_window (data->current_window);
396a830c
RS
5008 XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
5009 = selected_window;
7ab12479 5010
db269683 5011 if (NILP (data->focus_frame)
017b2bad 5012 || (FRAMEP (data->focus_frame)
db269683
JB
5013 && FRAME_LIVE_P (XFRAME (data->focus_frame))))
5014 Fredirect_frame_focus (frame, data->focus_frame);
7ab12479 5015
fd482be5
JB
5016#if 0 /* I don't understand why this is needed, and it causes problems
5017 when the frame's old selected window has been deleted. */
e4e59717 5018 if (f != selected_frame && FRAME_WINDOW_P (f))
9a7c6fc3 5019 do_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)),
d12f6f83 5020 0, 0);
fd482be5
JB
5021#endif
5022
5023 /* Set the screen height to the value it had before this function. */
5024 if (previous_frame_height != FRAME_HEIGHT (f)
5025 || previous_frame_width != FRAME_WIDTH (f))
5026 change_frame_size (f, previous_frame_height, previous_frame_width,
2b653806 5027 0, 0, 0);
e3678b64 5028#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
8f6ea2e9 5029 if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
f8ad443a
AS
5030 x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
5031 make_number (0));
4314246f 5032#ifdef HAVE_WINDOW_SYSTEM
9ea173e8
GM
5033 if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
5034 x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
5035 make_number (0));
4314246f 5036#endif
217f2871 5037#endif
d2b35234 5038
5500c422 5039 /* Now, free glyph matrices in windows that were not reused. */
c4280705
GM
5040 for (i = n = 0; i < n_leaf_windows; ++i)
5041 {
5042 if (NILP (leaf_windows[i]->buffer))
5043 {
5044 /* Assert it's not reused as a combination. */
5045 xassert (NILP (leaf_windows[i]->hchild)
5046 && NILP (leaf_windows[i]->vchild));
5047 free_window_matrices (leaf_windows[i]);
c4280705
GM
5048 }
5049 else if (EQ (leaf_windows[i]->buffer, new_current_buffer))
5050 ++n;
5051 }
5052
5053 /* If more than one window shows the new and old current buffer,
5054 don't try to preserve point in that buffer. */
5055 if (old_point > 0 && n > 1)
5056 old_point = -1;
5500c422
GM
5057
5058 adjust_glyphs (f);
5059
d2b35234 5060 UNBLOCK_INPUT;
756b6edc 5061
478292ed
RS
5062 /* Fselect_window will have made f the selected frame, so we
5063 reselect the proper frame here. Fhandle_switch_frame will change the
5064 selected window too, but that doesn't make the call to
5065 Fselect_window above totally superfluous; it still sets f's
5066 selected window. */
5067 if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
d12f6f83 5068 do_switch_frame (data->selected_frame, 0, 0);
478292ed
RS
5069
5070 if (! NILP (Vwindow_configuration_change_hook)
5071 && ! NILP (Vrun_hooks))
5072 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
5073 }
bdc727bf
JB
5074
5075 if (!NILP (new_current_buffer))
d2b35234
RS
5076 {
5077 Fset_buffer (new_current_buffer);
5078
5079 /* If the buffer that is current now is the same
5080 that was current before setting the window configuration,
5081 don't alter its PT. */
5082 if (old_point >= 0)
5083 SET_PT (old_point);
5084 }
bdc727bf 5085
478292ed
RS
5086 /* Restore the minimum heights recorded in the configuration. */
5087 window_min_height = XINT (data->min_height);
5088 window_min_width = XINT (data->min_width);
543f5fb1 5089
478292ed 5090 Vminibuf_scroll_window = data->minibuf_scroll_window;
543f5fb1 5091
3f8ab7bd 5092 return (FRAME_LIVE_P (f) ? Qt : Qnil);
7ab12479
JB
5093}
5094
44fa5b1e 5095/* Mark all windows now on frame as deleted
7ab12479
JB
5096 by setting their buffers to nil. */
5097
fd482be5 5098void
7ab12479
JB
5099delete_all_subwindows (w)
5100 register struct window *w;
5101{
265a9e55 5102 if (!NILP (w->next))
7ab12479 5103 delete_all_subwindows (XWINDOW (w->next));
265a9e55 5104 if (!NILP (w->vchild))
7ab12479 5105 delete_all_subwindows (XWINDOW (w->vchild));
265a9e55 5106 if (!NILP (w->hchild))
7ab12479 5107 delete_all_subwindows (XWINDOW (w->hchild));
605be8af
JB
5108
5109 w->height = w->buffer; /* See Fset_window_configuration for excuse. */
5110
86e48436
RS
5111 if (!NILP (w->buffer))
5112 unshow_buffer (w);
5113
605be8af
JB
5114 /* We set all three of these fields to nil, to make sure that we can
5115 distinguish this dead window from any live window. Live leaf
5116 windows will have buffer set, and combination windows will have
5117 vchild or hchild set. */
5118 w->buffer = Qnil;
5119 w->vchild = Qnil;
5120 w->hchild = Qnil;
acf70840
GM
5121
5122 Vwindow_list = Qnil;
7ab12479
JB
5123}
5124\f
5125static int
5126count_windows (window)
5127 register struct window *window;
5128{
5129 register int count = 1;
265a9e55 5130 if (!NILP (window->next))
7ab12479 5131 count += count_windows (XWINDOW (window->next));
265a9e55 5132 if (!NILP (window->vchild))
7ab12479 5133 count += count_windows (XWINDOW (window->vchild));
265a9e55 5134 if (!NILP (window->hchild))
7ab12479
JB
5135 count += count_windows (XWINDOW (window->hchild));
5136 return count;
5137}
5138
5500c422
GM
5139
5140/* Fill vector FLAT with leaf windows under W, starting at index I.
5141 Value is last index + 1. */
5142
5143static int
5144get_leaf_windows (w, flat, i)
5145 struct window *w;
5146 struct window **flat;
5147 int i;
5148{
5149 while (w)
5150 {
5151 if (!NILP (w->hchild))
5152 i = get_leaf_windows (XWINDOW (w->hchild), flat, i);
5153 else if (!NILP (w->vchild))
5154 i = get_leaf_windows (XWINDOW (w->vchild), flat, i);
5155 else
5156 flat[i++] = w;
5157
5158 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5159 }
5160
5161 return i;
5162}
5163
5164
5165/* Return a pointer to the glyph W's physical cursor is on. Value is
5166 null if W's current matrix is invalid, so that no meaningfull glyph
5167 can be returned. */
5168
5169struct glyph *
5170get_phys_cursor_glyph (w)
5171 struct window *w;
5172{
5173 struct glyph_row *row;
5174 struct glyph *glyph;
5175
5176 if (w->phys_cursor.vpos >= 0
5177 && w->phys_cursor.vpos < w->current_matrix->nrows
5178 && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
5179 row->enabled_p)
5180 && row->used[TEXT_AREA] > w->phys_cursor.hpos)
5181 glyph = row->glyphs[TEXT_AREA] + w->phys_cursor.hpos;
5182 else
5183 glyph = NULL;
5184
5185 return glyph;
5186}
5187
5188
7ab12479
JB
5189static int
5190save_window_save (window, vector, i)
5191 Lisp_Object window;
5192 struct Lisp_Vector *vector;
5193 int i;
5194{
5195 register struct saved_window *p;
5196 register struct window *w;
5197 register Lisp_Object tem;
5198
265a9e55 5199 for (;!NILP (window); window = w->next)
7ab12479
JB
5200 {
5201 p = SAVED_WINDOW_N (vector, i);
5202 w = XWINDOW (window);
5203
d834a2e9 5204 XSETFASTINT (w->temslot, i++);
7ab12479
JB
5205 p->window = window;
5206 p->buffer = w->buffer;
5207 p->left = w->left;
5208 p->top = w->top;
5209 p->width = w->width;
5210 p->height = w->height;
5211 p->hscroll = w->hscroll;
ea68264b 5212 p->min_hscroll = w->min_hscroll;
7ab12479 5213 p->display_table = w->display_table;
a1d58e5b
GM
5214 p->orig_top = w->orig_top;
5215 p->orig_height = w->orig_height;
265a9e55 5216 if (!NILP (w->buffer))
7ab12479
JB
5217 {
5218 /* Save w's value of point in the window configuration.
5219 If w is the selected window, then get the value of point
5220 from the buffer; pointm is garbage in the selected window. */
5221 if (EQ (window, selected_window))
5222 {
5223 p->pointm = Fmake_marker ();
b73ea88e
RS
5224 set_marker_both (p->pointm, w->buffer,
5225 BUF_PT (XBUFFER (w->buffer)),
5226 BUF_PT_BYTE (XBUFFER (w->buffer)));
7ab12479
JB
5227 }
5228 else
eeb82665 5229 p->pointm = Fcopy_marker (w->pointm, Qnil);
7ab12479 5230
eeb82665 5231 p->start = Fcopy_marker (w->start, Qnil);
7ab12479
JB
5232 p->start_at_line_beg = w->start_at_line_beg;
5233
5234 tem = XBUFFER (w->buffer)->mark;
eeb82665 5235 p->mark = Fcopy_marker (tem, Qnil);
7ab12479
JB
5236 }
5237 else
5238 {
5239 p->pointm = Qnil;
5240 p->start = Qnil;
5241 p->mark = Qnil;
5242 p->start_at_line_beg = Qnil;
5243 }
5244
265a9e55 5245 if (NILP (w->parent))
7ab12479
JB
5246 p->parent = Qnil;
5247 else
5248 p->parent = XWINDOW (w->parent)->temslot;
5249
265a9e55 5250 if (NILP (w->prev))
7ab12479
JB
5251 p->prev = Qnil;
5252 else
5253 p->prev = XWINDOW (w->prev)->temslot;
5254
265a9e55 5255 if (!NILP (w->vchild))
7ab12479 5256 i = save_window_save (w->vchild, vector, i);
265a9e55 5257 if (!NILP (w->hchild))
7ab12479
JB
5258 i = save_window_save (w->hchild, vector, i);
5259 }
5260
5261 return i;
5262}
5263
a0d76c27
EN
5264DEFUN ("current-window-configuration", Fcurrent_window_configuration,
5265 Scurrent_window_configuration, 0, 1, 0,
44fa5b1e
JB
5266 "Return an object representing the current window configuration of FRAME.\n\
5267If FRAME is nil or omitted, use the selected frame.\n\
7ab12479
JB
5268This describes the number of windows, their sizes and current buffers,\n\
5269and for each displayed buffer, where display starts, and the positions of\n\
5270point and mark. An exception is made for point in the current buffer:\n\
bdc727bf
JB
5271its value is -not- saved.\n\
5272This also records the currently selected frame, and FRAME's focus\n\
5273redirection (see `redirect-frame-focus').")
44fa5b1e
JB
5274 (frame)
5275 Lisp_Object frame;
7ab12479
JB
5276{
5277 register Lisp_Object tem;
5278 register int n_windows;
5279 register struct save_window_data *data;
da2792e0 5280 register struct Lisp_Vector *vec;
7ab12479 5281 register int i;
44fa5b1e 5282 FRAME_PTR f;
43bad991 5283
44fa5b1e 5284 if (NILP (frame))
1ae1a37d
GM
5285 frame = selected_frame;
5286 CHECK_LIVE_FRAME (frame, 0);
5287 f = XFRAME (frame);
7ab12479 5288
44fa5b1e 5289 n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
26605be9 5290 vec = allocate_other_vector (VECSIZE (struct save_window_data));
da2792e0
KH
5291 data = (struct save_window_data *)vec;
5292
d834a2e9
KH
5293 XSETFASTINT (data->frame_width, FRAME_WIDTH (f));
5294 XSETFASTINT (data->frame_height, FRAME_HEIGHT (f));
5295 XSETFASTINT (data->frame_menu_bar_lines, FRAME_MENU_BAR_LINES (f));
9ea173e8 5296 XSETFASTINT (data->frame_tool_bar_lines, FRAME_TOOL_BAR_LINES (f));
1ae1a37d 5297 data->selected_frame = selected_frame;
44fa5b1e 5298 data->current_window = FRAME_SELECTED_WINDOW (f);
74112613 5299 XSETBUFFER (data->current_buffer, current_buffer);
7ab12479 5300 data->minibuf_scroll_window = Vminibuf_scroll_window;
44fa5b1e 5301 data->root_window = FRAME_ROOT_WINDOW (f);
bdc727bf 5302 data->focus_frame = FRAME_FOCUS_FRAME (f);
74112613
KH
5303 XSETINT (data->min_height, window_min_height);
5304 XSETINT (data->min_width, window_min_width);
7ab12479
JB
5305 tem = Fmake_vector (make_number (n_windows), Qnil);
5306 data->saved_windows = tem;
5307 for (i = 0; i < n_windows; i++)
5308 XVECTOR (tem)->contents[i]
5309 = Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil);
a1d58e5b 5310 save_window_save (FRAME_ROOT_WINDOW (f), XVECTOR (tem), 0);
74112613 5311 XSETWINDOW_CONFIGURATION (tem, data);
7ab12479
JB
5312 return (tem);
5313}
5314
5315DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
5316 0, UNEVALLED, 0,
5317 "Execute body, preserving window sizes and contents.\n\
eb16ec06
RS
5318Restore which buffer appears in which window, where display starts,\n\
5319and the value of point and mark for each window.\n\
8ed92cf0 5320Also restore the choice of selected window.\n\
eb16ec06 5321Also restore which buffer is current.\n\
7ab12479
JB
5322Does not restore the value of point in current buffer.")
5323 (args)
5324 Lisp_Object args;
5325{
5326 register Lisp_Object val;
5327 register int count = specpdl_ptr - specpdl;
5328
5329 record_unwind_protect (Fset_window_configuration,
43bad991 5330 Fcurrent_window_configuration (Qnil));
7ab12479
JB
5331 val = Fprogn (args);
5332 return unbind_to (count, val);
5333}
5500c422
GM
5334
5335\f
5336/***********************************************************************
5337 Marginal Areas
5338 ***********************************************************************/
5339
5340DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
a7bdfc08 5341 2, 3, 0,
5500c422 5342 "Set width of marginal areas of window WINDOW.\n\
a7bdfc08 5343If window is nil, set margins of the currently selected window.\n\
5500c422
GM
5344First parameter LEFT-WIDTH specifies the number of character\n\
5345cells to reserve for the left marginal area. Second parameter\n\
5346RIGHT-WIDTH does the same for the right marginal area.\n\
5347A nil width parameter means no margin.")
cfa22082 5348 (window, left, right)
5500c422
GM
5349 Lisp_Object window, left, right;
5350{
5351 struct window *w = decode_window (window);
5500c422
GM
5352
5353 if (!NILP (left))
cfa22082 5354 CHECK_NUMBER_OR_FLOAT (left, 1);
5500c422 5355 if (!NILP (right))
cfa22082 5356 CHECK_NUMBER_OR_FLOAT (right, 2);
5500c422
GM
5357
5358 /* Check widths < 0 and translate a zero width to nil.
5359 Margins that are too wide have to be checked elsewhere. */
5360 if ((INTEGERP (left) && XINT (left) < 0)
7539e11f 5361 || (FLOATP (left) && XFLOAT_DATA (left) <= 0))
5500c422
GM
5362 XSETFASTINT (left, 0);
5363 if (INTEGERP (left) && XFASTINT (left) == 0)
5364 left = Qnil;
5365
5366 if ((INTEGERP (right) && XINT (right) < 0)
7539e11f 5367 || (FLOATP (right) && XFLOAT_DATA (right) <= 0))
5500c422
GM
5368 XSETFASTINT (right, 0);
5369 if (INTEGERP (right) && XFASTINT (right) == 0)
5370 right = Qnil;
5371
5372 w->left_margin_width = left;
5373 w->right_margin_width = right;
5374
5375 ++windows_or_buffers_changed;
5376 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
5377 return Qnil;
5378}
5379
5380
5381DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
5382 0, 1, 0,
5383 "Get width of marginal areas of window WINDOW.\n\
5384If WINDOW is omitted or nil, use the currently selected window.\n\
5385Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).\n\
5386If a marginal area does not exist, its width will be returned\n\
5387as nil.")
5388 (window)
5389 Lisp_Object window;
5390{
5391 struct window *w = decode_window (window);
5392 return Fcons (w->left_margin_width, w->right_margin_width);
5393}
5394
5395
7ab12479 5396\f
5500c422
GM
5397/***********************************************************************
5398 Smooth scrolling
5399 ***********************************************************************/
5400
5401DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 1, 0,
5402 "Return the amount by which WINDOW is scrolled vertically.\n\
5403Use the selected window if WINDOW is nil or omitted.\n\
5404Value is a multiple of the canonical character height of WINDOW.")
5405 (window)
5406 Lisp_Object window;
5407{
47004952 5408 Lisp_Object result;
5500c422
GM
5409 struct frame *f;
5410 struct window *w;
5411
5412 if (NILP (window))
5413 window = selected_window;
47004952
GM
5414 else
5415 CHECK_WINDOW (window, 0);
5500c422
GM
5416 w = XWINDOW (window);
5417 f = XFRAME (w->frame);
5418
5419 if (FRAME_WINDOW_P (f))
47004952 5420 result = CANON_Y_FROM_PIXEL_Y (f, -w->vscroll);
5500c422 5421 else
47004952
GM
5422 result = make_number (0);
5423 return result;
5500c422
GM
5424}
5425
5426
5427DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
47004952
GM
5428 2, 2, 0,
5429 "Set amount by which WINDOW should be scrolled vertically to VSCROLL.\n\
5500c422 5430WINDOW nil or omitted means use the selected window. VSCROLL is a\n\
47004952
GM
5431non-negative multiple of the canonical character height of WINDOW.")
5432 (window, vscroll)
5433 Lisp_Object window, vscroll;
5500c422
GM
5434{
5435 struct window *w;
5436 struct frame *f;
5437
5500c422
GM
5438 if (NILP (window))
5439 window = selected_window;
47004952
GM
5440 else
5441 CHECK_WINDOW (window, 0);
5442 CHECK_NUMBER_OR_FLOAT (vscroll, 1);
5443
5500c422
GM
5444 w = XWINDOW (window);
5445 f = XFRAME (w->frame);
5446
5447 if (FRAME_WINDOW_P (f))
5448 {
5449 int old_dy = w->vscroll;
47004952
GM
5450
5451 w->vscroll = - CANON_Y_UNIT (f) * XFLOATINT (vscroll);
5452 w->vscroll = min (w->vscroll, 0);
5500c422
GM
5453
5454 /* Adjust glyph matrix of the frame if the virtual display
5455 area becomes larger than before. */
5456 if (w->vscroll < 0 && w->vscroll < old_dy)
5457 adjust_glyphs (f);
5458
5459 /* Prevent redisplay shortcuts. */
b1599b4c 5460 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
5500c422
GM
5461 }
5462
47004952 5463 return Fwindow_vscroll (window);
5500c422
GM
5464}
5465
7bbb5782
GM
5466\f
5467/* Call FN for all leaf windows on frame F. FN is called with the
5468 first argument being a pointer to the leaf window, and with
f95464e4 5469 additional argument USER_DATA. Stops when FN returns 0. */
7bbb5782
GM
5470
5471void
f95464e4 5472foreach_window (f, fn, user_data)
7bbb5782 5473 struct frame *f;
f95464e4
GM
5474 int (* fn) P_ ((struct window *, void *));
5475 void *user_data;
7bbb5782 5476{
f95464e4 5477 foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data);
7bbb5782
GM
5478}
5479
5480
5481/* Helper function for foreach_window. Call FN for all leaf windows
5482 reachable from W. FN is called with the first argument being a
f95464e4 5483 pointer to the leaf window, and with additional argument USER_DATA.
67492200 5484 Stop when FN returns 0. Value is 0 if stopped by FN. */
7bbb5782 5485
67492200 5486static int
f95464e4 5487foreach_window_1 (w, fn, user_data)
7bbb5782 5488 struct window *w;
f95464e4
GM
5489 int (* fn) P_ ((struct window *, void *));
5490 void *user_data;
7bbb5782 5491{
67492200
GM
5492 int cont;
5493
5494 for (cont = 1; w && cont;)
7bbb5782
GM
5495 {
5496 if (!NILP (w->hchild))
f95464e4 5497 cont = foreach_window_1 (XWINDOW (w->hchild), fn, user_data);
7bbb5782 5498 else if (!NILP (w->vchild))
f95464e4 5499 cont = foreach_window_1 (XWINDOW (w->vchild), fn, user_data);
0f532a9a
GM
5500 else
5501 cont = fn (w, user_data);
7bbb5782
GM
5502
5503 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5504 }
67492200
GM
5505
5506 return cont;
7bbb5782
GM
5507}
5508
5509
5510/* Freeze or unfreeze the window start of W if unless it is a
f95464e4 5511 mini-window or the selected window. FREEZE_P non-null means freeze
7bbb5782
GM
5512 the window start. */
5513
67492200 5514static int
7bbb5782
GM
5515freeze_window_start (w, freeze_p)
5516 struct window *w;
f95464e4 5517 void *freeze_p;
7bbb5782
GM
5518{
5519 if (w == XWINDOW (selected_window)
5520 || MINI_WINDOW_P (w)
5521 || (MINI_WINDOW_P (XWINDOW (selected_window))
24d744ac 5522 && ! NILP (Vminibuf_scroll_window)
7bbb5782 5523 && w == XWINDOW (Vminibuf_scroll_window)))
f95464e4 5524 freeze_p = NULL;
7bbb5782 5525
f95464e4 5526 w->frozen_window_start_p = freeze_p != NULL;
67492200 5527 return 1;
7bbb5782
GM
5528}
5529
5530
5531/* Freeze or unfreeze the window starts of all leaf windows on frame
5532 F, except the selected window and a mini-window. FREEZE_P non-zero
5533 means freeze the window start. */
5534
5535void
5536freeze_window_starts (f, freeze_p)
5537 struct frame *f;
5538 int freeze_p;
5539{
cbccabec 5540 foreach_window (f, freeze_window_start, (void *) (freeze_p ? f : 0));
7bbb5782 5541}
5500c422
GM
5542
5543\f
5544/***********************************************************************
5545 Initialization
5546 ***********************************************************************/
5547
cbff28e8
RS
5548/* Return 1 if window configurations C1 and C2
5549 describe the same state of affairs. This is used by Fequal. */
5550
5551int
2f8274be 5552compare_window_configurations (c1, c2, ignore_positions)
cbff28e8 5553 Lisp_Object c1, c2;
2f8274be 5554 int ignore_positions;
cbff28e8
RS
5555{
5556 register struct save_window_data *d1, *d2;
5557 struct Lisp_Vector *sw1, *sw2;
5558 int i;
5559
4d3edcb4
GM
5560 if (!WINDOW_CONFIGURATIONP (c1))
5561 wrong_type_argument (Qwindow_configuration_p, c1);
5562 if (!WINDOW_CONFIGURATIONP (c2))
5563 wrong_type_argument (Qwindow_configuration_p, c2);
5564
cbff28e8
RS
5565 d1 = (struct save_window_data *) XVECTOR (c1);
5566 d2 = (struct save_window_data *) XVECTOR (c2);
5567 sw1 = XVECTOR (d1->saved_windows);
5568 sw2 = XVECTOR (d2->saved_windows);
5569
5570 if (! EQ (d1->frame_width, d2->frame_width))
5571 return 0;
5572 if (! EQ (d1->frame_height, d2->frame_height))
5573 return 0;
5574 if (! EQ (d1->frame_menu_bar_lines, d2->frame_menu_bar_lines))
5575 return 0;
5576 if (! EQ (d1->selected_frame, d2->selected_frame))
5577 return 0;
5578 /* Don't compare the current_window field directly.
5579 Instead see w1_is_current and w2_is_current, below. */
5580 if (! EQ (d1->current_buffer, d2->current_buffer))
5581 return 0;
2f8274be
RS
5582 if (! ignore_positions)
5583 if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
5584 return 0;
cbff28e8
RS
5585 /* Don't compare the root_window field.
5586 We don't require the two configurations
5587 to use the same window object,
5588 and the two root windows must be equivalent
5589 if everything else compares equal. */
5590 if (! EQ (d1->focus_frame, d2->focus_frame))
5591 return 0;
5592 if (! EQ (d1->min_width, d2->min_width))
5593 return 0;
5594 if (! EQ (d1->min_height, d2->min_height))
5595 return 0;
5596
5597 /* Verify that the two confis have the same number of windows. */
5598 if (sw1->size != sw2->size)
5599 return 0;
5600
5601 for (i = 0; i < sw1->size; i++)
5602 {
5603 struct saved_window *p1, *p2;
5604 int w1_is_current, w2_is_current;
5605
5606 p1 = SAVED_WINDOW_N (sw1, i);
5607 p2 = SAVED_WINDOW_N (sw2, i);
5608
5609 /* Verify that the current windows in the two
5610 configurations correspond to each other. */
5611 w1_is_current = EQ (d1->current_window, p1->window);
5612 w2_is_current = EQ (d2->current_window, p2->window);
5613
5614 if (w1_is_current != w2_is_current)
5615 return 0;
5616
5617 /* Verify that the corresponding windows do match. */
5618 if (! EQ (p1->buffer, p2->buffer))
5619 return 0;
5620 if (! EQ (p1->left, p2->left))
5621 return 0;
5622 if (! EQ (p1->top, p2->top))
5623 return 0;
5624 if (! EQ (p1->width, p2->width))
5625 return 0;
5626 if (! EQ (p1->height, p2->height))
5627 return 0;
cbff28e8
RS
5628 if (! EQ (p1->display_table, p2->display_table))
5629 return 0;
5630 if (! EQ (p1->parent, p2->parent))
5631 return 0;
5632 if (! EQ (p1->prev, p2->prev))
5633 return 0;
2f8274be
RS
5634 if (! ignore_positions)
5635 {
5636 if (! EQ (p1->hscroll, p2->hscroll))
5637 return 0;
ea68264b
GM
5638 if (!EQ (p1->min_hscroll, p2->min_hscroll))
5639 return 0;
2f8274be
RS
5640 if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
5641 return 0;
5642 if (NILP (Fequal (p1->start, p2->start)))
5643 return 0;
5644 if (NILP (Fequal (p1->pointm, p2->pointm)))
5645 return 0;
5646 if (NILP (Fequal (p1->mark, p2->mark)))
5647 return 0;
5648 }
cbff28e8
RS
5649 }
5650
5651 return 1;
5652}
2f8274be
RS
5653
5654DEFUN ("compare-window-configurations", Fcompare_window_configurations,
5655 Scompare_window_configurations, 2, 2, 0,
5656 "Compare two window configurations as regards the structure of windows.\n\
5657This function ignores details such as the values of point and mark\n\
5658and scrolling positions.")
5659 (x, y)
5660 Lisp_Object x, y;
5661{
5662 if (compare_window_configurations (x, y, 1))
5663 return Qt;
5664 return Qnil;
5665}
cbff28e8 5666\f
dfcf069d 5667void
7ab12479
JB
5668init_window_once ()
5669{
1ae1a37d
GM
5670 struct frame *f = make_terminal_frame ();
5671 XSETFRAME (selected_frame, f);
5672 Vterminal_frame = selected_frame;
5673 minibuf_window = f->minibuffer_window;
5674 selected_window = f->selected_window;
5675 last_nonminibuf_frame = f;
5b03d3c0
RS
5676
5677 window_initialized = 1;
7ab12479
JB
5678}
5679
67492200
GM
5680void
5681init_window ()
5682{
5683 Vwindow_list = Qnil;
5684}
5685
dfcf069d 5686void
7ab12479
JB
5687syms_of_window ()
5688{
7442878f
GM
5689 Qleft_fringe = intern ("left-fringe");
5690 staticpro (&Qleft_fringe);
5691 Qright_fringe = intern ("right-fringe");
5692 staticpro (&Qright_fringe);
fbad6f9a 5693
8a37516b
GM
5694 Qwindow_size_fixed = intern ("window-size-fixed");
5695 staticpro (&Qwindow_size_fixed);
233a4a2c 5696
543f5fb1
RS
5697 staticpro (&Qwindow_configuration_change_hook);
5698 Qwindow_configuration_change_hook
5699 = intern ("window-configuration-change-hook");
5700
7ab12479
JB
5701 Qwindowp = intern ("windowp");
5702 staticpro (&Qwindowp);
5703
3f8ab7bd
RS
5704 Qwindow_configuration_p = intern ("window-configuration-p");
5705 staticpro (&Qwindow_configuration_p);
5706
806b4d9b
JB
5707 Qwindow_live_p = intern ("window-live-p");
5708 staticpro (&Qwindow_live_p);
605be8af 5709
2cccc823 5710 Qtemp_buffer_show_hook = intern ("temp-buffer-show-hook");
a58ec57d
RS
5711 staticpro (&Qtemp_buffer_show_hook);
5712
67492200
GM
5713 staticpro (&Vwindow_list);
5714
7ab12479
JB
5715 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
5716 "Non-nil means call as function to display a help buffer.\n\
c3ef6b1d 5717The function is called with one argument, the buffer to be displayed.\n\
f52cca03
RS
5718Used by `with-output-to-temp-buffer'.\n\
5719If this function is used, then it must do the entire job of showing\n\
5720the buffer; `temp-buffer-show-hook' is not run unless this function runs it.");
7ab12479
JB
5721 Vtemp_buffer_show_function = Qnil;
5722
5723 DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
5724 "If non-nil, function to call to handle `display-buffer'.\n\
5725It will receive two args, the buffer and a flag which if non-nil means\n\
5726 that the currently selected window is not acceptable.\n\
5727Commands such as `switch-to-buffer-other-window' and `find-file-other-window'\n\
5728work using this function.");
5729 Vdisplay_buffer_function = Qnil;
5730
6529ed87
GM
5731 DEFVAR_LISP ("even-window-heights", &Veven_window_heights,
5732 "*If non-nil, `display-buffer' should even the window heights.\n\
85d19b32 5733If nil, `display-buffer' will leave the window configuration alone.");
6529ed87
GM
5734 Veven_window_heights = Qt;
5735
7ab12479
JB
5736 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
5737 "Non-nil means it is the window that C-M-v in minibuffer should scroll.");
5738 Vminibuf_scroll_window = Qnil;
5739
5740 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
5741 "If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.");
5742 Vother_window_scroll_buffer = Qnil;
5743
44fa5b1e 5744 DEFVAR_BOOL ("pop-up-frames", &pop_up_frames,
700f75a4 5745 "*Non-nil means `display-buffer' should make a separate frame.");
44fa5b1e 5746 pop_up_frames = 0;
7ab12479 5747
9c3da604 5748 DEFVAR_BOOL ("display-buffer-reuse-frames", &display_buffer_reuse_frames,
5372262f 5749 "*Non-nil means `display-buffer' should reuse frames.\n\
9c3da604
GM
5750If the buffer in question is already displayed in a frame, raise that frame.");
5751 display_buffer_reuse_frames = 0;
5752
44fa5b1e 5753 DEFVAR_LISP ("pop-up-frame-function", &Vpop_up_frame_function,
a90712c2 5754 "Function to call to handle automatic new frame creation.\n\
44fa5b1e 5755It is called with no arguments and should return a newly created frame.\n\
7ab12479 5756\n\
44fa5b1e
JB
5757A typical value might be `(lambda () (new-frame pop-up-frame-alist))'\n\
5758where `pop-up-frame-alist' would hold the default frame parameters.");
5759 Vpop_up_frame_function = Qnil;
7ab12479 5760
a90712c2
RS
5761 DEFVAR_LISP ("special-display-buffer-names", &Vspecial_display_buffer_names,
5762 "*List of buffer names that should have their own special frames.\n\
5763Displaying a buffer whose name is in this list makes a special frame for it\n\
524580a4 5764using `special-display-function'. See also `special-display-regexps'.\n\
3548e138 5765\n\
524580a4
RS
5766An element of the list can be a list instead of just a string.\n\
5767There are two ways to use a list as an element:\n\
5768 (BUFFER FRAME-PARAMETERS...) (BUFFER FUNCTION OTHER-ARGS...)\n\
5769In the first case, FRAME-PARAMETERS are used to create the frame.\n\
5770In the latter case, FUNCTION is called with BUFFER as the first argument,\n\
5771followed by OTHER-ARGS--it can display BUFFER in any way it likes.\n\
4caa7448
RS
5772All this is done by the function found in `special-display-function'.\n\
5773\n\
5774If this variable appears \"not to work\", because you add a name to it\n\
5775but that buffer still appears in the selected window, look at the\n\
5776values of `same-window-buffer-names' and `same-window-regexps'.\n\
5777Those variables take precedence over this one.");
a90712c2
RS
5778 Vspecial_display_buffer_names = Qnil;
5779
5780 DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
5781 "*List of regexps saying which buffers should have their own special frames.\n\
5782If a buffer name matches one of these regexps, it gets its own frame.\n\
5783Displaying a buffer whose name is in this list makes a special frame for it\n\
0a952b57 5784using `special-display-function'.\n\
3548e138 5785\n\
524580a4
RS
5786An element of the list can be a list instead of just a string.\n\
5787There are two ways to use a list as an element:\n\
5788 (REGEXP FRAME-PARAMETERS...) (REGEXP FUNCTION OTHER-ARGS...)\n\
5789In the first case, FRAME-PARAMETERS are used to create the frame.\n\
5790In the latter case, FUNCTION is called with the buffer as first argument,\n\
5791followed by OTHER-ARGS--it can display the buffer in any way it likes.\n\
4caa7448
RS
5792All this is done by the function found in `special-display-function'.\n\
5793\n\
5794If this variable appears \"not to work\", because you add a regexp to it\n\
5795but the matching buffers still appear in the selected window, look at the\n\
5796values of `same-window-buffer-names' and `same-window-regexps'.\n\
5797Those variables take precedence over this one.");
a90712c2
RS
5798 Vspecial_display_regexps = Qnil;
5799
5800 DEFVAR_LISP ("special-display-function", &Vspecial_display_function,
5801 "Function to call to make a new frame for a special buffer.\n\
0a952b57
RS
5802It is called with two arguments, the buffer and optional buffer specific\n\
5803data, and should return a window displaying that buffer.\n\
a90712c2 5804The default value makes a separate frame for the buffer,\n\
bdd3a802 5805using `special-display-frame-alist' to specify the frame parameters.\n\
a90712c2
RS
5806\n\
5807A buffer is special if its is listed in `special-display-buffer-names'\n\
5808or matches a regexp in `special-display-regexps'.");
5809 Vspecial_display_function = Qnil;
5810
855d8627
RS
5811 DEFVAR_LISP ("same-window-buffer-names", &Vsame_window_buffer_names,
5812 "*List of buffer names that should appear in the selected window.\n\
5813Displaying one of these buffers using `display-buffer' or `pop-to-buffer'\n\
5814switches to it in the selected window, rather than making it appear\n\
2e5ce1a0 5815in some other window.\n\
855d8627
RS
5816\n\
5817An element of the list can be a cons cell instead of just a string.\n\
5818Then the car must be a string, which specifies the buffer name.\n\
5819This is for compatibility with `special-display-buffer-names';\n\
5820the cdr of the cons cell is ignored.\n\
5821\n\
5822See also `same-window-regexps'.");
5823 Vsame_window_buffer_names = Qnil;
5824
5825 DEFVAR_LISP ("same-window-regexps", &Vsame_window_regexps,
5826 "*List of regexps saying which buffers should appear in the selected window.\n\
5827If a buffer name matches one of these regexps, then displaying it\n\
5828using `display-buffer' or `pop-to-buffer' switches to it\n\
5829in the selected window, rather than making it appear in some other window.\n\
5830\n\
5831An element of the list can be a cons cell instead of just a string.\n\
5832Then the car must be a string, which specifies the buffer name.\n\
5833This is for compatibility with `special-display-buffer-names';\n\
5834the cdr of the cons cell is ignored.\n\
5835\n\
5836See also `same-window-buffer-names'.");
5837 Vsame_window_regexps = Qnil;
5838
7ab12479
JB
5839 DEFVAR_BOOL ("pop-up-windows", &pop_up_windows,
5840 "*Non-nil means display-buffer should make new windows.");
5841 pop_up_windows = 1;
5842
5843 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
5844 "*Number of lines of continuity when scrolling by screenfuls.");
5845 next_screen_context_lines = 2;
5846
5847 DEFVAR_INT ("split-height-threshold", &split_height_threshold,
5848 "*display-buffer would prefer to split the largest window if this large.\n\
5849If there is only one window, it is split regardless of this value.");
5850 split_height_threshold = 500;
5851
5852 DEFVAR_INT ("window-min-height", &window_min_height,
5853 "*Delete any window less than this tall (including its mode line).");
5854 window_min_height = 4;
5855
5856 DEFVAR_INT ("window-min-width", &window_min_width,
5857 "*Delete any window less than this wide.");
5858 window_min_width = 10;
5859
5500c422
GM
5860 DEFVAR_LISP ("scroll-preserve-screen-position",
5861 &Vscroll_preserve_screen_position,
2afb2f41 5862 "*Non-nil means scroll commands move point to keep its screen line unchanged.");
5500c422 5863 Vscroll_preserve_screen_position = Qnil;
9317a85d 5864
543f5fb1
RS
5865 DEFVAR_LISP ("window-configuration-change-hook",
5866 &Vwindow_configuration_change_hook,
5867 "Functions to call when window configuration changes.\n\
e3e041eb 5868The selected frame is the one whose configuration has changed.");
543f5fb1
RS
5869 Vwindow_configuration_change_hook = Qnil;
5870
b0b7ed0e
GM
5871 DEFVAR_BOOL ("window-size-fixed", &window_size_fixed,
5872 "Non-nil in a buffer means windows displaying the buffer are fixed-size.\n\
5873Emacs won't change the size of any window displaying that buffer,\n\
5874unless you explicitly change the size, or Emacs has no other choice.\n\
5875This variable automatically becomes buffer-local when set.");
5876 Fmake_variable_buffer_local (Qwindow_size_fixed);
5877 window_size_fixed = 0;
5878
7ab12479
JB
5879 defsubr (&Sselected_window);
5880 defsubr (&Sminibuffer_window);
5881 defsubr (&Swindow_minibuffer_p);
5882 defsubr (&Swindowp);
806b4d9b 5883 defsubr (&Swindow_live_p);
7ab12479
JB
5884 defsubr (&Spos_visible_in_window_p);
5885 defsubr (&Swindow_buffer);
5886 defsubr (&Swindow_height);
5887 defsubr (&Swindow_width);
5888 defsubr (&Swindow_hscroll);
5889 defsubr (&Sset_window_hscroll);
190eb263
RS
5890 defsubr (&Swindow_redisplay_end_trigger);
5891 defsubr (&Sset_window_redisplay_end_trigger);
7ab12479 5892 defsubr (&Swindow_edges);
d5783c40
JB
5893 defsubr (&Scoordinates_in_window_p);
5894 defsubr (&Swindow_at);
7ab12479
JB
5895 defsubr (&Swindow_point);
5896 defsubr (&Swindow_start);
5897 defsubr (&Swindow_end);
5898 defsubr (&Sset_window_point);
5899 defsubr (&Sset_window_start);
5900 defsubr (&Swindow_dedicated_p);
d207b766 5901 defsubr (&Sset_window_dedicated_p);
7ab12479
JB
5902 defsubr (&Swindow_display_table);
5903 defsubr (&Sset_window_display_table);
5904 defsubr (&Snext_window);
5905 defsubr (&Sprevious_window);
5906 defsubr (&Sother_window);
5907 defsubr (&Sget_lru_window);
5908 defsubr (&Sget_largest_window);
5909 defsubr (&Sget_buffer_window);
5910 defsubr (&Sdelete_other_windows);
5911 defsubr (&Sdelete_windows_on);
5912 defsubr (&Sreplace_buffer_in_windows);
5913 defsubr (&Sdelete_window);
5914 defsubr (&Sset_window_buffer);
5915 defsubr (&Sselect_window);
4628f7a4
EN
5916 defsubr (&Sspecial_display_p);
5917 defsubr (&Ssame_window_p);
7ab12479
JB
5918 defsubr (&Sdisplay_buffer);
5919 defsubr (&Ssplit_window);
5920 defsubr (&Senlarge_window);
5921 defsubr (&Sshrink_window);
5922 defsubr (&Sscroll_up);
5923 defsubr (&Sscroll_down);
5924 defsubr (&Sscroll_left);
5925 defsubr (&Sscroll_right);
ccd0664b 5926 defsubr (&Sother_window_for_scrolling);
7ab12479
JB
5927 defsubr (&Sscroll_other_window);
5928 defsubr (&Srecenter);
81fe0836 5929 defsubr (&Swindow_text_height);
7ab12479
JB
5930 defsubr (&Smove_to_window_line);
5931 defsubr (&Swindow_configuration_p);
3f8ab7bd 5932 defsubr (&Swindow_configuration_frame);
7ab12479
JB
5933 defsubr (&Sset_window_configuration);
5934 defsubr (&Scurrent_window_configuration);
5935 defsubr (&Ssave_window_excursion);
5500c422
GM
5936 defsubr (&Sset_window_margins);
5937 defsubr (&Swindow_margins);
5938 defsubr (&Swindow_vscroll);
5939 defsubr (&Sset_window_vscroll);
2f8274be 5940 defsubr (&Scompare_window_configurations);
67492200 5941 defsubr (&Swindow_list);
7ab12479
JB
5942}
5943
dfcf069d 5944void
7ab12479
JB
5945keys_of_window ()
5946{
5947 initial_define_key (control_x_map, '1', "delete-other-windows");
5948 initial_define_key (control_x_map, '2', "split-window");
5949 initial_define_key (control_x_map, '0', "delete-window");
5950 initial_define_key (control_x_map, 'o', "other-window");
5951 initial_define_key (control_x_map, '^', "enlarge-window");
5952 initial_define_key (control_x_map, '<', "scroll-left");
5953 initial_define_key (control_x_map, '>', "scroll-right");
5954
5955 initial_define_key (global_map, Ctl ('V'), "scroll-up");
5956 initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
5957 initial_define_key (meta_map, 'v', "scroll-down");
5958
5959 initial_define_key (global_map, Ctl('L'), "recenter");
5960 initial_define_key (meta_map, 'r', "move-to-window-line");
5961}