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