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