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