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