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