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