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