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