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