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