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