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