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