(Splitting Windows): Clarify splitting nonselected window.
[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).
3781The upper or leftmost window is the original one and remains selected.
3782See Info node `(elisp)Splitting Windows' for more details and examples.*/)
fdb82f93 3783 (window, size, horflag)
77ae0fe3 3784 Lisp_Object window, size, horflag;
7ab12479
JB
3785{
3786 register Lisp_Object new;
3787 register struct window *o, *p;
c0807608 3788 FRAME_PTR fo;
77ae0fe3 3789 register int size_int;
7ab12479 3790
265a9e55 3791 if (NILP (window))
7ab12479
JB
3792 window = selected_window;
3793 else
b7826503 3794 CHECK_LIVE_WINDOW (window);
7ab12479
JB
3795
3796 o = XWINDOW (window);
c0807608 3797 fo = XFRAME (WINDOW_FRAME (o));
7ab12479 3798
77ae0fe3 3799 if (NILP (size))
7ab12479 3800 {
265a9e55 3801 if (!NILP (horflag))
c0807608 3802 /* Calculate the size of the left-hand window, by dividing
25b33244
KH
3803 the usable space in columns by two.
3804 We round up, since the left-hand window may include
3805 a dividing line, while the right-hand may not. */
949cf20f 3806 size_int = (XFASTINT (o->total_cols) + 1) >> 1;
7ab12479 3807 else
949cf20f 3808 size_int = XFASTINT (o->total_lines) >> 1;
7ab12479
JB
3809 }
3810 else
3811 {
b7826503 3812 CHECK_NUMBER (size);
77ae0fe3 3813 size_int = XINT (size);
7ab12479
JB
3814 }
3815
3816 if (MINI_WINDOW_P (o))
3817 error ("Attempt to split minibuffer window");
233a4a2c
GM
3818 else if (window_fixed_size_p (o, !NILP (horflag), 0))
3819 error ("Attempt to split fixed-size window");
7ab12479 3820
a481b3ea 3821 check_min_window_sizes ();
7ab12479 3822
265a9e55 3823 if (NILP (horflag))
7ab12479 3824 {
77ae0fe3
KH
3825 if (size_int < window_min_height)
3826 error ("Window height %d too small (after splitting)", size_int);
949cf20f 3827 if (size_int + window_min_height > XFASTINT (o->total_lines))
37962e60 3828 error ("Window height %d too small (after splitting)",
949cf20f 3829 XFASTINT (o->total_lines) - size_int);
265a9e55
JB
3830 if (NILP (o->parent)
3831 || NILP (XWINDOW (o->parent)->vchild))
7ab12479
JB
3832 {
3833 make_dummy_parent (window);
3834 new = o->parent;
3835 XWINDOW (new)->vchild = window;
3836 }
3837 }
3838 else
3839 {
77ae0fe3
KH
3840 if (size_int < window_min_width)
3841 error ("Window width %d too small (after splitting)", size_int);
a59fed7e 3842
949cf20f 3843 if (size_int + window_min_width > XFASTINT (o->total_cols))
37962e60 3844 error ("Window width %d too small (after splitting)",
949cf20f 3845 XFASTINT (o->total_cols) - size_int);
265a9e55
JB
3846 if (NILP (o->parent)
3847 || NILP (XWINDOW (o->parent)->hchild))
7ab12479
JB
3848 {
3849 make_dummy_parent (window);
3850 new = o->parent;
3851 XWINDOW (new)->hchild = window;
3852 }
3853 }
3854
3855 /* Now we know that window's parent is a vertical combination
3856 if we are dividing vertically, or a horizontal combination
3857 if we are making side-by-side windows */
3858
3859 windows_or_buffers_changed++;
c0807608 3860 FRAME_WINDOW_SIZES_CHANGED (fo) = 1;
7ab12479
JB
3861 new = make_window ();
3862 p = XWINDOW (new);
3863
44fa5b1e 3864 p->frame = o->frame;
7ab12479 3865 p->next = o->next;
265a9e55 3866 if (!NILP (p->next))
7ab12479
JB
3867 XWINDOW (p->next)->prev = new;
3868 p->prev = window;
3869 o->next = new;
3870 p->parent = o->parent;
3871 p->buffer = Qt;
5500c422
GM
3872 p->window_end_valid = Qnil;
3873 bzero (&p->last_cursor, sizeof p->last_cursor);
7ab12479 3874
949cf20f
KS
3875 /* Duplicate special geometry settings. */
3876
3877 p->left_margin_cols = o->left_margin_cols;
3878 p->right_margin_cols = o->right_margin_cols;
3879 p->left_fringe_width = o->left_fringe_width;
3880 p->right_fringe_width = o->right_fringe_width;
3881 p->fringes_outside_margins = o->fringes_outside_margins;
3882 p->scroll_bar_width = o->scroll_bar_width;
3883 p->vertical_scroll_bar_type = o->vertical_scroll_bar_type;
3884
44fa5b1e 3885 /* Apportion the available frame space among the two new windows */
7ab12479 3886
265a9e55 3887 if (!NILP (horflag))
7ab12479 3888 {
949cf20f
KS
3889 p->total_lines = o->total_lines;
3890 p->top_line = o->top_line;
3891 XSETFASTINT (p->total_cols, XFASTINT (o->total_cols) - size_int);
3892 XSETFASTINT (o->total_cols, size_int);
3893 XSETFASTINT (p->left_col, XFASTINT (o->left_col) + size_int);
3894 adjust_window_margins (p);
3895 adjust_window_margins (o);
7ab12479
JB
3896 }
3897 else
3898 {
949cf20f
KS
3899 p->left_col = o->left_col;
3900 p->total_cols = o->total_cols;
3901 XSETFASTINT (p->total_lines, XFASTINT (o->total_lines) - size_int);
3902 XSETFASTINT (o->total_lines, size_int);
3903 XSETFASTINT (p->top_line, XFASTINT (o->top_line) + size_int);
7ab12479
JB
3904 }
3905
5500c422
GM
3906 /* Adjust glyph matrices. */
3907 adjust_glyphs (fo);
949cf20f
KS
3908
3909 Fset_window_buffer (new, o->buffer, Qt);
7ab12479
JB
3910 return new;
3911}
3912\f
56ebfae2 3913DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
fdb82f93
PJ
3914 doc: /* Make current window ARG lines bigger.
3915From program, optional second arg non-nil means grow sideways ARG columns.
f95284d2 3916Interactively, if an argument is not given, make the window one line bigger.
5afc696a 3917If HORIZONTAL is non-nil, enlarge horizontally instead of vertically.
56ebfae2
RS
3918This function can delete windows, even the second window, if they get
3919too small. */)
3920 (arg, horizontal)
3921 Lisp_Object arg, horizontal;
7ab12479 3922{
b7826503 3923 CHECK_NUMBER (arg);
56ebfae2 3924 enlarge_window (selected_window, XINT (arg), !NILP (horizontal));
543f5fb1
RS
3925
3926 if (! NILP (Vwindow_configuration_change_hook))
3927 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
3928
7ab12479
JB
3929 return Qnil;
3930}
3931
56ebfae2 3932DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
fdb82f93
PJ
3933 doc: /* Make current window ARG lines smaller.
3934From program, optional second arg non-nil means shrink sideways arg columns.
56ebfae2 3935Interactively, if an argument is not given, make the window one line smaller. Only
a5731348 3936siblings to the right or below are changed. */)
56ebfae2
RS
3937 (arg, side)
3938 Lisp_Object arg, side;
7ab12479 3939{
b7826503 3940 CHECK_NUMBER (arg);
56ebfae2 3941 enlarge_window (selected_window, -XINT (arg), !NILP (side));
543f5fb1
RS
3942
3943 if (! NILP (Vwindow_configuration_change_hook))
3944 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
3945
7ab12479
JB
3946 return Qnil;
3947}
3948
3949int
3950window_height (window)
3951 Lisp_Object window;
3952{
3953 register struct window *p = XWINDOW (window);
949cf20f 3954 return WINDOW_TOTAL_LINES (p);
7ab12479
JB
3955}
3956
3957int
3958window_width (window)
3959 Lisp_Object window;
3960{
3961 register struct window *p = XWINDOW (window);
949cf20f 3962 return WINDOW_TOTAL_COLS (p);
7ab12479
JB
3963}
3964
177c0ea7 3965
7ab12479 3966#define CURBEG(w) \
5afc696a 3967 *(horiz_flag ? &(XWINDOW (w)->left_col) : &(XWINDOW (w)->top_line))
7ab12479
JB
3968
3969#define CURSIZE(w) \
5afc696a
RS
3970 *(horiz_flag ? &(XWINDOW (w)->total_cols) : &(XWINDOW (w)->total_lines))
3971
7ab12479 3972
5afc696a
RS
3973/* Enlarge WINDOW by DELTA.
3974 HORIZ_FLAG nonzero means enlarge it horizontally;
3975 zero means do it vertically.
233a4a2c 3976
5afc696a
RS
3977 Siblings of the selected window are resized to fulfill the size
3978 request. If they become too small in the process, they will be
56ebfae2 3979 deleted. */
7ab12479 3980
f984d4fc 3981static void
56ebfae2 3982enlarge_window (window, delta, horiz_flag)
86c8e823 3983 Lisp_Object window;
56ebfae2 3984 int delta, horiz_flag;
7ab12479 3985{
86c8e823 3986 Lisp_Object parent, next, prev;
233a4a2c 3987 struct window *p;
3578db3c
KR
3988 Lisp_Object *sizep;
3989 int maximum;
5e14b1fc 3990 int (*sizefun) P_ ((Lisp_Object))
5afc696a 3991 = horiz_flag ? window_width : window_height;
233a4a2c 3992 void (*setsizefun) P_ ((Lisp_Object, int, int))
5afc696a 3993 = (horiz_flag ? set_window_width : set_window_height);
7ab12479 3994
233a4a2c
GM
3995 /* Check values of window_min_width and window_min_height for
3996 validity. */
a481b3ea 3997 check_min_window_sizes ();
7ab12479 3998
233a4a2c 3999 /* Give up if this window cannot be resized. */
5afc696a 4000 if (window_fixed_size_p (XWINDOW (window), horiz_flag, 1))
233a4a2c
GM
4001 error ("Window is not resizable");
4002
4003 /* Find the parent of the selected window. */
7ab12479
JB
4004 while (1)
4005 {
4006 p = XWINDOW (window);
4007 parent = p->parent;
177c0ea7 4008
265a9e55 4009 if (NILP (parent))
7ab12479 4010 {
5afc696a 4011 if (horiz_flag)
7ab12479
JB
4012 error ("No other window to side of this one");
4013 break;
4014 }
177c0ea7 4015
5afc696a 4016 if (horiz_flag
233a4a2c 4017 ? !NILP (XWINDOW (parent)->hchild)
265a9e55 4018 : !NILP (XWINDOW (parent)->vchild))
7ab12479 4019 break;
177c0ea7 4020
7ab12479
JB
4021 window = parent;
4022 }
4023
05c2896a 4024 sizep = &CURSIZE (window);
7ab12479 4025
7ab12479
JB
4026 {
4027 register int maxdelta;
7ab12479 4028
f95284d2
RS
4029 /* Compute the maximum size increment this window can have. */
4030
56ebfae2
RS
4031 maxdelta = (!NILP (parent) ? (*sizefun) (parent) - XINT (*sizep)
4032 /* This is a main window followed by a minibuffer. */
4033 : !NILP (p->next) ? ((*sizefun) (p->next)
4034 - window_min_size (XWINDOW (p->next),
4035 horiz_flag, 0, 0))
4036 /* This is a minibuffer following a main window. */
4037 : !NILP (p->prev) ? ((*sizefun) (p->prev)
4038 - window_min_size (XWINDOW (p->prev),
4039 horiz_flag, 0, 0))
4040 /* This is a frame with only one window, a minibuffer-only
4041 or a minibufferless frame. */
4042 : (delta = 0));
7ab12479
JB
4043
4044 if (delta > maxdelta)
4045 /* This case traps trying to make the minibuffer
44fa5b1e
JB
4046 the full frame, or make the only window aside from the
4047 minibuffer the full frame. */
7ab12479 4048 delta = maxdelta;
6b54027b 4049 }
d5783c40 4050
5afc696a 4051 if (XINT (*sizep) + delta < window_min_size (XWINDOW (window), horiz_flag, 0, 0))
6b54027b 4052 {
543f5fb1 4053 delete_window (window);
d5783c40 4054 return;
6b54027b
RS
4055 }
4056
4057 if (delta == 0)
4058 return;
7ab12479 4059
f95284d2 4060 /* Find the total we can get from other siblings without deleting them. */
db98a733
RS
4061 maximum = 0;
4062 for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
c1636aa6 4063 maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
5afc696a 4064 horiz_flag, 0, 0);
56ebfae2
RS
4065 for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
4066 maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
4067 horiz_flag, 0, 0);
db98a733 4068
f95284d2 4069 /* If we can get it all from them without deleting them, do so. */
c6b530ed 4070 if (delta <= maximum)
7ab12479 4071 {
db98a733
RS
4072 Lisp_Object first_unaffected;
4073 Lisp_Object first_affected;
233a4a2c 4074 int fixed_p;
db98a733
RS
4075
4076 next = p->next;
4077 prev = p->prev;
4078 first_affected = window;
4079 /* Look at one sibling at a time,
4080 moving away from this window in both directions alternately,
4081 and take as much as we can get without deleting that sibling. */
f95284d2 4082 while (delta != 0
56ebfae2 4083 && (!NILP (next) || !NILP (prev)))
db98a733 4084 {
db98a733
RS
4085 if (! NILP (next))
4086 {
c1636aa6 4087 int this_one = ((*sizefun) (next)
233a4a2c 4088 - window_min_size (XWINDOW (next),
5afc696a 4089 horiz_flag, 0, &fixed_p));
233a4a2c
GM
4090 if (!fixed_p)
4091 {
4092 if (this_one > delta)
4093 this_one = delta;
177c0ea7 4094
233a4a2c 4095 (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
3578db3c 4096 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
db98a733 4097
233a4a2c
GM
4098 delta -= this_one;
4099 }
177c0ea7 4100
db98a733
RS
4101 next = XWINDOW (next)->next;
4102 }
177c0ea7 4103
db98a733
RS
4104 if (delta == 0)
4105 break;
177c0ea7 4106
56ebfae2 4107 if (! NILP (prev))
db98a733 4108 {
c1636aa6 4109 int this_one = ((*sizefun) (prev)
233a4a2c 4110 - window_min_size (XWINDOW (prev),
5afc696a 4111 horiz_flag, 0, &fixed_p));
233a4a2c
GM
4112 if (!fixed_p)
4113 {
4114 if (this_one > delta)
4115 this_one = delta;
177c0ea7 4116
233a4a2c 4117 first_affected = prev;
177c0ea7 4118
233a4a2c 4119 (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
3578db3c 4120 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
233a4a2c
GM
4121
4122 delta -= this_one;
4123 }
177c0ea7 4124
db98a733
RS
4125 prev = XWINDOW (prev)->prev;
4126 }
4127 }
4128
233a4a2c
GM
4129 xassert (delta == 0);
4130
db98a733
RS
4131 /* Now recalculate the edge positions of all the windows affected,
4132 based on the new sizes. */
4133 first_unaffected = next;
4134 prev = first_affected;
4135 for (next = XWINDOW (prev)->next; ! EQ (next, first_unaffected);
4136 prev = next, next = XWINDOW (next)->next)
4137 {
3578db3c 4138 XSETINT (CURBEG (next), XINT (CURBEG (prev)) + (*sizefun) (prev));
db98a733
RS
4139 /* This does not change size of NEXT,
4140 but it propagates the new top edge to its children */
4141 (*setsizefun) (next, (*sizefun) (next), 0);
4142 }
7ab12479
JB
4143 }
4144 else
4145 {
4146 register int delta1;
4147 register int opht = (*sizefun) (parent);
4148
3578db3c 4149 if (opht <= XINT (*sizep) + delta)
daf516d3
RS
4150 {
4151 /* If trying to grow this window to or beyond size of the parent,
4152 just delete all the sibling windows. */
dc1ab1ee 4153 Lisp_Object start, tem, next;
daf516d3 4154
dc1ab1ee
RS
4155 start = XWINDOW (parent)->vchild;
4156 if (NILP (start))
4157 start = XWINDOW (parent)->hchild;
daf516d3 4158
dc1ab1ee
RS
4159 /* Delete any siblings that come after WINDOW. */
4160 tem = XWINDOW (window)->next;
daf516d3
RS
4161 while (! NILP (tem))
4162 {
4163 next = XWINDOW (tem)->next;
dc1ab1ee
RS
4164 delete_window (tem);
4165 tem = next;
4166 }
4167
4168 /* Delete any siblings that come after WINDOW.
4169 Note that if START is not WINDOW, then WINDOW still
4170 Fhas siblings, so WINDOW has not yet replaced its parent. */
4171 tem = start;
4172 while (! EQ (tem, window))
4173 {
4174 next = XWINDOW (tem)->next;
4175 delete_window (tem);
daf516d3
RS
4176 tem = next;
4177 }
4178 }
7ab12479 4179 else
233a4a2c
GM
4180 {
4181 /* Otherwise, make delta1 just right so that if we add
4182 delta1 lines to this window and to the parent, and then
4183 shrink the parent back to its original size, the new
4184 proportional size of this window will increase by delta.
4185
4186 The function size_window will compute the new height h'
4187 of the window from delta1 as:
177c0ea7 4188
233a4a2c
GM
4189 e = delta1/n
4190 x = delta1 - delta1/n * n for the 1st resizable child
4191 h' = h + e + x
4192
4193 where n is the number of children that can be resized.
4194 We can ignore x by choosing a delta1 that is a multiple of
4195 n. We want the height of this window to come out as
177c0ea7 4196
233a4a2c
GM
4197 h' = h + delta
4198
4199 So, delta1 must be
177c0ea7 4200
233a4a2c
GM
4201 h + e = h + delta
4202 delta1/n = delta
4203 delta1 = n * delta.
4204
a5731348 4205 The number of children n equals the number of resizable
233a4a2c 4206 children of this window + 1 because we know window itself
6e0dca3d 4207 is resizable (otherwise we would have signalled an error). */
233a4a2c
GM
4208
4209 struct window *w = XWINDOW (window);
4210 Lisp_Object s;
4211 int n = 1;
4212
4213 for (s = w->next; !NILP (s); s = XWINDOW (s)->next)
5afc696a 4214 if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
233a4a2c
GM
4215 ++n;
4216 for (s = w->prev; !NILP (s); s = XWINDOW (s)->prev)
5afc696a 4217 if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
233a4a2c
GM
4218 ++n;
4219
4220 delta1 = n * delta;
7ab12479 4221
daf516d3
RS
4222 /* Add delta1 lines or columns to this window, and to the parent,
4223 keeping things consistent while not affecting siblings. */
4224 XSETINT (CURSIZE (parent), opht + delta1);
4225 (*setsizefun) (window, XINT (*sizep) + delta1, 0);
4226
4227 /* Squeeze out delta1 lines or columns from our parent,
4228 shriking this window and siblings proportionately.
4229 This brings parent back to correct size.
4230 Delta1 was calculated so this makes this window the desired size,
4231 taking it all out of the siblings. */
4232 (*setsizefun) (parent, opht, 0);
4233
4234 }
7ab12479
JB
4235 }
4236
d834a2e9 4237 XSETFASTINT (p->last_modified, 0);
3cd21523 4238 XSETFASTINT (p->last_overlay_modified, 0);
5500c422
GM
4239
4240 /* Adjust glyph matrices. */
4241 adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
7ab12479 4242}
c1636aa6 4243
0d384044
RS
4244
4245/* Adjust the size of WINDOW by DELTA, moving only its trailing edge.
4246 HORIZ_FLAG nonzero means adjust the width, moving the right edge.
4247 zero means adjust the height, moving the bottom edge.
4248
4249 Following siblings of the selected window are resized to fulfill
4250 the size request. If they become too small in the process, they
4251 are not deleted; instead, we signal an error. */
4252
4253static void
4254adjust_window_trailing_edge (window, delta, horiz_flag)
4255 Lisp_Object window;
4256 int delta, horiz_flag;
4257{
4258 Lisp_Object parent, child;
4259 struct window *p;
4260 Lisp_Object old_config = Fcurrent_window_configuration (Qnil);
4261 int delcount = window_deletion_count;
4262
4263 /* Check values of window_min_width and window_min_height for
4264 validity. */
4265 check_min_window_sizes ();
4266
4267 if (NILP (window))
4268 window = Fselected_window ();
4269
4270 CHECK_WINDOW (window);
4271
4272 /* Give up if this window cannot be resized. */
4273 if (window_fixed_size_p (XWINDOW (window), horiz_flag, 1))
4274 error ("Window is not resizable");
4275
4276 while (1)
4277 {
bd99e242
RS
4278 Lisp_Object first_parallel = Qnil;
4279
0d384044
RS
4280 p = XWINDOW (window);
4281 parent = p->parent;
4282
bd99e242 4283 if (NILP (XWINDOW (window)->next))
0d384044
RS
4284 {
4285 Fset_window_configuration (old_config);
4286 error ("No other window following this one");
4287 }
4288
bd99e242
RS
4289 /* See if this level has windows in parallel in the specified
4290 direction. If so, set FIRST_PARALLEL to the first one. */
4291 if (horiz_flag)
4292 {
4293 if (! NILP (parent) && !NILP (XWINDOW (parent)->vchild))
4294 first_parallel = XWINDOW (parent)->vchild;
4295 }
4296 else
4297 {
4298 if (! NILP (parent) && !NILP (XWINDOW (parent)->hchild))
4299 first_parallel = XWINDOW (parent)->hchild;
4300 }
4301
0d384044
RS
4302 /* Don't make this window too small. */
4303 if (XINT (CURSIZE (window)) + delta
4304 < (horiz_flag ? window_min_width : window_min_height))
4305 {
4306 Fset_window_configuration (old_config);
4307 error ("Cannot adjust window size as specified");
4308 }
4309
4310 /* Clear out some redisplay caches. */
4311 XSETFASTINT (p->last_modified, 0);
4312 XSETFASTINT (p->last_overlay_modified, 0);
4313
4314 /* Adjust this window's edge. */
4315 XSETINT (CURSIZE (window),
4316 XINT (CURSIZE (window)) + delta);
4317
4318 /* If this window has following siblings in the desired dimension,
bd99e242
RS
4319 make them smaller, and exit the loop.
4320
0d384044
RS
4321 (If we reach the top of the tree and can never do this,
4322 we will fail and report an error, above.) */
bd99e242 4323 if (NILP (first_parallel))
0d384044
RS
4324 {
4325 if (!NILP (XWINDOW (window)->next))
4326 {
e99c7521
JD
4327 /* This may happen for the minibuffer. In that case
4328 the window_deletion_count check below does not work. */
a53d44a8 4329 if (XINT (CURSIZE (p->next)) - delta <= 0)
e99c7521
JD
4330 {
4331 Fset_window_configuration (old_config);
4332 error ("Cannot adjust window size as specified");
4333 }
4334
0d384044
RS
4335 XSETINT (CURBEG (p->next),
4336 XINT (CURBEG (p->next)) + delta);
4337 size_window (p->next, XINT (CURSIZE (p->next)) - delta,
4338 horiz_flag, 0);
4339 break;
4340 }
4341 }
4342 else
4343 /* Here we have a chain of parallel siblings, in the other dimension.
4344 Change the size of the other siblings. */
bd99e242 4345 for (child = first_parallel;
0d384044
RS
4346 ! NILP (child);
4347 child = XWINDOW (child)->next)
4348 if (! EQ (child, window))
4349 size_window (child, XINT (CURSIZE (child)) + delta,
4350 horiz_flag, 0);
4351
4352 window = parent;
4353 }
4354
4355 /* If we made a window so small it got deleted,
4356 we failed. Report failure. */
4357 if (delcount != window_deletion_count)
4358 {
4359 Fset_window_configuration (old_config);
4360 error ("Cannot adjust window size as specified");
4361 }
4362
4363 /* Adjust glyph matrices. */
4364 adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
4365}
4366
7ab12479
JB
4367#undef CURBEG
4368#undef CURSIZE
4369
0d384044
RS
4370DEFUN ("adjust-window-trailing-edge", Fadjust_window_trailing_edge,
4371 Sadjust_window_trailing_edge, 3, 3, 0,
4372 doc: /* Adjust the bottom or right edge of WINDOW by DELTA.
56ebfae2 4373If HORIZONTAL is non-nil, that means adjust the width, moving the right edge.
0d384044
RS
4374Otherwise, adjust the height, moving the bottom edge.
4375
4376Following siblings of the selected window are resized to fulfill
4377the size request. If they become too small in the process, they
4378are not deleted; instead, we signal an error. */)
4379 (window, delta, horizontal)
4380 Lisp_Object window, delta, horizontal;
4381{
4382 CHECK_NUMBER (delta);
4383 adjust_window_trailing_edge (window, XINT (delta), !NILP (horizontal));
4384
4385 if (! NILP (Vwindow_configuration_change_hook))
4386 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
4387
4388 return Qnil;
4389}
4390
5500c422 4391
f984d4fc
GM
4392\f
4393/***********************************************************************
4394 Resizing Mini-Windows
4395 ***********************************************************************/
4396
4397static void shrink_window_lowest_first P_ ((struct window *, int));
f984d4fc 4398
43b4a21f
GM
4399enum save_restore_action
4400{
4401 CHECK_ORIG_SIZES,
4402 SAVE_ORIG_SIZES,
4403 RESTORE_ORIG_SIZES
4404};
4405
177c0ea7 4406static int save_restore_orig_size P_ ((struct window *,
43b4a21f 4407 enum save_restore_action));
f984d4fc
GM
4408
4409/* Shrink windows rooted in window W to HEIGHT. Take the space needed
4410 from lowest windows first. */
4411
4412static void
4413shrink_window_lowest_first (w, height)
4414 struct window *w;
4415 int height;
4416{
4417 struct window *c;
4418 Lisp_Object child;
4419 int old_height;
4420
4421 xassert (!MINI_WINDOW_P (w));
4422
4423 /* Set redisplay hints. */
4424 XSETFASTINT (w->last_modified, 0);
4425 XSETFASTINT (w->last_overlay_modified, 0);
4426 windows_or_buffers_changed++;
4427 FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
4428
949cf20f
KS
4429 old_height = XFASTINT (w->total_lines);
4430 XSETFASTINT (w->total_lines, height);
f984d4fc
GM
4431
4432 if (!NILP (w->hchild))
4433 {
4434 for (child = w->hchild; !NILP (child); child = c->next)
4435 {
4436 c = XWINDOW (child);
949cf20f 4437 c->top_line = w->top_line;
f984d4fc
GM
4438 shrink_window_lowest_first (c, height);
4439 }
4440 }
4441 else if (!NILP (w->vchild))
4442 {
4443 Lisp_Object last_child;
4444 int delta = old_height - height;
4445 int last_top;
6bbd7a29
GM
4446
4447 last_child = Qnil;
177c0ea7 4448
f984d4fc
GM
4449 /* Find the last child. We are taking space from lowest windows
4450 first, so we iterate over children from the last child
4451 backwards. */
4452 for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
4453 last_child = child;
4454
4455 /* Assign new heights. We leave only MIN_SAFE_WINDOW_HEIGHT. */
4456 for (child = last_child; delta && !NILP (child); child = c->prev)
4457 {
4458 int this_one;
177c0ea7 4459
f984d4fc 4460 c = XWINDOW (child);
949cf20f 4461 this_one = XFASTINT (c->total_lines) - MIN_SAFE_WINDOW_HEIGHT;
f984d4fc
GM
4462
4463 if (this_one > delta)
4464 this_one = delta;
4465
949cf20f 4466 shrink_window_lowest_first (c, XFASTINT (c->total_lines) - this_one);
f984d4fc
GM
4467 delta -= this_one;
4468 }
4469
4470 /* Compute new positions. */
949cf20f 4471 last_top = XINT (w->top_line);
f984d4fc
GM
4472 for (child = w->vchild; !NILP (child); child = c->next)
4473 {
4474 c = XWINDOW (child);
949cf20f
KS
4475 c->top_line = make_number (last_top);
4476 shrink_window_lowest_first (c, XFASTINT (c->total_lines));
4477 last_top += XFASTINT (c->total_lines);
f984d4fc
GM
4478 }
4479 }
4480}
4481
4482
43b4a21f
GM
4483/* Save, restore, or check positions and sizes in the window tree
4484 rooted at W. ACTION says what to do.
f984d4fc 4485
949cf20f
KS
4486 If ACTION is CHECK_ORIG_SIZES, check if orig_top_line and
4487 orig_total_lines members are valid for all windows in the window
4488 tree. Value is non-zero if they are valid.
177c0ea7 4489
43b4a21f 4490 If ACTION is SAVE_ORIG_SIZES, save members top and height in
949cf20f 4491 orig_top_line and orig_total_lines for all windows in the tree.
43b4a21f 4492
949cf20f
KS
4493 If ACTION is RESTORE_ORIG_SIZES, restore top and height from values
4494 stored in orig_top_line and orig_total_lines for all windows. */
43b4a21f
GM
4495
4496static int
4497save_restore_orig_size (w, action)
f984d4fc 4498 struct window *w;
43b4a21f 4499 enum save_restore_action action;
f984d4fc 4500{
43b4a21f
GM
4501 int success_p = 1;
4502
f984d4fc
GM
4503 while (w)
4504 {
4505 if (!NILP (w->hchild))
43b4a21f
GM
4506 {
4507 if (!save_restore_orig_size (XWINDOW (w->hchild), action))
4508 success_p = 0;
4509 }
f984d4fc 4510 else if (!NILP (w->vchild))
43b4a21f
GM
4511 {
4512 if (!save_restore_orig_size (XWINDOW (w->vchild), action))
4513 success_p = 0;
4514 }
177c0ea7 4515
43b4a21f 4516 switch (action)
f984d4fc 4517 {
43b4a21f 4518 case CHECK_ORIG_SIZES:
949cf20f 4519 if (!INTEGERP (w->orig_top_line) || !INTEGERP (w->orig_total_lines))
43b4a21f
GM
4520 return 0;
4521 break;
4522
4523 case SAVE_ORIG_SIZES:
949cf20f
KS
4524 w->orig_top_line = w->top_line;
4525 w->orig_total_lines = w->total_lines;
43b4a21f
GM
4526 XSETFASTINT (w->last_modified, 0);
4527 XSETFASTINT (w->last_overlay_modified, 0);
4528 break;
4529
4530 case RESTORE_ORIG_SIZES:
949cf20f
KS
4531 xassert (INTEGERP (w->orig_top_line) && INTEGERP (w->orig_total_lines));
4532 w->top_line = w->orig_top_line;
4533 w->total_lines = w->orig_total_lines;
4534 w->orig_total_lines = w->orig_top_line = Qnil;
43b4a21f
GM
4535 XSETFASTINT (w->last_modified, 0);
4536 XSETFASTINT (w->last_overlay_modified, 0);
4537 break;
4538
4539 default:
4540 abort ();
f984d4fc 4541 }
43b4a21f 4542
f984d4fc
GM
4543 w = NILP (w->next) ? NULL : XWINDOW (w->next);
4544 }
43b4a21f
GM
4545
4546 return success_p;
f984d4fc
GM
4547}
4548
4549
4550/* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we can
4551 without deleting other windows. */
4552
4553void
4554grow_mini_window (w, delta)
4555 struct window *w;
4556 int delta;
4557{
4558 struct frame *f = XFRAME (w->frame);
4559 struct window *root;
177c0ea7 4560
f984d4fc
GM
4561 xassert (MINI_WINDOW_P (w));
4562 xassert (delta >= 0);
177c0ea7 4563
f984d4fc
GM
4564 /* Check values of window_min_width and window_min_height for
4565 validity. */
4566 check_min_window_sizes ();
4567
4568 /* Compute how much we can enlarge the mini-window without deleting
4569 other windows. */
4570 root = XWINDOW (FRAME_ROOT_WINDOW (f));
4571 if (delta)
4572 {
4573 int min_height = window_min_size (root, 0, 0, 0);
949cf20f 4574 if (XFASTINT (root->total_lines) - delta < min_height)
8b8bd9c6 4575 /* Note that the root window may already be smaller than
eafa3196 4576 min_height. */
949cf20f 4577 delta = max (0, XFASTINT (root->total_lines) - min_height);
f984d4fc 4578 }
177c0ea7 4579
f984d4fc
GM
4580 if (delta)
4581 {
4582 /* Save original window sizes and positions, if not already done. */
43b4a21f
GM
4583 if (!save_restore_orig_size (root, CHECK_ORIG_SIZES))
4584 save_restore_orig_size (root, SAVE_ORIG_SIZES);
f984d4fc
GM
4585
4586 /* Shrink other windows. */
949cf20f 4587 shrink_window_lowest_first (root, XFASTINT (root->total_lines) - delta);
f984d4fc
GM
4588
4589 /* Grow the mini-window. */
949cf20f
KS
4590 w->top_line = make_number (XFASTINT (root->top_line) + XFASTINT (root->total_lines));
4591 w->total_lines = make_number (XFASTINT (w->total_lines) + delta);
f984d4fc
GM
4592 XSETFASTINT (w->last_modified, 0);
4593 XSETFASTINT (w->last_overlay_modified, 0);
177c0ea7 4594
f984d4fc
GM
4595 adjust_glyphs (f);
4596 }
4597}
4598
4599
86c8e823
GM
4600/* Shrink mini-window W. If there is recorded info about window sizes
4601 before a call to grow_mini_window, restore recorded window sizes.
4602 Otherwise, if the mini-window is higher than 1 line, resize it to 1
4603 line. */
f984d4fc
GM
4604
4605void
4606shrink_mini_window (w)
4607 struct window *w;
4608{
4609 struct frame *f = XFRAME (w->frame);
4610 struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
4611
43b4a21f 4612 if (save_restore_orig_size (root, CHECK_ORIG_SIZES))
f984d4fc 4613 {
43b4a21f 4614 save_restore_orig_size (root, RESTORE_ORIG_SIZES);
f984d4fc
GM
4615 adjust_glyphs (f);
4616 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
4617 windows_or_buffers_changed = 1;
4618 }
949cf20f 4619 else if (XFASTINT (w->total_lines) > 1)
86c8e823 4620 {
0130fe1a
GM
4621 /* Distribute the additional lines of the mini-window
4622 among the other windows. */
86c8e823
GM
4623 Lisp_Object window;
4624 XSETWINDOW (window, w);
56ebfae2 4625 enlarge_window (window, 1 - XFASTINT (w->total_lines), 0);
86c8e823 4626 }
f984d4fc
GM
4627}
4628
4629
4630\f
5500c422
GM
4631/* Mark window cursors off for all windows in the window tree rooted
4632 at W by setting their phys_cursor_on_p flag to zero. Called from
4633 xterm.c, e.g. when a frame is cleared and thereby all cursors on
4634 the frame are cleared. */
4635
4636void
4637mark_window_cursors_off (w)
4638 struct window *w;
4639{
4640 while (w)
4641 {
4642 if (!NILP (w->hchild))
4643 mark_window_cursors_off (XWINDOW (w->hchild));
4644 else if (!NILP (w->vchild))
4645 mark_window_cursors_off (XWINDOW (w->vchild));
4646 else
4647 w->phys_cursor_on_p = 0;
4648
4649 w = NILP (w->next) ? 0 : XWINDOW (w->next);
4650 }
4651}
4652
4653
e9c195b1 4654/* Return number of lines of text (not counting mode lines) in W. */
7ab12479
JB
4655
4656int
4657window_internal_height (w)
4658 struct window *w;
4659{
949cf20f 4660 int ht = XFASTINT (w->total_lines);
7ab12479 4661
e9c195b1
GM
4662 if (!MINI_WINDOW_P (w))
4663 {
4664 if (!NILP (w->parent)
4665 || !NILP (w->vchild)
4666 || !NILP (w->hchild)
4667 || !NILP (w->next)
4668 || !NILP (w->prev)
4669 || WINDOW_WANTS_MODELINE_P (w))
4670 --ht;
7ab12479 4671
e9c195b1
GM
4672 if (WINDOW_WANTS_HEADER_LINE_P (w))
4673 --ht;
4674 }
7ab12479
JB
4675
4676 return ht;
4677}
4678
535e0b8e
JB
4679
4680/* Return the number of columns in W.
a3c87d4e 4681 Don't count columns occupied by scroll bars or the vertical bar
535e0b8e 4682 separating W from the sibling to its right. */
5500c422 4683
535e0b8e 4684int
949cf20f 4685window_box_text_cols (w)
535e0b8e
JB
4686 struct window *w;
4687{
5500c422 4688 struct frame *f = XFRAME (WINDOW_FRAME (w));
949cf20f 4689 int width = XINT (w->total_cols);
535e0b8e 4690
949cf20f 4691 if (WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
5500c422 4692 /* Scroll bars occupy a few columns. */
949cf20f
KS
4693 width -= WINDOW_CONFIG_SCROLL_BAR_COLS (w);
4694 else if (!FRAME_WINDOW_P (f)
4695 && !WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
5500c422
GM
4696 /* The column of `|' characters separating side-by-side windows
4697 occupies one column only. */
4698 width -= 1;
4699
5500c422 4700 if (FRAME_WINDOW_P (f))
949cf20f
KS
4701 /* On window-systems, fringes and display margins cannot be
4702 used for normal text. */
4703 width -= (WINDOW_FRINGE_COLS (w)
4704 + WINDOW_LEFT_MARGIN_COLS (w)
4705 + WINDOW_RIGHT_MARGIN_COLS (w));
111e5992
RS
4706
4707 return width;
535e0b8e
JB
4708}
4709
5500c422
GM
4710\f
4711/************************************************************************
4712 Window Scrolling
4713 ***********************************************************************/
535e0b8e 4714
5500c422 4715/* Scroll contents of window WINDOW up. If WHOLE is non-zero, scroll
d4e7cf01 4716 N screen-fulls, which is defined as the height of the window minus
5500c422
GM
4717 next_screen_context_lines. If WHOLE is zero, scroll up N lines
4718 instead. Negative values of N mean scroll down. NOERROR non-zero
4719 means don't signal an error if we try to move over BEGV or ZV,
4720 respectively. */
7ab12479 4721
101d1605
RS
4722static void
4723window_scroll (window, n, whole, noerror)
7ab12479
JB
4724 Lisp_Object window;
4725 int n;
101d1605 4726 int whole;
f8026fd8 4727 int noerror;
5500c422 4728{
cba59f77
RS
4729 immediate_quit = 1;
4730
5500c422
GM
4731 /* If we must, use the pixel-based version which is much slower than
4732 the line-based one but can handle varying line heights. */
4733 if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
4734 window_scroll_pixel_based (window, n, whole, noerror);
4735 else
4736 window_scroll_line_based (window, n, whole, noerror);
cba59f77
RS
4737
4738 immediate_quit = 0;
5500c422
GM
4739}
4740
4741
4742/* Implementation of window_scroll that works based on pixel line
4743 heights. See the comment of window_scroll for parameter
4744 descriptions. */
4745
4746static void
4747window_scroll_pixel_based (window, n, whole, noerror)
4748 Lisp_Object window;
4749 int n;
4750 int whole;
4751 int noerror;
4752{
4753 struct it it;
4754 struct window *w = XWINDOW (window);
4755 struct text_pos start;
4756 Lisp_Object tem;
4757 int this_scroll_margin;
5cdb3cf3
MB
4758 /* True if we fiddled the window vscroll field without really scrolling. */
4759 int vscrolled = 0;
5500c422
GM
4760
4761 SET_TEXT_POS_FROM_MARKER (start, w->start);
177c0ea7 4762
5500c422 4763 /* If PT is not visible in WINDOW, move back one half of
288d4e06
GM
4764 the screen. Allow PT to be partially visible, otherwise
4765 something like (scroll-down 1) with PT in the line before
4766 the partially visible one would recenter. */
4767 tem = Fpos_visible_in_window_p (make_number (PT), window, Qt);
5500c422
GM
4768 if (NILP (tem))
4769 {
4770 /* Move backward half the height of the window. Performance note:
4771 vmotion used here is about 10% faster, but would give wrong
4772 results for variable height lines. */
4773 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
4774 it.current_y = it.last_visible_y;
f204989e 4775 move_it_vertically_backward (&it, window_box_height (w) / 2);
177c0ea7 4776
5500c422
GM
4777 /* The function move_iterator_vertically may move over more than
4778 the specified y-distance. If it->w is small, e.g. a
4779 mini-buffer window, we may end up in front of the window's
4780 display area. This is the case when Start displaying at the
4781 start of the line containing PT in this case. */
4782 if (it.current_y <= 0)
4783 {
4784 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
f204989e 4785 move_it_vertically_backward (&it, 0);
5500c422
GM
4786 it.current_y = 0;
4787 }
4788
4789 start = it.current.pos;
4790 }
e56263e5
KS
4791 else if (auto_window_vscroll_p)
4792 {
5b1ba1e3 4793 if (tem = XCAR (XCDR (XCDR (tem))), CONSP (tem))
e56263e5
KS
4794 {
4795 int px;
4796 int dy = WINDOW_FRAME_LINE_HEIGHT (w);
4797 if (whole)
e856c216
KS
4798 dy = max ((window_box_height (w)
4799 - next_screen_context_lines * dy),
4800 dy);
e56263e5
KS
4801 dy *= n;
4802
5b1ba1e3 4803 if (n < 0 && (px = XINT (XCAR (tem))) > 0)
e56263e5
KS
4804 {
4805 px = max (0, -w->vscroll - min (px, -dy));
4806 Fset_window_vscroll (window, make_number (px), Qt);
4807 return;
4808 }
5b1ba1e3 4809 if (n > 0 && (px = XINT (XCDR (tem))) > 0)
e56263e5
KS
4810 {
4811 px = max (0, -w->vscroll + min (px, dy));
4812 Fset_window_vscroll (window, make_number (px), Qt);
4813 return;
4814 }
4815 }
4816 Fset_window_vscroll (window, make_number (0), Qt);
4817 }
5500c422 4818
d0c38d63 4819 /* If scroll_preserve_screen_position is non-nil, we try to set
5500c422
GM
4820 point in the same window line as it is now, so get that line. */
4821 if (!NILP (Vscroll_preserve_screen_position))
4822 {
c525d842
CY
4823 /* We preserve the goal pixel coordinate across consecutive
4824 calls to scroll-up or scroll-down. This avoids the
4825 possibility of point becoming "stuck" on a tall line when
4826 scrolling by one line. */
66fe93d1 4827 if (window_scroll_pixel_based_preserve_y < 0
7d619454
SM
4828 || (!EQ (current_kboard->Vlast_command, Qscroll_up)
4829 && !EQ (current_kboard->Vlast_command, Qscroll_down)))
c525d842
CY
4830 {
4831 start_display (&it, w, start);
4832 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
66fe93d1 4833 window_scroll_pixel_based_preserve_y = it.current_y;
c525d842 4834 }
5500c422
GM
4835 }
4836 else
66fe93d1 4837 window_scroll_pixel_based_preserve_y = -1;
5500c422
GM
4838
4839 /* Move iterator it from start the specified distance forward or
4840 backward. The result is the new window start. */
4841 start_display (&it, w, start);
4842 if (whole)
4843 {
e856c216
KS
4844 int start_pos = IT_CHARPOS (it);
4845 int dy = WINDOW_FRAME_LINE_HEIGHT (w);
4846 dy = max ((window_box_height (w)
4847 - next_screen_context_lines * dy),
4848 dy) * n;
d72340d4
GM
4849
4850 /* Note that move_it_vertically always moves the iterator to the
4851 start of a line. So, if the last line doesn't have a newline,
4852 we would end up at the start of the line ending at ZV. */
4853 if (dy <= 0)
e856c216
KS
4854 {
4855 move_it_vertically_backward (&it, -dy);
4856 /* Ensure we actually does move, e.g. in case we are currently
4857 looking at an image that is taller that the window height. */
4858 while (start_pos == IT_CHARPOS (it)
4859 && start_pos > BEGV)
4860 move_it_by_lines (&it, -1, 1);
4861 }
d72340d4 4862 else if (dy > 0)
bed83ee4 4863 {
bed83ee4
KS
4864 move_it_to (&it, ZV, -1, it.current_y + dy, -1,
4865 MOVE_TO_POS | MOVE_TO_Y);
4866 /* Ensure we actually does move, e.g. in case we are currently
4867 looking at an image that is taller that the window height. */
4868 while (start_pos == IT_CHARPOS (it)
4869 && start_pos < ZV)
4870 move_it_by_lines (&it, 1, 1);
4871 }
5500c422
GM
4872 }
4873 else
4874 move_it_by_lines (&it, n, 1);
4875
96ae58c8
RS
4876 /* We failed if we find ZV is already on the screen (scrolling up,
4877 means there's nothing past the end), or if we can't start any
4878 earlier (scrolling down, means there's nothing past the top). */
5500c422 4879 if ((n > 0 && IT_CHARPOS (it) == ZV)
96ae58c8 4880 || (n < 0 && IT_CHARPOS (it) == CHARPOS (start)))
5500c422 4881 {
5cdb3cf3
MB
4882 if (IT_CHARPOS (it) == ZV)
4883 {
07ce8b53
RS
4884 if (it.current_y < it.last_visible_y
4885 && (it.current_y + it.max_ascent + it.max_descent
3f489dc7 4886 > it.last_visible_y))
a74eca50
GM
4887 {
4888 /* The last line was only partially visible, make it fully
4889 visible. */
4890 w->vscroll = (it.last_visible_y
4891 - it.current_y + it.max_ascent + it.max_descent);
4892 adjust_glyphs (it.f);
4893 }
5cdb3cf3
MB
4894 else if (noerror)
4895 return;
4896 else
4897 Fsignal (Qend_of_buffer, Qnil);
4898 }
5500c422 4899 else
5cdb3cf3
MB
4900 {
4901 if (w->vscroll != 0)
4902 /* The first line was only partially visible, make it fully
4903 visible. */
4904 w->vscroll = 0;
4905 else if (noerror)
4906 return;
4907 else
4908 Fsignal (Qbeginning_of_buffer, Qnil);
4909 }
4910
4911 /* If control gets here, then we vscrolled. */
4912
4913 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
4914
4915 /* Don't try to change the window start below. */
4916 vscrolled = 1;
5500c422
GM
4917 }
4918
5cdb3cf3
MB
4919 if (! vscrolled)
4920 {
dad67609
RS
4921 int pos = IT_CHARPOS (it);
4922 int bytepos;
e68def1e
AS
4923
4924 /* If in the middle of a multi-glyph character move forward to
4925 the next character. */
4926 if (in_display_vector_p (&it))
4927 {
4928 ++pos;
4929 move_it_to (&it, pos, -1, -1, -1, MOVE_TO_POS);
4930 }
4931
5cdb3cf3 4932 /* Set the window start, and set up the window for redisplay. */
dad67609 4933 set_marker_restricted (w->start, make_number (pos),
5cdb3cf3 4934 w->buffer);
dad67609
RS
4935 bytepos = XMARKER (w->start)->bytepos;
4936 w->start_at_line_beg = ((pos == BEGV || FETCH_BYTE (bytepos - 1) == '\n')
4937 ? Qt : Qnil);
5cdb3cf3
MB
4938 w->update_mode_line = Qt;
4939 XSETFASTINT (w->last_modified, 0);
4940 XSETFASTINT (w->last_overlay_modified, 0);
4941 /* Set force_start so that redisplay_window will run the
4942 window-scroll-functions. */
4943 w->force_start = Qt;
4944 }
177c0ea7 4945
dc297565
RS
4946 /* The rest of this function uses current_y in a nonstandard way,
4947 not including the height of the header line if any. */
5500c422 4948 it.current_y = it.vpos = 0;
177c0ea7 4949
940f53e5
RS
4950 /* Move PT out of scroll margins.
4951 This code wants current_y to be zero at the window start position
4952 even if there is a header line. */
4953 this_scroll_margin = max (0, scroll_margin);
4954 this_scroll_margin = min (this_scroll_margin, XFASTINT (w->total_lines) / 4);
4955 this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
4956
4957 if (n > 0)
5500c422 4958 {
940f53e5
RS
4959 /* We moved the window start towards ZV, so PT may be now
4960 in the scroll margin at the top. */
4961 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
bdf4ec93
RS
4962 if (IT_CHARPOS (it) == PT && it.current_y >= this_scroll_margin
4963 && (NILP (Vscroll_preserve_screen_position)
4964 || EQ (Vscroll_preserve_screen_position, Qt)))
940f53e5
RS
4965 /* We found PT at a legitimate height. Leave it alone. */
4966 ;
66fe93d1 4967 else if (window_scroll_pixel_based_preserve_y >= 0)
940f53e5 4968 {
fa3c3426
RS
4969 /* If we have a header line, take account of it.
4970 This is necessary because we set it.current_y to 0, above. */
c525d842 4971 move_it_to (&it, -1, -1,
66fe93d1
LT
4972 window_scroll_pixel_based_preserve_y
4973 - (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0 ),
c525d842 4974 -1, MOVE_TO_Y);
940f53e5
RS
4975 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
4976 }
4977 else
5500c422 4978 {
5500c422 4979 while (it.current_y < this_scroll_margin)
e9b2c961
RS
4980 {
4981 int prev = it.current_y;
4982 move_it_by_lines (&it, 1, 1);
4983 if (prev == it.current_y)
4984 break;
4985 }
5500c422
GM
4986 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
4987 }
940f53e5
RS
4988 }
4989 else if (n < 0)
4990 {
4991 int charpos, bytepos;
aed328bf 4992 int partial_p;
940f53e5 4993
66fe93d1
LT
4994 /* Save our position, for the
4995 window_scroll_pixel_based_preserve_y case. */
940f53e5
RS
4996 charpos = IT_CHARPOS (it);
4997 bytepos = IT_BYTEPOS (it);
5cdb3cf3 4998
940f53e5
RS
4999 /* We moved the window start towards BEGV, so PT may be now
5000 in the scroll margin at the bottom. */
5001 move_it_to (&it, PT, -1,
7ad53239
RS
5002 (it.last_visible_y - CURRENT_HEADER_LINE_HEIGHT (w)
5003 - this_scroll_margin - 1),
5004 -1,
940f53e5
RS
5005 MOVE_TO_POS | MOVE_TO_Y);
5006
aed328bf
KS
5007 /* Save our position, in case it's correct. */
5008 charpos = IT_CHARPOS (it);
5009 bytepos = IT_BYTEPOS (it);
5010
5011 /* See if point is on a partially visible line at the end. */
5012 if (it.what == IT_EOB)
5013 partial_p = it.current_y + it.ascent + it.descent > it.last_visible_y;
5014 else
5015 {
5016 move_it_by_lines (&it, 1, 1);
5017 partial_p = it.current_y > it.last_visible_y;
5018 }
5019
bdf4ec93
RS
5020 if (charpos == PT && !partial_p
5021 && (NILP (Vscroll_preserve_screen_position)
5022 || EQ (Vscroll_preserve_screen_position, Qt)))
940f53e5
RS
5023 /* We found PT before we found the display margin, so PT is ok. */
5024 ;
66fe93d1 5025 else if (window_scroll_pixel_based_preserve_y >= 0)
940f53e5
RS
5026 {
5027 SET_TEXT_POS_FROM_MARKER (start, w->start);
5028 start_display (&it, w, start);
c525d842
CY
5029 /* It would be wrong to subtract CURRENT_HEADER_LINE_HEIGHT
5030 here because we called start_display again and did not
5031 alter it.current_y this time. */
66fe93d1
LT
5032 move_it_to (&it, -1, -1, window_scroll_pixel_based_preserve_y, -1,
5033 MOVE_TO_Y);
940f53e5
RS
5034 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5035 }
5036 else
5037 {
aed328bf 5038 if (partial_p)
5cdb3cf3
MB
5039 /* The last line was only partially visible, so back up two
5040 lines to make sure we're on a fully visible line. */
5041 {
5042 move_it_by_lines (&it, -2, 0);
5043 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5044 }
5045 else
5046 /* No, the position we saved is OK, so use it. */
5047 SET_PT_BOTH (charpos, bytepos);
5500c422
GM
5048 }
5049 }
5050}
5051
5052
5053/* Implementation of window_scroll that works based on screen lines.
5054 See the comment of window_scroll for parameter descriptions. */
5055
5056static void
5057window_scroll_line_based (window, n, whole, noerror)
5058 Lisp_Object window;
5059 int n;
5060 int whole;
5061 int noerror;
7ab12479
JB
5062{
5063 register struct window *w = XWINDOW (window);
5500c422 5064 register int opoint = PT, opoint_byte = PT_BYTE;
b73ea88e 5065 register int pos, pos_byte;
7ab12479
JB
5066 register int ht = window_internal_height (w);
5067 register Lisp_Object tem;
5068 int lose;
5500c422 5069 Lisp_Object bolp;
345d45b2 5070 int startpos;
101d1605
RS
5071 struct position posit;
5072 int original_vpos;
5073
d4e7cf01
GM
5074 /* If scrolling screen-fulls, compute the number of lines to
5075 scroll from the window's height. */
5076 if (whole)
5077 n *= max (1, ht - next_screen_context_lines);
5078
101d1605
RS
5079 startpos = marker_position (w->start);
5080
5081 posit = *compute_motion (startpos, 0, 0, 0,
5082 PT, ht, 0,
ec2b66c4 5083 -1, XINT (w->hscroll),
101d1605
RS
5084 0, w);
5085 original_vpos = posit.vpos;
0a1f771a 5086
d834a2e9 5087 XSETFASTINT (tem, PT);
6ffdb539 5088 tem = Fpos_visible_in_window_p (tem, window, Qnil);
7ab12479 5089
265a9e55 5090 if (NILP (tem))
7ab12479 5091 {
cd2be1dd 5092 Fvertical_motion (make_number (- (ht / 2)), window);
345d45b2 5093 startpos = PT;
7ab12479
JB
5094 }
5095
345d45b2 5096 SET_PT (startpos);
5ce7b543 5097 lose = n < 0 && PT == BEGV;
540b6aa0 5098 Fvertical_motion (make_number (n), window);
5ce7b543 5099 pos = PT;
b73ea88e 5100 pos_byte = PT_BYTE;
7ab12479 5101 bolp = Fbolp ();
b73ea88e 5102 SET_PT_BOTH (opoint, opoint_byte);
7ab12479
JB
5103
5104 if (lose)
f8026fd8
JB
5105 {
5106 if (noerror)
5107 return;
5108 else
5109 Fsignal (Qbeginning_of_buffer, Qnil);
5110 }
7ab12479
JB
5111
5112 if (pos < ZV)
7ab12479 5113 {
0c7da84e
RS
5114 int this_scroll_margin = scroll_margin;
5115
5116 /* Don't use a scroll margin that is negative or too large. */
5117 if (this_scroll_margin < 0)
5118 this_scroll_margin = 0;
5119
949cf20f
KS
5120 if (XINT (w->total_lines) < 4 * scroll_margin)
5121 this_scroll_margin = XINT (w->total_lines) / 4;
0c7da84e 5122
b73ea88e 5123 set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
7ab12479
JB
5124 w->start_at_line_beg = bolp;
5125 w->update_mode_line = Qt;
d834a2e9 5126 XSETFASTINT (w->last_modified, 0);
3cd21523 5127 XSETFASTINT (w->last_overlay_modified, 0);
345d45b2
RS
5128 /* Set force_start so that redisplay_window will run
5129 the window-scroll-functions. */
5130 w->force_start = Qt;
0c7da84e 5131
bdf4ec93
RS
5132 if (!NILP (Vscroll_preserve_screen_position)
5133 && (whole || !EQ (Vscroll_preserve_screen_position, Qt)))
0c7da84e 5134 {
b73ea88e 5135 SET_PT_BOTH (pos, pos_byte);
101d1605 5136 Fvertical_motion (make_number (original_vpos), window);
0c7da84e 5137 }
101d1605
RS
5138 /* If we scrolled forward, put point enough lines down
5139 that it is outside the scroll margin. */
5140 else if (n > 0)
0c7da84e 5141 {
101d1605
RS
5142 int top_margin;
5143
5144 if (this_scroll_margin > 0)
5145 {
b73ea88e 5146 SET_PT_BOTH (pos, pos_byte);
101d1605
RS
5147 Fvertical_motion (make_number (this_scroll_margin), window);
5148 top_margin = PT;
5149 }
5150 else
5151 top_margin = pos;
5152
5153 if (top_margin <= opoint)
b73ea88e 5154 SET_PT_BOTH (opoint, opoint_byte);
5500c422 5155 else if (!NILP (Vscroll_preserve_screen_position))
101d1605 5156 {
b73ea88e 5157 SET_PT_BOTH (pos, pos_byte);
101d1605
RS
5158 Fvertical_motion (make_number (original_vpos), window);
5159 }
9317a85d 5160 else
335406fc 5161 SET_PT (top_margin);
0c7da84e 5162 }
101d1605 5163 else if (n < 0)
7ab12479 5164 {
101d1605
RS
5165 int bottom_margin;
5166
0c7da84e
RS
5167 /* If we scrolled backward, put point near the end of the window
5168 but not within the scroll margin. */
b73ea88e 5169 SET_PT_BOTH (pos, pos_byte);
0c7da84e 5170 tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
101d1605
RS
5171 if (XFASTINT (tem) == ht - this_scroll_margin)
5172 bottom_margin = PT;
5173 else
5174 bottom_margin = PT + 1;
5175
5176 if (bottom_margin > opoint)
b73ea88e 5177 SET_PT_BOTH (opoint, opoint_byte);
7ab12479 5178 else
101d1605 5179 {
5500c422 5180 if (!NILP (Vscroll_preserve_screen_position))
9317a85d 5181 {
b73ea88e 5182 SET_PT_BOTH (pos, pos_byte);
9317a85d
RS
5183 Fvertical_motion (make_number (original_vpos), window);
5184 }
5185 else
5186 Fvertical_motion (make_number (-1), window);
101d1605 5187 }
7ab12479
JB
5188 }
5189 }
5190 else
f8026fd8
JB
5191 {
5192 if (noerror)
5193 return;
5194 else
5195 Fsignal (Qend_of_buffer, Qnil);
5196 }
7ab12479 5197}
5500c422
GM
5198
5199
5200/* Scroll selected_window up or down. If N is nil, scroll a
5201 screen-full which is defined as the height of the window minus
5202 next_screen_context_lines. If N is the symbol `-', scroll.
5203 DIRECTION may be 1 meaning to scroll down, or -1 meaning to scroll
5204 up. This is the guts of Fscroll_up and Fscroll_down. */
7ab12479
JB
5205
5206static void
5207scroll_command (n, direction)
5500c422 5208 Lisp_Object n;
7ab12479
JB
5209 int direction;
5210{
331379bf 5211 int count = SPECPDL_INDEX ();
7ab12479 5212
5500c422
GM
5213 xassert (abs (direction) == 1);
5214
5215 /* If selected window's buffer isn't current, make it current for
5216 the moment. But don't screw up if window_scroll gets an error. */
7ab12479 5217 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
95605e15
JB
5218 {
5219 record_unwind_protect (save_excursion_restore, save_excursion_save ());
5220 Fset_buffer (XWINDOW (selected_window)->buffer);
5500c422
GM
5221
5222 /* Make redisplay consider other windows than just selected_window. */
5223 ++windows_or_buffers_changed;
95605e15 5224 }
7ab12479 5225
265a9e55 5226 if (NILP (n))
d4e7cf01 5227 window_scroll (selected_window, direction, 1, 0);
7ab12479 5228 else if (EQ (n, Qminus))
d4e7cf01 5229 window_scroll (selected_window, -direction, 1, 0);
7ab12479
JB
5230 else
5231 {
5232 n = Fprefix_numeric_value (n);
101d1605 5233 window_scroll (selected_window, XINT (n) * direction, 0, 0);
7ab12479 5234 }
95605e15
JB
5235
5236 unbind_to (count, Qnil);
7ab12479
JB
5237}
5238
5239DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
a0a37a6f
LT
5240 doc: /* Scroll text of current window upward ARG lines.
5241If ARG is omitted or nil, scroll upward by a near full screen.
fdb82f93
PJ
5242A near full screen is `next-screen-context-lines' less than a full screen.
5243Negative ARG means scroll downward.
5244If ARG is the atom `-', scroll downward by nearly full screen.
5245When calling from a program, supply as argument a number, nil, or `-'. */)
5246 (arg)
413430c5 5247 Lisp_Object arg;
7ab12479 5248{
413430c5 5249 scroll_command (arg, 1);
7ab12479
JB
5250 return Qnil;
5251}
5252
5253DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
a0a37a6f
LT
5254 doc: /* Scroll text of current window down ARG lines.
5255If ARG is omitted or nil, scroll down by a near full screen.
fdb82f93
PJ
5256A near full screen is `next-screen-context-lines' less than a full screen.
5257Negative ARG means scroll upward.
5258If ARG is the atom `-', scroll upward by nearly full screen.
5259When calling from a program, supply as argument a number, nil, or `-'. */)
5260 (arg)
413430c5 5261 Lisp_Object arg;
7ab12479 5262{
413430c5 5263 scroll_command (arg, -1);
7ab12479
JB
5264 return Qnil;
5265}
ccd0664b
RS
5266\f
5267DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0,
fdb82f93 5268 doc: /* Return the other window for \"other window scroll\" commands.
fdb82f93 5269If `other-window-scroll-buffer' is non-nil, a window
a0a37a6f
LT
5270showing that buffer is used.
5271If in the minibuffer, `minibuffer-scroll-window' if non-nil
5272specifies the window. This takes precedence over
5273`other-window-scroll-buffer'. */)
fdb82f93 5274 ()
7ab12479 5275{
ccd0664b 5276 Lisp_Object window;
7ab12479
JB
5277
5278 if (MINI_WINDOW_P (XWINDOW (selected_window))
265a9e55 5279 && !NILP (Vminibuf_scroll_window))
7ab12479
JB
5280 window = Vminibuf_scroll_window;
5281 /* If buffer is specified, scroll that buffer. */
265a9e55 5282 else if (!NILP (Vother_window_scroll_buffer))
7ab12479
JB
5283 {
5284 window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
265a9e55 5285 if (NILP (window))
53f76081 5286 window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt, Qnil);
7ab12479
JB
5287 }
5288 else
dbc4e1c1
JB
5289 {
5290 /* Nothing specified; look for a neighboring window on the same
5291 frame. */
5292 window = Fnext_window (selected_window, Qnil, Qnil);
5293
5294 if (EQ (window, selected_window))
5295 /* That didn't get us anywhere; look for a window on another
5296 visible frame. */
5297 do
5298 window = Fnext_window (window, Qnil, Qt);
5299 while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
5300 && ! EQ (window, selected_window));
5301 }
5302
b7826503 5303 CHECK_LIVE_WINDOW (window);
7ab12479
JB
5304
5305 if (EQ (window, selected_window))
5306 error ("There is no other window");
5307
ccd0664b
RS
5308 return window;
5309}
5310
5311DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
fdb82f93
PJ
5312 doc: /* Scroll next window upward ARG lines; or near full screen if no ARG.
5313A near full screen is `next-screen-context-lines' less than a full screen.
5314The next window is the one below the current one; or the one at the top
5315if the current one is at the bottom. Negative ARG means scroll downward.
5316If ARG is the atom `-', scroll downward by nearly full screen.
5317When calling from a program, supply as argument a number, nil, or `-'.
5318
fdb82f93 5319If `other-window-scroll-buffer' is non-nil, scroll the window
a0a37a6f
LT
5320showing that buffer, popping the buffer up if necessary.
5321If in the minibuffer, `minibuffer-scroll-window' if non-nil
5322specifies the window to scroll. This takes precedence over
5323`other-window-scroll-buffer'. */)
fdb82f93 5324 (arg)
d4e7cf01 5325 Lisp_Object arg;
ccd0664b 5326{
d4e7cf01
GM
5327 Lisp_Object window;
5328 struct window *w;
331379bf 5329 int count = SPECPDL_INDEX ();
ccd0664b
RS
5330
5331 window = Fother_window_for_scrolling ();
7ab12479 5332 w = XWINDOW (window);
7ab12479
JB
5333
5334 /* Don't screw up if window_scroll gets an error. */
5335 record_unwind_protect (save_excursion_restore, save_excursion_save ());
5500c422 5336 ++windows_or_buffers_changed;
7ab12479
JB
5337
5338 Fset_buffer (w->buffer);
5339 SET_PT (marker_position (w->pointm));
5340
413430c5 5341 if (NILP (arg))
d4e7cf01 5342 window_scroll (window, 1, 1, 1);
413430c5 5343 else if (EQ (arg, Qminus))
d4e7cf01 5344 window_scroll (window, -1, 1, 1);
7ab12479
JB
5345 else
5346 {
413430c5
EN
5347 if (CONSP (arg))
5348 arg = Fcar (arg);
b7826503 5349 CHECK_NUMBER (arg);
101d1605 5350 window_scroll (window, XINT (arg), 0, 1);
7ab12479
JB
5351 }
5352
b73ea88e 5353 set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
f4e7b2c2 5354 unbind_to (count, Qnil);
7ab12479
JB
5355
5356 return Qnil;
5357}
5358\f
dc297565 5359DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 2, "P\np",
fdb82f93 5360 doc: /* Scroll selected window display ARG columns left.
2fe41216
EZ
5361Default for ARG is window width minus 2.
5362Value is the total amount of leftward horizontal scrolling in
5363effect after the change.
dc297565
RS
5364If SET_MINIMUM is non-nil, the new scroll amount becomes the
5365lower bound for automatic scrolling, i.e. automatic scrolling
2fe41216 5366will not scroll a window to a column less than the value returned
dc297565
RS
5367by this function. This happens in an interactive call. */)
5368 (arg, set_minimum)
5369 register Lisp_Object arg, set_minimum;
7ab12479 5370{
c67fa410
GM
5371 Lisp_Object result;
5372 int hscroll;
5373 struct window *w = XWINDOW (selected_window);
177c0ea7 5374
265a9e55 5375 if (NILP (arg))
949cf20f 5376 XSETFASTINT (arg, window_box_text_cols (w) - 2);
7ab12479
JB
5377 else
5378 arg = Fprefix_numeric_value (arg);
5379
c67fa410
GM
5380 hscroll = XINT (w->hscroll) + XINT (arg);
5381 result = Fset_window_hscroll (selected_window, make_number (hscroll));
5382
dc297565 5383 if (!NILP (set_minimum))
c67fa410
GM
5384 w->min_hscroll = w->hscroll;
5385
5386 return result;
7ab12479
JB
5387}
5388
dc297565 5389DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 2, "P\np",
fdb82f93 5390 doc: /* Scroll selected window display ARG columns right.
2fe41216
EZ
5391Default for ARG is window width minus 2.
5392Value is the total amount of leftward horizontal scrolling in
5393effect after the change.
dc297565
RS
5394If SET_MINIMUM is non-nil, the new scroll amount becomes the
5395lower bound for automatic scrolling, i.e. automatic scrolling
2fe41216 5396will not scroll a window to a column less than the value returned
dc297565
RS
5397by this function. This happens in an interactive call. */)
5398 (arg, set_minimum)
a93563fd 5399 register Lisp_Object arg, set_minimum;
7ab12479 5400{
c67fa410
GM
5401 Lisp_Object result;
5402 int hscroll;
5403 struct window *w = XWINDOW (selected_window);
177c0ea7 5404
265a9e55 5405 if (NILP (arg))
949cf20f 5406 XSETFASTINT (arg, window_box_text_cols (w) - 2);
7ab12479
JB
5407 else
5408 arg = Fprefix_numeric_value (arg);
5409
c67fa410
GM
5410 hscroll = XINT (w->hscroll) - XINT (arg);
5411 result = Fset_window_hscroll (selected_window, make_number (hscroll));
177c0ea7 5412
dc297565 5413 if (!NILP (set_minimum))
c67fa410
GM
5414 w->min_hscroll = w->hscroll;
5415
5416 return result;
7ab12479
JB
5417}
5418
fa832261
KS
5419DEFUN ("minibuffer-selected-window", Fminibuffer_selected_window, Sminibuffer_selected_window, 0, 0, 0,
5420 doc: /* Return the window which was selected when entering the minibuffer.
5421Returns nil, if current window is not a minibuffer window. */)
5422 ()
5423{
5424 if (minibuf_level > 0
5425 && MINI_WINDOW_P (XWINDOW (selected_window))
fa832261
KS
5426 && WINDOW_LIVE_P (minibuf_selected_window))
5427 return minibuf_selected_window;
5428
5429 return Qnil;
5430}
5431
12c8b416
GM
5432/* Value is the number of lines actually displayed in window W,
5433 as opposed to its height. */
5434
5435static int
5436displayed_window_lines (w)
5437 struct window *w;
5438{
5439 struct it it;
5440 struct text_pos start;
5441 int height = window_box_height (w);
5442 struct buffer *old_buffer;
5443 int bottom_y;
5444
5445 if (XBUFFER (w->buffer) != current_buffer)
5446 {
5447 old_buffer = current_buffer;
5448 set_buffer_internal (XBUFFER (w->buffer));
5449 }
5450 else
5451 old_buffer = NULL;
5452
521b203e
GM
5453 /* In case W->start is out of the accessible range, do something
5454 reasonable. This happens in Info mode when Info-scroll-down
5455 calls (recenter -1) while W->start is 1. */
5456 if (XMARKER (w->start)->charpos < BEGV)
5457 SET_TEXT_POS (start, BEGV, BEGV_BYTE);
5458 else if (XMARKER (w->start)->charpos > ZV)
5459 SET_TEXT_POS (start, ZV, ZV_BYTE);
5460 else
5461 SET_TEXT_POS_FROM_MARKER (start, w->start);
5462
12c8b416
GM
5463 start_display (&it, w, start);
5464 move_it_vertically (&it, height);
c8bc6f65 5465 bottom_y = line_bottom_y (&it);
12c8b416 5466
1de65f51
RS
5467 /* rms: On a non-window display,
5468 the value of it.vpos at the bottom of the screen
5469 seems to be 1 larger than window_box_height (w).
5470 This kludge fixes a bug whereby (move-to-window-line -1)
5471 when ZV is on the last screen line
5472 moves to the previous screen line instead of the last one. */
5473 if (! FRAME_WINDOW_P (XFRAME (w->frame)))
5474 height++;
5475
12c8b416
GM
5476 /* Add in empty lines at the bottom of the window. */
5477 if (bottom_y < height)
5478 {
949cf20f 5479 int uy = FRAME_LINE_HEIGHT (it.f);
c8bc6f65 5480 it.vpos += (height - bottom_y + uy - 1) / uy;
12c8b416
GM
5481 }
5482
c8bc6f65
GM
5483 if (old_buffer)
5484 set_buffer_internal (old_buffer);
5485
12c8b416
GM
5486 return it.vpos;
5487}
5488
5489
7ab12479 5490DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
fdb82f93
PJ
5491 doc: /* Center point in window and redisplay frame.
5492With prefix argument ARG, recenter putting point on screen line ARG
5493relative to the current window. If ARG is negative, it counts up from the
5494bottom of the window. (ARG should be less than the height of the window.)
5495
5496If ARG is omitted or nil, erase the entire frame and then
5497redraw with point in the center of the current window.
5498Just C-u as prefix means put point in the center of the window
5499and redisplay normally--don't erase and redraw the frame. */)
5500 (arg)
413430c5 5501 register Lisp_Object arg;
7ab12479 5502{
6df47b59 5503 struct window *w = XWINDOW (selected_window);
478292ed
RS
5504 struct buffer *buf = XBUFFER (w->buffer);
5505 struct buffer *obuf = current_buffer;
6df47b59
GM
5506 int center_p = 0;
5507 int charpos, bytepos;
f6b43440
RS
5508 int iarg;
5509 int this_scroll_margin;
7ab12479 5510
0fa5d25b
RS
5511 /* If redisplay is suppressed due to an error, try again. */
5512 obuf->display_error_modiff = 0;
5513
413430c5 5514 if (NILP (arg))
7ab12479 5515 {
f02d6d5c
KH
5516 int i;
5517
5518 /* Invalidate pixel data calculated for all compositions. */
5519 for (i = 0; i < n_compositions; i++)
5520 composition_table[i]->font = NULL;
7ab12479 5521
527b6458 5522 Fredraw_frame (w->frame);
44fa5b1e 5523 SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
6df47b59 5524 center_p = 1;
7ab12479 5525 }
413430c5 5526 else if (CONSP (arg)) /* Just C-u. */
6df47b59 5527 center_p = 1;
7ab12479
JB
5528 else
5529 {
413430c5 5530 arg = Fprefix_numeric_value (arg);
b7826503 5531 CHECK_NUMBER (arg);
ae12ecd7 5532 iarg = XINT (arg);
7ab12479
JB
5533 }
5534
478292ed 5535 set_buffer_internal (buf);
7ab12479 5536
f6b43440
RS
5537 /* Do this after making BUF current
5538 in case scroll_margin is buffer-local. */
5539 this_scroll_margin = max (0, scroll_margin);
5540 this_scroll_margin = min (this_scroll_margin,
5541 XFASTINT (w->total_lines) / 4);
5542
521b203e 5543 /* Handle centering on a graphical frame specially. Such frames can
6df47b59
GM
5544 have variable-height lines and centering point on the basis of
5545 line counts would lead to strange effects. */
521b203e 5546 if (FRAME_WINDOW_P (XFRAME (w->frame)))
6df47b59 5547 {
6df47b59
GM
5548 if (center_p)
5549 {
521b203e
GM
5550 struct it it;
5551 struct text_pos pt;
177c0ea7 5552
521b203e
GM
5553 SET_TEXT_POS (pt, PT, PT_BYTE);
5554 start_display (&it, w, pt);
f204989e 5555 move_it_vertically_backward (&it, window_box_height (w) / 2);
521b203e
GM
5556 charpos = IT_CHARPOS (it);
5557 bytepos = IT_BYTEPOS (it);
6df47b59 5558 }
f6b43440 5559 else if (iarg < 0)
6df47b59 5560 {
521b203e
GM
5561 struct it it;
5562 struct text_pos pt;
f6b43440 5563 int nlines = -iarg;
f204989e
KS
5564 int extra_line_spacing;
5565 int h = window_box_height (w);
177c0ea7 5566
f6b43440
RS
5567 iarg = - max (-iarg, this_scroll_margin);
5568
521b203e
GM
5569 SET_TEXT_POS (pt, PT, PT_BYTE);
5570 start_display (&it, w, pt);
f204989e
KS
5571
5572 /* Be sure we have the exact height of the full line containing PT. */
5573 move_it_by_lines (&it, 0, 1);
521b203e 5574
d466fa4d 5575 /* The amount of pixels we have to move back is the window
521b203e
GM
5576 height minus what's displayed in the line containing PT,
5577 and the lines below. */
f204989e
KS
5578 it.current_y = 0;
5579 it.vpos = 0;
d466fa4d
GM
5580 move_it_by_lines (&it, nlines, 1);
5581
f204989e
KS
5582 if (it.vpos == nlines)
5583 h -= it.current_y;
5584 else
5585 {
5586 /* Last line has no newline */
5587 h -= line_bottom_y (&it);
5588 it.vpos++;
5589 }
5590
5591 /* Don't reserve space for extra line spacing of last line. */
5592 extra_line_spacing = it.max_extra_line_spacing;
d466fa4d
GM
5593
5594 /* If we can't move down NLINES lines because we hit
5595 the end of the buffer, count in some empty lines. */
5596 if (it.vpos < nlines)
f204989e
KS
5597 {
5598 nlines -= it.vpos;
5599 extra_line_spacing = it.extra_line_spacing;
5600 h -= nlines * (FRAME_LINE_HEIGHT (it.f) + extra_line_spacing);
5601 }
5602 if (h <= 0)
5603 return Qnil;
201c831a 5604
f204989e 5605 /* Now find the new top line (starting position) of the window. */
521b203e 5606 start_display (&it, w, pt);
f204989e
KS
5607 it.current_y = 0;
5608 move_it_vertically_backward (&it, h);
5609
5610 /* If extra line spacing is present, we may move too far
5611 back. This causes the last line to be only partially
5612 visible (which triggers redisplay to recenter that line
5613 in the middle), so move forward.
5614 But ignore extra line spacing on last line, as it is not
5615 considered to be part of the visible height of the line.
5616 */
5617 h += extra_line_spacing;
5618 while (-it.current_y > h)
5619 move_it_by_lines (&it, 1, 1);
5620
521b203e
GM
5621 charpos = IT_CHARPOS (it);
5622 bytepos = IT_BYTEPOS (it);
6df47b59 5623 }
521b203e
GM
5624 else
5625 {
5626 struct position pos;
f6b43440 5627
f6b43440
RS
5628 iarg = max (iarg, this_scroll_margin);
5629
5630 pos = *vmotion (PT, -iarg, w);
521b203e
GM
5631 charpos = pos.bufpos;
5632 bytepos = pos.bytepos;
5633 }
5634 }
5635 else
5636 {
5637 struct position pos;
5638 int ht = window_internal_height (w);
5639
5640 if (center_p)
a4429c5b 5641 iarg = ht / 2;
f567c488
KS
5642 else if (iarg < 0)
5643 iarg += ht;
f6b43440
RS
5644
5645 /* Don't let it get into the margin at either top or bottom. */
5646 iarg = max (iarg, this_scroll_margin);
5647 iarg = min (iarg, ht - this_scroll_margin - 1);
177c0ea7 5648
f6b43440 5649 pos = *vmotion (PT, - iarg, w);
6df47b59
GM
5650 charpos = pos.bufpos;
5651 bytepos = pos.bytepos;
5652 }
5653
5654 /* Set the new window start. */
5655 set_marker_both (w->start, w->buffer, charpos, bytepos);
2f3cad6c 5656 w->window_end_valid = Qnil;
177c0ea7 5657
95605b1b
RS
5658 w->optional_new_start = Qt;
5659
6df47b59
GM
5660 if (bytepos == BEGV_BYTE || FETCH_BYTE (bytepos - 1) == '\n')
5661 w->start_at_line_beg = Qt;
5662 else
5663 w->start_at_line_beg = Qnil;
177c0ea7 5664
478292ed 5665 set_buffer_internal (obuf);
7ab12479
JB
5666 return Qnil;
5667}
b7617575
GM
5668
5669
81fe0836 5670DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height,
fdb82f93
PJ
5671 0, 1, 0,
5672 doc: /* Return the height in lines of the text display area of WINDOW.
5673This doesn't include the mode-line (or header-line if any) or any
5674partial-height lines in the text display area. */)
5675 (window)
81fe0836
MB
5676 Lisp_Object window;
5677{
5678 struct window *w = decode_window (window);
5679 int pixel_height = window_box_height (w);
949cf20f 5680 int line_height = pixel_height / FRAME_LINE_HEIGHT (XFRAME (w->frame));
81fe0836
MB
5681 return make_number (line_height);
5682}
5683
5684
7ab12479
JB
5685\f
5686DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
fdb82f93
PJ
5687 1, 1, "P",
5688 doc: /* Position point relative to window.
5689With no argument, position point at center of window.
5690An argument specifies vertical position within the window;
5691zero means top of window, negative means relative to bottom of window. */)
5692 (arg)
b7617575 5693 Lisp_Object arg;
7ab12479 5694{
b7617575
GM
5695 struct window *w = XWINDOW (selected_window);
5696 int lines, start;
540b6aa0 5697 Lisp_Object window;
f6b43440
RS
5698#if 0
5699 int this_scroll_margin;
5700#endif
7ab12479 5701
b7617575 5702 window = selected_window;
7ab12479
JB
5703 start = marker_position (w->start);
5704 if (start < BEGV || start > ZV)
5705 {
b7617575 5706 int height = window_internal_height (w);
cd2be1dd 5707 Fvertical_motion (make_number (- (height / 2)), window);
b73ea88e 5708 set_marker_both (w->start, w->buffer, PT, PT_BYTE);
7ab12479
JB
5709 w->start_at_line_beg = Fbolp ();
5710 w->force_start = Qt;
5711 }
5712 else
b73ea88e 5713 Fgoto_char (w->start);
7ab12479 5714
b7617575 5715 lines = displayed_window_lines (w);
f6b43440
RS
5716
5717#if 0
5718 this_scroll_margin = max (0, scroll_margin);
5719 this_scroll_margin = min (this_scroll_margin, lines / 4);
5720#endif
5721
b7617575
GM
5722 if (NILP (arg))
5723 XSETFASTINT (arg, lines / 2);
5724 else
5725 {
f6b43440
RS
5726 int iarg = XINT (Fprefix_numeric_value (arg));
5727
5728 if (iarg < 0)
5729 iarg = iarg + lines;
5730
5731#if 0 /* This code would prevent move-to-window-line from moving point
5732 to a place inside the scroll margins (which would cause the
5733 next redisplay to scroll). I wrote this code, but then concluded
5734 it is probably better not to install it. However, it is here
5735 inside #if 0 so as not to lose it. -- rms. */
5736
5737 /* Don't let it get into the margin at either top or bottom. */
5738 iarg = max (iarg, this_scroll_margin);
5739 iarg = min (iarg, lines - this_scroll_margin - 1);
5740#endif
5741
5742 arg = make_number (iarg);
b7617575
GM
5743 }
5744
c8bc6f65 5745 /* Skip past a partially visible first line. */
163784df 5746 if (w->vscroll)
163784df
MB
5747 XSETINT (arg, XINT (arg) + 1);
5748
540b6aa0 5749 return Fvertical_motion (arg, window);
7ab12479 5750}
5500c422
GM
5751
5752
7ab12479 5753\f
5500c422
GM
5754/***********************************************************************
5755 Window Configuration
5756 ***********************************************************************/
5757
7ab12479
JB
5758struct save_window_data
5759 {
f5ccc0cc 5760 EMACS_INT size_from_Lisp_Vector_struct;
7ab12479 5761 struct Lisp_Vector *next_from_Lisp_Vector_struct;
949cf20f 5762 Lisp_Object frame_cols, frame_lines, frame_menu_bar_lines;
9ea173e8 5763 Lisp_Object frame_tool_bar_lines;
bdc727bf 5764 Lisp_Object selected_frame;
7ab12479
JB
5765 Lisp_Object current_window;
5766 Lisp_Object current_buffer;
5767 Lisp_Object minibuf_scroll_window;
3f49fddc 5768 Lisp_Object minibuf_selected_window;
7ab12479 5769 Lisp_Object root_window;
bdc727bf 5770 Lisp_Object focus_frame;
756b6edc
RS
5771 /* Record the values of window-min-width and window-min-height
5772 so that window sizes remain consistent with them. */
5773 Lisp_Object min_width, min_height;
cbff28e8
RS
5774 /* A vector, each of whose elements is a struct saved_window
5775 for one window. */
7ab12479
JB
5776 Lisp_Object saved_windows;
5777 };
ff06df24 5778
cbff28e8 5779/* This is saved as a Lisp_Vector */
7ab12479 5780struct saved_window
ea68264b
GM
5781{
5782 /* these first two must agree with struct Lisp_Vector in lisp.h */
5783 EMACS_INT size_from_Lisp_Vector_struct;
5784 struct Lisp_Vector *next_from_Lisp_Vector_struct;
7ab12479 5785
ea68264b
GM
5786 Lisp_Object window;
5787 Lisp_Object buffer, start, pointm, mark;
949cf20f
KS
5788 Lisp_Object left_col, top_line, total_cols, total_lines;
5789 Lisp_Object hscroll, min_hscroll;
ea68264b
GM
5790 Lisp_Object parent, prev;
5791 Lisp_Object start_at_line_beg;
5792 Lisp_Object display_table;
949cf20f
KS
5793 Lisp_Object orig_top_line, orig_total_lines;
5794 Lisp_Object left_margin_cols, right_margin_cols;
5795 Lisp_Object left_fringe_width, right_fringe_width, fringes_outside_margins;
5796 Lisp_Object scroll_bar_width, vertical_scroll_bar_type;
6ad0381c 5797 Lisp_Object dedicated;
ea68264b
GM
5798};
5799
7ab12479
JB
5800#define SAVED_WINDOW_N(swv,n) \
5801 ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
5802
5803DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
fdb82f93
PJ
5804 doc: /* Return t if OBJECT is a window-configuration object. */)
5805 (object)
413430c5 5806 Lisp_Object object;
7ab12479 5807{
6ad0381c 5808 return WINDOW_CONFIGURATIONP (object) ? Qt : Qnil;
7ab12479
JB
5809}
5810
3f8ab7bd 5811DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
fdb82f93
PJ
5812 doc: /* Return the frame that CONFIG, a window-configuration object, is about. */)
5813 (config)
3f8ab7bd
RS
5814 Lisp_Object config;
5815{
5816 register struct save_window_data *data;
5817 struct Lisp_Vector *saved_windows;
5818
5819 if (! WINDOW_CONFIGURATIONP (config))
5820 wrong_type_argument (Qwindow_configuration_p, config);
5821
5822 data = (struct save_window_data *) XVECTOR (config);
5823 saved_windows = XVECTOR (data->saved_windows);
5824 return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
5825}
5826
d5b2799e 5827DEFUN ("set-window-configuration", Fset_window_configuration,
fdb82f93
PJ
5828 Sset_window_configuration, 1, 1, 0,
5829 doc: /* Set the configuration of windows and buffers as specified by CONFIGURATION.
5830CONFIGURATION must be a value previously returned
5831by `current-window-configuration' (which see).
5832If CONFIGURATION was made from a frame that is now deleted,
5833only frame-independent values can be restored. In this case,
5834the return value is nil. Otherwise the value is t. */)
5835 (configuration)
2f83aebe 5836 Lisp_Object configuration;
7ab12479 5837{
7ab12479
JB
5838 register struct save_window_data *data;
5839 struct Lisp_Vector *saved_windows;
7ab12479 5840 Lisp_Object new_current_buffer;
fd482be5 5841 Lisp_Object frame;
44fa5b1e 5842 FRAME_PTR f;
72695e47 5843 int old_point = -1;
7ab12479 5844
017b2bad 5845 while (!WINDOW_CONFIGURATIONP (configuration))
3f8ab7bd 5846 wrong_type_argument (Qwindow_configuration_p, configuration);
7ab12479 5847
2f83aebe 5848 data = (struct save_window_data *) XVECTOR (configuration);
7ab12479
JB
5849 saved_windows = XVECTOR (data->saved_windows);
5850
7ab12479 5851 new_current_buffer = data->current_buffer;
265a9e55 5852 if (NILP (XBUFFER (new_current_buffer)->name))
7ab12479 5853 new_current_buffer = Qnil;
72695e47 5854 else
73cadfc1
DK
5855 {
5856 if (XBUFFER (new_current_buffer) == current_buffer)
e67a1dea
SM
5857 /* The code further down "preserves point" by saving here PT in
5858 old_point and then setting it later back into PT. When the
5859 current-selected-window and the final-selected-window both show
5860 the current buffer, this suffers from the problem that the
5861 current PT is the window-point of the current-selected-window,
5862 while the final PT is the point of the final-selected-window, so
5863 this copy from one PT to the other would end up moving the
5864 window-point of the final-selected-window to the window-point of
5865 the current-selected-window. So we have to be careful which
5866 point of the current-buffer we copy into old_point. */
5867 if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer)
5868 && WINDOWP (selected_window)
5869 && EQ (XWINDOW (selected_window)->buffer, new_current_buffer)
5870 && !EQ (selected_window, data->current_window))
5871 old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos;
5872 else
5873 old_point = PT;
73cadfc1 5874 else
203eb0aa
SM
5875 /* BUF_PT (XBUFFER (new_current_buffer)) gives us the position of
5876 point in new_current_buffer as of the last time this buffer was
5877 used. This can be non-deterministic since it can be changed by
5878 things like jit-lock by mere temporary selection of some random
5879 window that happens to show this buffer.
5880 So if possible we want this arbitrary choice of "which point" to
5881 be the one from the to-be-selected-window so as to prevent this
5882 window's cursor from being copied from another window. */
5883 if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer)
5884 /* If current_window = selected_window, its point is in BUF_PT. */
5885 && !EQ (selected_window, data->current_window))
5886 old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos;
5887 else
5888 old_point = BUF_PT (XBUFFER (new_current_buffer));
73cadfc1 5889 }
7ab12479 5890
fd482be5
JB
5891 frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
5892 f = XFRAME (frame);
177c0ea7 5893
fd482be5
JB
5894 /* If f is a dead frame, don't bother rebuilding its window tree.
5895 However, there is other stuff we should still try to do below. */
5896 if (FRAME_LIVE_P (f))
7ab12479 5897 {
fd482be5
JB
5898 register struct window *w;
5899 register struct saved_window *p;
5500c422
GM
5900 struct window *root_window;
5901 struct window **leaf_windows;
5902 int n_leaf_windows;
c4280705 5903 int k, i, n;
fd482be5
JB
5904
5905 /* If the frame has been resized since this window configuration was
5906 made, we change the frame to the size specified in the
5907 configuration, restore the configuration, and then resize it
5908 back. We keep track of the prevailing height in these variables. */
949cf20f
KS
5909 int previous_frame_lines = FRAME_LINES (f);
5910 int previous_frame_cols = FRAME_COLS (f);
8f6ea2e9 5911 int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
9ea173e8 5912 int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
fd482be5 5913
d2b35234
RS
5914 /* The mouse highlighting code could get screwed up
5915 if it runs during this. */
5916 BLOCK_INPUT;
5917
949cf20f
KS
5918 if (XFASTINT (data->frame_lines) != previous_frame_lines
5919 || XFASTINT (data->frame_cols) != previous_frame_cols)
5920 change_frame_size (f, XFASTINT (data->frame_lines),
5921 XFASTINT (data->frame_cols), 0, 0, 0);
e3678b64 5922#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
8f6ea2e9
KH
5923 if (XFASTINT (data->frame_menu_bar_lines)
5924 != previous_frame_menu_bar_lines)
f8ad443a 5925 x_set_menu_bar_lines (f, data->frame_menu_bar_lines, make_number (0));
4314246f 5926#ifdef HAVE_WINDOW_SYSTEM
9ea173e8
GM
5927 if (XFASTINT (data->frame_tool_bar_lines)
5928 != previous_frame_tool_bar_lines)
5929 x_set_tool_bar_lines (f, data->frame_tool_bar_lines, make_number (0));
4314246f 5930#endif
217f2871 5931#endif
fd482be5 5932
a46c0153
RS
5933 /* "Swap out" point from the selected window's buffer
5934 into the window itself. (Normally the pointm of the selected
5935 window holds garbage.) We do this now, before
719eaeb1
GM
5936 restoring the window contents, and prevent it from
5937 being done later on when we select a new window. */
596ae0cf
RS
5938 if (! NILP (XWINDOW (selected_window)->buffer))
5939 {
5940 w = XWINDOW (selected_window);
5941 set_marker_both (w->pointm,
5942 w->buffer,
5943 BUF_PT (XBUFFER (w->buffer)),
5944 BUF_PT_BYTE (XBUFFER (w->buffer)));
5945 }
5946
fd482be5 5947 windows_or_buffers_changed++;
29aeee73 5948 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
fd482be5 5949
5500c422 5950 /* Problem: Freeing all matrices and later allocating them again
177c0ea7 5951 is a serious redisplay flickering problem. What we would
5500c422
GM
5952 really like to do is to free only those matrices not reused
5953 below. */
5954 root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
5955 leaf_windows
5956 = (struct window **) alloca (count_windows (root_window)
5957 * sizeof (struct window *));
5958 n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
5959
756b6edc
RS
5960 /* Temporarily avoid any problems with windows that are smaller
5961 than they are supposed to be. */
5962 window_min_height = 1;
5963 window_min_width = 1;
5964
fd482be5
JB
5965 /* Kludge Alert!
5966 Mark all windows now on frame as "deleted".
5967 Restoring the new configuration "undeletes" any that are in it.
37962e60 5968
fd482be5
JB
5969 Save their current buffers in their height fields, since we may
5970 need it later, if a buffer saved in the configuration is now
5971 dead. */
5972 delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
5973
5974 for (k = 0; k < saved_windows->size; k++)
5975 {
5976 p = SAVED_WINDOW_N (saved_windows, k);
5977 w = XWINDOW (p->window);
5978 w->next = Qnil;
7ab12479 5979
fd482be5
JB
5980 if (!NILP (p->parent))
5981 w->parent = SAVED_WINDOW_N (saved_windows,
5982 XFASTINT (p->parent))->window;
5983 else
5984 w->parent = Qnil;
7ab12479 5985
fd482be5 5986 if (!NILP (p->prev))
7ab12479 5987 {
fd482be5
JB
5988 w->prev = SAVED_WINDOW_N (saved_windows,
5989 XFASTINT (p->prev))->window;
5990 XWINDOW (w->prev)->next = p->window;
5991 }
5992 else
5993 {
5994 w->prev = Qnil;
5995 if (!NILP (w->parent))
5996 {
949cf20f 5997 if (EQ (p->total_cols, XWINDOW (w->parent)->total_cols))
fd482be5
JB
5998 {
5999 XWINDOW (w->parent)->vchild = p->window;
6000 XWINDOW (w->parent)->hchild = Qnil;
6001 }
6002 else
6003 {
6004 XWINDOW (w->parent)->hchild = p->window;
6005 XWINDOW (w->parent)->vchild = Qnil;
6006 }
6007 }
6008 }
6009
6010 /* If we squirreled away the buffer in the window's height,
6011 restore it now. */
949cf20f
KS
6012 if (BUFFERP (w->total_lines))
6013 w->buffer = w->total_lines;
6014 w->left_col = p->left_col;
6015 w->top_line = p->top_line;
6016 w->total_cols = p->total_cols;
6017 w->total_lines = p->total_lines;
fd482be5 6018 w->hscroll = p->hscroll;
ea68264b 6019 w->min_hscroll = p->min_hscroll;
fd482be5 6020 w->display_table = p->display_table;
949cf20f
KS
6021 w->orig_top_line = p->orig_top_line;
6022 w->orig_total_lines = p->orig_total_lines;
6023 w->left_margin_cols = p->left_margin_cols;
6024 w->right_margin_cols = p->right_margin_cols;
6025 w->left_fringe_width = p->left_fringe_width;
6026 w->right_fringe_width = p->right_fringe_width;
6027 w->fringes_outside_margins = p->fringes_outside_margins;
6028 w->scroll_bar_width = p->scroll_bar_width;
6029 w->vertical_scroll_bar_type = p->vertical_scroll_bar_type;
6ad0381c 6030 w->dedicated = p->dedicated;
d834a2e9 6031 XSETFASTINT (w->last_modified, 0);
3cd21523 6032 XSETFASTINT (w->last_overlay_modified, 0);
fd482be5
JB
6033
6034 /* Reinstall the saved buffer and pointers into it. */
6035 if (NILP (p->buffer))
6036 w->buffer = p->buffer;
6037 else
6038 {
6039 if (!NILP (XBUFFER (p->buffer)->name))
6040 /* If saved buffer is alive, install it. */
6041 {
6042 w->buffer = p->buffer;
6043 w->start_at_line_beg = p->start_at_line_beg;
b73ea88e
RS
6044 set_marker_restricted (w->start, p->start, w->buffer);
6045 set_marker_restricted (w->pointm, p->pointm, w->buffer);
fd482be5 6046 Fset_marker (XBUFFER (w->buffer)->mark,
b73ea88e 6047 p->mark, w->buffer);
fd482be5
JB
6048
6049 /* As documented in Fcurrent_window_configuration, don't
243a5ce6
RS
6050 restore the location of point in the buffer which was
6051 current when the window configuration was recorded. */
6b54027b
RS
6052 if (!EQ (p->buffer, new_current_buffer)
6053 && XBUFFER (p->buffer) == current_buffer)
fd482be5
JB
6054 Fgoto_char (w->pointm);
6055 }
52a68e98
RS
6056 else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
6057 /* Else unless window has a live buffer, get one. */
7ab12479 6058 {
fd482be5
JB
6059 w->buffer = Fcdr (Fcar (Vbuffer_alist));
6060 /* This will set the markers to beginning of visible
6061 range. */
6062 set_marker_restricted (w->start, make_number (0), w->buffer);
6063 set_marker_restricted (w->pointm, make_number (0),w->buffer);
6064 w->start_at_line_beg = Qt;
7ab12479
JB
6065 }
6066 else
fd482be5 6067 /* Keeping window's old buffer; make sure the markers
52a68e98 6068 are real. */
7ab12479 6069 {
fd482be5
JB
6070 /* Set window markers at start of visible range. */
6071 if (XMARKER (w->start)->buffer == 0)
6072 set_marker_restricted (w->start, make_number (0),
6073 w->buffer);
6074 if (XMARKER (w->pointm)->buffer == 0)
b73ea88e
RS
6075 set_marker_restricted_both (w->pointm, w->buffer,
6076 BUF_PT (XBUFFER (w->buffer)),
6077 BUF_PT_BYTE (XBUFFER (w->buffer)));
fd482be5 6078 w->start_at_line_beg = Qt;
7ab12479
JB
6079 }
6080 }
6081 }
9ace597f 6082
fd482be5 6083 FRAME_ROOT_WINDOW (f) = data->root_window;
719eaeb1
GM
6084 /* Prevent "swapping out point" in the old selected window
6085 using the buffer that has been restored into it.
a46c0153 6086 We already swapped out point that from that window's old buffer. */
719eaeb1 6087 selected_window = Qnil;
a46c0153
RS
6088
6089 /* Arrange *not* to restore point in the buffer that was
6090 current when the window configuration was saved. */
243a5ce6
RS
6091 if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer))
6092 set_marker_restricted (XWINDOW (data->current_window)->pointm,
18787f5e 6093 make_number (old_point),
243a5ce6 6094 XWINDOW (data->current_window)->buffer);
177c0ea7 6095
14d87dc9 6096 Fselect_window (data->current_window, Qnil);
396a830c
RS
6097 XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
6098 = selected_window;
7ab12479 6099
db269683 6100 if (NILP (data->focus_frame)
017b2bad 6101 || (FRAMEP (data->focus_frame)
db269683
JB
6102 && FRAME_LIVE_P (XFRAME (data->focus_frame))))
6103 Fredirect_frame_focus (frame, data->focus_frame);
7ab12479 6104
fd482be5
JB
6105#if 0 /* I don't understand why this is needed, and it causes problems
6106 when the frame's old selected window has been deleted. */
e4e59717 6107 if (f != selected_frame && FRAME_WINDOW_P (f))
9a7c6fc3 6108 do_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)),
d12f6f83 6109 0, 0);
fd482be5
JB
6110#endif
6111
6112 /* Set the screen height to the value it had before this function. */
949cf20f
KS
6113 if (previous_frame_lines != FRAME_LINES (f)
6114 || previous_frame_cols != FRAME_COLS (f))
6115 change_frame_size (f, previous_frame_lines, previous_frame_cols,
2b653806 6116 0, 0, 0);
e3678b64 6117#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
8f6ea2e9 6118 if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
f8ad443a
AS
6119 x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
6120 make_number (0));
4314246f 6121#ifdef HAVE_WINDOW_SYSTEM
9ea173e8
GM
6122 if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
6123 x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
6124 make_number (0));
4314246f 6125#endif
217f2871 6126#endif
d2b35234 6127
5500c422 6128 /* Now, free glyph matrices in windows that were not reused. */
c4280705
GM
6129 for (i = n = 0; i < n_leaf_windows; ++i)
6130 {
6131 if (NILP (leaf_windows[i]->buffer))
6132 {
6133 /* Assert it's not reused as a combination. */
177c0ea7 6134 xassert (NILP (leaf_windows[i]->hchild)
c4280705
GM
6135 && NILP (leaf_windows[i]->vchild));
6136 free_window_matrices (leaf_windows[i]);
c4280705
GM
6137 }
6138 else if (EQ (leaf_windows[i]->buffer, new_current_buffer))
6139 ++n;
6140 }
177c0ea7 6141
5500c422
GM
6142 adjust_glyphs (f);
6143
d2b35234 6144 UNBLOCK_INPUT;
756b6edc 6145
478292ed
RS
6146 /* Fselect_window will have made f the selected frame, so we
6147 reselect the proper frame here. Fhandle_switch_frame will change the
6148 selected window too, but that doesn't make the call to
6149 Fselect_window above totally superfluous; it still sets f's
6150 selected window. */
6151 if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
d12f6f83 6152 do_switch_frame (data->selected_frame, 0, 0);
478292ed
RS
6153
6154 if (! NILP (Vwindow_configuration_change_hook)
6155 && ! NILP (Vrun_hooks))
6156 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
6157 }
bdc727bf
JB
6158
6159 if (!NILP (new_current_buffer))
243a5ce6 6160 Fset_buffer (new_current_buffer);
bdc727bf 6161
478292ed
RS
6162 /* Restore the minimum heights recorded in the configuration. */
6163 window_min_height = XINT (data->min_height);
6164 window_min_width = XINT (data->min_width);
543f5fb1 6165
478292ed 6166 Vminibuf_scroll_window = data->minibuf_scroll_window;
3dbab091 6167 minibuf_selected_window = data->minibuf_selected_window;
543f5fb1 6168
3f8ab7bd 6169 return (FRAME_LIVE_P (f) ? Qt : Qnil);
7ab12479
JB
6170}
6171
44fa5b1e 6172/* Mark all windows now on frame as deleted
7ab12479
JB
6173 by setting their buffers to nil. */
6174
fd482be5 6175void
7ab12479
JB
6176delete_all_subwindows (w)
6177 register struct window *w;
6178{
265a9e55 6179 if (!NILP (w->next))
7ab12479 6180 delete_all_subwindows (XWINDOW (w->next));
265a9e55 6181 if (!NILP (w->vchild))
7ab12479 6182 delete_all_subwindows (XWINDOW (w->vchild));
265a9e55 6183 if (!NILP (w->hchild))
7ab12479 6184 delete_all_subwindows (XWINDOW (w->hchild));
605be8af 6185
949cf20f 6186 w->total_lines = w->buffer; /* See Fset_window_configuration for excuse. */
605be8af 6187
86e48436
RS
6188 if (!NILP (w->buffer))
6189 unshow_buffer (w);
6190
605be8af
JB
6191 /* We set all three of these fields to nil, to make sure that we can
6192 distinguish this dead window from any live window. Live leaf
6193 windows will have buffer set, and combination windows will have
6194 vchild or hchild set. */
6195 w->buffer = Qnil;
6196 w->vchild = Qnil;
6197 w->hchild = Qnil;
acf70840
GM
6198
6199 Vwindow_list = Qnil;
7ab12479
JB
6200}
6201\f
6202static int
6203count_windows (window)
6204 register struct window *window;
6205{
6206 register int count = 1;
265a9e55 6207 if (!NILP (window->next))
7ab12479 6208 count += count_windows (XWINDOW (window->next));
265a9e55 6209 if (!NILP (window->vchild))
7ab12479 6210 count += count_windows (XWINDOW (window->vchild));
265a9e55 6211 if (!NILP (window->hchild))
7ab12479
JB
6212 count += count_windows (XWINDOW (window->hchild));
6213 return count;
6214}
6215
5500c422 6216
177c0ea7 6217/* Fill vector FLAT with leaf windows under W, starting at index I.
5500c422
GM
6218 Value is last index + 1. */
6219
6220static int
6221get_leaf_windows (w, flat, i)
6222 struct window *w;
6223 struct window **flat;
6224 int i;
6225{
6226 while (w)
6227 {
6228 if (!NILP (w->hchild))
6229 i = get_leaf_windows (XWINDOW (w->hchild), flat, i);
6230 else if (!NILP (w->vchild))
6231 i = get_leaf_windows (XWINDOW (w->vchild), flat, i);
177c0ea7 6232 else
5500c422
GM
6233 flat[i++] = w;
6234
6235 w = NILP (w->next) ? 0 : XWINDOW (w->next);
6236 }
6237
6238 return i;
6239}
6240
6241
6242/* Return a pointer to the glyph W's physical cursor is on. Value is
6243 null if W's current matrix is invalid, so that no meaningfull glyph
6244 can be returned. */
6245
6246struct glyph *
6247get_phys_cursor_glyph (w)
6248 struct window *w;
6249{
6250 struct glyph_row *row;
6251 struct glyph *glyph;
6252
6253 if (w->phys_cursor.vpos >= 0
6254 && w->phys_cursor.vpos < w->current_matrix->nrows
6255 && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
6256 row->enabled_p)
6257 && row->used[TEXT_AREA] > w->phys_cursor.hpos)
6258 glyph = row->glyphs[TEXT_AREA] + w->phys_cursor.hpos;
6259 else
6260 glyph = NULL;
6261
6262 return glyph;
6263}
6264
6265
7ab12479
JB
6266static int
6267save_window_save (window, vector, i)
6268 Lisp_Object window;
6269 struct Lisp_Vector *vector;
6270 int i;
6271{
6272 register struct saved_window *p;
6273 register struct window *w;
6274 register Lisp_Object tem;
6275
265a9e55 6276 for (;!NILP (window); window = w->next)
7ab12479
JB
6277 {
6278 p = SAVED_WINDOW_N (vector, i);
6279 w = XWINDOW (window);
6280
2a1893f4 6281 XSETFASTINT (w->temslot, i); i++;
7ab12479
JB
6282 p->window = window;
6283 p->buffer = w->buffer;
949cf20f
KS
6284 p->left_col = w->left_col;
6285 p->top_line = w->top_line;
6286 p->total_cols = w->total_cols;
6287 p->total_lines = w->total_lines;
7ab12479 6288 p->hscroll = w->hscroll;
ea68264b 6289 p->min_hscroll = w->min_hscroll;
7ab12479 6290 p->display_table = w->display_table;
949cf20f
KS
6291 p->orig_top_line = w->orig_top_line;
6292 p->orig_total_lines = w->orig_total_lines;
6293 p->left_margin_cols = w->left_margin_cols;
6294 p->right_margin_cols = w->right_margin_cols;
6295 p->left_fringe_width = w->left_fringe_width;
6296 p->right_fringe_width = w->right_fringe_width;
6297 p->fringes_outside_margins = w->fringes_outside_margins;
6298 p->scroll_bar_width = w->scroll_bar_width;
6299 p->vertical_scroll_bar_type = w->vertical_scroll_bar_type;
6ad0381c 6300 p->dedicated = w->dedicated;
265a9e55 6301 if (!NILP (w->buffer))
7ab12479
JB
6302 {
6303 /* Save w's value of point in the window configuration.
6304 If w is the selected window, then get the value of point
6305 from the buffer; pointm is garbage in the selected window. */
6306 if (EQ (window, selected_window))
6307 {
6308 p->pointm = Fmake_marker ();
b73ea88e
RS
6309 set_marker_both (p->pointm, w->buffer,
6310 BUF_PT (XBUFFER (w->buffer)),
6311 BUF_PT_BYTE (XBUFFER (w->buffer)));
7ab12479
JB
6312 }
6313 else
eeb82665 6314 p->pointm = Fcopy_marker (w->pointm, Qnil);
7ab12479 6315
eeb82665 6316 p->start = Fcopy_marker (w->start, Qnil);
7ab12479
JB
6317 p->start_at_line_beg = w->start_at_line_beg;
6318
6319 tem = XBUFFER (w->buffer)->mark;
eeb82665 6320 p->mark = Fcopy_marker (tem, Qnil);
7ab12479
JB
6321 }
6322 else
6323 {
6324 p->pointm = Qnil;
6325 p->start = Qnil;
6326 p->mark = Qnil;
6327 p->start_at_line_beg = Qnil;
6328 }
6329
265a9e55 6330 if (NILP (w->parent))
7ab12479
JB
6331 p->parent = Qnil;
6332 else
6333 p->parent = XWINDOW (w->parent)->temslot;
6334
265a9e55 6335 if (NILP (w->prev))
7ab12479
JB
6336 p->prev = Qnil;
6337 else
6338 p->prev = XWINDOW (w->prev)->temslot;
6339
265a9e55 6340 if (!NILP (w->vchild))
7ab12479 6341 i = save_window_save (w->vchild, vector, i);
265a9e55 6342 if (!NILP (w->hchild))
7ab12479
JB
6343 i = save_window_save (w->hchild, vector, i);
6344 }
6345
6346 return i;
6347}
6348
a0d76c27 6349DEFUN ("current-window-configuration", Fcurrent_window_configuration,
fdb82f93
PJ
6350 Scurrent_window_configuration, 0, 1, 0,
6351 doc: /* Return an object representing the current window configuration of FRAME.
6352If FRAME is nil or omitted, use the selected frame.
6353This describes the number of windows, their sizes and current buffers,
6354and for each displayed buffer, where display starts, and the positions of
6355point and mark. An exception is made for point in the current buffer:
6356its value is -not- saved.
6357This also records the currently selected frame, and FRAME's focus
6358redirection (see `redirect-frame-focus'). */)
6359 (frame)
44fa5b1e 6360 Lisp_Object frame;
7ab12479
JB
6361{
6362 register Lisp_Object tem;
6363 register int n_windows;
6364 register struct save_window_data *data;
da2792e0 6365 register struct Lisp_Vector *vec;
7ab12479 6366 register int i;
44fa5b1e 6367 FRAME_PTR f;
43bad991 6368
44fa5b1e 6369 if (NILP (frame))
1ae1a37d 6370 frame = selected_frame;
b7826503 6371 CHECK_LIVE_FRAME (frame);
1ae1a37d 6372 f = XFRAME (frame);
7ab12479 6373
44fa5b1e 6374 n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
26605be9 6375 vec = allocate_other_vector (VECSIZE (struct save_window_data));
da2792e0
KH
6376 data = (struct save_window_data *)vec;
6377
949cf20f
KS
6378 XSETFASTINT (data->frame_cols, FRAME_COLS (f));
6379 XSETFASTINT (data->frame_lines, FRAME_LINES (f));
d834a2e9 6380 XSETFASTINT (data->frame_menu_bar_lines, FRAME_MENU_BAR_LINES (f));
9ea173e8 6381 XSETFASTINT (data->frame_tool_bar_lines, FRAME_TOOL_BAR_LINES (f));
1ae1a37d 6382 data->selected_frame = selected_frame;
44fa5b1e 6383 data->current_window = FRAME_SELECTED_WINDOW (f);
74112613 6384 XSETBUFFER (data->current_buffer, current_buffer);
3f49fddc 6385 data->minibuf_scroll_window = minibuf_level > 0 ? Vminibuf_scroll_window : Qnil;
3dbab091 6386 data->minibuf_selected_window = minibuf_level > 0 ? minibuf_selected_window : Qnil;
44fa5b1e 6387 data->root_window = FRAME_ROOT_WINDOW (f);
bdc727bf 6388 data->focus_frame = FRAME_FOCUS_FRAME (f);
74112613
KH
6389 XSETINT (data->min_height, window_min_height);
6390 XSETINT (data->min_width, window_min_width);
7ab12479
JB
6391 tem = Fmake_vector (make_number (n_windows), Qnil);
6392 data->saved_windows = tem;
6393 for (i = 0; i < n_windows; i++)
6394 XVECTOR (tem)->contents[i]
8a450f0a 6395 = Fmake_vector (make_number (VECSIZE (struct saved_window)), Qnil);
a1d58e5b 6396 save_window_save (FRAME_ROOT_WINDOW (f), XVECTOR (tem), 0);
74112613 6397 XSETWINDOW_CONFIGURATION (tem, data);
7ab12479
JB
6398 return (tem);
6399}
6400
6401DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
fdb82f93 6402 0, UNEVALLED, 0,
a0a37a6f
LT
6403 doc: /* Execute BODY, preserving window sizes and contents.
6404Return the value of the last form in BODY.
fdb82f93
PJ
6405Restore which buffer appears in which window, where display starts,
6406and the value of point and mark for each window.
6407Also restore the choice of selected window.
6408Also restore which buffer is current.
6924dda6
MB
6409Does not restore the value of point in current buffer.
6410usage: (save-window-excursion BODY ...) */)
fdb82f93 6411 (args)
7ab12479
JB
6412 Lisp_Object args;
6413{
6414 register Lisp_Object val;
aed13378 6415 register int count = SPECPDL_INDEX ();
7ab12479
JB
6416
6417 record_unwind_protect (Fset_window_configuration,
43bad991 6418 Fcurrent_window_configuration (Qnil));
7ab12479
JB
6419 val = Fprogn (args);
6420 return unbind_to (count, val);
6421}
5500c422 6422
94e16dd5
KS
6423
6424\f
6425/***********************************************************************
6426 Window Split Tree
6427 ***********************************************************************/
6428
6429static Lisp_Object
c16e1cc3 6430window_tree (w)
94e16dd5
KS
6431 struct window *w;
6432{
6433 Lisp_Object tail = Qnil;
6434 Lisp_Object result = Qnil;
6435
6436 while (w)
6437 {
6438 Lisp_Object wn;
6439
6440 XSETWINDOW (wn, w);
6441 if (!NILP (w->hchild))
6442 wn = Fcons (Qnil, Fcons (Fwindow_edges (wn),
c16e1cc3 6443 window_tree (XWINDOW (w->hchild))));
94e16dd5
KS
6444 else if (!NILP (w->vchild))
6445 wn = Fcons (Qt, Fcons (Fwindow_edges (wn),
c16e1cc3 6446 window_tree (XWINDOW (w->vchild))));
94e16dd5
KS
6447
6448 if (NILP (result))
6449 {
6450 result = tail = Fcons (wn, Qnil);
6451 }
6452 else
6453 {
6454 XSETCDR (tail, Fcons (wn, Qnil));
6455 tail = XCDR (tail);
6456 }
6457
6458 w = NILP (w->next) ? 0 : XWINDOW (w->next);
6459 }
6460
6461 return result;
6462}
6463
6464
6465
c16e1cc3 6466DEFUN ("window-tree", Fwindow_tree, Swindow_tree,
94e16dd5 6467 0, 1, 0,
c16e1cc3 6468 doc: /* Return the window tree for frame FRAME.
94e16dd5
KS
6469
6470The return value is a list of the form (ROOT MINI), where ROOT
c16e1cc3 6471represents the window tree of the frame's root window, and MINI
94e16dd5
KS
6472is the frame's minibuffer window.
6473
6474If the root window is not split, ROOT is the root window itself.
6475Otherwise, ROOT is a list (DIR EDGES W1 W2 ...) where DIR is nil for a
008171a4 6476horizontal split, and t for a vertical split, EDGES gives the combined
94e16dd5
KS
6477size and position of the subwindows in the split, and the rest of the
6478elements are the subwindows in the split. Each of the subwindows may
6479again be a window or a list representing a window split, and so on.
6480EDGES is a list \(LEFT TOP RIGHT BOTTOM) as returned by `window-edges'.
6481
6482If FRAME is nil or omitted, return information on the currently
6483selected frame. */)
6484 (frame)
6485 Lisp_Object frame;
6486{
94e16dd5
KS
6487 FRAME_PTR f;
6488
6489 if (NILP (frame))
6490 frame = selected_frame;
6491
6492 CHECK_FRAME (frame);
6493 f = XFRAME (frame);
6494
6495 if (!FRAME_LIVE_P (f))
6496 return Qnil;
6497
c16e1cc3 6498 return window_tree (XWINDOW (FRAME_ROOT_WINDOW (f)));
94e16dd5
KS
6499}
6500
5500c422
GM
6501\f
6502/***********************************************************************
6503 Marginal Areas
6504 ***********************************************************************/
6505
6506DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
a7bdfc08 6507 2, 3, 0,
fdb82f93 6508 doc: /* Set width of marginal areas of window WINDOW.
e661376d
KS
6509If WINDOW is nil, set margins of the currently selected window.
6510Second arg LEFT-WIDTH specifies the number of character cells to
6511reserve for the left marginal area. Optional third arg RIGHT-WIDTH
6512does the same for the right marginal area. A nil width parameter
6513means no margin. */)
c10ce82e
JB
6514 (window, left_width, right_width)
6515 Lisp_Object window, left_width, right_width;
5500c422
GM
6516{
6517 struct window *w = decode_window (window);
5500c422 6518
c2c3f202
KS
6519 /* Translate negative or zero widths to nil.
6520 Margins that are too wide have to be checked elsewhere. */
6521
c10ce82e 6522 if (!NILP (left_width))
c2c3f202 6523 {
c10ce82e
JB
6524 CHECK_NUMBER (left_width);
6525 if (XINT (left_width) <= 0)
6526 left_width = Qnil;
c2c3f202 6527 }
5500c422 6528
c10ce82e 6529 if (!NILP (right_width))
c2c3f202 6530 {
c10ce82e
JB
6531 CHECK_NUMBER (right_width);
6532 if (XINT (right_width) <= 0)
6533 right_width = Qnil;
c2c3f202 6534 }
5500c422 6535
c10ce82e
JB
6536 if (!EQ (w->left_margin_cols, left_width)
6537 || !EQ (w->right_margin_cols, right_width))
949cf20f 6538 {
c10ce82e
JB
6539 w->left_margin_cols = left_width;
6540 w->right_margin_cols = right_width;
949cf20f
KS
6541
6542 adjust_window_margins (w);
6543
6544 ++windows_or_buffers_changed;
6545 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6546 }
5500c422 6547
5500c422
GM
6548 return Qnil;
6549}
6550
6551
6552DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
6553 0, 1, 0,
fdb82f93
PJ
6554 doc: /* Get width of marginal areas of window WINDOW.
6555If WINDOW is omitted or nil, use the currently selected window.
6556Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).
6557If a marginal area does not exist, its width will be returned
6558as nil. */)
6559 (window)
5500c422
GM
6560 Lisp_Object window;
6561{
6562 struct window *w = decode_window (window);
949cf20f
KS
6563 return Fcons (w->left_margin_cols, w->right_margin_cols);
6564}
6565
6566
6567\f
6568/***********************************************************************
6569 Fringes
6570 ***********************************************************************/
6571
6572DEFUN ("set-window-fringes", Fset_window_fringes, Sset_window_fringes,
6573 2, 4, 0,
62c2f759 6574 doc: /* Set the fringe widths of window WINDOW.
62c2f759
LK
6575If WINDOW is nil, set the fringe widths of the currently selected
6576window.
e661376d
KS
6577Second arg LEFT-WIDTH specifies the number of pixels to reserve for
6578the left fringe. Optional third arg RIGHT-WIDTH specifies the right
6579fringe width. If a fringe width arg is nil, that means to use the
6580frame's default fringe width. Default fringe widths can be set with
6581the command `set-fringe-style'.
6582If optional fourth arg OUTSIDE-MARGINS is non-nil, draw the fringes
62c2f759
LK
6583outside of the display margins. By default, fringes are drawn between
6584display marginal areas and the text area. */)
c10ce82e
JB
6585 (window, left_width, right_width, outside_margins)
6586 Lisp_Object window, left_width, right_width, outside_margins;
949cf20f
KS
6587{
6588 struct window *w = decode_window (window);
6589
c10ce82e
JB
6590 if (!NILP (left_width))
6591 CHECK_NATNUM (left_width);
6592 if (!NILP (right_width))
6593 CHECK_NATNUM (right_width);
949cf20f 6594
c10ce82e
JB
6595 if (!EQ (w->left_fringe_width, left_width)
6596 || !EQ (w->right_fringe_width, right_width)
949cf20f
KS
6597 || !EQ (w->fringes_outside_margins, outside_margins))
6598 {
c10ce82e
JB
6599 w->left_fringe_width = left_width;
6600 w->right_fringe_width = right_width;
949cf20f
KS
6601 w->fringes_outside_margins = outside_margins;
6602
6603 adjust_window_margins (w);
6604
6605 clear_glyph_matrix (w->current_matrix);
6606 w->window_end_valid = Qnil;
6607
6608 ++windows_or_buffers_changed;
6609 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6610 }
6611
6612 return Qnil;
6613}
6614
6615
6616DEFUN ("window-fringes", Fwindow_fringes, Swindow_fringes,
6617 0, 1, 0,
6618 doc: /* Get width of fringes of window WINDOW.
6619If WINDOW is omitted or nil, use the currently selected window.
467e281a 6620Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS). */)
949cf20f
KS
6621 (window)
6622 Lisp_Object window;
6623{
6624 struct window *w = decode_window (window);
6625 return Fcons (make_number (WINDOW_LEFT_FRINGE_WIDTH (w)),
6626 Fcons (make_number (WINDOW_RIGHT_FRINGE_WIDTH (w)),
6627 Fcons ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) ?
6628 Qt : Qnil), Qnil)));
6629}
6630
6631
6632\f
6633/***********************************************************************
6634 Scroll bars
6635 ***********************************************************************/
6636
6637DEFUN ("set-window-scroll-bars", Fset_window_scroll_bars, Sset_window_scroll_bars,
6638 2, 4, 0,
6639 doc: /* Set width and type of scroll bars of window WINDOW.
6640If window is nil, set scroll bars of the currently selected window.
6641Second parameter WIDTH specifies the pixel width for the scroll bar;
6642this is automatically adjusted to a multiple of the frame column width.
6643Third parameter VERTICAL-TYPE specifies the type of the vertical scroll
6644bar: left, right, or nil.
2f71b5ea 6645If WIDTH is nil, use the frame's scroll-bar width.
a53d44a8
JB
6646If VERTICAL-TYPE is t, use the frame's scroll-bar type.
6647Fourth parameter HORIZONTAL-TYPE is currently unused. */)
79fd290e
JB
6648 (window, width, vertical_type, horizontal_type)
6649 Lisp_Object window, width, vertical_type, horizontal_type;
949cf20f
KS
6650{
6651 struct window *w = decode_window (window);
6652
6653 if (!NILP (width))
0f8fe9a2
SM
6654 {
6655 CHECK_NATNUM (width);
949cf20f 6656
0f8fe9a2
SM
6657 if (XINT (width) == 0)
6658 vertical_type = Qnil;
6659 }
949cf20f 6660
2f71b5ea 6661 if (!(EQ (vertical_type, Qnil)
0cc1039f 6662 || EQ (vertical_type, Qleft)
2f71b5ea
MY
6663 || EQ (vertical_type, Qright)
6664 || EQ (vertical_type, Qt)))
6665 error ("Invalid type of vertical scroll bar");
6666
949cf20f
KS
6667 if (!EQ (w->scroll_bar_width, width)
6668 || !EQ (w->vertical_scroll_bar_type, vertical_type))
6669 {
6670 w->scroll_bar_width = width;
6671 w->vertical_scroll_bar_type = vertical_type;
6672
6673 adjust_window_margins (w);
6674
6675 clear_glyph_matrix (w->current_matrix);
6676 w->window_end_valid = Qnil;
6677
6678 ++windows_or_buffers_changed;
6679 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6680 }
6681
6682 return Qnil;
6683}
6684
6685
6686DEFUN ("window-scroll-bars", Fwindow_scroll_bars, Swindow_scroll_bars,
6687 0, 1, 0,
6688 doc: /* Get width and type of scroll bars of window WINDOW.
6689If WINDOW is omitted or nil, use the currently selected window.
12853c58
KS
6690Value is a list of the form (WIDTH COLS VERTICAL-TYPE HORIZONTAL-TYPE).
6691If WIDTH is nil or TYPE is t, the window is using the frame's corresponding
6692value. */)
949cf20f
KS
6693 (window)
6694 Lisp_Object window;
6695{
6696 struct window *w = decode_window (window);
6697 return Fcons (make_number ((WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
6698 ? WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
6699 : WINDOW_SCROLL_BAR_AREA_WIDTH (w))),
6700 Fcons (make_number (WINDOW_SCROLL_BAR_COLS (w)),
6701 Fcons (w->vertical_scroll_bar_type,
6702 Fcons (Qnil, Qnil))));
5500c422
GM
6703}
6704
6705
7ab12479 6706\f
5500c422
GM
6707/***********************************************************************
6708 Smooth scrolling
6709 ***********************************************************************/
6710
0cc1039f 6711DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 2, 0,
fdb82f93
PJ
6712 doc: /* Return the amount by which WINDOW is scrolled vertically.
6713Use the selected window if WINDOW is nil or omitted.
0cc1039f 6714Normally, value is a multiple of the canonical character height of WINDOW;
8cd0d661 6715optional second arg PIXELS-P means value is measured in pixels. */)
0cc1039f
KS
6716 (window, pixels_p)
6717 Lisp_Object window, pixels_p;
5500c422 6718{
47004952 6719 Lisp_Object result;
5500c422
GM
6720 struct frame *f;
6721 struct window *w;
177c0ea7 6722
5500c422
GM
6723 if (NILP (window))
6724 window = selected_window;
47004952 6725 else
b7826503 6726 CHECK_WINDOW (window);
5500c422
GM
6727 w = XWINDOW (window);
6728 f = XFRAME (w->frame);
177c0ea7 6729
5500c422 6730 if (FRAME_WINDOW_P (f))
0cc1039f
KS
6731 result = (NILP (pixels_p)
6732 ? FRAME_CANON_Y_FROM_PIXEL_Y (f, -w->vscroll)
6733 : make_number (-w->vscroll));
5500c422 6734 else
47004952
GM
6735 result = make_number (0);
6736 return result;
5500c422
GM
6737}
6738
6739
6740DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
0cc1039f 6741 2, 3, 0,
fdb82f93 6742 doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL.
0cc1039f
KS
6743WINDOW nil means use the selected window. Normally, VSCROLL is a
6744non-negative multiple of the canonical character height of WINDOW;
8cd0d661 6745optional third arg PIXELS-P non-nil means that VSCROLL is in pixels.
a0a37a6f
LT
6746If PIXELS-P is nil, VSCROLL may have to be rounded so that it
6747corresponds to an integral number of pixels. The return value is the
6748result of this rounding.
6749If PIXELS-P is non-nil, the return value is VSCROLL. */)
0cc1039f
KS
6750 (window, vscroll, pixels_p)
6751 Lisp_Object window, vscroll, pixels_p;
5500c422
GM
6752{
6753 struct window *w;
6754 struct frame *f;
177c0ea7 6755
5500c422
GM
6756 if (NILP (window))
6757 window = selected_window;
47004952 6758 else
b7826503
PJ
6759 CHECK_WINDOW (window);
6760 CHECK_NUMBER_OR_FLOAT (vscroll);
177c0ea7 6761
5500c422
GM
6762 w = XWINDOW (window);
6763 f = XFRAME (w->frame);
6764
6765 if (FRAME_WINDOW_P (f))
6766 {
6767 int old_dy = w->vscroll;
177c0ea7 6768
0cc1039f
KS
6769 w->vscroll = - (NILP (pixels_p)
6770 ? FRAME_LINE_HEIGHT (f) * XFLOATINT (vscroll)
6771 : XFLOATINT (vscroll));
47004952 6772 w->vscroll = min (w->vscroll, 0);
5500c422 6773
e56263e5
KS
6774 if (w->vscroll != old_dy)
6775 {
6776 /* Adjust glyph matrix of the frame if the virtual display
6777 area becomes larger than before. */
6778 if (w->vscroll < 0 && w->vscroll < old_dy)
6779 adjust_glyphs (f);
177c0ea7 6780
e56263e5
KS
6781 /* Prevent redisplay shortcuts. */
6782 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
6783 }
5500c422 6784 }
177c0ea7 6785
0cc1039f 6786 return Fwindow_vscroll (window, pixels_p);
5500c422 6787}
177c0ea7 6788
7bbb5782
GM
6789\f
6790/* Call FN for all leaf windows on frame F. FN is called with the
6791 first argument being a pointer to the leaf window, and with
f95464e4 6792 additional argument USER_DATA. Stops when FN returns 0. */
7bbb5782
GM
6793
6794void
f95464e4 6795foreach_window (f, fn, user_data)
7bbb5782 6796 struct frame *f;
f95464e4
GM
6797 int (* fn) P_ ((struct window *, void *));
6798 void *user_data;
7bbb5782 6799{
76fb556f
YM
6800 /* Fdelete_frame may set FRAME_ROOT_WINDOW (f) to Qnil. */
6801 if (WINDOWP (FRAME_ROOT_WINDOW (f)))
6802 foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data);
7bbb5782
GM
6803}
6804
6805
6806/* Helper function for foreach_window. Call FN for all leaf windows
6807 reachable from W. FN is called with the first argument being a
f95464e4 6808 pointer to the leaf window, and with additional argument USER_DATA.
67492200 6809 Stop when FN returns 0. Value is 0 if stopped by FN. */
7bbb5782 6810
67492200 6811static int
f95464e4 6812foreach_window_1 (w, fn, user_data)
7bbb5782 6813 struct window *w;
f95464e4
GM
6814 int (* fn) P_ ((struct window *, void *));
6815 void *user_data;
7bbb5782 6816{
67492200 6817 int cont;
177c0ea7 6818
67492200 6819 for (cont = 1; w && cont;)
7bbb5782
GM
6820 {
6821 if (!NILP (w->hchild))
f95464e4 6822 cont = foreach_window_1 (XWINDOW (w->hchild), fn, user_data);
7bbb5782 6823 else if (!NILP (w->vchild))
f95464e4 6824 cont = foreach_window_1 (XWINDOW (w->vchild), fn, user_data);
177c0ea7 6825 else
0f532a9a 6826 cont = fn (w, user_data);
177c0ea7 6827
7bbb5782
GM
6828 w = NILP (w->next) ? 0 : XWINDOW (w->next);
6829 }
67492200
GM
6830
6831 return cont;
7bbb5782
GM
6832}
6833
6834
6d194a45 6835/* Freeze or unfreeze the window start of W unless it is a
f95464e4 6836 mini-window or the selected window. FREEZE_P non-null means freeze
7bbb5782
GM
6837 the window start. */
6838
67492200 6839static int
7bbb5782
GM
6840freeze_window_start (w, freeze_p)
6841 struct window *w;
f95464e4 6842 void *freeze_p;
7bbb5782
GM
6843{
6844 if (w == XWINDOW (selected_window)
6845 || MINI_WINDOW_P (w)
6846 || (MINI_WINDOW_P (XWINDOW (selected_window))
24d744ac 6847 && ! NILP (Vminibuf_scroll_window)
7bbb5782 6848 && w == XWINDOW (Vminibuf_scroll_window)))
f95464e4 6849 freeze_p = NULL;
177c0ea7 6850
f95464e4 6851 w->frozen_window_start_p = freeze_p != NULL;
67492200 6852 return 1;
7bbb5782
GM
6853}
6854
6855
6856/* Freeze or unfreeze the window starts of all leaf windows on frame
6857 F, except the selected window and a mini-window. FREEZE_P non-zero
6858 means freeze the window start. */
6859
6860void
6861freeze_window_starts (f, freeze_p)
6862 struct frame *f;
6863 int freeze_p;
6864{
cbccabec 6865 foreach_window (f, freeze_window_start, (void *) (freeze_p ? f : 0));
7bbb5782 6866}
5500c422
GM
6867
6868\f
6869/***********************************************************************
6870 Initialization
6871 ***********************************************************************/
6872
cbff28e8
RS
6873/* Return 1 if window configurations C1 and C2
6874 describe the same state of affairs. This is used by Fequal. */
6875
6876int
2f8274be 6877compare_window_configurations (c1, c2, ignore_positions)
cbff28e8 6878 Lisp_Object c1, c2;
2f8274be 6879 int ignore_positions;
cbff28e8
RS
6880{
6881 register struct save_window_data *d1, *d2;
6882 struct Lisp_Vector *sw1, *sw2;
6883 int i;
6884
4d3edcb4
GM
6885 if (!WINDOW_CONFIGURATIONP (c1))
6886 wrong_type_argument (Qwindow_configuration_p, c1);
6887 if (!WINDOW_CONFIGURATIONP (c2))
6888 wrong_type_argument (Qwindow_configuration_p, c2);
177c0ea7 6889
cbff28e8
RS
6890 d1 = (struct save_window_data *) XVECTOR (c1);
6891 d2 = (struct save_window_data *) XVECTOR (c2);
6892 sw1 = XVECTOR (d1->saved_windows);
6893 sw2 = XVECTOR (d2->saved_windows);
6894
949cf20f 6895 if (! EQ (d1->frame_cols, d2->frame_cols))
cbff28e8 6896 return 0;
949cf20f 6897 if (! EQ (d1->frame_lines, d2->frame_lines))
cbff28e8
RS
6898 return 0;
6899 if (! EQ (d1->frame_menu_bar_lines, d2->frame_menu_bar_lines))
6900 return 0;
6901 if (! EQ (d1->selected_frame, d2->selected_frame))
6902 return 0;
6903 /* Don't compare the current_window field directly.
6904 Instead see w1_is_current and w2_is_current, below. */
6905 if (! EQ (d1->current_buffer, d2->current_buffer))
6906 return 0;
2f8274be 6907 if (! ignore_positions)
3f49fddc
KS
6908 {
6909 if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
6910 return 0;
6911 if (! EQ (d1->minibuf_selected_window, d2->minibuf_selected_window))
6912 return 0;
6913 }
cbff28e8
RS
6914 /* Don't compare the root_window field.
6915 We don't require the two configurations
6916 to use the same window object,
6917 and the two root windows must be equivalent
6918 if everything else compares equal. */
6919 if (! EQ (d1->focus_frame, d2->focus_frame))
6920 return 0;
6921 if (! EQ (d1->min_width, d2->min_width))
6922 return 0;
6923 if (! EQ (d1->min_height, d2->min_height))
6924 return 0;
6925
6926 /* Verify that the two confis have the same number of windows. */
6927 if (sw1->size != sw2->size)
6928 return 0;
6929
6930 for (i = 0; i < sw1->size; i++)
6931 {
6932 struct saved_window *p1, *p2;
6933 int w1_is_current, w2_is_current;
6934
6935 p1 = SAVED_WINDOW_N (sw1, i);
6936 p2 = SAVED_WINDOW_N (sw2, i);
6937
6938 /* Verify that the current windows in the two
6939 configurations correspond to each other. */
6940 w1_is_current = EQ (d1->current_window, p1->window);
6941 w2_is_current = EQ (d2->current_window, p2->window);
6942
6943 if (w1_is_current != w2_is_current)
6944 return 0;
6945
6946 /* Verify that the corresponding windows do match. */
6947 if (! EQ (p1->buffer, p2->buffer))
6948 return 0;
949cf20f 6949 if (! EQ (p1->left_col, p2->left_col))
cbff28e8 6950 return 0;
949cf20f 6951 if (! EQ (p1->top_line, p2->top_line))
cbff28e8 6952 return 0;
949cf20f 6953 if (! EQ (p1->total_cols, p2->total_cols))
cbff28e8 6954 return 0;
949cf20f 6955 if (! EQ (p1->total_lines, p2->total_lines))
cbff28e8 6956 return 0;
cbff28e8
RS
6957 if (! EQ (p1->display_table, p2->display_table))
6958 return 0;
6959 if (! EQ (p1->parent, p2->parent))
6960 return 0;
6961 if (! EQ (p1->prev, p2->prev))
6962 return 0;
2f8274be
RS
6963 if (! ignore_positions)
6964 {
6965 if (! EQ (p1->hscroll, p2->hscroll))
6966 return 0;
ea68264b
GM
6967 if (!EQ (p1->min_hscroll, p2->min_hscroll))
6968 return 0;
2f8274be
RS
6969 if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
6970 return 0;
6971 if (NILP (Fequal (p1->start, p2->start)))
6972 return 0;
6973 if (NILP (Fequal (p1->pointm, p2->pointm)))
6974 return 0;
6975 if (NILP (Fequal (p1->mark, p2->mark)))
6976 return 0;
6977 }
949cf20f
KS
6978 if (! EQ (p1->left_margin_cols, p2->left_margin_cols))
6979 return 0;
6980 if (! EQ (p1->right_margin_cols, p2->right_margin_cols))
6981 return 0;
6982 if (! EQ (p1->left_fringe_width, p2->left_fringe_width))
6983 return 0;
6984 if (! EQ (p1->right_fringe_width, p2->right_fringe_width))
6985 return 0;
6986 if (! EQ (p1->fringes_outside_margins, p2->fringes_outside_margins))
6987 return 0;
6988 if (! EQ (p1->scroll_bar_width, p2->scroll_bar_width))
6989 return 0;
6990 if (! EQ (p1->vertical_scroll_bar_type, p2->vertical_scroll_bar_type))
6991 return 0;
cbff28e8
RS
6992 }
6993
6994 return 1;
6995}
2f8274be
RS
6996
6997DEFUN ("compare-window-configurations", Fcompare_window_configurations,
6998 Scompare_window_configurations, 2, 2, 0,
fdb82f93
PJ
6999 doc: /* Compare two window configurations as regards the structure of windows.
7000This function ignores details such as the values of point and mark
7001and scrolling positions. */)
7002 (x, y)
2f8274be
RS
7003 Lisp_Object x, y;
7004{
7005 if (compare_window_configurations (x, y, 1))
7006 return Qt;
7007 return Qnil;
7008}
cbff28e8 7009\f
dfcf069d 7010void
7ab12479
JB
7011init_window_once ()
7012{
1ae1a37d
GM
7013 struct frame *f = make_terminal_frame ();
7014 XSETFRAME (selected_frame, f);
7015 Vterminal_frame = selected_frame;
7016 minibuf_window = f->minibuffer_window;
7017 selected_window = f->selected_window;
7018 last_nonminibuf_frame = f;
5b03d3c0
RS
7019
7020 window_initialized = 1;
7ab12479
JB
7021}
7022
67492200
GM
7023void
7024init_window ()
7025{
7026 Vwindow_list = Qnil;
7027}
7028
dfcf069d 7029void
7ab12479
JB
7030syms_of_window ()
7031{
c525d842
CY
7032 Qscroll_up = intern ("scroll-up");
7033 staticpro (&Qscroll_up);
7034
7035 Qscroll_down = intern ("scroll-down");
7036 staticpro (&Qscroll_down);
7037
8a37516b
GM
7038 Qwindow_size_fixed = intern ("window-size-fixed");
7039 staticpro (&Qwindow_size_fixed);
c0e7ccd3 7040 Fset (Qwindow_size_fixed, Qnil);
177c0ea7 7041
543f5fb1
RS
7042 staticpro (&Qwindow_configuration_change_hook);
7043 Qwindow_configuration_change_hook
7044 = intern ("window-configuration-change-hook");
7045
7ab12479
JB
7046 Qwindowp = intern ("windowp");
7047 staticpro (&Qwindowp);
7048
3f8ab7bd
RS
7049 Qwindow_configuration_p = intern ("window-configuration-p");
7050 staticpro (&Qwindow_configuration_p);
7051
806b4d9b
JB
7052 Qwindow_live_p = intern ("window-live-p");
7053 staticpro (&Qwindow_live_p);
605be8af 7054
2cccc823 7055 Qtemp_buffer_show_hook = intern ("temp-buffer-show-hook");
a58ec57d
RS
7056 staticpro (&Qtemp_buffer_show_hook);
7057
67492200 7058 staticpro (&Vwindow_list);
8bfb170b
KS
7059
7060 minibuf_selected_window = Qnil;
3dbab091 7061 staticpro (&minibuf_selected_window);
67492200 7062
66fe93d1 7063 window_scroll_pixel_based_preserve_y = -1;
66d43aea 7064
7ab12479 7065 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
fdb82f93
PJ
7066 doc: /* Non-nil means call as function to display a help buffer.
7067The function is called with one argument, the buffer to be displayed.
7068Used by `with-output-to-temp-buffer'.
7069If this function is used, then it must do the entire job of showing
7070the buffer; `temp-buffer-show-hook' is not run unless this function runs it. */);
7ab12479
JB
7071 Vtemp_buffer_show_function = Qnil;
7072
7073 DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
fdb82f93
PJ
7074 doc: /* If non-nil, function to call to handle `display-buffer'.
7075It will receive two args, the buffer and a flag which if non-nil means
c2755926
LT
7076that the currently selected window is not acceptable.
7077It should choose or create a window, display the specified buffer in it,
7078and return the window.
fdb82f93
PJ
7079Commands such as `switch-to-buffer-other-window' and `find-file-other-window'
7080work using this function. */);
7ab12479
JB
7081 Vdisplay_buffer_function = Qnil;
7082
6529ed87 7083 DEFVAR_LISP ("even-window-heights", &Veven_window_heights,
fdb82f93
PJ
7084 doc: /* *If non-nil, `display-buffer' should even the window heights.
7085If nil, `display-buffer' will leave the window configuration alone. */);
6529ed87
GM
7086 Veven_window_heights = Qt;
7087
7ab12479 7088 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
fdb82f93 7089 doc: /* Non-nil means it is the window that C-M-v in minibuffer should scroll. */);
7ab12479
JB
7090 Vminibuf_scroll_window = Qnil;
7091
cc91894c 7092 DEFVAR_BOOL ("mode-line-in-non-selected-windows", &mode_line_in_non_selected_windows,
26124d5e 7093 doc: /* Non-nil means to use `mode-line-inactive' face in non-selected windows.
cc91894c
KS
7094If the minibuffer is active, the `minibuffer-scroll-window' mode line
7095is displayed in the `mode-line' face. */);
7096 mode_line_in_non_selected_windows = 1;
26124d5e 7097
7ab12479 7098 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
fdb82f93 7099 doc: /* If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window. */);
7ab12479
JB
7100 Vother_window_scroll_buffer = Qnil;
7101
44fa5b1e 7102 DEFVAR_BOOL ("pop-up-frames", &pop_up_frames,
fdb82f93 7103 doc: /* *Non-nil means `display-buffer' should make a separate frame. */);
44fa5b1e 7104 pop_up_frames = 0;
7ab12479 7105
e56263e5
KS
7106 DEFVAR_BOOL ("auto-window-vscroll", &auto_window_vscroll_p,
7107 doc: /* *Non-nil means to automatically adjust `window-vscroll' to view tall lines. */);
7108 auto_window_vscroll_p = 1;
7109
9c3da604 7110 DEFVAR_BOOL ("display-buffer-reuse-frames", &display_buffer_reuse_frames,
fdb82f93
PJ
7111 doc: /* *Non-nil means `display-buffer' should reuse frames.
7112If the buffer in question is already displayed in a frame, raise that frame. */);
9c3da604
GM
7113 display_buffer_reuse_frames = 0;
7114
44fa5b1e 7115 DEFVAR_LISP ("pop-up-frame-function", &Vpop_up_frame_function,
fdb82f93
PJ
7116 doc: /* Function to call to handle automatic new frame creation.
7117It is called with no arguments and should return a newly created frame.
7118
7119A typical value might be `(lambda () (new-frame pop-up-frame-alist))'
7120where `pop-up-frame-alist' would hold the default frame parameters. */);
44fa5b1e 7121 Vpop_up_frame_function = Qnil;
7ab12479 7122
a90712c2 7123 DEFVAR_LISP ("special-display-buffer-names", &Vspecial_display_buffer_names,
fdb82f93 7124 doc: /* *List of buffer names that should have their own special frames.
c019856e
RS
7125Displaying a buffer with `display-buffer' or `pop-to-buffer',
7126if its name is in this list, makes a special frame for it
fdb82f93
PJ
7127using `special-display-function'. See also `special-display-regexps'.
7128
7129An element of the list can be a list instead of just a string.
7130There are two ways to use a list as an element:
7131 (BUFFER FRAME-PARAMETERS...) (BUFFER FUNCTION OTHER-ARGS...)
3cb7143c
RS
7132In the first case, the FRAME-PARAMETERS are pairs of the form
7133\(PARAMETER . VALUE); these parameter values are used to create the frame.
7134In the second case, FUNCTION is called with BUFFER as the first argument,
7135followed by the OTHER-ARGS--it can display BUFFER in any way it likes.
fdb82f93
PJ
7136All this is done by the function found in `special-display-function'.
7137
499858c5
RS
7138If the specified frame parameters include (same-buffer . t), the
7139buffer is displayed in the currently selected window. Otherwise, if
7140they include (same-frame . t), the buffer is displayed in a new window
7141in the currently selected frame.
7142
fdb82f93
PJ
7143If this variable appears \"not to work\", because you add a name to it
7144but that buffer still appears in the selected window, look at the
7145values of `same-window-buffer-names' and `same-window-regexps'.
7146Those variables take precedence over this one. */);
a90712c2
RS
7147 Vspecial_display_buffer_names = Qnil;
7148
7149 DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
fdb82f93 7150 doc: /* *List of regexps saying which buffers should have their own special frames.
c019856e
RS
7151When displaying a buffer with `display-buffer' or `pop-to-buffer',
7152if any regexp in this list matches the buffer name, it makes a
7153special frame for the buffer by calling `special-display-function'.
fdb82f93
PJ
7154
7155An element of the list can be a list instead of just a string.
7156There are two ways to use a list as an element:
7157 (REGEXP FRAME-PARAMETERS...) (REGEXP FUNCTION OTHER-ARGS...)
3cb7143c
RS
7158In the first case, the FRAME-PARAMETERS are pairs of the form
7159\(PARAMETER . VALUE); these parameter values are used to create the frame.
7160In the second case, FUNCTION is called with BUFFER as the first argument,
7161followed by the OTHER-ARGS--it can display the buffer in any way it likes.
fdb82f93
PJ
7162All this is done by the function found in `special-display-function'.
7163
499858c5
RS
7164If the specified frame parameters include (same-buffer . t), the
7165buffer is displayed in the currently selected window. Otherwise, if
7166they include (same-frame . t), the buffer is displayed in a new window
7167in the currently selected frame.
7168
fdb82f93
PJ
7169If this variable appears \"not to work\", because you add a regexp to it
7170but the matching buffers still appear in the selected window, look at the
7171values of `same-window-buffer-names' and `same-window-regexps'.
7172Those variables take precedence over this one. */);
a90712c2
RS
7173 Vspecial_display_regexps = Qnil;
7174
7175 DEFVAR_LISP ("special-display-function", &Vspecial_display_function,
fdb82f93
PJ
7176 doc: /* Function to call to make a new frame for a special buffer.
7177It is called with two arguments, the buffer and optional buffer specific
7178data, and should return a window displaying that buffer.
a5731348
SM
7179The default value normally makes a separate frame for the buffer,
7180 using `special-display-frame-alist' to specify the frame parameters.
7181But if the buffer specific data includes (same-buffer . t) then the
7182 buffer is displayed in the current selected window.
7183Otherwise if it includes (same-frame . t) then the buffer is displayed in
7184 a new window in the currently selected frame.
7185
7186A buffer is special if it is listed in `special-display-buffer-names'
fdb82f93 7187or matches a regexp in `special-display-regexps'. */);
a90712c2
RS
7188 Vspecial_display_function = Qnil;
7189
855d8627 7190 DEFVAR_LISP ("same-window-buffer-names", &Vsame_window_buffer_names,
fdb82f93
PJ
7191 doc: /* *List of buffer names that should appear in the selected window.
7192Displaying one of these buffers using `display-buffer' or `pop-to-buffer'
7193switches to it in the selected window, rather than making it appear
7194in some other window.
7195
7196An element of the list can be a cons cell instead of just a string.
7197Then the car must be a string, which specifies the buffer name.
7198This is for compatibility with `special-display-buffer-names';
7199the cdr of the cons cell is ignored.
7200
7201See also `same-window-regexps'. */);
855d8627
RS
7202 Vsame_window_buffer_names = Qnil;
7203
7204 DEFVAR_LISP ("same-window-regexps", &Vsame_window_regexps,
fdb82f93
PJ
7205 doc: /* *List of regexps saying which buffers should appear in the selected window.
7206If a buffer name matches one of these regexps, then displaying it
7207using `display-buffer' or `pop-to-buffer' switches to it
7208in the selected window, rather than making it appear in some other window.
7209
7210An element of the list can be a cons cell instead of just a string.
7211Then the car must be a string, which specifies the buffer name.
7212This is for compatibility with `special-display-buffer-names';
7213the cdr of the cons cell is ignored.
7214
7215See also `same-window-buffer-names'. */);
855d8627
RS
7216 Vsame_window_regexps = Qnil;
7217
7ab12479 7218 DEFVAR_BOOL ("pop-up-windows", &pop_up_windows,
fdb82f93 7219 doc: /* *Non-nil means display-buffer should make new windows. */);
7ab12479
JB
7220 pop_up_windows = 1;
7221
7222 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
fdb82f93 7223 doc: /* *Number of lines of continuity when scrolling by screenfuls. */);
7ab12479
JB
7224 next_screen_context_lines = 2;
7225
7226 DEFVAR_INT ("split-height-threshold", &split_height_threshold,
876e2665 7227 doc: /* *A window must be at least this tall to be eligible for splitting by `display-buffer'.
fdb82f93 7228If there is only one window, it is split regardless of this value. */);
7ab12479
JB
7229 split_height_threshold = 500;
7230
7231 DEFVAR_INT ("window-min-height", &window_min_height,
fdb82f93 7232 doc: /* *Delete any window less than this tall (including its mode line). */);
7ab12479
JB
7233 window_min_height = 4;
7234
7235 DEFVAR_INT ("window-min-width", &window_min_width,
fdb82f93 7236 doc: /* *Delete any window less than this wide. */);
7ab12479
JB
7237 window_min_width = 10;
7238
5500c422
GM
7239 DEFVAR_LISP ("scroll-preserve-screen-position",
7240 &Vscroll_preserve_screen_position,
bdf4ec93
RS
7241 doc: /* *Controls if scroll commands move point to keep its screen line unchanged.
7242A value of nil means point does not keep its screen position except
7243at the scroll margin or window boundary respectively.
7244A value of t means point keeps its screen position if the scroll
7245command moved it vertically out of the window, e.g. when scrolling
7246by full screens.
7247Any other value means point always keeps its screen position. */);
5500c422 7248 Vscroll_preserve_screen_position = Qnil;
9317a85d 7249
543f5fb1
RS
7250 DEFVAR_LISP ("window-configuration-change-hook",
7251 &Vwindow_configuration_change_hook,
fdb82f93
PJ
7252 doc: /* Functions to call when window configuration changes.
7253The selected frame is the one whose configuration has changed. */);
543f5fb1
RS
7254 Vwindow_configuration_change_hook = Qnil;
7255
7ab12479
JB
7256 defsubr (&Sselected_window);
7257 defsubr (&Sminibuffer_window);
7258 defsubr (&Swindow_minibuffer_p);
7259 defsubr (&Swindowp);
806b4d9b 7260 defsubr (&Swindow_live_p);
7ab12479
JB
7261 defsubr (&Spos_visible_in_window_p);
7262 defsubr (&Swindow_buffer);
7263 defsubr (&Swindow_height);
7264 defsubr (&Swindow_width);
7265 defsubr (&Swindow_hscroll);
7266 defsubr (&Sset_window_hscroll);
190eb263
RS
7267 defsubr (&Swindow_redisplay_end_trigger);
7268 defsubr (&Sset_window_redisplay_end_trigger);
7ab12479 7269 defsubr (&Swindow_edges);
c99a9eb3
RS
7270 defsubr (&Swindow_pixel_edges);
7271 defsubr (&Swindow_inside_edges);
7272 defsubr (&Swindow_inside_pixel_edges);
d5783c40
JB
7273 defsubr (&Scoordinates_in_window_p);
7274 defsubr (&Swindow_at);
7ab12479
JB
7275 defsubr (&Swindow_point);
7276 defsubr (&Swindow_start);
7277 defsubr (&Swindow_end);
7278 defsubr (&Sset_window_point);
7279 defsubr (&Sset_window_start);
7280 defsubr (&Swindow_dedicated_p);
d207b766 7281 defsubr (&Sset_window_dedicated_p);
7ab12479
JB
7282 defsubr (&Swindow_display_table);
7283 defsubr (&Sset_window_display_table);
7284 defsubr (&Snext_window);
7285 defsubr (&Sprevious_window);
7286 defsubr (&Sother_window);
7287 defsubr (&Sget_lru_window);
7288 defsubr (&Sget_largest_window);
7289 defsubr (&Sget_buffer_window);
7290 defsubr (&Sdelete_other_windows);
7291 defsubr (&Sdelete_windows_on);
7292 defsubr (&Sreplace_buffer_in_windows);
7293 defsubr (&Sdelete_window);
7294 defsubr (&Sset_window_buffer);
7295 defsubr (&Sselect_window);
4628f7a4
EN
7296 defsubr (&Sspecial_display_p);
7297 defsubr (&Ssame_window_p);
7ab12479 7298 defsubr (&Sdisplay_buffer);
e661376d 7299 defsubr (&Sforce_window_update);
7ab12479
JB
7300 defsubr (&Ssplit_window);
7301 defsubr (&Senlarge_window);
7302 defsubr (&Sshrink_window);
0d384044 7303 defsubr (&Sadjust_window_trailing_edge);
7ab12479
JB
7304 defsubr (&Sscroll_up);
7305 defsubr (&Sscroll_down);
7306 defsubr (&Sscroll_left);
7307 defsubr (&Sscroll_right);
ccd0664b 7308 defsubr (&Sother_window_for_scrolling);
7ab12479 7309 defsubr (&Sscroll_other_window);
fa832261 7310 defsubr (&Sminibuffer_selected_window);
7ab12479 7311 defsubr (&Srecenter);
81fe0836 7312 defsubr (&Swindow_text_height);
7ab12479
JB
7313 defsubr (&Smove_to_window_line);
7314 defsubr (&Swindow_configuration_p);
3f8ab7bd 7315 defsubr (&Swindow_configuration_frame);
7ab12479
JB
7316 defsubr (&Sset_window_configuration);
7317 defsubr (&Scurrent_window_configuration);
7318 defsubr (&Ssave_window_excursion);
c16e1cc3 7319 defsubr (&Swindow_tree);
5500c422
GM
7320 defsubr (&Sset_window_margins);
7321 defsubr (&Swindow_margins);
949cf20f
KS
7322 defsubr (&Sset_window_fringes);
7323 defsubr (&Swindow_fringes);
7324 defsubr (&Sset_window_scroll_bars);
7325 defsubr (&Swindow_scroll_bars);
5500c422
GM
7326 defsubr (&Swindow_vscroll);
7327 defsubr (&Sset_window_vscroll);
2f8274be 7328 defsubr (&Scompare_window_configurations);
67492200 7329 defsubr (&Swindow_list);
7ab12479
JB
7330}
7331
dfcf069d 7332void
7ab12479
JB
7333keys_of_window ()
7334{
7335 initial_define_key (control_x_map, '1', "delete-other-windows");
7336 initial_define_key (control_x_map, '2', "split-window");
7337 initial_define_key (control_x_map, '0', "delete-window");
7338 initial_define_key (control_x_map, 'o', "other-window");
7339 initial_define_key (control_x_map, '^', "enlarge-window");
7340 initial_define_key (control_x_map, '<', "scroll-left");
7341 initial_define_key (control_x_map, '>', "scroll-right");
7342
7343 initial_define_key (global_map, Ctl ('V'), "scroll-up");
7344 initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
7345 initial_define_key (meta_map, 'v', "scroll-down");
7346
7347 initial_define_key (global_map, Ctl('L'), "recenter");
7348 initial_define_key (meta_map, 'r', "move-to-window-line");
7349}
ab5796a9
MB
7350
7351/* arch-tag: 90a9c576-0590-48f1-a5f1-6c96a0452d9f
7352 (do not change this comment) */