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