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