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