*** empty log message ***
[bpt/emacs.git] / src / window.c
CommitLineData
7ab12479
JB
1/* Window creation, deletion and examination for GNU Emacs.
2 Does not include redisplay.
1113d9db 3 Copyright (C) 1985, 1986, 1987, 1992 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
19the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
7ab12479
JB
21#include "config.h"
22#include "lisp.h"
23#include "buffer.h"
24#include "screen.h"
25#include "window.h"
26#include "commands.h"
27#include "indent.h"
28#include "termchar.h"
29#include "disptab.h"
f8026fd8 30#include "keyboard.h"
7ab12479
JB
31
32Lisp_Object Qwindowp;
33
34Lisp_Object Fnext_window (), Fdelete_window (), Fselect_window ();
35Lisp_Object Fset_window_buffer (), Fsplit_window (), Frecenter ();
36
37static void delete_all_subwindows ();
38static struct window *decode_window();
39
40/* This is the window in which the terminal's cursor should
41 be left when nothing is being done with it. This must
42 always be a leaf window, and its buffer is selected by
43 the top level editing loop at the end of each command.
44
45 This value is always the same as
46 SCREEN_SELECTED_WINDOW (selected_screen). */
47
48Lisp_Object selected_window;
49
7ab12479
JB
50/* The minibuffer window of the selected screen.
51 Note that you cannot test for minibufferness of an arbitrary window
52 by comparing against this; but you can test for minibufferness of
53 the selected window. */
54Lisp_Object minibuf_window;
55
56/* Non-nil means it is the window for C-M-v to scroll
57 when the minibuffer is selected. */
58Lisp_Object Vminibuf_scroll_window;
59
60/* Non-nil means this is the buffer whose window C-M-v should scroll. */
61Lisp_Object Vother_window_scroll_buffer;
62
63/* Window that the mouse is over (nil if no mouse support). */
64Lisp_Object Vmouse_window;
65
66/* Last mouse click data structure (nil if no mouse support). */
67Lisp_Object Vmouse_event;
68
69/* Non-nil means it's function to call to display temp buffers. */
70Lisp_Object Vtemp_buffer_show_function;
71
72/* If a window gets smaller than either of these, it is removed. */
73int window_min_height;
74int window_min_width;
75
76/* Nonzero implies Fdisplay_buffer should create windows. */
77int pop_up_windows;
78
79/* Nonzero implies make new X screens for Fdisplay_buffer. */
43bad991 80int pop_up_screens;
7ab12479
JB
81
82/* Non-nil means use this function instead of default */
43bad991 83Lisp_Object Vpop_up_screen_function;
7ab12479
JB
84
85/* Function to call to handle Fdisplay_buffer. */
86Lisp_Object Vdisplay_buffer_function;
87
88/* Fdisplay_buffer always splits the largest window
89 if that window is more than this high. */
90int split_height_threshold;
91
92/* Number of lines of continuity in scrolling by screenfuls. */
93int next_screen_context_lines;
94
95/* Incremented for each window created. */
96static int sequence_number;
97
98#define min(a, b) ((a) < (b) ? (a) : (b))
99\f
100DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
101 "Returns t if OBJ is a window.")
102 (obj)
103 Lisp_Object obj;
104{
105 return XTYPE (obj) == Lisp_Window ? Qt : Qnil;
106}
107
108Lisp_Object
109make_window ()
110{
111 register Lisp_Object val;
112 register struct window *p;
113
114 /* Add sizeof (Lisp_Object) here because sizeof (struct Lisp_Vector)
115 includes the first element. */
116 val = Fmake_vector (
117 make_number ((sizeof (struct window) - sizeof (struct Lisp_Vector)
118 + sizeof (Lisp_Object))
119 / sizeof (Lisp_Object)),
120 Qnil);
121 XSETTYPE (val, Lisp_Window);
122 p = XWINDOW (val);
123 XFASTINT (p->sequence_number) = ++sequence_number;
124 XFASTINT (p->left) = XFASTINT (p->top)
125 = XFASTINT (p->height) = XFASTINT (p->width)
126 = XFASTINT (p->hscroll) = 0;
127 XFASTINT (p->last_point_x) = XFASTINT (p->last_point_y) = 0;
128 p->start = Fmake_marker ();
129 p->pointm = Fmake_marker ();
130 XFASTINT (p->use_time) = 0;
131 p->screen = Qnil;
132 p->display_table = Qnil;
133 p->dedicated = Qnil;
134 return val;
135}
136
137DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0,
138 "Return the window that the cursor now appears in and commands apply to.")
139 ()
140{
141 return selected_window;
142}
143
144DEFUN ("minibuffer-window", Fminibuffer_window, Sminibuffer_window, 0, 0, 0,
145 "Return the window used now for minibuffers.")
146 ()
147{
148#ifdef MULTI_SCREEN
d5783c40 149 choose_minibuf_screen ();
7ab12479
JB
150#endif /* MULTI_SCREEN */
151 return minibuf_window;
152}
153
154DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 1, 1, 0,
155 "Returns non-nil if WINDOW is a minibuffer window.")
156 (window)
157 Lisp_Object window;
158{
159 struct window *w = decode_window (window);
160 return (MINI_WINDOW_P (w) ? Qt : Qnil);
161}
162
163DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
164 Spos_visible_in_window_p, 0, 2, 0,
165 "Return t if position POS is currently on the screen in WINDOW.\n\
166Returns nil if that position is scrolled vertically out of view.\n\
167POS defaults to point; WINDOW, to the selected window.")
168 (pos, window)
169 Lisp_Object pos, window;
170{
171 register struct window *w;
172 register int top;
173 register int height;
174 register int posint;
175 register struct buffer *buf;
176 struct position posval;
177
265a9e55 178 if (NILP (pos))
7ab12479
JB
179 posint = point;
180 else
181 {
182 CHECK_NUMBER_COERCE_MARKER (pos, 0);
183 posint = XINT (pos);
184 }
185
265a9e55 186 if (NILP (window))
7ab12479
JB
187 window = selected_window;
188 else
189 CHECK_WINDOW (window, 1);
190 w = XWINDOW (window);
191 top = marker_position (w->start);
192
193 if (posint < top)
194 return Qnil;
195
196 height = XFASTINT (w->height) - ! MINI_WINDOW_P (w);
197
198 buf = XBUFFER (w->buffer);
199 if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf))
200 {
201 /* If screen is up to date,
202 use the info recorded about how much text fit on it. */
203 if (posint < BUF_Z (buf) - XFASTINT (w->window_end_pos)
204 || (XFASTINT (w->window_end_vpos) < height))
205 return Qt;
206 return Qnil;
207 }
208 else
209 {
210 if (posint > BUF_Z (buf))
211 return Qnil;
212
213 /* If that info is not correct, calculate afresh */
214 posval = *compute_motion (top, 0, 0, posint, height, 0,
215 XFASTINT (w->width) - 1
216 - (XFASTINT (w->width) + XFASTINT (w->left)
e5d77022 217 != SCREEN_WIDTH (XSCREEN (w->screen))),
7ab12479
JB
218 XINT (w->hscroll), 0);
219
220 return posval.vpos < height ? Qt : Qnil;
221 }
222}
223\f
224static struct window *
225decode_window (window)
226 register Lisp_Object window;
227{
265a9e55 228 if (NILP (window))
7ab12479
JB
229 return XWINDOW (selected_window);
230
231 CHECK_WINDOW (window, 0);
232 return XWINDOW (window);
233}
234
235DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
236 "Return the buffer that WINDOW is displaying.")
237 (window)
238 Lisp_Object window;
239{
240 return decode_window (window)->buffer;
241}
242
243DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0,
244 "Return the number of lines in WINDOW (including its mode line).")
245 (window)
246 Lisp_Object window;
247{
248 return decode_window (window)->height;
249}
250
251DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
252 "Return the number of columns in WINDOW.")
253 (window)
254 Lisp_Object window;
255{
256 register struct window *w = decode_window (window);
257 register int width = w->width;
258
259 /* If this window does not end at the right margin,
260 must deduct one column for the border */
261 if ((width + w->left) == SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w))))
262 return width;
263 return width - 1;
264}
265
266DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
267 "Return the number of columns by which WINDOW is scrolled from left margin.")
268 (window)
269 Lisp_Object window;
270{
271 return decode_window (window)->hscroll;
272}
273
274DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
275 "Set number of columns WINDOW is scrolled from left margin to NCOL.\n\
276NCOL should be zero or positive.")
277 (window, ncol)
278 register Lisp_Object window, ncol;
279{
280 register struct window *w;
281
282 CHECK_NUMBER (ncol, 1);
283 if (XINT (ncol) < 0) XFASTINT (ncol) = 0;
284 if (XFASTINT (ncol) >= (1 << (SHORTBITS - 1)))
285 args_out_of_range (ncol, Qnil);
286 w = decode_window (window);
287 if (w->hscroll != ncol)
288 clip_changed = 1; /* Prevent redisplay shortcuts */
289 w->hscroll = ncol;
290 return ncol;
291}
292
293DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0,
294 "Return a list of the edge coordinates of WINDOW.\n\
295\(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of screen.\n\
296RIGHT is one more than the rightmost column used by WINDOW,\n\
297and BOTTOM is one more than the bottommost row used by WINDOW\n\
298 and its mode-line.")
299 (window)
300 Lisp_Object window;
301{
302 register struct window *w = decode_window (window);
303
304 return Fcons (w->left, Fcons (w->top,
305 Fcons (make_number (XFASTINT (w->left) + XFASTINT (w->width)),
306 Fcons (make_number (XFASTINT (w->top)
307 + XFASTINT (w->height)),
308 Qnil))));
309}
310
d5783c40
JB
311/* Test if the character at column *x, row *y is within window *w.
312 If it is not, return 0;
313 if it is in the window's text area,
314 set *x and *y to its location relative to the upper left corner
315 of the window, and
316 return 1;
317 if it is on the window's modeline, return 2;
318 if it is on the border between the window and its right sibling,
319 return 3. */
320static int
321coordinates_in_window (w, x, y)
322 register struct window *w;
323 register int *x, *y;
324{
325 register int left = XINT (w->left);
326 register int width = XINT (w->width);
327 register int window_height = XINT (w->height);
328 register int top = XFASTINT (w->top);
329
330 if ( *x < left || *x >= left + width
331 || *y < top || *y >= top + window_height)
332 return 0;
333
334 /* Is the character is the mode line? */
335 if (*y == top + window_height - 1
336 && window_height > 1) /* 1 line => minibuffer */
337 return 2;
338
339 /* Is the character in the right border? */
340 if (*x == left + width - 1
341 && left + width != SCREEN_WIDTH (XSCREEN (w->screen)))
342 return 3;
343
344 *x -= left;
345 *y -= top;
346 return 1;
347}
348
349DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
350 Scoordinates_in_window_p, 2, 2, 0,
351 "Return non-nil if COORDINATES are in WINDOW.\n\
1113d9db
JB
352COORDINATES is a cons of the form (X . Y), X and Y being distances\n\
353measured in characters from the upper-left corner of the screen.\n\
354(0 . 0) denotes the character in the upper left corner of the\n\
355screen.\n\
d5783c40
JB
356If COORDINATES are in the text portion of WINDOW,\n\
357 the coordinates relative to the window are returned.\n\
e5d77022 358If they are in the mode line of WINDOW, `mode-line' is returned.\n\
d5783c40 359If they are on the border between WINDOW and its right sibling,\n\
e5d77022 360 `vertical-line' is returned.")
d5783c40
JB
361 (coordinates, window)
362 register Lisp_Object coordinates, window;
363{
364 int x, y;
365
366 CHECK_WINDOW (window, 0);
367 CHECK_CONS (coordinates, 1);
368 x = XINT (Fcar (coordinates));
369 y = XINT (Fcdr (coordinates));
370
371 switch (coordinates_in_window (XWINDOW (window), &x, &y))
372 {
373 case 0: /* NOT in window at all. */
374 return Qnil;
375
376 case 1: /* In text part of window. */
377 return Fcons (x, y);
378
379 case 2: /* In mode line of window. */
380 return Qmode_line;
381
382 case 3: /* On right border of window. */
e5d77022 383 return Qvertical_line;
d5783c40
JB
384
385 default:
386 abort ();
387 }
388}
389
7ab12479 390/* Find the window containing column x, row y, and return it as a
d5783c40
JB
391 Lisp_Object. If x, y is on the window's modeline, set *part
392 to 1; if it is on the separating line between the window and its
393 right sibling, set it to 2; otherwise set it to 0. If there is no
394 window under x, y return nil and leave *part unmodified. */
7ab12479 395Lisp_Object
d5783c40 396window_from_coordinates (screen, x, y, part)
7ab12479
JB
397 SCREEN_PTR screen;
398 int x, y;
d5783c40 399 int *part;
7ab12479
JB
400{
401 register Lisp_Object tem, first;
402
d5783c40 403 tem = first = SCREEN_SELECTED_WINDOW (screen);
7ab12479 404
d5783c40 405 do
7ab12479
JB
406 {
407 int found = coordinates_in_window (XWINDOW (tem), &x, &y);
408
409 if (found)
410 {
d5783c40 411 *part = found - 1;
7ab12479
JB
412 return tem;
413 }
414
d5783c40 415 tem = Fnext_window (tem, Qt, Qlambda);
7ab12479 416 }
d5783c40
JB
417 while (! EQ (tem, first));
418
419 return Qnil;
7ab12479
JB
420}
421
ab17c3f2 422DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
95605e15 423 "Return window containing row ROW, column COLUMN on SCREEN.\n\
d5783c40 424If omitted, SCREEN defaults to the currently selected screen.\n\
95605e15
JB
425The top left corner of the screen is considered to be row 0,\n\
426column 0.")
427 (row, column, screen)
428 Lisp_Object row, column, screen;
7ab12479
JB
429{
430 int part;
431
265a9e55 432 if (NILP (screen))
d5783c40
JB
433 XSET (screen, Lisp_Screen, selected_screen);
434 else
95605e15
JB
435 CHECK_LIVE_SCREEN (screen, 2);
436 CHECK_NUMBER (row, 0);
437 CHECK_NUMBER (column, 1);
7ab12479
JB
438
439 return window_from_coordinates (XSCREEN (screen),
95605e15 440 XINT (row), XINT (column),
7ab12479
JB
441 &part);
442}
443
444DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
445 "Return current value of point in WINDOW.\n\
446For a nonselected window, this is the value point would have\n\
447if that window were selected.\n\
448\n\
449Note that, when WINDOW is the selected window and its buffer\n\
450is also currently selected, the value returned is the same as (point).\n\
451It would be more strictly correct to return the `top-level' value\n\
452of point, outside of any save-excursion forms.\n\
453But that is hard to define.")
454 (window)
455 Lisp_Object window;
456{
457 register struct window *w = decode_window (window);
458
459 if (w == XWINDOW (selected_window)
460 && current_buffer == XBUFFER (w->buffer))
461 return Fpoint ();
462 return Fmarker_position (w->pointm);
463}
464
465DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
466 "Return position at which display currently starts in WINDOW.")
467 (window)
468 Lisp_Object window;
469{
470 return Fmarker_position (decode_window (window)->start);
471}
472
473DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 1, 0,
474 "Return position at which display currently ends in WINDOW.")
475 (window)
476 Lisp_Object window;
477{
478 Lisp_Object value;
479 struct window *w = decode_window (window);
480
481 XSET (value, Lisp_Int,
482 BUF_Z (current_buffer) - XFASTINT (w->window_end_pos));
483
484 return value;
485}
486
487DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
488 "Make point value in WINDOW be at position POS in WINDOW's buffer.")
489 (window, pos)
490 Lisp_Object window, pos;
491{
492 register struct window *w = decode_window (window);
493
494 CHECK_NUMBER_COERCE_MARKER (pos, 1);
495 if (w == XWINDOW (selected_window))
496 Fgoto_char (pos);
497 else
498 set_marker_restricted (w->pointm, pos, w->buffer);
499
500 return pos;
501}
502
503DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
504 "Make display in WINDOW start at position POS in WINDOW's buffer.\n\
505Optional third arg NOFORCE non-nil inhibits next redisplay\n\
506from overriding motion of point in order to display at this exact start.")
507 (window, pos, noforce)
508 Lisp_Object window, pos, noforce;
509{
510 register struct window *w = decode_window (window);
511
512 CHECK_NUMBER_COERCE_MARKER (pos, 1);
513 set_marker_restricted (w->start, pos, w->buffer);
514 /* this is not right, but much easier than doing what is right. */
515 w->start_at_line_beg = Qnil;
265a9e55 516 if (NILP (noforce))
7ab12479
JB
517 w->force_start = Qt;
518 w->update_mode_line = Qt;
519 XFASTINT (w->last_modified) = 0;
62c07cc7
JB
520 if (!EQ (window, selected_window))
521 windows_or_buffers_changed++;
7ab12479
JB
522 return pos;
523}
524
525DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
526 1, 1, 0,
527 "Return WINDOW's dedicated object, usually t or nil.\n\
528See also `set-window-buffer-dedicated'.")
529 (window)
530 Lisp_Object window;
531{
532 return decode_window (window)->dedicated;
533}
534
d207b766
RS
535DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p,
536 Sset_window_dedicated_p, 2, 2, 0,
537 "Control whether WINDOW is dedicated to the buffer it displays.\n\
538If it is dedicated, Emacs will not automatically change\n\
539which buffer appears in it.\n\
540The second argument is the new value for the dedication flag;\n\
541non-nil means yes.")
7ab12479
JB
542 (window, arg)
543 Lisp_Object window, arg;
544{
545 register struct window *w = decode_window (window);
546
265a9e55 547 if (NILP (arg))
7ab12479
JB
548 w->dedicated = Qnil;
549 else
d207b766 550 w->dedicated = Qt;
7ab12479
JB
551
552 return w->dedicated;
553}
554
555DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
556 0, 1, 0,
557 "Return the display-table that WINDOW is using.")
558 (window)
559 Lisp_Object window;
560{
561 return decode_window (window)->display_table;
562}
563
564/* Get the display table for use currently on window W.
565 This is either W's display table or W's buffer's display table.
566 Ignore the specified tables if they are not valid;
567 if no valid table is specified, return 0. */
568
569struct Lisp_Vector *
570window_display_table (w)
571 struct window *w;
572{
573 Lisp_Object tem;
574 tem = w->display_table;
575 if (XTYPE (tem) == Lisp_Vector && XVECTOR (tem)->size == DISP_TABLE_SIZE)
576 return XVECTOR (tem);
577 tem = XBUFFER (w->buffer)->display_table;
578 if (XTYPE (tem) == Lisp_Vector && XVECTOR (tem)->size == DISP_TABLE_SIZE)
579 return XVECTOR (tem);
580 tem = Vstandard_display_table;
581 if (XTYPE (tem) == Lisp_Vector && XVECTOR (tem)->size == DISP_TABLE_SIZE)
582 return XVECTOR (tem);
583 return 0;
584}
585
3a2712f9 586DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_display_table, 2, 2, 0,
7ab12479
JB
587 "Set WINDOW's display-table to TABLE.")
588 (window, table)
589 register Lisp_Object window, table;
590{
591 register struct window *w;
592 register Lisp_Object z; /* Return value. */
593
594 w = decode_window (window);
595 w->display_table = table;
596 return table;
597}
598\f
599/* Record info on buffer window w is displaying
600 when it is about to cease to display that buffer. */
601static
602unshow_buffer (w)
603 register struct window *w;
604{
605 Lisp_Object buf = w->buffer;
606
607 if (XBUFFER (buf) != XMARKER (w->pointm)->buffer)
608 abort ();
609
610 if (w == XWINDOW (selected_window)
611 || ! EQ (buf, XWINDOW (selected_window)->buffer))
612 /* Do this except when the selected window's buffer
613 is being removed from some other window. */
614 XBUFFER (buf)->last_window_start = marker_position (w->start);
615
616 /* Point in the selected window's buffer
617 is actually stored in that buffer, and the window's pointm isn't used.
618 So don't clobber point in that buffer. */
619 if (! EQ (buf, XWINDOW (selected_window)->buffer))
620 BUF_PT (XBUFFER (buf))
621 = clip_to_bounds (BUF_BEGV (XBUFFER (buf)),
622 marker_position (w->pointm),
623 BUF_ZV (XBUFFER (buf)));
624}
625
626/* Put replacement into the window structure in place of old. */
627static
628replace_window (old, replacement)
629 Lisp_Object old, replacement;
630{
631 register Lisp_Object tem;
632 register struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
633
634 /* If OLD is its screen's root_window, then replacement is the new
635 root_window for that screen. */
636
e5d77022
JB
637 if (old == SCREEN_ROOT_WINDOW (XSCREEN (o->screen)))
638 SCREEN_ROOT_WINDOW (XSCREEN (o->screen)) = replacement;
7ab12479
JB
639
640 p->left = o->left;
641 p->top = o->top;
642 p->width = o->width;
643 p->height = o->height;
644
645 p->next = tem = o->next;
265a9e55 646 if (!NILP (tem))
7ab12479
JB
647 XWINDOW (tem)->prev = replacement;
648
649 p->prev = tem = o->prev;
265a9e55 650 if (!NILP (tem))
7ab12479
JB
651 XWINDOW (tem)->next = replacement;
652
653 p->parent = tem = o->parent;
265a9e55 654 if (!NILP (tem))
7ab12479
JB
655 {
656 if (EQ (XWINDOW (tem)->vchild, old))
657 XWINDOW (tem)->vchild = replacement;
658 if (EQ (XWINDOW (tem)->hchild, old))
659 XWINDOW (tem)->hchild = replacement;
660 }
661
662/*** Here, if replacement is a vertical combination
663and so is its new parent, we should make replacement's
664children be children of that parent instead. ***/
665}
666
667DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
668 "Remove WINDOW from the display. Default is selected window.")
669 (window)
670 register Lisp_Object window;
671{
672 register Lisp_Object tem, parent, sib;
673 register struct window *p;
674 register struct window *par;
675
265a9e55 676 if (NILP (window))
7ab12479
JB
677 window = selected_window;
678 else
679 CHECK_WINDOW (window, 0);
680
681 p = XWINDOW (window);
682 parent = p->parent;
265a9e55 683 if (NILP (parent))
7ab12479
JB
684 error ("Attempt to delete minibuffer or sole ordinary window");
685 par = XWINDOW (parent);
686
687 windows_or_buffers_changed++;
688
689 if (EQ (window, selected_window))
690 Fselect_window (Fnext_window (window, Qnil, Qnil));
691
692 tem = p->buffer;
693 /* tem is null for dummy parent windows
694 (which have inferiors but not any contents themselves) */
265a9e55 695 if (!NILP (tem))
7ab12479
JB
696 {
697 unshow_buffer (p);
698 unchain_marker (p->pointm);
699 unchain_marker (p->start);
700 p->buffer = Qnil;
701 }
702
703 tem = p->next;
265a9e55 704 if (!NILP (tem))
7ab12479
JB
705 XWINDOW (tem)->prev = p->prev;
706
707 tem = p->prev;
265a9e55 708 if (!NILP (tem))
7ab12479
JB
709 XWINDOW (tem)->next = p->next;
710
711 if (EQ (window, par->hchild))
712 par->hchild = p->next;
713 if (EQ (window, par->vchild))
714 par->vchild = p->next;
715
716 /* Find one of our siblings to give our space to. */
717 sib = p->prev;
265a9e55 718 if (NILP (sib))
7ab12479
JB
719 {
720 /* If p gives its space to its next sibling, that sibling needs
721 to have its top/left side pulled back to where p's is.
722 set_window_{height,width} will re-position the sibling's
723 children. */
724 sib = p->next;
725 XFASTINT (XWINDOW (sib)->top) = p->top;
726 XFASTINT (XWINDOW (sib)->left) = p->left;
727 }
728
729 /* Stretch that sibling. */
265a9e55 730 if (!NILP (par->vchild))
7ab12479
JB
731 set_window_height (sib,
732 XFASTINT (XWINDOW (sib)->height) + XFASTINT (p->height),
733 1);
265a9e55 734 if (!NILP (par->hchild))
7ab12479
JB
735 set_window_width (sib,
736 XFASTINT (XWINDOW (sib)->width) + XFASTINT (p->width),
737 1);
738
739 /* If parent now has only one child,
740 put the child into the parent's place. */
741
742 tem = par->hchild;
265a9e55 743 if (NILP (tem))
7ab12479 744 tem = par->vchild;
265a9e55 745 if (NILP (XWINDOW (tem)->next))
7ab12479
JB
746 replace_window (parent, tem);
747 return Qnil;
748}
749\f
7ab12479
JB
750
751extern Lisp_Object next_screen (), prev_screen ();
752
753DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
754 "Return next window after WINDOW in canonical ordering of windows.\n\
d5783c40
JB
755If omitted, WINDOW defaults to the selected window.\n\
756\n\
757Optional second arg MINIBUF t means count the minibuffer window even\n\
758if not active. MINIBUF nil or omitted means count the minibuffer iff\n\
759it is active. MINIBUF neither t nor nil means not to count the\n\
760minibuffer even if it is active.\n\
761\n\
762Several screens may share a single minibuffer; if the minibuffer\n\
763counts, all windows on all screens that share that minibuffer count\n\
764too. This means that next-window may be used to iterate through the\n\
765set of windows even when the minibuffer is on another screen. If the\n\
766minibuffer does not count, only windows from WINDOW's screen count.\n\
767\n\
768Optional third arg ALL-SCREENS t means include windows on all screens.\n\
769ALL-SCREENS nil or omitted means cycle within the screens as specified\n\
770above. If neither nil nor t, restrict to WINDOW's screen.")
771 (window, minibuf, all_screens)
772 register Lisp_Object window, minibuf, all_screens;
7ab12479
JB
773{
774 register Lisp_Object tem;
d5783c40 775 Lisp_Object start_window;
7ab12479 776
265a9e55 777 if (NILP (window))
7ab12479
JB
778 window = selected_window;
779 else
780 CHECK_WINDOW (window, 0);
781
d5783c40
JB
782 start_window = window;
783
784 /* minibuf == nil may or may not include minibuffers.
785 Decide if it does. */
265a9e55 786 if (NILP (minibuf))
d5783c40
JB
787 minibuf = (minibuf_level ? Qt : Qlambda);
788
789 /* all_screens == nil doesn't specify which screens to include.
790 Decide which screens it includes. */
265a9e55 791 if (NILP (all_screens))
d5783c40
JB
792 all_screens = (EQ (minibuf, Qt)
793 ? (SCREEN_MINIBUF_WINDOW
794 (XSCREEN
795 (WINDOW_SCREEN
796 (XWINDOW (window)))))
797 : Qnil);
798 else if (! EQ (all_screens, Qt))
799 all_screens = Qnil;
7ab12479
JB
800
801 /* Do this loop at least once, to get the next window, and perhaps
802 again, if we hit the minibuffer and that is not acceptable. */
803 do
804 {
805 /* Find a window that actually has a next one. This loop
806 climbs up the tree. */
265a9e55
JB
807 while (tem = XWINDOW (window)->next, NILP (tem))
808 if (tem = XWINDOW (window)->parent, !NILP (tem))
7ab12479 809 window = tem;
d5783c40 810 else
7ab12479 811 {
d5783c40
JB
812 /* We've reached the end of this screen.
813 Which other screens are acceptable? */
7ab12479
JB
814 tem = WINDOW_SCREEN (XWINDOW (window));
815#ifdef MULTI_SCREEN
265a9e55 816 if (! NILP (all_screens))
d5783c40 817 tem = next_screen (tem, all_screens);
7ab12479
JB
818#endif
819 tem = SCREEN_ROOT_WINDOW (XSCREEN (tem));
d5783c40 820
7ab12479
JB
821 break;
822 }
823
824 window = tem;
d5783c40 825
7ab12479
JB
826 /* If we're in a combination window, find its first child and
827 recurse on that. Otherwise, we've found the window we want. */
828 while (1)
829 {
265a9e55 830 if (!NILP (XWINDOW (window)->hchild))
7ab12479 831 window = XWINDOW (window)->hchild;
265a9e55 832 else if (!NILP (XWINDOW (window)->vchild))
7ab12479
JB
833 window = XWINDOW (window)->vchild;
834 else break;
835 }
836 }
d5783c40
JB
837 /* Which windows are acceptible?
838 Exit the loop and accept this window if
7ab12479 839 this isn't a minibuffer window, or
d5783c40
JB
840 we're accepting minibuffer windows, or
841 we've come all the way around and we're back at the original window. */
7ab12479 842 while (MINI_WINDOW_P (XWINDOW (window))
d5783c40
JB
843 && ! EQ (minibuf, Qt)
844 && window != start_window);
7ab12479
JB
845
846 return window;
847}
848
849DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
d5783c40
JB
850 "Return the window preceeding WINDOW in canonical ordering of windows.\n\
851If omitted, WINDOW defaults to the selected window.\n\
852\n\
853Optional second arg MINIBUF t means count the minibuffer window even\n\
854if not active. MINIBUF nil or omitted means count the minibuffer iff\n\
855it is active. MINIBUF neither t nor nil means not to count the\n\
856minibuffer even if it is active.\n\
857\n\
858Several screens may share a single minibuffer; if the minibuffer\n\
859counts, all windows on all screens that share that minibuffer count\n\
860too. This means that previous-window may be used to iterate through\n\
861the set of windows even when the minibuffer is on another screen. If\n\
862the minibuffer does not count, only windows from WINDOW's screen\n\
863count.\n\
864\n\
865Optional third arg ALL-SCREENS t means include windows on all screens.\n\
866ALL-SCREENS nil or omitted means cycle within the screens as specified\n\
867above. If neither nil nor t, restrict to WINDOW's screen.")
868 (window, minibuf, all_screens)
869 register Lisp_Object window, minibuf, all_screens;
7ab12479
JB
870{
871 register Lisp_Object tem;
d5783c40 872 Lisp_Object start_window;
7ab12479 873
265a9e55 874 if (NILP (window))
7ab12479
JB
875 window = selected_window;
876 else
877 CHECK_WINDOW (window, 0);
878
d5783c40
JB
879 start_window = window;
880
881 /* minibuf == nil may or may not include minibuffers.
882 Decide if it does. */
265a9e55 883 if (NILP (minibuf))
d5783c40
JB
884 minibuf = (minibuf_level ? Qt : Qlambda);
885
886 /* all_screens == nil doesn't specify which screens to include.
887 Decide which screens it includes. */
265a9e55 888 if (NILP (all_screens))
d5783c40
JB
889 all_screens = (EQ (minibuf, Qt)
890 ? (SCREEN_MINIBUF_WINDOW
891 (XSCREEN
892 (WINDOW_SCREEN
893 (XWINDOW (window)))))
894 : Qnil);
895 else if (! EQ (all_screens, Qt))
896 all_screens = Qnil;
7ab12479
JB
897
898 /* Do this loop at least once, to get the previous window, and perhaps
899 again, if we hit the minibuffer and that is not acceptable. */
900 do
901 {
902 /* Find a window that actually has a previous one. This loop
903 climbs up the tree. */
265a9e55
JB
904 while (tem = XWINDOW (window)->prev, NILP (tem))
905 if (tem = XWINDOW (window)->parent, !NILP (tem))
7ab12479 906 window = tem;
d5783c40 907 else
7ab12479 908 {
d5783c40
JB
909 /* We have found the top window on the screen.
910 Which screens are acceptable? */
7ab12479
JB
911 tem = WINDOW_SCREEN (XWINDOW (window));
912#ifdef MULTI_SCREEN
265a9e55 913 if (! NILP (all_screens))
d5783c40 914 tem = next_screen (tem, all_screens);
7ab12479
JB
915#endif
916 tem = SCREEN_ROOT_WINDOW (XSCREEN (tem));
d5783c40 917
7ab12479
JB
918 break;
919 }
920
921 window = tem;
922 /* If we're in a combination window, find its last child and
923 recurse on that. Otherwise, we've found the window we want. */
924 while (1)
925 {
265a9e55 926 if (!NILP (XWINDOW (window)->hchild))
7ab12479 927 window = XWINDOW (window)->hchild;
265a9e55 928 else if (!NILP (XWINDOW (window)->vchild))
7ab12479
JB
929 window = XWINDOW (window)->vchild;
930 else break;
265a9e55 931 while (tem = XWINDOW (window)->next, !NILP (tem))
7ab12479
JB
932 window = tem;
933 }
934 }
d5783c40
JB
935 /* Which windows are acceptable?
936 Exit the loop and accept this window if
7ab12479 937 this isn't a minibuffer window, or
d5783c40
JB
938 we're accepting minibuffer windows, or
939 we've come all the way around and we're back at the original window. */
7ab12479 940 while (MINI_WINDOW_P (XWINDOW (window))
d5783c40
JB
941 && !EQ (minibuf, Qt)
942 && window != start_window);
7ab12479
JB
943
944 return window;
945}
946
62c07cc7 947DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
7ab12479
JB
948 "Select the ARG'th different window on this screen.\n\
949All windows on current screen are arranged in a cyclic order.\n\
950This command selects the window ARG steps away in that order.\n\
951A negative ARG moves in the opposite order. If the optional second\n\
952argument ALL_SCREENS is non-nil, cycle through all screens.")
953 (n, all_screens)
954 register Lisp_Object n, all_screens;
955{
956 register int i;
957 register Lisp_Object w;
958
959 CHECK_NUMBER (n, 0);
960 w = selected_window;
961 i = XINT (n);
962
963 while (i > 0)
964 {
965 w = Fnext_window (w, Qnil, all_screens);
966 i--;
967 }
968 while (i < 0)
969 {
970 w = Fprevious_window (w, Qnil, all_screens);
971 i++;
972 }
973 Fselect_window (w);
974 return Qnil;
975}
976\f
977/* Look at all windows, performing an operation specified by TYPE
978 with argument OBJ.
979 If SCREENS is Qt, look at all screens, if Qnil, look at just the selected
980 screen. If SCREENS is a screen, just look at windows on that screen.
981 If MINI is non-zero, perform the operation on minibuffer windows too.
982*/
983
984enum window_loop
985{
986 WINDOW_LOOP_UNUSED,
987 GET_BUFFER_WINDOW, /* Arg is buffer */
988 GET_LRU_WINDOW, /* Arg is t for full-width windows only */
989 DELETE_OTHER_WINDOWS, /* Arg is window not to delete */
990 DELETE_BUFFER_WINDOWS, /* Arg is buffer */
991 GET_LARGEST_WINDOW,
992 UNSHOW_BUFFER, /* Arg is buffer */
993};
994
995static Lisp_Object
996window_loop (type, obj, mini, screens)
997 enum window_loop type;
998 register Lisp_Object obj, screens;
999 int mini;
1000{
1001 register Lisp_Object w;
1002 register Lisp_Object best_window;
1003 register Lisp_Object next_window;
1004 register Lisp_Object first_window;
1005 SCREEN_PTR screen;
1006
1007 /* If we're only looping through windows on a particular screen,
1008 screen points to that screen. If we're looping through windows
1009 on all screens, screen is 0. */
1010 if (SCREENP (screens))
1011 screen = XSCREEN (screens);
265a9e55 1012 else if (NILP (screens))
7ab12479
JB
1013 screen = selected_screen;
1014 else
1015 screen = 0;
1016
1017 /* Pick a window to start with. */
1018 if (XTYPE (obj) == Lisp_Window)
1019 first_window = obj;
1020 else if (screen)
1021 first_window = SCREEN_SELECTED_WINDOW (screen);
1022 else
1023 first_window = SCREEN_SELECTED_WINDOW (selected_screen);
1024
1025 w = first_window;
1026 best_window = Qnil;
1027 do
1028 {
1029 /* Pick the next window now, since some operations will delete
1030 the current window. */
1031#ifdef MULTI_SCREEN
1032 if (screen)
d5783c40 1033 next_window = Fnext_window (w, (mini ? Qt : Qnil), Qlambda);
7ab12479
JB
1034 else
1035#endif /* MULTI_SCREEN */
1036 /* We know screen is 0, so we're looping through all screens.
1037 Or we know this isn't a MULTI_SCREEN Emacs, so who cares? */
1038 next_window = Fnext_window (w, mini ? Qt : Qnil, Qt);
1039
1040 if (!MINI_WINDOW_P (XWINDOW (w))
1041 || (mini && minibuf_level > 0))
1042 switch (type)
1043 {
1044 case GET_BUFFER_WINDOW:
1045#if 0
1046 /* Ignore invisible and iconified screens. */
1047 if (! SCREEN_VISIBLE_P (XSCREEN (WINDOW_SCREEN (XWINDOW (w))))
1048 || SCREEN_ICONIFIED_P (XSCREEN (WINDOW_SCREEN (XWINDOW (w)))))
1049 break;
1050#endif
1051 if (XBUFFER (XWINDOW (w)->buffer) == XBUFFER (obj))
1052 return w;
1053 break;
1054
1055 case GET_LRU_WINDOW:
1056 /* t as arg means consider only full-width windows */
e5d77022
JB
1057 if (!NILP (obj) && XFASTINT (XWINDOW (w)->width)
1058 != SCREEN_WIDTH (screen))
7ab12479
JB
1059 break;
1060#if 0
1061 /* Ignore invisible and iconified screens. */
1062 if (! SCREEN_VISIBLE_P (XSCREEN (WINDOW_SCREEN (XWINDOW (w))))
1063 || SCREEN_ICONIFIED_P (XSCREEN (WINDOW_SCREEN (XWINDOW (w)))))
1064 break;
1065#endif
1066 /* Ignore dedicated windows and minibuffers. */
1067 if (MINI_WINDOW_P (XWINDOW (w))
265a9e55 1068 || !NILP (XWINDOW (w)->dedicated))
7ab12479 1069 break;
265a9e55 1070 if (NILP (best_window)
7ab12479
JB
1071 || (XFASTINT (XWINDOW (best_window)->use_time)
1072 > XFASTINT (XWINDOW (w)->use_time)))
1073 best_window = w;
1074 break;
1075
1076 case DELETE_OTHER_WINDOWS:
1077 if (XWINDOW (w) != XWINDOW (obj))
1078 Fdelete_window (w);
1079 break;
1080
1081 case DELETE_BUFFER_WINDOWS:
1082 if (EQ (XWINDOW (w)->buffer, obj))
1083 {
1084 /* If we're deleting the buffer displayed in the only window
1085 on the screen, find a new buffer to display there. */
265a9e55 1086 if (NILP (XWINDOW (w)->parent))
7ab12479
JB
1087 {
1088 Lisp_Object new_buffer = Fother_buffer (obj);
265a9e55 1089 if (NILP (new_buffer))
7ab12479
JB
1090 new_buffer
1091 = Fget_buffer_create (build_string ("*scratch*"));
1092 Fset_window_buffer (w, new_buffer);
1093 Fset_buffer (XWINDOW (w)->buffer);
1094 }
1095 else
1096 Fdelete_window (w);
1097 }
1098 break;
1099
1100 case GET_LARGEST_WINDOW:
1101#if 0
1102 /* Ignore invisible and iconified screens. */
1103 if (! SCREEN_VISIBLE_P (XSCREEN (WINDOW_SCREEN (XWINDOW (w))))
1104 || SCREEN_ICONIFIED_P (XSCREEN (WINDOW_SCREEN (XWINDOW (w)))))
1105 break;
1106#endif
1107 /* Ignore dedicated windows and minibuffers. */
1108 if (MINI_WINDOW_P (XWINDOW (w))
265a9e55 1109 || !NILP (XWINDOW (w)->dedicated))
7ab12479
JB
1110 break;
1111 {
1112 struct window *best_window_ptr = XWINDOW (best_window);
1113 struct window *w_ptr = XWINDOW (w);
265a9e55 1114 if (NILP (best_window) ||
7ab12479
JB
1115 (XFASTINT (w_ptr->height) * XFASTINT (w_ptr->width))
1116 > (XFASTINT (best_window_ptr->height)
1117 * XFASTINT (best_window_ptr->width)))
1118 best_window = w;
1119 }
1120 break;
1121
1122 case UNSHOW_BUFFER:
1123 if (EQ (XWINDOW (w)->buffer, obj))
1124 {
1125 /* Find another buffer to show in this window. */
1126 Lisp_Object another_buffer = Fother_buffer (obj);
265a9e55 1127 if (NILP (another_buffer))
7ab12479
JB
1128 another_buffer
1129 = Fget_buffer_create (build_string ("*scratch*"));
1130 Fset_window_buffer (w, another_buffer);
1131 if (EQ (w, selected_window))
1132 Fset_buffer (XWINDOW (w)->buffer);
1133 }
1134 break;
1135 }
1136 w = next_window;
1137 }
1138 while (! EQ (w, first_window));
1139
1140 return best_window;
1141}
1142\f
1143DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
1144 "Return the window least recently selected or used for display.\n\
1145If optional argument SCREENS is t, search all screens. If SCREEN is a\n\
1146screen, search only that screen.\n")
1147 (screens)
1148 Lisp_Object screens;
1149{
1150 register Lisp_Object w;
1151 /* First try for a window that is full-width */
1152 w = window_loop (GET_LRU_WINDOW, Qt, 0, screens);
265a9e55 1153 if (!NILP (w) && !EQ (w, selected_window))
7ab12479
JB
1154 return w;
1155 /* If none of them, try the rest */
1156 return window_loop (GET_LRU_WINDOW, Qnil, 0, screens);
1157}
1158
1159DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 1, 0,
1160 "Return the largest window in area.\n\
1161If optional argument SCREENS is t, search all screens. If SCREEN is a\n\
1162screen, search only that screen.\n")
1163 (screen)
1164 Lisp_Object screen;
1165{
1166 return window_loop (GET_LARGEST_WINDOW, Qnil, 0,
1167 screen);
1168}
1169
1170DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 1, 2, 0,
1171 "Return a window currently displaying BUFFER, or nil if none.\n\
1172If optional argument SCREENS is t, search all screens. If SCREEN is a\n\
1173screen, search only that screen.\n")
1174 (buffer, screen)
1175 Lisp_Object buffer, screen;
1176{
1177 buffer = Fget_buffer (buffer);
1178 if (XTYPE (buffer) == Lisp_Buffer)
1179 return window_loop (GET_BUFFER_WINDOW, buffer, 1, screen);
1180 else
1181 return Qnil;
1182}
1183
1184DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
1185 0, 1, "",
1186 "Make WINDOW (or the selected window) fill its screen.\n\
1187Only the screen WINDOW is on is affected.")
1188 (window)
1189 Lisp_Object window;
1190{
1191 struct window *w;
1192 int opoint = point;
1193 struct buffer *obuf = current_buffer;
1194 int top;
1195
265a9e55 1196 if (NILP (window))
7ab12479
JB
1197 window = selected_window;
1198 else
1199 CHECK_WINDOW (window, 0);
1200
1201 w = XWINDOW (window);
1202 top = XFASTINT (w->top);
1203
1204 window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_SCREEN(w));
1205
1206 Fset_buffer (w->buffer);
1207 SET_PT (marker_position (w->start));
1208 Frecenter (make_number (top));
1209
1210 set_buffer_internal (obuf);
1211 SET_PT (opoint);
1212 return Qnil;
1213}
1214
1215DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
1216 1, 1, "bDelete windows on (buffer): ",
1217 "Delete all windows showing BUFFER.")
1218 (buffer)
1219 Lisp_Object buffer;
1220{
265a9e55 1221 if (!NILP (buffer))
7ab12479
JB
1222 {
1223 buffer = Fget_buffer (buffer);
1224 CHECK_BUFFER (buffer, 0);
1225 window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, Qt);
1226 }
1227 return Qnil;
1228}
1229
1230DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
1231 Sreplace_buffer_in_windows,
1232 1, 1, "bReplace buffer in windows: ",
1233 "Replace BUFFER with some other buffer in all windows showing it.")
1234 (buffer)
1235 Lisp_Object buffer;
1236{
265a9e55 1237 if (!NILP (buffer))
7ab12479
JB
1238 {
1239 buffer = Fget_buffer (buffer);
1240 CHECK_BUFFER (buffer, 0);
1241 window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
1242 }
1243 return Qnil;
1244}
1245\f
1246/* Set the height of WINDOW and all its inferiors. */
1247/* Normally the window is deleted if it gets too small.
1248 nodelete nonzero means do not do this.
1249 (The caller should check later and do so if appropriate) */
1250
1251set_window_height (window, height, nodelete)
1252 Lisp_Object window;
1253 int height;
1254 int nodelete;
1255{
1256 register struct window *w = XWINDOW (window);
1257 register struct window *c;
1258 int oheight = XFASTINT (w->height);
1259 int top, pos, lastbot, opos, lastobot;
1260 Lisp_Object child;
1261
1262 if (!nodelete
265a9e55 1263 && ! NILP (w->parent)
7ab12479
JB
1264 && height < window_min_height)
1265 {
1266 Fdelete_window (window);
1267 return;
1268 }
1269
1270 XFASTINT (w->last_modified) = 0;
1271 windows_or_buffers_changed++;
1272 XFASTINT (w->height) = height;
265a9e55 1273 if (!NILP (w->hchild))
7ab12479 1274 {
265a9e55 1275 for (child = w->hchild; !NILP (child); child = XWINDOW (child)->next)
7ab12479
JB
1276 {
1277 XWINDOW (child)->top = w->top;
1278 set_window_height (child, height, nodelete);
1279 }
1280 }
265a9e55 1281 else if (!NILP (w->vchild))
7ab12479
JB
1282 {
1283 lastbot = top = XFASTINT (w->top);
1284 lastobot = 0;
265a9e55 1285 for (child = w->vchild; !NILP (child); child = c->next)
7ab12479
JB
1286 {
1287 c = XWINDOW (child);
1288
1289 opos = lastobot + XFASTINT (c->height);
1290
1291 XFASTINT (c->top) = lastbot;
1292
1293 pos = (((opos * height) << 1) + oheight) / (oheight << 1);
1294
1295 /* Avoid confusion: inhibit deletion of child if becomes too small */
1296 set_window_height (child, pos + top - lastbot, 1);
1297
1298 /* Now advance child to next window,
1299 and set lastbot if child was not just deleted. */
1300 lastbot = pos + top;
1301 lastobot = opos;
1302 }
1303 /* Now delete any children that became too small. */
1304 if (!nodelete)
265a9e55 1305 for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
7ab12479
JB
1306 {
1307 set_window_height (child, XINT (XWINDOW (child)->height), 0);
1308 }
1309 }
1310}
1311
1312/* Recursively set width of WINDOW and its inferiors. */
1313
1314set_window_width (window, width, nodelete)
1315 Lisp_Object window;
1316 int width;
1317 int nodelete;
1318{
1319 register struct window *w = XWINDOW (window);
1320 register struct window *c;
1321 int owidth = XFASTINT (w->width);
1322 int left, pos, lastright, opos, lastoright;
1323 Lisp_Object child;
1324
1325 if (!nodelete && width < window_min_width)
1326 {
1327 Fdelete_window (window);
1328 return;
1329 }
1330
1331 XFASTINT (w->last_modified) = 0;
1332 windows_or_buffers_changed++;
1333 XFASTINT (w->width) = width;
265a9e55 1334 if (!NILP (w->vchild))
7ab12479 1335 {
265a9e55 1336 for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
7ab12479
JB
1337 {
1338 XWINDOW (child)->left = w->left;
1339 set_window_width (child, width, nodelete);
1340 }
1341 }
265a9e55 1342 else if (!NILP (w->hchild))
7ab12479
JB
1343 {
1344 lastright = left = XFASTINT (w->left);
1345 lastoright = 0;
265a9e55 1346 for (child = w->hchild; !NILP (child); child = c->next)
7ab12479
JB
1347 {
1348 c = XWINDOW (child);
1349
1350 opos = lastoright + XFASTINT (c->width);
1351
1352 XFASTINT (c->left) = lastright;
1353
1354 pos = (((opos * width) << 1) + owidth) / (owidth << 1);
1355
1356 /* Inhibit deletion for becoming too small */
1357 set_window_width (child, pos + left - lastright, 1);
1358
1359 /* Now advance child to next window,
1360 and set lastright if child was not just deleted. */
1361 lastright = pos + left, lastoright = opos;
1362 }
1363 /* Delete children that became too small */
1364 if (!nodelete)
265a9e55 1365 for (child = w->hchild; !NILP (child); child = XWINDOW (child)->next)
7ab12479
JB
1366 {
1367 set_window_width (child, XINT (XWINDOW (child)->width), 0);
1368 }
1369 }
1370}
1371\f
1d8d96fa 1372int window_select_count;
7ab12479
JB
1373
1374DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 2, 0,
1375 "Make WINDOW display BUFFER as its contents.\n\
1376BUFFER can be a buffer or buffer name.")
1377 (window, buffer)
1378 register Lisp_Object window, buffer;
1379{
1380 register Lisp_Object tem;
1381 register struct window *w = decode_window (window);
1382
1383 buffer = Fget_buffer (buffer);
1384 CHECK_BUFFER (buffer, 1);
1385
265a9e55 1386 if (NILP (XBUFFER (buffer)->name))
7ab12479
JB
1387 error ("Attempt to display deleted buffer");
1388
1389 tem = w->buffer;
265a9e55 1390 if (NILP (tem))
7ab12479
JB
1391 error ("Window is deleted");
1392 else if (! EQ (tem, Qt)) /* w->buffer is t when the window
1393 is first being set up. */
1394 {
265a9e55 1395 if (!NILP (w->dedicated) && !EQ (tem, buffer))
7ab12479
JB
1396 error ("Window is dedicated to %s\n", tem);
1397
1398 unshow_buffer (w);
1399 }
1400
1401 w->buffer = buffer;
1402 Fset_marker (w->pointm,
1403 make_number (BUF_PT (XBUFFER (buffer))),
1404 buffer);
1405 set_marker_restricted (w->start,
1406 make_number (XBUFFER (buffer)->last_window_start),
1407 buffer);
1408 w->start_at_line_beg = Qnil;
1409 XFASTINT (w->last_modified) = 0;
1410 windows_or_buffers_changed++;
1411 if (EQ (window, selected_window))
1412 Fset_buffer (buffer);
1413
1414 return Qnil;
1415}
1416
1417DEFUN ("select-window", Fselect_window, Sselect_window, 1, 1, 0,
1418 "Select WINDOW. Most editing will apply to WINDOW's buffer.\n\
1419The main editor command loop selects the buffer of the selected window\n\
1420before each command.")
1421 (window)
1422 register Lisp_Object window;
1423{
1424 register struct window *w;
1425 register struct window *ow = XWINDOW (selected_window);
1426
1427 CHECK_WINDOW (window, 0);
1428
1429 w = XWINDOW (window);
1430
265a9e55 1431 if (NILP (w->buffer))
7ab12479
JB
1432 error ("Trying to select deleted window or non-leaf window");
1433
1434 XFASTINT (w->use_time) = ++window_select_count;
1435 if (EQ (window, selected_window))
1436 return window;
1437
1438 Fset_marker (ow->pointm, make_number (BUF_PT (XBUFFER (ow->buffer))),
1439 ow->buffer);
1440
1441 selected_window = window;
1442#ifdef MULTI_SCREEN
43bad991 1443 if (XSCREEN (WINDOW_SCREEN (w)) != selected_screen)
7ab12479
JB
1444 {
1445 XSCREEN (WINDOW_SCREEN (w))->selected_window = window;
1446 Fselect_screen (WINDOW_SCREEN (w), Qnil);
1447 }
1448 else
1449 selected_screen->selected_window = window;
1450#endif
1451
1452 record_buffer (w->buffer);
1453 Fset_buffer (w->buffer);
1454
1455 /* Go to the point recorded in the window.
1456 This is important when the buffer is in more
1457 than one window. It also matters when
1458 redisplay_window has altered point after scrolling,
1459 because it makes the change only in the window. */
1460 {
1461 register int new_point = marker_position (w->pointm);
1462 if (new_point < BEGV)
1463 SET_PT (BEGV);
1464 if (new_point > ZV)
1465 SET_PT (ZV);
1466 else
1467 SET_PT (new_point);
1468 }
1469
1470 windows_or_buffers_changed++;
1471 return window;
1472}
1473
1474DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 2, 0,
1475 "Make BUFFER appear in some window but don't select it.\n\
1476BUFFER can be a buffer or a buffer name.\n\
1477If BUFFER is shown already in some window, just use that one,\n\
1478unless the window is the selected window and the optional second\n\
1479argument NOT_THIS_WINDOW is non-nil.\n\
1480Returns the window displaying BUFFER.")
1481 (buffer, not_this_window)
1482 register Lisp_Object buffer, not_this_window;
1483{
1484 register Lisp_Object window;
1485
1486 buffer = Fget_buffer (buffer);
1487 CHECK_BUFFER (buffer, 0);
1488
265a9e55 1489 if (!NILP (Vdisplay_buffer_function))
7ab12479
JB
1490 return call2 (Vdisplay_buffer_function, buffer, not_this_window);
1491
265a9e55 1492 if (NILP (not_this_window)
7ab12479
JB
1493 && XBUFFER (XWINDOW (selected_window)->buffer) == XBUFFER (buffer))
1494 return selected_window;
1495
1496 window = Fget_buffer_window (buffer, Qnil);
265a9e55
JB
1497 if (!NILP (window)
1498 && (NILP (not_this_window) || !EQ (window, selected_window)))
7ab12479
JB
1499 return window;
1500
1501#ifdef MULTI_SCREEN
43bad991
JB
1502 /* If there are no screens open that have more than a minibuffer,
1503 we need to create a new screen. */
1504 if (pop_up_screens || last_nonminibuf_screen == 0)
7ab12479
JB
1505 {
1506 window
43bad991 1507 = Fscreen_selected_window (call0 (Vpop_up_screen_function));
7ab12479
JB
1508 Fset_window_buffer (window, buffer);
1509#if 0
43bad991 1510 Fselect_screen (XWINDOW (window)->screen, Qnil);
7ab12479
JB
1511#endif
1512 return window;
1513 }
1514#endif /* MULTI_SCREEN */
1515
43bad991
JB
1516 if (pop_up_windows
1517#ifdef MULTI_SCREEN
d5783c40 1518 || SCREEN_MINIBUF_ONLY_P (selected_screen)
43bad991
JB
1519#endif
1520 )
7ab12479 1521 {
43bad991
JB
1522 Lisp_Object screens = Qnil;
1523
7ab12479 1524#ifdef MULTI_SCREEN
d5783c40 1525 if (SCREEN_MINIBUF_ONLY_P (selected_screen))
43bad991 1526 XSET (screens, Lisp_Screen, last_nonminibuf_screen);
7ab12479
JB
1527#endif
1528 /* Don't try to create a window if would get an error */
1529 if (split_height_threshold < window_min_height << 1)
1530 split_height_threshold = window_min_height << 1;
1531
1532 window = Fget_largest_window (screens);
1533
265a9e55 1534 if (!NILP (window)
7ab12479
JB
1535 && window_height (window) >= split_height_threshold
1536 &&
1537 (XFASTINT (XWINDOW (window)->width)
1538 == SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (XWINDOW (window))))))
1539 window = Fsplit_window (window, Qnil, Qnil);
1540 else
1541 {
1542 window = Fget_lru_window (screens);
1543 if ((EQ (window, selected_window)
1544 || EQ (XWINDOW (window)->parent, Qnil))
1545 && window_height (window) >= window_min_height << 1)
1546 window = Fsplit_window (window, Qnil, Qnil);
1547 }
1548 }
1549 else
1550 window = Fget_lru_window (Qnil);
1551
1552 Fset_window_buffer (window, buffer);
1553 return window;
1554}
1555
1556void
1557temp_output_buffer_show (buf)
1558 register Lisp_Object buf;
1559{
1560 register struct buffer *old = current_buffer;
1561 register Lisp_Object window;
1562 register struct window *w;
1563
1564 Fset_buffer (buf);
1565 XBUFFER (buf)->save_modified = MODIFF;
1566 BEGV = BEG;
1567 ZV = Z;
1568 SET_PT (BEG);
1569 clip_changed = 1;
1570 set_buffer_internal (old);
1571
1572 if (!EQ (Vtemp_buffer_show_function, Qnil))
1573 call1 (Vtemp_buffer_show_function, buf);
1574 else
1575 {
1576 window = Fdisplay_buffer (buf, Qnil);
1577
1578#ifdef MULTI_SCREEN
1579 if (XSCREEN (XWINDOW (window)->screen) != selected_screen)
1580 Fmake_screen_visible (XWINDOW (window)->screen);
1581#endif /* MULTI_SCREEN */
1582 Vminibuf_scroll_window = window;
1583 w = XWINDOW (window);
1584 XFASTINT (w->hscroll) = 0;
1585 set_marker_restricted (w->start, make_number (1), buf);
1586 set_marker_restricted (w->pointm, make_number (1), buf);
1587 }
1588}
1589\f
1590static
1591make_dummy_parent (window)
1592 Lisp_Object window;
1593{
1594 register Lisp_Object old, new;
1595 register struct window *o, *p;
1596
1597 old = window;
1598 XSETTYPE (old, Lisp_Vector);
1599 new = Fcopy_sequence (old);
1600 XSETTYPE (new, Lisp_Window);
1601
1602 o = XWINDOW (old);
1603 p = XWINDOW (new);
1604 XFASTINT (p->sequence_number) = ++sequence_number;
1605
1606 /* Put new into window structure in place of window */
1607 replace_window (window, new);
1608
1609 o->next = Qnil;
1610 o->prev = Qnil;
1611 o->vchild = Qnil;
1612 o->hchild = Qnil;
1613 o->parent = new;
1614
1615 p->start = Qnil;
1616 p->pointm = Qnil;
1617 p->buffer = Qnil;
1618}
1619
1620DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
1621 "Split WINDOW, putting SIZE lines in the first of the pair.\n\
1622WINDOW defaults to selected one and SIZE to half its size.\n\
1623If optional third arg HOR-FLAG is non-nil, split side by side\n\
1624and put SIZE columns in the first of the pair.")
1625 (window, chsize, horflag)
1626 Lisp_Object window, chsize, horflag;
1627{
1628 register Lisp_Object new;
1629 register struct window *o, *p;
1630 register int size;
1631
265a9e55 1632 if (NILP (window))
7ab12479
JB
1633 window = selected_window;
1634 else
1635 CHECK_WINDOW (window, 0);
1636
1637 o = XWINDOW (window);
1638
265a9e55 1639 if (NILP (chsize))
7ab12479 1640 {
265a9e55 1641 if (!NILP (horflag))
7ab12479
JB
1642 /* Round odd size up, since this is for the left-hand window,
1643 and it will lose a column for the separators. */
1644 size = ((XFASTINT (o->width) + 1) & -2) >> 1;
1645 else
1646 size = XFASTINT (o->height) >> 1;
1647 }
1648 else
1649 {
1650 CHECK_NUMBER (chsize, 1);
1651 size = XINT (chsize);
1652 }
1653
1654 if (MINI_WINDOW_P (o))
1655 error ("Attempt to split minibuffer window");
1656 else if (SCREEN_NO_SPLIT_P (XSCREEN (WINDOW_SCREEN (o))))
1657 error ("Attempt to split unsplittable screen");
1658
1659 /* Smaller values might permit a crash. */
1660 if (window_min_width < 2)
1661 window_min_width = 2;
1662 if (window_min_height < 2)
1663 window_min_height = 2;
1664
265a9e55 1665 if (NILP (horflag))
7ab12479
JB
1666 {
1667 if (size < window_min_height
1668 || size + window_min_height > XFASTINT (o->height))
1669 args_out_of_range_3 (window, chsize, horflag);
265a9e55
JB
1670 if (NILP (o->parent)
1671 || NILP (XWINDOW (o->parent)->vchild))
7ab12479
JB
1672 {
1673 make_dummy_parent (window);
1674 new = o->parent;
1675 XWINDOW (new)->vchild = window;
1676 }
1677 }
1678 else
1679 {
1680 if (size < window_min_width
1681 || size + window_min_width > XFASTINT (o->width))
1682 args_out_of_range_3 (window, chsize, horflag);
265a9e55
JB
1683 if (NILP (o->parent)
1684 || NILP (XWINDOW (o->parent)->hchild))
7ab12479
JB
1685 {
1686 make_dummy_parent (window);
1687 new = o->parent;
1688 XWINDOW (new)->hchild = window;
1689 }
1690 }
1691
1692 /* Now we know that window's parent is a vertical combination
1693 if we are dividing vertically, or a horizontal combination
1694 if we are making side-by-side windows */
1695
1696 windows_or_buffers_changed++;
1697 new = make_window ();
1698 p = XWINDOW (new);
1699
1700 p->screen = o->screen;
1701 p->next = o->next;
265a9e55 1702 if (!NILP (p->next))
7ab12479
JB
1703 XWINDOW (p->next)->prev = new;
1704 p->prev = window;
1705 o->next = new;
1706 p->parent = o->parent;
1707 p->buffer = Qt;
1708
1709 Fset_window_buffer (new, o->buffer);
1710
1711 /* Apportion the available screen space among the two new windows */
1712
265a9e55 1713 if (!NILP (horflag))
7ab12479
JB
1714 {
1715 p->height = o->height;
1716 p->top = o->top;
1717 XFASTINT (p->width) = XFASTINT (o->width) - size;
1718 XFASTINT (o->width) = size;
1719 XFASTINT (p->left) = XFASTINT (o->left) + size;
1720 }
1721 else
1722 {
1723 p->left = o->left;
1724 p->width = o->width;
1725 XFASTINT (p->height) = XFASTINT (o->height) - size;
1726 XFASTINT (o->height) = size;
1727 XFASTINT (p->top) = XFASTINT (o->top) + size;
1728 }
1729
1730 return new;
1731}
1732\f
1733DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
1734 "Make current window ARG lines bigger.\n\
1735From program, optional second arg non-nil means grow sideways ARG columns.")
1736 (n, side)
1737 register Lisp_Object n, side;
1738{
1739 CHECK_NUMBER (n, 0);
265a9e55 1740 change_window_height (XINT (n), !NILP (side));
7ab12479
JB
1741 return Qnil;
1742}
1743
1744DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
1745 "Make current window ARG lines smaller.\n\
1746From program, optional second arg non-nil means shrink sideways ARG columns.")
1747 (n, side)
1748 register Lisp_Object n, side;
1749{
1750 CHECK_NUMBER (n, 0);
265a9e55 1751 change_window_height (-XINT (n), !NILP (side));
7ab12479
JB
1752 return Qnil;
1753}
1754
1755int
1756window_height (window)
1757 Lisp_Object window;
1758{
1759 register struct window *p = XWINDOW (window);
1760 return XFASTINT (p->height);
1761}
1762
1763int
1764window_width (window)
1765 Lisp_Object window;
1766{
1767 register struct window *p = XWINDOW (window);
1768 return XFASTINT (p->width);
1769}
1770
1771#define MINSIZE(w) \
1772 (widthflag ? window_min_width : window_min_height)
1773
1774#define CURBEG(w) \
1775 *(widthflag ? (int *) &(w)->left : (int *) &(w)->top)
1776
1777#define CURSIZE(w) \
1778 *(widthflag ? (int *) &(w)->width : (int *) &(w)->height)
1779
1780/* Unlike set_window_height, this function
1781 also changes the heights of the siblings so as to
1782 keep everything consistent. */
1783
1784change_window_height (delta, widthflag)
1785 register int delta;
1786 int widthflag;
1787{
1788 register Lisp_Object parent;
1789 Lisp_Object window;
1790 register struct window *p;
1791 int *sizep;
1792 int (*sizefun) () = widthflag ? window_width : window_height;
1793 register int (*setsizefun) () = (widthflag
1794 ? set_window_width
1795 : set_window_height);
1796
1797 /* Smaller values might permit a crash. */
1798 if (window_min_width < 2)
1799 window_min_width = 2;
1800 if (window_min_height < 2)
1801 window_min_height = 2;
1802
1803 window = selected_window;
1804 while (1)
1805 {
1806 p = XWINDOW (window);
1807 parent = p->parent;
265a9e55 1808 if (NILP (parent))
7ab12479
JB
1809 {
1810 if (widthflag)
1811 error ("No other window to side of this one");
1812 break;
1813 }
265a9e55
JB
1814 if (widthflag ? !NILP (XWINDOW (parent)->hchild)
1815 : !NILP (XWINDOW (parent)->vchild))
7ab12479
JB
1816 break;
1817 window = parent;
1818 }
1819
1820 sizep = &CURSIZE (p);
1821
1822 if (*sizep + delta < MINSIZE (p)
265a9e55 1823 && !NILP (XWINDOW (window)->parent))
7ab12479
JB
1824 {
1825 Fdelete_window (window);
1826 return;
1827 }
1828
1829 {
1830 register int maxdelta;
7ab12479 1831
265a9e55
JB
1832 maxdelta = (!NILP (parent) ? (*sizefun) (parent) - *sizep
1833 : !NILP (p->next) ? (*sizefun) (p->next) - MINSIZE (p->next)
1834 : !NILP (p->prev) ? (*sizefun) (p->prev) - MINSIZE (p->prev)
d5783c40
JB
1835 /* This is a screen with only one window, a minibuffer-only
1836 or a minibufferless screen. */
1837 : (delta = 0));
7ab12479
JB
1838
1839 if (delta > maxdelta)
1840 /* This case traps trying to make the minibuffer
1841 the full screen, or make the only window aside from the
1842 minibuffer the full screen. */
1843 delta = maxdelta;
d5783c40
JB
1844
1845 if (delta == 0)
1846 return;
7ab12479
JB
1847 }
1848
265a9e55 1849 if (!NILP (p->next) &&
7ab12479
JB
1850 (*sizefun) (p->next) - delta >= MINSIZE (p->next))
1851 {
1852 (*setsizefun) (p->next, (*sizefun) (p->next) - delta, 0);
1853 (*setsizefun) (window, *sizep + delta, 0);
1854 CURBEG (XWINDOW (p->next)) += delta;
1855 /* This does not change size of p->next,
1856 but it propagates the new top edge to its children */
1857 (*setsizefun) (p->next, (*sizefun) (p->next), 0);
1858 }
265a9e55 1859 else if (!NILP (p->prev) &&
7ab12479
JB
1860 (*sizefun) (p->prev) - delta >= MINSIZE (p->prev))
1861 {
1862 (*setsizefun) (p->prev, (*sizefun) (p->prev) - delta, 0);
1863 CURBEG (p) -= delta;
1864 (*setsizefun) (window, *sizep + delta, 0);
1865 }
1866 else
1867 {
1868 register int delta1;
1869 register int opht = (*sizefun) (parent);
1870
1871 /* If trying to grow this window to or beyond size of the parent,
1872 make delta1 so big that, on shrinking back down,
1873 all the siblings end up with less than one line and are deleted. */
1874 if (opht <= *sizep + delta)
1875 delta1 = opht * opht * 2;
1876 /* Otherwise, make delta1 just right so that if we add delta1
1877 lines to this window and to the parent, and then shrink
1878 the parent back to its original size, the new proportional
1879 size of this window will increase by delta. */
1880 else
1881 delta1 = (delta * opht * 100) / ((opht - *sizep - delta) * 100);
1882
1883 /* Add delta1 lines or columns to this window, and to the parent,
1884 keeping things consistent while not affecting siblings. */
1885 CURSIZE (XWINDOW (parent)) = opht + delta1;
1886 (*setsizefun) (window, *sizep + delta1, 0);
1887
1888 /* Squeeze out delta1 lines or columns from our parent,
1889 shriking this window and siblings proportionately.
1890 This brings parent back to correct size.
1891 Delta1 was calculated so this makes this window the desired size,
1892 taking it all out of the siblings. */
1893 (*setsizefun) (parent, opht, 0);
1894 }
1895
1896 XFASTINT (p->last_modified) = 0;
1897}
1898#undef MINSIZE
1899#undef CURBEG
1900#undef CURSIZE
1901
1902\f
1903/* Return number of lines of text (not counting mode line) in W. */
1904
1905int
1906window_internal_height (w)
1907 struct window *w;
1908{
1909 int ht = XFASTINT (w->height);
1910
1911 if (MINI_WINDOW_P (w))
1912 return ht;
1913
265a9e55
JB
1914 if (!NILP (w->parent) || !NILP (w->vchild) || !NILP (w->hchild)
1915 || !NILP (w->next) || !NILP (w->prev)
7ab12479
JB
1916 || SCREEN_WANTS_MODELINE_P (XSCREEN (WINDOW_SCREEN (w))))
1917 return ht - 1;
1918
1919 return ht;
1920}
1921
1922/* Scroll contents of window WINDOW up N lines. */
1923
1924void
f8026fd8 1925window_scroll (window, n, noerror)
7ab12479
JB
1926 Lisp_Object window;
1927 int n;
f8026fd8 1928 int noerror;
7ab12479
JB
1929{
1930 register struct window *w = XWINDOW (window);
1931 register int opoint = point;
1932 register int pos;
1933 register int ht = window_internal_height (w);
1934 register Lisp_Object tem;
1935 int lose;
1936 Lisp_Object bolp, nmoved;
1937
1938 XFASTINT (tem) = point;
1939 tem = Fpos_visible_in_window_p (tem, window);
1940
265a9e55 1941 if (NILP (tem))
7ab12479
JB
1942 {
1943 Fvertical_motion (make_number (- ht / 2));
1944 XFASTINT (tem) = point;
1945 Fset_marker (w->start, tem, w->buffer);
1946 w->force_start = Qt;
1947 }
1948
1949 SET_PT (marker_position (w->start));
1950 lose = n < 0 && point == BEGV;
1951 Fvertical_motion (make_number (n));
1952 pos = point;
1953 bolp = Fbolp ();
1954 SET_PT (opoint);
1955
1956 if (lose)
f8026fd8
JB
1957 {
1958 if (noerror)
1959 return;
1960 else
1961 Fsignal (Qbeginning_of_buffer, Qnil);
1962 }
7ab12479
JB
1963
1964 if (pos < ZV)
7ab12479
JB
1965 {
1966 set_marker_restricted (w->start, make_number (pos), w->buffer);
1967 w->start_at_line_beg = bolp;
1968 w->update_mode_line = Qt;
1969 XFASTINT (w->last_modified) = 0;
1970 if (pos > opoint)
1971 SET_PT (pos);
1972 if (n < 0)
1973 {
1974 SET_PT (pos);
1975 tem = Fvertical_motion (make_number (ht));
1976 if (point > opoint || XFASTINT (tem) < ht)
1977 SET_PT (opoint);
1978 else
1979 Fvertical_motion (make_number (-1));
1980 }
1981 }
1982 else
f8026fd8
JB
1983 {
1984 if (noerror)
1985 return;
1986 else
1987 Fsignal (Qend_of_buffer, Qnil);
1988 }
7ab12479
JB
1989}
1990\f
1991/* This is the guts of Fscroll_up and Fscroll_down. */
1992
1993static void
1994scroll_command (n, direction)
1995 register Lisp_Object n;
1996 int direction;
1997{
1998 register int defalt;
1999 int count = specpdl_ptr - specpdl;
2000
95605e15
JB
2001 /* If selected window's buffer isn't current, make it current for the moment.
2002 But don't screw up if window_scroll gets an error. */
7ab12479 2003 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
95605e15
JB
2004 {
2005 record_unwind_protect (save_excursion_restore, save_excursion_save ());
2006 Fset_buffer (XWINDOW (selected_window)->buffer);
2007 }
7ab12479
JB
2008
2009 defalt = (window_internal_height (XWINDOW (selected_window))
2010 - next_screen_context_lines);
2011 defalt = direction * (defalt < 1 ? 1 : defalt);
2012
265a9e55 2013 if (NILP (n))
f8026fd8 2014 window_scroll (selected_window, defalt, 0);
7ab12479 2015 else if (EQ (n, Qminus))
f8026fd8 2016 window_scroll (selected_window, - defalt, 0);
7ab12479
JB
2017 else
2018 {
2019 n = Fprefix_numeric_value (n);
f8026fd8 2020 window_scroll (selected_window, XINT (n) * direction, 0);
7ab12479 2021 }
95605e15
JB
2022
2023 unbind_to (count, Qnil);
7ab12479
JB
2024}
2025
2026DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
2027 "Scroll text of current window upward ARG lines; or near full screen if no ARG.\n\
2028A near full screen is `next-screen-context-lines' less than a full screen.\n\
2029When calling from a program, supply a number as argument or nil.")
2030 (n)
2031 Lisp_Object n;
2032{
2033 scroll_command (n, 1);
2034 return Qnil;
2035}
2036
2037DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
2038 "Scroll text of current window downward ARG lines; or near full screen if no ARG.\n\
2039A near full screen is `next-screen-context-lines' less than a full screen.\n\
2040When calling from a program, supply a number as argument or nil.")
2041 (n)
2042 Lisp_Object n;
2043{
2044 scroll_command (n, -1);
2045 return Qnil;
2046}
2047
2048DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
2049 "Scroll text of next window upward ARG lines; or near full screen if no ARG.\n\
2050The next window is the one below the current one; or the one at the top\n\
2051if the current one is at the bottom.\n\
2052When calling from a program, supply a number as argument or nil.\n\
2053\n\
2054If in the minibuffer, `minibuf-scroll-window' if non-nil\n\
2055specifies the window to scroll.\n\
2056If `other-window-scroll-buffer' is non-nil, scroll the window\n\
2057showing that buffer, popping the buffer up if necessary.")
2058 (n)
2059 register Lisp_Object n;
2060{
2061 register Lisp_Object window;
2062 register int ht;
2063 register struct window *w;
2064 register int count = specpdl_ptr - specpdl;
2065
2066 if (MINI_WINDOW_P (XWINDOW (selected_window))
265a9e55 2067 && !NILP (Vminibuf_scroll_window))
7ab12479
JB
2068 window = Vminibuf_scroll_window;
2069 /* If buffer is specified, scroll that buffer. */
265a9e55 2070 else if (!NILP (Vother_window_scroll_buffer))
7ab12479
JB
2071 {
2072 window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
265a9e55 2073 if (NILP (window))
7ab12479
JB
2074 window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt);
2075 }
2076 else
2077 /* Nothing specified; pick a neighboring window. */
2078 window = Fnext_window (selected_window, Qnil, Qt);
2079 CHECK_WINDOW (window, 0);
2080
2081 if (EQ (window, selected_window))
2082 error ("There is no other window");
2083
2084 w = XWINDOW (window);
2085 ht = window_internal_height (w);
2086
2087 /* Don't screw up if window_scroll gets an error. */
2088 record_unwind_protect (save_excursion_restore, save_excursion_save ());
2089
2090 Fset_buffer (w->buffer);
2091 SET_PT (marker_position (w->pointm));
2092
265a9e55 2093 if (NILP (n))
f8026fd8 2094 window_scroll (window, ht - next_screen_context_lines, 1);
7ab12479 2095 else if (EQ (n, Qminus))
f8026fd8 2096 window_scroll (window, next_screen_context_lines - ht, 1);
7ab12479
JB
2097 else
2098 {
2099 if (XTYPE (n) == Lisp_Cons)
2100 n = Fcar (n);
2101 CHECK_NUMBER (n, 0);
f8026fd8 2102 window_scroll (window, XINT (n), 1);
7ab12479
JB
2103 }
2104
2105 Fset_marker (w->pointm, make_number (point), Qnil);
2106 unbind_to (count);
2107
2108 return Qnil;
2109}
2110\f
2111DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 1, 1, "P",
2112 "Scroll selected window display ARG columns left.\n\
2113Default for ARG is window width minus 2.")
2114 (arg)
2115 register Lisp_Object arg;
2116{
2117
265a9e55 2118 if (NILP (arg))
7ab12479
JB
2119 XFASTINT (arg) = XFASTINT (XWINDOW (selected_window)->width) - 2;
2120 else
2121 arg = Fprefix_numeric_value (arg);
2122
2123 return
2124 Fset_window_hscroll (selected_window,
2125 make_number (XINT (XWINDOW (selected_window)->hscroll)
2126 + XINT (arg)));
2127}
2128
2129DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 1, 1, "P",
2130 "Scroll selected window display ARG columns right.\n\
2131Default for ARG is window width minus 2.")
2132 (arg)
2133 register Lisp_Object arg;
2134{
265a9e55 2135 if (NILP (arg))
7ab12479
JB
2136 XFASTINT (arg) = XFASTINT (XWINDOW (selected_window)->width) - 2;
2137 else
2138 arg = Fprefix_numeric_value (arg);
2139
2140 return
2141 Fset_window_hscroll (selected_window,
2142 make_number (XINT (XWINDOW (selected_window)->hscroll)
2143 - XINT (arg)));
2144}
2145
2146DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
2147 "Center point in window and redisplay screen. With ARG, put point on line ARG.\n\
2148The desired position of point is always relative to the current window.\n\
2149Just C-u as prefix means put point in the center of the screen.\n\
2150No arg (i.e., it is nil) erases the entire screen and then\n\
2151redraws with point in the center.")
2152 (n)
2153 register Lisp_Object n;
2154{
2155 register struct window *w = XWINDOW (selected_window);
2156 register int ht = window_internal_height (w);
2157 register int opoint = point;
2158
265a9e55 2159 if (NILP (n))
7ab12479
JB
2160 {
2161 extern int screen_garbaged;
2162
2163 SET_SCREEN_GARBAGED (XSCREEN (WINDOW_SCREEN (w)));
2164 XFASTINT (n) = ht / 2;
2165 }
2166 else if (XTYPE (n) == Lisp_Cons) /* Just C-u. */
2167 {
2168 XFASTINT (n) = ht / 2;
2169 }
2170 else
2171 {
2172 n = Fprefix_numeric_value (n);
2173 CHECK_NUMBER (n, 0);
2174 }
2175
2176 if (XINT (n) < 0)
2177 XSETINT (n, XINT (n) + ht);
2178
2179 XSETINT (n, - XINT (n));
2180
2181 Fvertical_motion (n);
2182 Fset_marker (w->start, make_number (point), w->buffer);
2183 w->start_at_line_beg = Fbolp ();
2184
2185 SET_PT (opoint);
2186 w->force_start = Qt;
2187
2188 return Qnil;
2189}
2190\f
2191DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
2192 1, 1, "P",
2193 "Position point relative to window.\n\
2194With no argument, position text at center of window.\n\
2195An argument specifies screen line; zero means top of window,\n\
2196negative means relative to bottom of window.")
2197 (arg)
2198 register Lisp_Object arg;
2199{
2200 register struct window *w = XWINDOW (selected_window);
2201 register int height = window_internal_height (w);
2202 register int start;
2203
265a9e55 2204 if (NILP (arg))
7ab12479
JB
2205 XFASTINT (arg) = height / 2;
2206 else
2207 {
2208 arg = Fprefix_numeric_value (arg);
2209 if (XINT (arg) < 0)
2210 XSETINT (arg, XINT (arg) + height);
2211 }
2212
2213 start = marker_position (w->start);
2214 if (start < BEGV || start > ZV)
2215 {
2216 Fvertical_motion (make_number (- height / 2));
2217 Fset_marker (w->start, make_number (point), w->buffer);
2218 w->start_at_line_beg = Fbolp ();
2219 w->force_start = Qt;
2220 }
2221 else
2222 SET_PT (start);
2223
2224 return Fvertical_motion (arg);
2225}
2226\f
2227struct save_window_data
2228 {
2229 int size_from_Lisp_Vector_struct;
2230 struct Lisp_Vector *next_from_Lisp_Vector_struct;
2231 Lisp_Object screen_width, screen_height;
2232 Lisp_Object current_window;
2233 Lisp_Object current_buffer;
2234 Lisp_Object minibuf_scroll_window;
2235 Lisp_Object root_window;
2236 /* A vector, interpreted as a struct saved_window */
2237 Lisp_Object saved_windows;
2238 };
2239#define SAVE_WINDOW_DATA_SIZE 7 /* Arg to Fmake_vector */
2240
2241/* This is saved as a Lisp_Vector */
2242struct saved_window
2243 {
2244 /* these first two must agree with struct Lisp_Vector in lisp.h */
2245 int size_from_Lisp_Vector_struct;
2246 struct Lisp_Vector *next_from_Lisp_Vector_struct;
2247
2248 Lisp_Object window;
2249 Lisp_Object buffer, start, pointm, mark;
2250 Lisp_Object left, top, width, height, hscroll;
2251 Lisp_Object parent, prev;
2252 Lisp_Object start_at_line_beg;
2253 Lisp_Object display_table;
2254 };
2255#define SAVED_WINDOW_VECTOR_SIZE 14 /* Arg to Fmake_vector */
2256
2257#define SAVED_WINDOW_N(swv,n) \
2258 ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
2259
2260DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
2261 "T if OBJECT is a window-configration object.")
2262 (obj)
2263 Lisp_Object obj;
2264{
2265 if (XTYPE (obj) == Lisp_Window_Configuration)
2266 return Qt;
2267 return Qnil;
2268}
2269
2270
2271DEFUN ("set-window-configuration",
2272 Fset_window_configuration, Sset_window_configuration,
2273 1, 1, 0,
2274 "Set the configuration of windows and buffers as specified by CONFIGURATION.\n\
2275CONFIGURATION must be a value previously returned\n\
2276by `current-window-configuration' (which see).")
2277 (arg)
2278 Lisp_Object arg;
2279{
2280 register struct window *w;
2281 register struct save_window_data *data;
2282 struct Lisp_Vector *saved_windows;
2283 register struct saved_window *p;
2284 register Lisp_Object tem;
2285 Lisp_Object new_current_buffer;
2286 int k;
43bad991 2287 SCREEN_PTR s;
7ab12479
JB
2288
2289 while (XTYPE (arg) != Lisp_Window_Configuration)
2290 {
2291 arg = wrong_type_argument (intern ("window-configuration-p"), arg);
2292 }
2293
2294 data = (struct save_window_data *) XVECTOR (arg);
2295 saved_windows = XVECTOR (data->saved_windows);
2296
2297 s = XSCREEN (XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->screen);
2298
2299 if (XFASTINT (data->screen_height) != SCREEN_HEIGHT (s)
2300 || XFASTINT (data->screen_width) != SCREEN_WIDTH (s))
2301 {
2302 /* Presumably something clever could be done.
2303 However, it doesn't seem worth the effort */
2304 error ("Screen size %dx%d in saved window configuration mismatches screen.",
2305 XFASTINT (data->screen_height),
2306 XFASTINT (data->screen_width));
2307 }
2308
2309 windows_or_buffers_changed++;
2310 new_current_buffer = data->current_buffer;
265a9e55 2311 if (NILP (XBUFFER (new_current_buffer)->name))
7ab12479
JB
2312 new_current_buffer = Qnil;
2313
2314 /* Mark all windows now on screen as "deleted".
2315 Restoring the new configuration "undeletes" any that are in it. */
2316
43bad991 2317 delete_all_subwindows (XWINDOW (SCREEN_ROOT_WINDOW (s)));
7ab12479
JB
2318#if 0
2319 /* This loses when the minibuf screen is not s. */
2320 delete_all_subwindows (XWINDOW (XWINDOW (minibuf_window)->prev));
2321#endif
2322
2323 for (k = 0; k < saved_windows->size; k++)
2324 {
2325 p = SAVED_WINDOW_N (saved_windows, k);
2326 w = XWINDOW (p->window);
2327 w->next = Qnil;
2328
265a9e55 2329 if (!NILP (p->parent))
7ab12479
JB
2330 w->parent = SAVED_WINDOW_N (saved_windows, XFASTINT (p->parent))->window;
2331 else
2332 w->parent = Qnil;
2333
265a9e55 2334 if (!NILP (p->prev))
7ab12479
JB
2335 {
2336 w->prev = SAVED_WINDOW_N (saved_windows, XFASTINT (p->prev))->window;
2337#ifdef MULTI_SCREEN
2338 /* This is true for a minibuffer-only screen. */
2339 if (w->mini_p && EQ (w->prev, p->window))
2340 w->next = Qnil;
2341 else
2342#endif /* MULTI_SCREEN */
2343 XWINDOW (w->prev)->next = p->window;
2344 }
2345 else
2346 {
2347 w->prev = Qnil;
265a9e55 2348 if (!NILP (w->parent))
7ab12479
JB
2349 {
2350 if (EQ (p->width, XWINDOW (w->parent)->width))
2351 {
2352 XWINDOW (w->parent)->vchild = p->window;
2353 XWINDOW (w->parent)->hchild = Qnil;
2354 }
2355 else
2356 {
2357 XWINDOW (w->parent)->hchild = p->window;
2358 XWINDOW (w->parent)->vchild = Qnil;
2359 }
2360 }
2361 }
2362 w->left = p->left;
2363 w->top = p->top;
2364 w->width = p->width;
2365 w->height = p->height;
2366 w->hscroll = p->hscroll;
2367 w->display_table = p->display_table;
2368 XFASTINT (w->last_modified) = 0;
2369
2370 /* Reinstall the saved buffer and pointers into it. */
265a9e55 2371 if (NILP (p->buffer))
7ab12479
JB
2372 w->buffer = p->buffer;
2373 else
2374 {
265a9e55 2375 if (!NILP (XBUFFER (p->buffer)->name))
7ab12479
JB
2376 /* If saved buffer is alive, install it. */
2377 {
2378 w->buffer = p->buffer;
2379 w->start_at_line_beg = p->start_at_line_beg;
2380 set_marker_restricted (w->start, Fmarker_position (p->start), w->buffer);
2381 set_marker_restricted (w->pointm, Fmarker_position (p->pointm), w->buffer);
2382 Fset_marker (XBUFFER (w->buffer)->mark,
2383 Fmarker_position (p->mark), w->buffer);
2384
2385 if (!EQ (p->buffer, new_current_buffer) &&
2386 XBUFFER (p->buffer) == current_buffer)
2387 Fgoto_char (w->pointm);
2388 }
265a9e55 2389 else if (NILP (XBUFFER (w->buffer)->name))
7ab12479
JB
2390 /* Else if window's old buffer is dead too, get a live one. */
2391 {
2392 w->buffer = Fcdr (Fcar (Vbuffer_alist));
2393 /* This will set the markers to beginning of visible range. */
2394 set_marker_restricted (w->start, make_number (0), w->buffer);
2395 set_marker_restricted (w->pointm, make_number (0), w->buffer);
2396 w->start_at_line_beg = Qt;
2397 }
2398 else
2399 /* Keeping window's old buffer; make sure the markers are real. */
2400 /* Else if window's old buffer is dead too, get a live one. */
2401 {
2402 /* Set window markers at start of visible range. */
2403 if (XMARKER (w->start)->buffer == 0)
2404 set_marker_restricted (w->start, make_number (0), w->buffer);
2405 if (XMARKER (w->pointm)->buffer == 0)
2406 set_marker_restricted (w->pointm,
2407 make_number (BUF_PT (XBUFFER (w->buffer))),
2408 w->buffer);
2409 w->start_at_line_beg = Qt;
2410 }
2411 }
2412 }
2413
2414 SCREEN_ROOT_WINDOW (s) = data->root_window;
2415
2416#ifdef MULTI_SCREEN
2417 if (s != selected_screen && ! SCREEN_IS_TERMCAP (s))
2418 Fselect_screen (WINDOW_SCREEN (XWINDOW (data->root_window)), Qnil);
2419#endif
2420
2421 if (s == selected_screen)
2422 {
2423 Fselect_window (data->current_window);
265a9e55 2424 if (!NILP (new_current_buffer))
7ab12479
JB
2425 Fset_buffer (new_current_buffer);
2426 else
2427 Fset_buffer (XWINDOW (selected_window)->buffer);
2428 }
2429
2430 Vminibuf_scroll_window = data->minibuf_scroll_window;
2431 return (Qnil);
2432}
2433
2434/* Mark all windows now on screen as deleted
2435 by setting their buffers to nil. */
2436
2437static void
2438delete_all_subwindows (w)
2439 register struct window *w;
2440{
2441 register int count = 1;
2442 w->buffer = Qnil;
265a9e55 2443 if (!NILP (w->next))
7ab12479 2444 delete_all_subwindows (XWINDOW (w->next));
265a9e55 2445 if (!NILP (w->vchild))
7ab12479 2446 delete_all_subwindows (XWINDOW (w->vchild));
265a9e55 2447 if (!NILP (w->hchild))
7ab12479
JB
2448 delete_all_subwindows (XWINDOW (w->hchild));
2449}
2450\f
2451static int
2452count_windows (window)
2453 register struct window *window;
2454{
2455 register int count = 1;
265a9e55 2456 if (!NILP (window->next))
7ab12479 2457 count += count_windows (XWINDOW (window->next));
265a9e55 2458 if (!NILP (window->vchild))
7ab12479 2459 count += count_windows (XWINDOW (window->vchild));
265a9e55 2460 if (!NILP (window->hchild))
7ab12479
JB
2461 count += count_windows (XWINDOW (window->hchild));
2462 return count;
2463}
2464
2465static int
2466save_window_save (window, vector, i)
2467 Lisp_Object window;
2468 struct Lisp_Vector *vector;
2469 int i;
2470{
2471 register struct saved_window *p;
2472 register struct window *w;
2473 register Lisp_Object tem;
2474
265a9e55 2475 for (;!NILP (window); window = w->next)
7ab12479
JB
2476 {
2477 p = SAVED_WINDOW_N (vector, i);
2478 w = XWINDOW (window);
2479
2480 XFASTINT (w->temslot) = i++;
2481 p->window = window;
2482 p->buffer = w->buffer;
2483 p->left = w->left;
2484 p->top = w->top;
2485 p->width = w->width;
2486 p->height = w->height;
2487 p->hscroll = w->hscroll;
2488 p->display_table = w->display_table;
265a9e55 2489 if (!NILP (w->buffer))
7ab12479
JB
2490 {
2491 /* Save w's value of point in the window configuration.
2492 If w is the selected window, then get the value of point
2493 from the buffer; pointm is garbage in the selected window. */
2494 if (EQ (window, selected_window))
2495 {
2496 p->pointm = Fmake_marker ();
2497 Fset_marker (p->pointm, BUF_PT (XBUFFER (w->buffer)),
2498 w->buffer);
2499 }
2500 else
2501 p->pointm = Fcopy_marker (w->pointm);
2502
2503 p->start = Fcopy_marker (w->start);
2504 p->start_at_line_beg = w->start_at_line_beg;
2505
2506 tem = XBUFFER (w->buffer)->mark;
2507 p->mark = Fcopy_marker (tem);
2508 }
2509 else
2510 {
2511 p->pointm = Qnil;
2512 p->start = Qnil;
2513 p->mark = Qnil;
2514 p->start_at_line_beg = Qnil;
2515 }
2516
265a9e55 2517 if (NILP (w->parent))
7ab12479
JB
2518 p->parent = Qnil;
2519 else
2520 p->parent = XWINDOW (w->parent)->temslot;
2521
265a9e55 2522 if (NILP (w->prev))
7ab12479
JB
2523 p->prev = Qnil;
2524 else
2525 p->prev = XWINDOW (w->prev)->temslot;
2526
265a9e55 2527 if (!NILP (w->vchild))
7ab12479 2528 i = save_window_save (w->vchild, vector, i);
265a9e55 2529 if (!NILP (w->hchild))
7ab12479
JB
2530 i = save_window_save (w->hchild, vector, i);
2531 }
2532
2533 return i;
2534}
2535
2536DEFUN ("current-window-configuration",
43bad991
JB
2537 Fcurrent_window_configuration, Scurrent_window_configuration, 0, 1, 0,
2538 "Return an object representing the current window configuration of SCREEN.\n\
2539If SCREEN is nil or omitted, use the selected screen.\n\
7ab12479
JB
2540This describes the number of windows, their sizes and current buffers,\n\
2541and for each displayed buffer, where display starts, and the positions of\n\
2542point and mark. An exception is made for point in the current buffer:\n\
2543its value is -not- saved.")
43bad991
JB
2544 (screen)
2545 Lisp_Object screen;
7ab12479
JB
2546{
2547 register Lisp_Object tem;
2548 register int n_windows;
2549 register struct save_window_data *data;
2550 register int i;
43bad991
JB
2551 SCREEN_PTR s;
2552
265a9e55 2553 if (NILP (screen))
43bad991
JB
2554 s = selected_screen;
2555 else
2556 {
d5783c40 2557 CHECK_LIVE_SCREEN (screen, 0);
43bad991
JB
2558 s = XSCREEN (screen);
2559 }
7ab12479 2560
43bad991 2561 n_windows = count_windows (XWINDOW (SCREEN_ROOT_WINDOW (s)));
7ab12479
JB
2562 data = (struct save_window_data *)
2563 XVECTOR (Fmake_vector (make_number (SAVE_WINDOW_DATA_SIZE),
2564 Qnil));
43bad991
JB
2565 XFASTINT (data->screen_width) = SCREEN_WIDTH (s);
2566 XFASTINT (data->screen_height) = SCREEN_HEIGHT (s);
2567 data->current_window = SCREEN_SELECTED_WINDOW (s);
7ab12479
JB
2568 XSET (data->current_buffer, Lisp_Buffer, current_buffer);
2569 data->minibuf_scroll_window = Vminibuf_scroll_window;
43bad991 2570 data->root_window = SCREEN_ROOT_WINDOW (s);
7ab12479
JB
2571 tem = Fmake_vector (make_number (n_windows), Qnil);
2572 data->saved_windows = tem;
2573 for (i = 0; i < n_windows; i++)
2574 XVECTOR (tem)->contents[i]
2575 = Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil);
43bad991 2576 save_window_save (SCREEN_ROOT_WINDOW (s),
7ab12479
JB
2577 XVECTOR (tem), 0);
2578 XSET (tem, Lisp_Window_Configuration, data);
2579 return (tem);
2580}
2581
2582DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
2583 0, UNEVALLED, 0,
2584 "Execute body, preserving window sizes and contents.\n\
2585Restores which buffer appears in which window, where display starts,\n\
2586as well as the current buffer.\n\
2587Does not restore the value of point in current buffer.")
2588 (args)
2589 Lisp_Object args;
2590{
2591 register Lisp_Object val;
2592 register int count = specpdl_ptr - specpdl;
2593
2594 record_unwind_protect (Fset_window_configuration,
43bad991 2595 Fcurrent_window_configuration (Qnil));
7ab12479
JB
2596 val = Fprogn (args);
2597 return unbind_to (count, val);
2598}
2599\f
2600init_window_once ()
2601{
2602#ifdef MULTI_SCREEN
2603 selected_screen = make_terminal_screen ();
2604 minibuf_window = selected_screen->minibuffer_window;
2605 selected_window = selected_screen->selected_window;
d5783c40 2606 last_nonminibuf_screen = selected_screen;
7ab12479
JB
2607#else /* not MULTI_SCREEN */
2608 extern Lisp_Object get_minibuffer ();
2609
e5d77022 2610 SCREEN_ROOT_WINDOW (selected_screen) = make_window ();
95605e15 2611 minibuf_window = make_window ();
7ab12479 2612
e5d77022
JB
2613 XWINDOW (SCREEN_ROOT_WINDOW (selected_screen))->next = minibuf_window;
2614 XWINDOW (minibuf_window)->prev = SCREEN_ROOT_WINDOW (selected_screen);
7ab12479
JB
2615
2616 /* These values 9 and 10 are arbitrary,
2617 just so that there is "something there."
2618 Correct values are put in in init_xdisp */
2619
e5d77022 2620 XFASTINT (XWINDOW (SCREEN_ROOT_WINDOW (selected_screen))->width) = 10;
7ab12479
JB
2621 XFASTINT (XWINDOW (minibuf_window)->width) = 10;
2622
e5d77022 2623 XFASTINT (XWINDOW (SCREEN_ROOT_WINDOW (selected_screen))->height) = 9;
7ab12479
JB
2624 XFASTINT (XWINDOW (minibuf_window)->top) = 9;
2625 XFASTINT (XWINDOW (minibuf_window)->height) = 1;
2626
2627 /* Prevent error in Fset_window_buffer. */
e5d77022 2628 XWINDOW (SCREEN_ROOT_WINDOW (selected_screen))->buffer = Qt;
7ab12479
JB
2629 XWINDOW (minibuf_window)->buffer = Qt;
2630
2631 /* Now set them up for real. */
e5d77022
JB
2632 Fset_window_buffer (SCREEN_ROOT_WINDOW (selected_screen),
2633 Fcurrent_buffer ());
7ab12479
JB
2634 Fset_window_buffer (minibuf_window, get_minibuffer (0));
2635
e5d77022 2636 selected_window = SCREEN_ROOT_WINDOW (selected_screen);
1d8d96fa
JB
2637 /* Make sure this window seems more recently used than
2638 a newly-created, never-selected window. Increment
2639 window_select_count so the first selection ever will get
2640 something newer than this. */
2641 XFASTINT (XWINDOW (selected_window)->use_time) = ++window_select_count;
7ab12479
JB
2642#endif /* not MULTI_SCREEN */
2643}
2644
2645syms_of_window ()
2646{
2647 Qwindowp = intern ("windowp");
2648 staticpro (&Qwindowp);
2649
2650 /* Make sure all windows get marked */
2651 staticpro (&minibuf_window);
2652
2653 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
2654 "Non-nil means call as function to display a help buffer.\n\
2655Used by `with-output-to-temp-buffer'.");
2656 Vtemp_buffer_show_function = Qnil;
2657
2658 DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
2659 "If non-nil, function to call to handle `display-buffer'.\n\
2660It will receive two args, the buffer and a flag which if non-nil means\n\
2661 that the currently selected window is not acceptable.\n\
2662Commands such as `switch-to-buffer-other-window' and `find-file-other-window'\n\
2663work using this function.");
2664 Vdisplay_buffer_function = Qnil;
2665
2666 DEFVAR_LISP ("mouse-window", &Vmouse_window,
2667 "Window that the last mouse click occurred on.");
2668 Vmouse_window = Qnil;
2669
2670 DEFVAR_LISP ("mouse-event", &Vmouse_event,
2671 "The last mouse-event object. A list of four elements:\n\
2672 ((X-POS Y-POS) WINDOW SCREEN-PART KEYSEQ).\n\
2673KEYSEQ is a string, the key sequence to be looked up in the mouse maps.\n\
2674WINDOW is the window that the click applies do.\n\
2675If SCREEN-PART is non-nil, the event was on a scrollbar;\n\
2676then Y-POS is really the total length of the scrollbar, while X-POS is\n\
2677the relative position of the scrollbar's value within that total length.\n\
2678SCREEN-PART is one of the following symbols:\n\
2679 `vertical-scrollbar', `vertical-slider',\n\
2680 `vertical-thumbup', `vertical-thumbdown',\n\
2681 `horizontal-scrollbar', `horizontal-slider',\n\
2682 `horizontal-thumbleft', `horizontal-thumbright'");
2683 Vmouse_event = Qnil;
2684
2685 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
2686 "Non-nil means it is the window that C-M-v in minibuffer should scroll.");
2687 Vminibuf_scroll_window = Qnil;
2688
2689 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
2690 "If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.");
2691 Vother_window_scroll_buffer = Qnil;
2692
2693#ifdef MULTI_SCREEN
43bad991 2694 DEFVAR_BOOL ("pop-up-screens", &pop_up_screens,
7ab12479 2695 "*Non-nil means `display-buffer' should make a separate X-window.");
43bad991 2696 pop_up_screens = 0;
7ab12479 2697
43bad991 2698 DEFVAR_LISP ("pop-up-screen-function", &Vpop_up_screen_function,
7ab12479
JB
2699 "*If non-nil, function to call to handle automatic new screen creation.\n\
2700It is called with no arguments and should return a newly created screen.\n\
7ab12479
JB
2701\n\
2702A typical value might be `(lambda () (x-create-screen auto-screen-parms))'\n\
2703where `auto-screen-parms' would hold the default screen parameters.");
43bad991 2704 Vpop_up_screen_function = Qnil;
7ab12479
JB
2705#endif
2706
2707 DEFVAR_BOOL ("pop-up-windows", &pop_up_windows,
2708 "*Non-nil means display-buffer should make new windows.");
2709 pop_up_windows = 1;
2710
2711 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
2712 "*Number of lines of continuity when scrolling by screenfuls.");
2713 next_screen_context_lines = 2;
2714
2715 DEFVAR_INT ("split-height-threshold", &split_height_threshold,
2716 "*display-buffer would prefer to split the largest window if this large.\n\
2717If there is only one window, it is split regardless of this value.");
2718 split_height_threshold = 500;
2719
2720 DEFVAR_INT ("window-min-height", &window_min_height,
2721 "*Delete any window less than this tall (including its mode line).");
2722 window_min_height = 4;
2723
2724 DEFVAR_INT ("window-min-width", &window_min_width,
2725 "*Delete any window less than this wide.");
2726 window_min_width = 10;
2727
2728 defsubr (&Sselected_window);
2729 defsubr (&Sminibuffer_window);
2730 defsubr (&Swindow_minibuffer_p);
2731 defsubr (&Swindowp);
2732 defsubr (&Spos_visible_in_window_p);
2733 defsubr (&Swindow_buffer);
2734 defsubr (&Swindow_height);
2735 defsubr (&Swindow_width);
2736 defsubr (&Swindow_hscroll);
2737 defsubr (&Sset_window_hscroll);
2738 defsubr (&Swindow_edges);
d5783c40
JB
2739 defsubr (&Scoordinates_in_window_p);
2740 defsubr (&Swindow_at);
7ab12479
JB
2741 defsubr (&Swindow_point);
2742 defsubr (&Swindow_start);
2743 defsubr (&Swindow_end);
2744 defsubr (&Sset_window_point);
2745 defsubr (&Sset_window_start);
2746 defsubr (&Swindow_dedicated_p);
d207b766 2747 defsubr (&Sset_window_dedicated_p);
7ab12479
JB
2748 defsubr (&Swindow_display_table);
2749 defsubr (&Sset_window_display_table);
2750 defsubr (&Snext_window);
2751 defsubr (&Sprevious_window);
2752 defsubr (&Sother_window);
2753 defsubr (&Sget_lru_window);
2754 defsubr (&Sget_largest_window);
2755 defsubr (&Sget_buffer_window);
2756 defsubr (&Sdelete_other_windows);
2757 defsubr (&Sdelete_windows_on);
2758 defsubr (&Sreplace_buffer_in_windows);
2759 defsubr (&Sdelete_window);
2760 defsubr (&Sset_window_buffer);
2761 defsubr (&Sselect_window);
2762 defsubr (&Sdisplay_buffer);
2763 defsubr (&Ssplit_window);
2764 defsubr (&Senlarge_window);
2765 defsubr (&Sshrink_window);
2766 defsubr (&Sscroll_up);
2767 defsubr (&Sscroll_down);
2768 defsubr (&Sscroll_left);
2769 defsubr (&Sscroll_right);
2770 defsubr (&Sscroll_other_window);
2771 defsubr (&Srecenter);
2772 defsubr (&Smove_to_window_line);
2773 defsubr (&Swindow_configuration_p);
2774 defsubr (&Sset_window_configuration);
2775 defsubr (&Scurrent_window_configuration);
2776 defsubr (&Ssave_window_excursion);
2777}
2778
2779keys_of_window ()
2780{
2781 initial_define_key (control_x_map, '1', "delete-other-windows");
2782 initial_define_key (control_x_map, '2', "split-window");
2783 initial_define_key (control_x_map, '0', "delete-window");
2784 initial_define_key (control_x_map, 'o', "other-window");
2785 initial_define_key (control_x_map, '^', "enlarge-window");
2786 initial_define_key (control_x_map, '<', "scroll-left");
2787 initial_define_key (control_x_map, '>', "scroll-right");
2788
2789 initial_define_key (global_map, Ctl ('V'), "scroll-up");
2790 initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
2791 initial_define_key (meta_map, 'v', "scroll-down");
2792
2793 initial_define_key (global_map, Ctl('L'), "recenter");
2794 initial_define_key (meta_map, 'r', "move-to-window-line");
2795}