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