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