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