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