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