Add 2012 to FSF copyright years for Emacs files (do not merge to trunk)
[bpt/emacs.git] / src / window.c
1 /* Window creation, deletion and examination for GNU Emacs.
2 Does not include redisplay.
3 Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1996, 1997, 1998, 2000,
4 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
5 Free Software Foundation, Inc.
6
7 This file is part of GNU Emacs.
8
9 GNU Emacs is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 GNU Emacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <setjmp.h>
25
26 #include "lisp.h"
27 #include "buffer.h"
28 #include "keyboard.h"
29 #include "keymap.h"
30 #include "frame.h"
31 #include "window.h"
32 #include "commands.h"
33 #include "indent.h"
34 #include "termchar.h"
35 #include "disptab.h"
36 #include "dispextern.h"
37 #include "blockinput.h"
38 #include "intervals.h"
39 #include "termhooks.h" /* For FRAME_TERMINAL. */
40
41 #ifdef HAVE_X_WINDOWS
42 #include "xterm.h"
43 #endif /* HAVE_X_WINDOWS */
44 #ifdef WINDOWSNT
45 #include "w32term.h"
46 #endif
47 #ifdef MSDOS
48 #include "msdos.h"
49 #endif
50 #ifdef HAVE_NS
51 #include "nsterm.h"
52 #endif
53
54
55 Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
56 Lisp_Object Qdisplay_buffer;
57 Lisp_Object Qscroll_up, Qscroll_down;
58 Lisp_Object Qwindow_size_fixed;
59
60 extern Lisp_Object Qleft_margin, Qright_margin;
61
62 static int displayed_window_lines P_ ((struct window *));
63 static struct window *decode_window P_ ((Lisp_Object));
64 static int count_windows P_ ((struct window *));
65 static int get_leaf_windows P_ ((struct window *, struct window **, int));
66 static void window_scroll P_ ((Lisp_Object, int, int, int));
67 static void window_scroll_pixel_based P_ ((Lisp_Object, int, int, int));
68 static void window_scroll_line_based P_ ((Lisp_Object, int, int, int));
69 static int window_min_size_1 P_ ((struct window *, int, int));
70 static int window_min_size_2 P_ ((struct window *, int, int));
71 static int window_min_size P_ ((struct window *, int, int, int, int *));
72 static void size_window P_ ((Lisp_Object, int, int, int, int, int));
73 static int freeze_window_start P_ ((struct window *, void *));
74 static int window_fixed_size_p P_ ((struct window *, int, int));
75 static void enlarge_window P_ ((Lisp_Object, int, int));
76 static Lisp_Object window_list P_ ((void));
77 static int add_window_to_list P_ ((struct window *, void *));
78 static int candidate_window_p P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
79 Lisp_Object));
80 static Lisp_Object next_window P_ ((Lisp_Object, Lisp_Object,
81 Lisp_Object, int));
82 static void decode_next_window_args P_ ((Lisp_Object *, Lisp_Object *,
83 Lisp_Object *));
84 static int foreach_window_1 P_ ((struct window *,
85 int (* fn) (struct window *, void *),
86 void *));
87 static Lisp_Object window_list_1 P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
88 static Lisp_Object select_window P_ ((Lisp_Object, Lisp_Object, int));
89
90 /* This is the window in which the terminal's cursor should
91 be left when nothing is being done with it. This must
92 always be a leaf window, and its buffer is selected by
93 the top level editing loop at the end of each command.
94
95 This value is always the same as
96 FRAME_SELECTED_WINDOW (selected_frame). */
97
98 Lisp_Object selected_window;
99
100 /* A list of all windows for use by next_window and Fwindow_list.
101 Functions creating or deleting windows should invalidate this cache
102 by setting it to nil. */
103
104 Lisp_Object Vwindow_list;
105
106 /* The mini-buffer window of the selected frame.
107 Note that you cannot test for mini-bufferness of an arbitrary window
108 by comparing against this; but you can test for mini-bufferness of
109 the selected window. */
110
111 Lisp_Object minibuf_window;
112
113 /* Non-nil means it is the window whose mode line should be
114 shown as the selected window when the minibuffer is selected. */
115
116 Lisp_Object minibuf_selected_window;
117
118 /* Non-nil means it is the window for C-M-v to scroll
119 when the mini-buffer is selected. */
120
121 Lisp_Object Vminibuf_scroll_window;
122
123 /* Non-nil means this is the buffer whose window C-M-v should scroll. */
124
125 Lisp_Object Vother_window_scroll_buffer;
126
127 /* Non-nil means it's function to call to display temp buffers. */
128
129 Lisp_Object Vtemp_buffer_show_function;
130
131 /* Non-zero means line and page scrolling on tall lines (with images)
132 does partial scrolling by modifying window-vscroll. */
133
134 int auto_window_vscroll_p;
135
136 /* Non-zero means to use mode-line-inactive face in all windows but the
137 selected-window and the minibuffer-scroll-window when the
138 minibuffer is active. */
139 int mode_line_in_non_selected_windows;
140
141 /* If a window gets smaller than either of these, it is removed. */
142
143 EMACS_INT window_min_height;
144 EMACS_INT window_min_width;
145
146 /* Hook run at end of temp_output_buffer_show. */
147
148 Lisp_Object Qtemp_buffer_show_hook;
149
150 /* Number of lines of continuity in scrolling by screenfuls. */
151
152 EMACS_INT next_screen_context_lines;
153
154 /* Incremented for each window created. */
155
156 static int sequence_number;
157
158 /* Nonzero after init_window_once has finished. */
159
160 static int window_initialized;
161
162 /* Hook to run when window config changes. */
163
164 static Lisp_Object Qwindow_configuration_change_hook;
165 static Lisp_Object Vwindow_configuration_change_hook;
166
167 /* Non-nil means scroll commands try to put point
168 at the same screen height as previously. */
169
170 Lisp_Object Vscroll_preserve_screen_position;
171
172 /* Non-nil means that text is inserted before window's markers. */
173
174 Lisp_Object Vwindow_point_insertion_type;
175
176 /* Incremented by 1 whenever a window is deleted. */
177
178 int window_deletion_count;
179
180 /* Used by the function window_scroll_pixel_based */
181
182 static int window_scroll_pixel_based_preserve_x;
183 static int window_scroll_pixel_based_preserve_y;
184
185 /* Same for window_scroll_line_based. */
186
187 static int window_scroll_preserve_hpos;
188 static int window_scroll_preserve_vpos;
189
190 extern EMACS_INT scroll_margin;
191
192 extern Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
193
194 /* If non-nil, then the `recenter' command with a nil argument
195 the entire frame to be redrawn; the special value `tty' causes the
196 frame to be redrawn only if it is a tty frame. */
197
198 static Lisp_Object Vrecenter_redisplay;
199 extern Lisp_Object Qtty;
200
201 \f
202 DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
203 doc: /* Return t if OBJECT is a window. */)
204 (object)
205 Lisp_Object object;
206 {
207 return WINDOWP (object) ? Qt : Qnil;
208 }
209
210 DEFUN ("window-live-p", Fwindow_live_p, Swindow_live_p, 1, 1, 0,
211 doc: /* Return t if OBJECT is a window which is currently visible. */)
212 (object)
213 Lisp_Object object;
214 {
215 return WINDOW_LIVE_P (object) ? Qt : Qnil;
216 }
217
218 Lisp_Object
219 make_window ()
220 {
221 Lisp_Object val;
222 register struct window *p;
223
224 p = allocate_window ();
225 ++sequence_number;
226 XSETFASTINT (p->sequence_number, sequence_number);
227 XSETFASTINT (p->left_col, 0);
228 XSETFASTINT (p->top_line, 0);
229 XSETFASTINT (p->total_lines, 0);
230 XSETFASTINT (p->total_cols, 0);
231 XSETFASTINT (p->hscroll, 0);
232 XSETFASTINT (p->min_hscroll, 0);
233 p->orig_top_line = p->orig_total_lines = Qnil;
234 p->start = Fmake_marker ();
235 p->pointm = Fmake_marker ();
236 XSETFASTINT (p->use_time, 0);
237 p->frame = Qnil;
238 p->display_table = Qnil;
239 p->dedicated = Qnil;
240 p->window_parameters = Qnil;
241 p->pseudo_window_p = 0;
242 bzero (&p->cursor, sizeof (p->cursor));
243 bzero (&p->last_cursor, sizeof (p->last_cursor));
244 bzero (&p->phys_cursor, sizeof (p->phys_cursor));
245 p->desired_matrix = p->current_matrix = 0;
246 p->nrows_scale_factor = p->ncols_scale_factor = 1;
247 p->phys_cursor_type = -1;
248 p->phys_cursor_width = -1;
249 p->must_be_updated_p = 0;
250 XSETFASTINT (p->window_end_vpos, 0);
251 XSETFASTINT (p->window_end_pos, 0);
252 p->window_end_valid = Qnil;
253 p->vscroll = 0;
254 XSETWINDOW (val, p);
255 XSETFASTINT (p->last_point, 0);
256 p->frozen_window_start_p = 0;
257 p->last_cursor_off_p = p->cursor_off_p = 0;
258 p->left_margin_cols = Qnil;
259 p->right_margin_cols = Qnil;
260 p->left_fringe_width = Qnil;
261 p->right_fringe_width = Qnil;
262 p->fringes_outside_margins = Qnil;
263 p->scroll_bar_width = Qnil;
264 p->vertical_scroll_bar_type = Qt;
265 p->resize_proportionally = Qnil;
266
267 Vwindow_list = Qnil;
268 return val;
269 }
270
271 DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0,
272 doc: /* Return the window that the cursor now appears in and commands apply to. */)
273 ()
274 {
275 return selected_window;
276 }
277
278 DEFUN ("minibuffer-window", Fminibuffer_window, Sminibuffer_window, 0, 1, 0,
279 doc: /* Return the window used now for minibuffers.
280 If the optional argument FRAME is specified, return the minibuffer window
281 used by that frame. */)
282 (frame)
283 Lisp_Object frame;
284 {
285 if (NILP (frame))
286 frame = selected_frame;
287 CHECK_LIVE_FRAME (frame);
288 return FRAME_MINIBUF_WINDOW (XFRAME (frame));
289 }
290
291 DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1, 0,
292 doc: /* Return non-nil if WINDOW is a minibuffer window.
293 WINDOW defaults to the selected window. */)
294 (window)
295 Lisp_Object window;
296 {
297 struct window *w = decode_window (window);
298 return MINI_WINDOW_P (w) ? Qt : Qnil;
299 }
300
301
302 DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
303 Spos_visible_in_window_p, 0, 3, 0,
304 doc: /* Return non-nil if position POS is currently on the frame in WINDOW.
305 Return nil if that position is scrolled vertically out of view.
306 If a character is only partially visible, nil is returned, unless the
307 optional argument PARTIALLY is non-nil.
308 If POS is only out of view because of horizontal scrolling, return non-nil.
309 If POS is t, it specifies the position of the last visible glyph in WINDOW.
310 POS defaults to point in WINDOW; WINDOW defaults to the selected window.
311
312 If POS is visible, return t if PARTIALLY is nil; if PARTIALLY is non-nil,
313 return value is a list of 2 or 6 elements (X Y [RTOP RBOT ROWH VPOS]),
314 where X and Y are the pixel coordinates relative to the top left corner
315 of the window. The remaining elements are omitted if the character after
316 POS is fully visible; otherwise, RTOP and RBOT are the number of pixels
317 off-window at the top and bottom of the row, ROWH is the height of the
318 display row, and VPOS is the row number (0-based) containing POS. */)
319 (pos, window, partially)
320 Lisp_Object pos, window, partially;
321 {
322 register struct window *w;
323 register int posint;
324 register struct buffer *buf;
325 struct text_pos top;
326 Lisp_Object in_window = Qnil;
327 int rtop, rbot, rowh, vpos, fully_p = 1;
328 int x, y;
329
330 w = decode_window (window);
331 buf = XBUFFER (w->buffer);
332 SET_TEXT_POS_FROM_MARKER (top, w->start);
333
334 if (EQ (pos, Qt))
335 posint = -1;
336 else if (!NILP (pos))
337 {
338 CHECK_NUMBER_COERCE_MARKER (pos);
339 posint = XINT (pos);
340 }
341 else if (w == XWINDOW (selected_window))
342 posint = PT;
343 else
344 posint = XMARKER (w->pointm)->charpos;
345
346 /* If position is above window start or outside buffer boundaries,
347 or if window start is out of range, position is not visible. */
348 if ((EQ (pos, Qt)
349 || (posint >= CHARPOS (top) && posint <= BUF_ZV (buf)))
350 && CHARPOS (top) >= BUF_BEGV (buf)
351 && CHARPOS (top) <= BUF_ZV (buf)
352 && pos_visible_p (w, posint, &x, &y, &rtop, &rbot, &rowh, &vpos)
353 && (fully_p = !rtop && !rbot, (!NILP (partially) || fully_p)))
354 in_window = Qt;
355
356 if (!NILP (in_window) && !NILP (partially))
357 {
358 Lisp_Object part = Qnil;
359 if (!fully_p)
360 part = list4 (make_number (rtop), make_number (rbot),
361 make_number (rowh), make_number (vpos));
362 in_window = Fcons (make_number (x),
363 Fcons (make_number (y), part));
364 }
365
366 return in_window;
367 }
368
369 DEFUN ("window-line-height", Fwindow_line_height,
370 Swindow_line_height, 0, 2, 0,
371 doc: /* Return height in pixels of text line LINE in window WINDOW.
372 If WINDOW is nil or omitted, use selected window.
373
374 Return height of current line if LINE is omitted or nil. Return height of
375 header or mode line if LINE is `header-line' and `mode-line'.
376 Otherwise, LINE is a text line number starting from 0. A negative number
377 counts from the end of the window.
378
379 Value is a list (HEIGHT VPOS YPOS OFFBOT), where HEIGHT is the height
380 in pixels of the visible part of the line, VPOS and YPOS are the
381 vertical position in lines and pixels of the line, relative to the top
382 of the first text line, and OFFBOT is the number of off-window pixels at
383 the bottom of the text line. If there are off-window pixels at the top
384 of the (first) text line, YPOS is negative.
385
386 Return nil if window display is not up-to-date. In that case, use
387 `pos-visible-in-window-p' to obtain the information. */)
388 (line, window)
389 Lisp_Object line, window;
390 {
391 register struct window *w;
392 register struct buffer *b;
393 struct glyph_row *row, *end_row;
394 int max_y, crop, i, n;
395
396 w = decode_window (window);
397
398 if (noninteractive
399 || w->pseudo_window_p)
400 return Qnil;
401
402 CHECK_BUFFER (w->buffer);
403 b = XBUFFER (w->buffer);
404
405 /* Fail if current matrix is not up-to-date. */
406 if (NILP (w->window_end_valid)
407 || current_buffer->clip_changed
408 || current_buffer->prevent_redisplay_optimizations_p
409 || XFASTINT (w->last_modified) < BUF_MODIFF (b)
410 || XFASTINT (w->last_overlay_modified) < BUF_OVERLAY_MODIFF (b))
411 return Qnil;
412
413 if (NILP (line))
414 {
415 i = w->cursor.vpos;
416 if (i < 0 || i >= w->current_matrix->nrows
417 || (row = MATRIX_ROW (w->current_matrix, i), !row->enabled_p))
418 return Qnil;
419 max_y = window_text_bottom_y (w);
420 goto found_row;
421 }
422
423 if (EQ (line, Qheader_line))
424 {
425 if (!WINDOW_WANTS_HEADER_LINE_P (w))
426 return Qnil;
427 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
428 if (!row->enabled_p)
429 return Qnil;
430 return list4 (make_number (row->height),
431 make_number (0), make_number (0),
432 make_number (0));
433 }
434
435 if (EQ (line, Qmode_line))
436 {
437 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
438 if (!row->enabled_p)
439 return Qnil;
440 return list4 (make_number (row->height),
441 make_number (0), /* not accurate */
442 make_number (WINDOW_HEADER_LINE_HEIGHT (w)
443 + window_text_bottom_y (w)),
444 make_number (0));
445 }
446
447 CHECK_NUMBER (line);
448 n = XINT (line);
449
450 row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
451 end_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
452 max_y = window_text_bottom_y (w);
453 i = 0;
454
455 while ((n < 0 || i < n)
456 && row <= end_row && row->enabled_p
457 && row->y + row->height < max_y)
458 row++, i++;
459
460 if (row > end_row || !row->enabled_p)
461 return Qnil;
462
463 if (++n < 0)
464 {
465 if (-n > i)
466 return Qnil;
467 row += n;
468 i += n;
469 }
470
471 found_row:
472 crop = max (0, (row->y + row->height) - max_y);
473 return list4 (make_number (row->height + min (0, row->y) - crop),
474 make_number (i),
475 make_number (row->y),
476 make_number (crop));
477 }
478
479
480 \f
481 static struct window *
482 decode_window (window)
483 register Lisp_Object window;
484 {
485 if (NILP (window))
486 return XWINDOW (selected_window);
487
488 CHECK_LIVE_WINDOW (window);
489 return XWINDOW (window);
490 }
491
492 static struct window *
493 decode_any_window (window)
494 register Lisp_Object window;
495 {
496 if (NILP (window))
497 return XWINDOW (selected_window);
498
499 CHECK_WINDOW (window);
500 return XWINDOW (window);
501 }
502
503 DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
504 doc: /* Return the buffer that WINDOW is displaying.
505 WINDOW defaults to the selected window. */)
506 (window)
507 Lisp_Object window;
508 {
509 return decode_window (window)->buffer;
510 }
511
512 DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0,
513 doc: /* Return the number of lines in WINDOW.
514 WINDOW defaults to the selected window.
515
516 The return value includes WINDOW's mode line and header line, if any.
517
518 Note: The function does not take into account the value of `line-spacing'
519 when calculating the number of lines in WINDOW. */)
520 (window)
521 Lisp_Object window;
522 {
523 return decode_any_window (window)->total_lines;
524 }
525
526 DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
527 doc: /* Return the number of display columns in WINDOW.
528 WINDOW defaults to the selected window.
529
530 Note: The return value is the number of columns available for text in
531 WINDOW. If you want to find out how many columns WINDOW takes up, use
532 (let ((edges (window-edges))) (- (nth 2 edges) (nth 0 edges))). */)
533 (window)
534 Lisp_Object window;
535 {
536 return make_number (window_box_text_cols (decode_any_window (window)));
537 }
538
539 DEFUN ("window-full-width-p", Fwindow_full_width_p, Swindow_full_width_p, 0, 1, 0,
540 doc: /* Return t if WINDOW is as wide as its frame.
541 WINDOW defaults to the selected window. */)
542 (window)
543 Lisp_Object window;
544 {
545 return WINDOW_FULL_WIDTH_P (decode_any_window (window)) ? Qt : Qnil;
546 }
547
548 DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
549 doc: /* Return the number of columns by which WINDOW is scrolled from left margin.
550 WINDOW defaults to the selected window. */)
551 (window)
552 Lisp_Object window;
553 {
554 return decode_window (window)->hscroll;
555 }
556
557 DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
558 doc: /* Set number of columns WINDOW is scrolled from left margin to NCOL.
559 Return NCOL. NCOL should be zero or positive.
560
561 Note that if `automatic-hscrolling' is non-nil, you cannot scroll the
562 window so that the location of point moves off-window. */)
563 (window, ncol)
564 Lisp_Object window, ncol;
565 {
566 struct window *w = decode_window (window);
567 int hscroll;
568
569 CHECK_NUMBER (ncol);
570 hscroll = max (0, XINT (ncol));
571
572 /* Prevent redisplay shortcuts when changing the hscroll. */
573 if (XINT (w->hscroll) != hscroll)
574 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
575
576 w->hscroll = make_number (hscroll);
577 return ncol;
578 }
579
580 DEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger,
581 Swindow_redisplay_end_trigger, 0, 1, 0,
582 doc: /* Return WINDOW's redisplay end trigger value.
583 WINDOW defaults to the selected window.
584 See `set-window-redisplay-end-trigger' for more information. */)
585 (window)
586 Lisp_Object window;
587 {
588 return decode_window (window)->redisplay_end_trigger;
589 }
590
591 DEFUN ("set-window-redisplay-end-trigger", Fset_window_redisplay_end_trigger,
592 Sset_window_redisplay_end_trigger, 2, 2, 0,
593 doc: /* Set WINDOW's redisplay end trigger value to VALUE.
594 VALUE should be a buffer position (typically a marker) or nil.
595 If it is a buffer position, then if redisplay in WINDOW reaches a position
596 beyond VALUE, the functions in `redisplay-end-trigger-functions' are called
597 with two arguments: WINDOW, and the end trigger value.
598 Afterwards the end-trigger value is reset to nil. */)
599 (window, value)
600 register Lisp_Object window, value;
601 {
602 register struct window *w;
603
604 w = decode_window (window);
605 w->redisplay_end_trigger = value;
606 return value;
607 }
608
609 DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0,
610 doc: /* Return a list of the edge coordinates of WINDOW.
611 The list has the form (LEFT TOP RIGHT BOTTOM).
612 TOP and BOTTOM count by lines, and LEFT and RIGHT count by columns,
613 all relative to 0, 0 at top left corner of frame.
614
615 RIGHT is one more than the rightmost column occupied by WINDOW.
616 BOTTOM is one more than the bottommost row occupied by WINDOW.
617 The edges include the space used by WINDOW's scroll bar, display
618 margins, fringes, header line, and/or mode line. For the edges of
619 just the text area, use `window-inside-edges'. */)
620 (window)
621 Lisp_Object window;
622 {
623 register struct window *w = decode_any_window (window);
624
625 return Fcons (make_number (WINDOW_LEFT_EDGE_COL (w)),
626 Fcons (make_number (WINDOW_TOP_EDGE_LINE (w)),
627 Fcons (make_number (WINDOW_RIGHT_EDGE_COL (w)),
628 Fcons (make_number (WINDOW_BOTTOM_EDGE_LINE (w)),
629 Qnil))));
630 }
631
632 DEFUN ("window-pixel-edges", Fwindow_pixel_edges, Swindow_pixel_edges, 0, 1, 0,
633 doc: /* Return a list of the edge pixel coordinates of WINDOW.
634 The list has the form (LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at
635 the top left corner of the frame.
636
637 RIGHT is one more than the rightmost x position occupied by WINDOW.
638 BOTTOM is one more than the bottommost y position occupied by WINDOW.
639 The pixel edges include the space used by WINDOW's scroll bar, display
640 margins, fringes, header line, and/or mode line. For the pixel edges
641 of just the text area, use `window-inside-pixel-edges'. */)
642 (window)
643 Lisp_Object window;
644 {
645 register struct window *w = decode_any_window (window);
646
647 return Fcons (make_number (WINDOW_LEFT_EDGE_X (w)),
648 Fcons (make_number (WINDOW_TOP_EDGE_Y (w)),
649 Fcons (make_number (WINDOW_RIGHT_EDGE_X (w)),
650 Fcons (make_number (WINDOW_BOTTOM_EDGE_Y (w)),
651 Qnil))));
652 }
653
654 DEFUN ("window-inside-edges", Fwindow_inside_edges, Swindow_inside_edges, 0, 1, 0,
655 doc: /* Return a list of the edge coordinates of WINDOW.
656 The list has the form (LEFT TOP RIGHT BOTTOM).
657 TOP and BOTTOM count by lines, and LEFT and RIGHT count by columns,
658 all relative to 0, 0 at top left corner of frame.
659
660 RIGHT is one more than the rightmost column of WINDOW's text area.
661 BOTTOM is one more than the bottommost row of WINDOW's text area.
662 The inside edges do not include the space used by the WINDOW's scroll
663 bar, display margins, fringes, header line, and/or mode line. */)
664 (window)
665 Lisp_Object window;
666 {
667 register struct window *w = decode_any_window (window);
668
669 return list4 (make_number (WINDOW_BOX_LEFT_EDGE_COL (w)
670 + WINDOW_LEFT_MARGIN_COLS (w)
671 + WINDOW_LEFT_FRINGE_COLS (w)),
672 make_number (WINDOW_TOP_EDGE_LINE (w)
673 + WINDOW_HEADER_LINE_LINES (w)),
674 make_number (WINDOW_BOX_RIGHT_EDGE_COL (w)
675 - WINDOW_RIGHT_MARGIN_COLS (w)
676 - WINDOW_RIGHT_FRINGE_COLS (w)),
677 make_number (WINDOW_BOTTOM_EDGE_LINE (w)
678 - WINDOW_MODE_LINE_LINES (w)));
679 }
680
681 DEFUN ("window-inside-pixel-edges", Fwindow_inside_pixel_edges, Swindow_inside_pixel_edges, 0, 1, 0,
682 doc: /* Return a list of the edge pixel coordinates of WINDOW.
683 The list has the form (LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at
684 the top left corner of the frame.
685
686 RIGHT is one more than the rightmost x position of WINDOW's text area.
687 BOTTOM is one more than the bottommost y position of WINDOW's text area.
688 The inside edges do not include the space used by WINDOW's scroll bar,
689 display margins, fringes, header line, and/or mode line. */)
690 (window)
691 Lisp_Object window;
692 {
693 register struct window *w = decode_any_window (window);
694
695 return list4 (make_number (WINDOW_BOX_LEFT_EDGE_X (w)
696 + WINDOW_LEFT_MARGIN_WIDTH (w)
697 + WINDOW_LEFT_FRINGE_WIDTH (w)),
698 make_number (WINDOW_TOP_EDGE_Y (w)
699 + WINDOW_HEADER_LINE_HEIGHT (w)),
700 make_number (WINDOW_BOX_RIGHT_EDGE_X (w)
701 - WINDOW_RIGHT_MARGIN_WIDTH (w)
702 - WINDOW_RIGHT_FRINGE_WIDTH (w)),
703 make_number (WINDOW_BOTTOM_EDGE_Y (w)
704 - WINDOW_MODE_LINE_HEIGHT (w)));
705 }
706
707 /* Test if the character at column *X, row *Y is within window W.
708 If it is not, return ON_NOTHING;
709 if it is in the window's text area,
710 set *x and *y to its location relative to the upper left corner
711 of the window, and
712 return ON_TEXT;
713 if it is on the window's modeline, return ON_MODE_LINE;
714 if it is on the border between the window and its right sibling,
715 return ON_VERTICAL_BORDER.
716 if it is on a scroll bar,
717 return ON_SCROLL_BAR.
718 if it is on the window's top line, return ON_HEADER_LINE;
719 if it is in left or right fringe of the window,
720 return ON_LEFT_FRINGE or ON_RIGHT_FRINGE, and convert *X and *Y
721 to window-relative coordinates;
722 if it is in the marginal area to the left/right of the window,
723 return ON_LEFT_MARGIN or ON_RIGHT_MARGIN, and convert *X and *Y
724 to window-relative coordinates.
725
726 X and Y are frame relative pixel coordinates. */
727
728 static enum window_part
729 coordinates_in_window (w, x, y)
730 register struct window *w;
731 register int *x, *y;
732 {
733 struct frame *f = XFRAME (WINDOW_FRAME (w));
734 int left_x, right_x, top_y, bottom_y;
735 enum window_part part;
736 int ux = FRAME_COLUMN_WIDTH (f);
737 int x0 = WINDOW_LEFT_EDGE_X (w);
738 int x1 = WINDOW_RIGHT_EDGE_X (w);
739 /* The width of the area where the vertical line can be dragged.
740 (Between mode lines for instance. */
741 int grabbable_width = ux;
742 int lmargin_width, rmargin_width, text_left, text_right;
743
744 /* In what's below, we subtract 1 when computing right_x because we
745 want the rightmost pixel, which is given by left_pixel+width-1. */
746 if (w->pseudo_window_p)
747 {
748 left_x = 0;
749 right_x = WINDOW_TOTAL_WIDTH (w) - 1;
750 top_y = WINDOW_TOP_EDGE_Y (w);
751 bottom_y = WINDOW_BOTTOM_EDGE_Y (w);
752 }
753 else
754 {
755 left_x = WINDOW_BOX_LEFT_EDGE_X (w);
756 right_x = WINDOW_BOX_RIGHT_EDGE_X (w) - 1;
757 top_y = WINDOW_TOP_EDGE_Y (w);
758 bottom_y = WINDOW_BOTTOM_EDGE_Y (w);
759 }
760
761 /* Outside any interesting row? */
762 if (*y < top_y || *y >= bottom_y)
763 return ON_NOTHING;
764
765 /* On the mode line or header line? If it's near the start of
766 the mode or header line of window that's has a horizontal
767 sibling, say it's on the vertical line. That's to be able
768 to resize windows horizontally in case we're using toolkit
769 scroll bars. */
770
771 if (WINDOW_WANTS_MODELINE_P (w)
772 && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
773 {
774 part = ON_MODE_LINE;
775
776 header_vertical_border_check:
777 /* We're somewhere on the mode line. We consider the place
778 between mode lines of horizontally adjacent mode lines
779 as the vertical border. If scroll bars on the left,
780 return the right window. */
781 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
782 || WINDOW_RIGHTMOST_P (w))
783 {
784 if (!WINDOW_LEFTMOST_P (w) && eabs (*x - x0) < grabbable_width)
785 {
786 /* Convert X and Y to window relative coordinates.
787 Vertical border is at the left edge of window. */
788 *x = max (0, *x - x0);
789 *y -= top_y;
790 return ON_VERTICAL_BORDER;
791 }
792 }
793 else
794 {
795 /* Make sure we're not at the rightmost position of a
796 mode-/header-line and there's yet another window on
797 the right. (Bug#1372) */
798 if ((WINDOW_RIGHTMOST_P (w) || *x < x1)
799 && eabs (*x - x1) < grabbable_width)
800 {
801 /* Convert X and Y to window relative coordinates.
802 Vertical border is at the right edge of window. */
803 *x = min (x1, *x) - x0;
804 *y -= top_y;
805 return ON_VERTICAL_BORDER;
806 }
807 }
808
809 if (*x < x0 || *x >= x1)
810 return ON_NOTHING;
811
812 /* Convert X and Y to window relative coordinates.
813 Mode line starts at left edge of window. */
814 *x -= x0;
815 *y -= top_y;
816 return part;
817 }
818
819 if (WINDOW_WANTS_HEADER_LINE_P (w)
820 && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
821 {
822 part = ON_HEADER_LINE;
823 goto header_vertical_border_check;
824 }
825
826 if (*x < x0 || *x >= x1)
827 return ON_NOTHING;
828
829 /* Outside any interesting column? */
830 if (*x < left_x || *x > right_x)
831 {
832 *y -= top_y;
833 return ON_SCROLL_BAR;
834 }
835
836 lmargin_width = window_box_width (w, LEFT_MARGIN_AREA);
837 rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA);
838
839 text_left = window_box_left (w, TEXT_AREA);
840 text_right = text_left + window_box_width (w, TEXT_AREA);
841
842 if (FRAME_WINDOW_P (f))
843 {
844 if (!w->pseudo_window_p
845 && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
846 && !WINDOW_RIGHTMOST_P (w)
847 && (eabs (*x - right_x) < grabbable_width))
848 {
849 /* Convert X and Y to window relative coordinates.
850 Vertical border is at the right edge of window. */
851 *x = min (right_x, *x) - left_x;
852 *y -= top_y;
853 return ON_VERTICAL_BORDER;
854 }
855 }
856 else
857 {
858 /* Need to say "*x > right_x" rather than >=, since on character
859 terminals, the vertical line's x coordinate is right_x. */
860 if (!w->pseudo_window_p
861 && !WINDOW_RIGHTMOST_P (w)
862 && *x > right_x - ux)
863 {
864 /* On the border on the right side of the window? Assume that
865 this area begins at RIGHT_X minus a canonical char width. */
866 *x = min (right_x, *x) - left_x;
867 *y -= top_y;
868 return ON_VERTICAL_BORDER;
869 }
870 }
871
872 if (*x < text_left)
873 {
874 if (lmargin_width > 0
875 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
876 ? (*x >= left_x + WINDOW_LEFT_FRINGE_WIDTH (w))
877 : (*x < left_x + lmargin_width)))
878 {
879 *x -= left_x;
880 if (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
881 *x -= WINDOW_LEFT_FRINGE_WIDTH (w);
882 *y -= top_y;
883 return ON_LEFT_MARGIN;
884 }
885
886 /* Convert X and Y to window-relative pixel coordinates. */
887 *x -= left_x;
888 *y -= top_y;
889 return ON_LEFT_FRINGE;
890 }
891
892 if (*x >= text_right)
893 {
894 if (rmargin_width > 0
895 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
896 ? (*x < right_x - WINDOW_RIGHT_FRINGE_WIDTH (w))
897 : (*x >= right_x - rmargin_width)))
898 {
899 *x -= right_x - rmargin_width;
900 if (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
901 *x += WINDOW_RIGHT_FRINGE_WIDTH (w);
902 *y -= top_y;
903 return ON_RIGHT_MARGIN;
904 }
905
906 /* Convert X and Y to window-relative pixel coordinates. */
907 *x -= left_x + WINDOW_LEFT_FRINGE_WIDTH (w);
908 *y -= top_y;
909 return ON_RIGHT_FRINGE;
910 }
911
912 /* Everything special ruled out - must be on text area */
913 *x -= text_left;
914 *y -= top_y;
915 return ON_TEXT;
916 }
917
918
919 DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
920 Scoordinates_in_window_p, 2, 2, 0,
921 doc: /* Return non-nil if COORDINATES are in WINDOW.
922 COORDINATES is a cons of the form (X . Y), X and Y being distances
923 measured in characters from the upper-left corner of the frame.
924 \(0 . 0) denotes the character in the upper left corner of the
925 frame.
926 If COORDINATES are in the text portion of WINDOW,
927 the coordinates relative to the window are returned.
928 If they are in the mode line of WINDOW, `mode-line' is returned.
929 If they are in the top mode line of WINDOW, `header-line' is returned.
930 If they are in the left fringe of WINDOW, `left-fringe' is returned.
931 If they are in the right fringe of WINDOW, `right-fringe' is returned.
932 If they are on the border between WINDOW and its right sibling,
933 `vertical-line' is returned.
934 If they are in the windows's left or right marginal areas, `left-margin'\n\
935 or `right-margin' is returned. */)
936 (coordinates, window)
937 register Lisp_Object coordinates, window;
938 {
939 struct window *w;
940 struct frame *f;
941 int x, y;
942 Lisp_Object lx, ly;
943
944 CHECK_WINDOW (window);
945 w = XWINDOW (window);
946 f = XFRAME (w->frame);
947 CHECK_CONS (coordinates);
948 lx = Fcar (coordinates);
949 ly = Fcdr (coordinates);
950 CHECK_NUMBER_OR_FLOAT (lx);
951 CHECK_NUMBER_OR_FLOAT (ly);
952 x = FRAME_PIXEL_X_FROM_CANON_X (f, lx) + FRAME_INTERNAL_BORDER_WIDTH (f);
953 y = FRAME_PIXEL_Y_FROM_CANON_Y (f, ly) + FRAME_INTERNAL_BORDER_WIDTH (f);
954
955 switch (coordinates_in_window (w, &x, &y))
956 {
957 case ON_NOTHING:
958 return Qnil;
959
960 case ON_TEXT:
961 /* X and Y are now window relative pixel coordinates. Convert
962 them to canonical char units before returning them. */
963 return Fcons (FRAME_CANON_X_FROM_PIXEL_X (f, x),
964 FRAME_CANON_Y_FROM_PIXEL_Y (f, y));
965
966 case ON_MODE_LINE:
967 return Qmode_line;
968
969 case ON_VERTICAL_BORDER:
970 return Qvertical_line;
971
972 case ON_HEADER_LINE:
973 return Qheader_line;
974
975 case ON_LEFT_FRINGE:
976 return Qleft_fringe;
977
978 case ON_RIGHT_FRINGE:
979 return Qright_fringe;
980
981 case ON_LEFT_MARGIN:
982 return Qleft_margin;
983
984 case ON_RIGHT_MARGIN:
985 return Qright_margin;
986
987 case ON_SCROLL_BAR:
988 /* Historically we are supposed to return nil in this case. */
989 return Qnil;
990
991 default:
992 abort ();
993 }
994 }
995
996
997 /* Callback for foreach_window, used in window_from_coordinates.
998 Check if window W contains coordinates specified by USER_DATA which
999 is actually a pointer to a struct check_window_data CW.
1000
1001 Check if window W contains coordinates *CW->x and *CW->y. If it
1002 does, return W in *CW->window, as Lisp_Object, and return in
1003 *CW->part the part of the window under coordinates *X,*Y. Return
1004 zero from this function to stop iterating over windows. */
1005
1006 struct check_window_data
1007 {
1008 Lisp_Object *window;
1009 int *x, *y;
1010 enum window_part *part;
1011 };
1012
1013 static int
1014 check_window_containing (w, user_data)
1015 struct window *w;
1016 void *user_data;
1017 {
1018 struct check_window_data *cw = (struct check_window_data *) user_data;
1019 enum window_part found;
1020 int continue_p = 1;
1021
1022 found = coordinates_in_window (w, cw->x, cw->y);
1023 if (found != ON_NOTHING)
1024 {
1025 *cw->part = found;
1026 XSETWINDOW (*cw->window, w);
1027 continue_p = 0;
1028 }
1029
1030 return continue_p;
1031 }
1032
1033
1034 /* Find the window containing frame-relative pixel position X/Y and
1035 return it as a Lisp_Object.
1036
1037 If X, Y is on one of the window's special `window_part' elements,
1038 set *PART to the id of that element, and return X and Y converted
1039 to window relative coordinates in WX and WY.
1040
1041 If there is no window under X, Y return nil and leave *PART
1042 unmodified. TOOL_BAR_P non-zero means detect tool-bar windows.
1043
1044 This function was previously implemented with a loop cycling over
1045 windows with Fnext_window, and starting with the frame's selected
1046 window. It turned out that this doesn't work with an
1047 implementation of next_window using Vwindow_list, because
1048 FRAME_SELECTED_WINDOW (F) is not always contained in the window
1049 tree of F when this function is called asynchronously from
1050 note_mouse_highlight. The original loop didn't terminate in this
1051 case. */
1052
1053 Lisp_Object
1054 window_from_coordinates (f, x, y, part, wx, wy, tool_bar_p)
1055 struct frame *f;
1056 int x, y;
1057 enum window_part *part;
1058 int *wx, *wy;
1059 int tool_bar_p;
1060 {
1061 Lisp_Object window;
1062 struct check_window_data cw;
1063 enum window_part dummy;
1064
1065 if (part == 0)
1066 part = &dummy;
1067
1068 window = Qnil;
1069 cw.window = &window, cw.x = &x, cw.y = &y; cw.part = part;
1070 foreach_window (f, check_window_containing, &cw);
1071
1072 /* If not found above, see if it's in the tool bar window, if a tool
1073 bar exists. */
1074 if (NILP (window)
1075 && tool_bar_p
1076 && WINDOWP (f->tool_bar_window)
1077 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0
1078 && (coordinates_in_window (XWINDOW (f->tool_bar_window), &x, &y)
1079 != ON_NOTHING))
1080 {
1081 *part = ON_TEXT;
1082 window = f->tool_bar_window;
1083 }
1084
1085 if (wx) *wx = x;
1086 if (wy) *wy = y;
1087
1088 return window;
1089 }
1090
1091 DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
1092 doc: /* Return window containing coordinates X and Y on FRAME.
1093 If omitted, FRAME defaults to the currently selected frame.
1094 The top left corner of the frame is considered to be row 0,
1095 column 0. */)
1096 (x, y, frame)
1097 Lisp_Object x, y, frame;
1098 {
1099 struct frame *f;
1100
1101 if (NILP (frame))
1102 frame = selected_frame;
1103 CHECK_LIVE_FRAME (frame);
1104 f = XFRAME (frame);
1105
1106 /* Check that arguments are integers or floats. */
1107 CHECK_NUMBER_OR_FLOAT (x);
1108 CHECK_NUMBER_OR_FLOAT (y);
1109
1110 return window_from_coordinates (f,
1111 (FRAME_PIXEL_X_FROM_CANON_X (f, x)
1112 + FRAME_INTERNAL_BORDER_WIDTH (f)),
1113 (FRAME_PIXEL_Y_FROM_CANON_Y (f, y)
1114 + FRAME_INTERNAL_BORDER_WIDTH (f)),
1115 0, 0, 0, 0);
1116 }
1117
1118 DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
1119 doc: /* Return current value of point in WINDOW.
1120 WINDOW defaults to the selected window.
1121
1122 For a nonselected window, this is the value point would have
1123 if that window were selected.
1124
1125 Note that, when WINDOW is the selected window and its buffer
1126 is also currently selected, the value returned is the same as (point).
1127 It would be more strictly correct to return the `top-level' value
1128 of point, outside of any save-excursion forms.
1129 But that is hard to define. */)
1130 (window)
1131 Lisp_Object window;
1132 {
1133 register struct window *w = decode_window (window);
1134
1135 if (w == XWINDOW (selected_window)
1136 && current_buffer == XBUFFER (w->buffer))
1137 return Fpoint ();
1138 return Fmarker_position (w->pointm);
1139 }
1140
1141 DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
1142 doc: /* Return position at which display currently starts in WINDOW.
1143 WINDOW defaults to the selected window.
1144 This is updated by redisplay or by calling `set-window-start'. */)
1145 (window)
1146 Lisp_Object window;
1147 {
1148 return Fmarker_position (decode_window (window)->start);
1149 }
1150
1151 /* This is text temporarily removed from the doc string below.
1152
1153 This function returns nil if the position is not currently known.
1154 That happens when redisplay is preempted and doesn't finish.
1155 If in that case you want to compute where the end of the window would
1156 have been if redisplay had finished, do this:
1157 (save-excursion
1158 (goto-char (window-start window))
1159 (vertical-motion (1- (window-height window)) window)
1160 (point))") */
1161
1162 DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
1163 doc: /* Return position at which display currently ends in WINDOW.
1164 WINDOW defaults to the selected window.
1165 This is updated by redisplay, when it runs to completion.
1166 Simply changing the buffer text or setting `window-start'
1167 does not update this value.
1168 Return nil if there is no recorded value. \(This can happen if the
1169 last redisplay of WINDOW was preempted, and did not finish.)
1170 If UPDATE is non-nil, compute the up-to-date position
1171 if it isn't already recorded. */)
1172 (window, update)
1173 Lisp_Object window, update;
1174 {
1175 Lisp_Object value;
1176 struct window *w = decode_window (window);
1177 Lisp_Object buf;
1178 struct buffer *b;
1179
1180 buf = w->buffer;
1181 CHECK_BUFFER (buf);
1182 b = XBUFFER (buf);
1183
1184 #if 0 /* This change broke some things. We should make it later. */
1185 /* If we don't know the end position, return nil.
1186 The user can compute it with vertical-motion if he wants to.
1187 It would be nicer to do it automatically,
1188 but that's so slow that it would probably bother people. */
1189 if (NILP (w->window_end_valid))
1190 return Qnil;
1191 #endif
1192
1193 if (! NILP (update)
1194 && ! (! NILP (w->window_end_valid)
1195 && XFASTINT (w->last_modified) >= BUF_MODIFF (b)
1196 && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (b))
1197 && !noninteractive)
1198 {
1199 struct text_pos startp;
1200 struct it it;
1201 struct buffer *old_buffer = NULL;
1202
1203 /* Cannot use Fvertical_motion because that function doesn't
1204 cope with variable-height lines. */
1205 if (b != current_buffer)
1206 {
1207 old_buffer = current_buffer;
1208 set_buffer_internal (b);
1209 }
1210
1211 /* In case W->start is out of the range, use something
1212 reasonable. This situation occurred when loading a file with
1213 `-l' containing a call to `rmail' with subsequent other
1214 commands. At the end, W->start happened to be BEG, while
1215 rmail had already narrowed the buffer. */
1216 if (XMARKER (w->start)->charpos < BEGV)
1217 SET_TEXT_POS (startp, BEGV, BEGV_BYTE);
1218 else if (XMARKER (w->start)->charpos > ZV)
1219 SET_TEXT_POS (startp, ZV, ZV_BYTE);
1220 else
1221 SET_TEXT_POS_FROM_MARKER (startp, w->start);
1222
1223 start_display (&it, w, startp);
1224 move_it_vertically (&it, window_box_height (w));
1225 if (it.current_y < it.last_visible_y)
1226 move_it_past_eol (&it);
1227 value = make_number (IT_CHARPOS (it));
1228
1229 if (old_buffer)
1230 set_buffer_internal (old_buffer);
1231 }
1232 else
1233 XSETINT (value, BUF_Z (b) - XFASTINT (w->window_end_pos));
1234
1235 return value;
1236 }
1237
1238 DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
1239 doc: /* Make point value in WINDOW be at position POS in WINDOW's buffer.
1240 Return POS. */)
1241 (window, pos)
1242 Lisp_Object window, pos;
1243 {
1244 register struct window *w = decode_window (window);
1245
1246 CHECK_NUMBER_COERCE_MARKER (pos);
1247 if (w == XWINDOW (selected_window)
1248 && XBUFFER (w->buffer) == current_buffer)
1249 Fgoto_char (pos);
1250 else
1251 set_marker_restricted (w->pointm, pos, w->buffer);
1252
1253 /* We have to make sure that redisplay updates the window to show
1254 the new value of point. */
1255 if (!EQ (window, selected_window))
1256 ++windows_or_buffers_changed;
1257
1258 return pos;
1259 }
1260
1261 DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
1262 doc: /* Make display in WINDOW start at position POS in WINDOW's buffer.
1263 WINDOW defaults to the selected window. Return POS.
1264 Optional third arg NOFORCE non-nil inhibits next redisplay from
1265 overriding motion of point in order to display at this exact start. */)
1266 (window, pos, noforce)
1267 Lisp_Object window, pos, noforce;
1268 {
1269 register struct window *w = decode_window (window);
1270
1271 CHECK_NUMBER_COERCE_MARKER (pos);
1272 set_marker_restricted (w->start, pos, w->buffer);
1273 /* this is not right, but much easier than doing what is right. */
1274 w->start_at_line_beg = Qnil;
1275 if (NILP (noforce))
1276 w->force_start = Qt;
1277 w->update_mode_line = Qt;
1278 XSETFASTINT (w->last_modified, 0);
1279 XSETFASTINT (w->last_overlay_modified, 0);
1280 if (!EQ (window, selected_window))
1281 windows_or_buffers_changed++;
1282
1283 return pos;
1284 }
1285
1286
1287 DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
1288 0, 1, 0,
1289 doc: /* Return non-nil when WINDOW is dedicated to its buffer.
1290 More precisely, return the value assigned by the last call of
1291 `set-window-dedicated-p' for WINDOW. Return nil if that function was
1292 never called with WINDOW as its argument, or the value set by that
1293 function was internally reset since its last call. WINDOW defaults to
1294 the selected window.
1295
1296 When a window is dedicated to its buffer, `display-buffer' will refrain
1297 from displaying another buffer in it. `get-lru-window' and
1298 `get-largest-window' treat dedicated windows specially.
1299 `delete-windows-on', `replace-buffer-in-windows', `quit-window' and
1300 `kill-buffer' can delete a dedicated window and the containing frame.
1301
1302 Functions like `set-window-buffer' may change the buffer displayed by a
1303 window, unless that window is "strongly" dedicated to its buffer, that
1304 is the value returned by `window-dedicated-p' is t. */)
1305 (window)
1306 Lisp_Object window;
1307 {
1308 return decode_window (window)->dedicated;
1309 }
1310
1311 DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p,
1312 Sset_window_dedicated_p, 2, 2, 0,
1313 doc: /* Mark WINDOW as dedicated according to FLAG.
1314 WINDOW defaults to the selected window. FLAG non-nil means mark WINDOW
1315 as dedicated to its buffer. FLAG nil means mark WINDOW as non-dedicated.
1316 Return FLAG.
1317
1318 When a window is dedicated to its buffer, `display-buffer' will refrain
1319 from displaying another buffer in it. `get-lru-window' and
1320 `get-largest-window' treat dedicated windows specially.
1321 `delete-windows-on', `replace-buffer-in-windows', `quit-window' and
1322 `kill-buffer' can delete a dedicated window and the containing
1323 frame.
1324
1325 As a special case, if FLAG is t, mark WINDOW as "strongly" dedicated to
1326 its buffer. Functions like `set-window-buffer' may change the buffer
1327 displayed by a window, unless that window is strongly dedicated to its
1328 buffer. If and when `set-window-buffer' displays another buffer in a
1329 window, it also makes sure that the window is not marked as dedicated. */)
1330 (window, flag)
1331 Lisp_Object window, flag;
1332 {
1333 register struct window *w = decode_window (window);
1334
1335 w->dedicated = flag;
1336 return w->dedicated;
1337 }
1338
1339
1340 DEFUN ("window-parameters", Fwindow_parameters, Swindow_parameters,
1341 0, 1, 0,
1342 doc: /* Return the parameters of WINDOW and their values.
1343 WINDOW defaults to the selected window. The return value is a list of
1344 elements of the form (PARAMETER . VALUE). */)
1345 (window)
1346 Lisp_Object window;
1347 {
1348 return Fcopy_alist (decode_window (window)->window_parameters);
1349 }
1350
1351 DEFUN ("window-parameter", Fwindow_parameter, Swindow_parameter,
1352 2, 2, 0,
1353 doc: /* Return WINDOW's value for PARAMETER.
1354 WINDOW defaults to the selected window. */)
1355 (window, parameter)
1356 Lisp_Object window, parameter;
1357 {
1358 Lisp_Object result;
1359
1360 result = Fassq (parameter, decode_window (window)->window_parameters);
1361 return CDR_SAFE (result);
1362 }
1363
1364 DEFUN ("set-window-parameter", Fset_window_parameter,
1365 Sset_window_parameter, 3, 3, 0,
1366 doc: /* Set WINDOW's value of PARAMETER to VALUE.
1367 WINDOW defaults to the selected window. Return VALUE. */)
1368 (window, parameter, value)
1369 Lisp_Object window, parameter, value;
1370 {
1371 register struct window *w = decode_window (window);
1372 Lisp_Object old_alist_elt;
1373
1374 old_alist_elt = Fassq (parameter, w->window_parameters);
1375 if (NILP (old_alist_elt))
1376 w->window_parameters = Fcons (Fcons (parameter, value), w->window_parameters);
1377 else
1378 Fsetcdr (old_alist_elt, value);
1379 return value;
1380 }
1381
1382
1383 DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
1384 0, 1, 0,
1385 doc: /* Return the display-table that WINDOW is using.
1386 WINDOW defaults to the selected window. */)
1387 (window)
1388 Lisp_Object window;
1389 {
1390 return decode_window (window)->display_table;
1391 }
1392
1393 /* Get the display table for use on window W. This is either W's
1394 display table or W's buffer's display table. Ignore the specified
1395 tables if they are not valid; if no valid table is specified,
1396 return 0. */
1397
1398 struct Lisp_Char_Table *
1399 window_display_table (w)
1400 struct window *w;
1401 {
1402 struct Lisp_Char_Table *dp = NULL;
1403
1404 if (DISP_TABLE_P (w->display_table))
1405 dp = XCHAR_TABLE (w->display_table);
1406 else if (BUFFERP (w->buffer))
1407 {
1408 struct buffer *b = XBUFFER (w->buffer);
1409
1410 if (DISP_TABLE_P (b->display_table))
1411 dp = XCHAR_TABLE (b->display_table);
1412 else if (DISP_TABLE_P (Vstandard_display_table))
1413 dp = XCHAR_TABLE (Vstandard_display_table);
1414 }
1415
1416 return dp;
1417 }
1418
1419 DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_display_table, 2, 2, 0,
1420 doc: /* Set WINDOW's display-table to TABLE. */)
1421 (window, table)
1422 register Lisp_Object window, table;
1423 {
1424 register struct window *w;
1425
1426 w = decode_window (window);
1427 w->display_table = table;
1428 return table;
1429 }
1430 \f
1431 /* Record info on buffer window w is displaying
1432 when it is about to cease to display that buffer. */
1433 static void
1434 unshow_buffer (w)
1435 register struct window *w;
1436 {
1437 Lisp_Object buf;
1438 struct buffer *b;
1439
1440 buf = w->buffer;
1441 b = XBUFFER (buf);
1442 if (b != XMARKER (w->pointm)->buffer)
1443 abort ();
1444
1445 #if 0
1446 if (w == XWINDOW (selected_window)
1447 || ! EQ (buf, XWINDOW (selected_window)->buffer))
1448 /* Do this except when the selected window's buffer
1449 is being removed from some other window. */
1450 #endif
1451 /* last_window_start records the start position that this buffer
1452 had in the last window to be disconnected from it.
1453 Now that this statement is unconditional,
1454 it is possible for the buffer to be displayed in the
1455 selected window, while last_window_start reflects another
1456 window which was recently showing the same buffer.
1457 Some people might say that might be a good thing. Let's see. */
1458 b->last_window_start = marker_position (w->start);
1459
1460 /* Point in the selected window's buffer
1461 is actually stored in that buffer, and the window's pointm isn't used.
1462 So don't clobber point in that buffer. */
1463 if (! EQ (buf, XWINDOW (selected_window)->buffer)
1464 /* This line helps to fix Horsley's testbug.el bug. */
1465 && !(WINDOWP (b->last_selected_window)
1466 && w != XWINDOW (b->last_selected_window)
1467 && EQ (buf, XWINDOW (b->last_selected_window)->buffer)))
1468 temp_set_point_both (b,
1469 clip_to_bounds (BUF_BEGV (b),
1470 XMARKER (w->pointm)->charpos,
1471 BUF_ZV (b)),
1472 clip_to_bounds (BUF_BEGV_BYTE (b),
1473 marker_byte_position (w->pointm),
1474 BUF_ZV_BYTE (b)));
1475
1476 if (WINDOWP (b->last_selected_window)
1477 && w == XWINDOW (b->last_selected_window))
1478 b->last_selected_window = Qnil;
1479 }
1480
1481 /* Put replacement into the window structure in place of old. */
1482 static void
1483 replace_window (old, replacement)
1484 Lisp_Object old, replacement;
1485 {
1486 register Lisp_Object tem;
1487 register struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
1488
1489 /* If OLD is its frame's root_window, then replacement is the new
1490 root_window for that frame. */
1491
1492 if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
1493 FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
1494
1495 p->left_col = o->left_col;
1496 p->top_line = o->top_line;
1497 p->total_cols = o->total_cols;
1498 p->total_lines = o->total_lines;
1499 p->desired_matrix = p->current_matrix = 0;
1500 p->vscroll = 0;
1501 bzero (&p->cursor, sizeof (p->cursor));
1502 bzero (&p->last_cursor, sizeof (p->last_cursor));
1503 bzero (&p->phys_cursor, sizeof (p->phys_cursor));
1504 p->phys_cursor_type = -1;
1505 p->phys_cursor_width = -1;
1506 p->must_be_updated_p = 0;
1507 p->pseudo_window_p = 0;
1508 XSETFASTINT (p->window_end_vpos, 0);
1509 XSETFASTINT (p->window_end_pos, 0);
1510 p->window_end_valid = Qnil;
1511 p->frozen_window_start_p = 0;
1512 p->orig_top_line = p->orig_total_lines = Qnil;
1513
1514 p->next = tem = o->next;
1515 if (!NILP (tem))
1516 XWINDOW (tem)->prev = replacement;
1517
1518 p->prev = tem = o->prev;
1519 if (!NILP (tem))
1520 XWINDOW (tem)->next = replacement;
1521
1522 p->parent = tem = o->parent;
1523 if (!NILP (tem))
1524 {
1525 if (EQ (XWINDOW (tem)->vchild, old))
1526 XWINDOW (tem)->vchild = replacement;
1527 if (EQ (XWINDOW (tem)->hchild, old))
1528 XWINDOW (tem)->hchild = replacement;
1529 }
1530
1531 /*** Here, if replacement is a vertical combination
1532 and so is its new parent, we should make replacement's
1533 children be children of that parent instead. ***/
1534 }
1535
1536 DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
1537 doc: /* Remove WINDOW from its frame.
1538 WINDOW defaults to the selected window. Return nil.
1539 Signal an error when WINDOW is the only window on its frame. */)
1540 (window)
1541 register Lisp_Object window;
1542 {
1543 struct frame *f;
1544 if (NILP (window))
1545 window = selected_window;
1546 else
1547 CHECK_LIVE_WINDOW (window);
1548
1549 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
1550 delete_window (window);
1551
1552 run_window_configuration_change_hook (f);
1553
1554 return Qnil;
1555 }
1556
1557 void
1558 delete_window (window)
1559 register Lisp_Object window;
1560 {
1561 register Lisp_Object tem, parent, sib;
1562 register struct window *p;
1563 register struct window *par;
1564 struct frame *f;
1565
1566 /* Because this function is called by other C code on non-leaf
1567 windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
1568 so we can't decode_window here. */
1569 CHECK_WINDOW (window);
1570 p = XWINDOW (window);
1571
1572 /* It's a no-op to delete an already-deleted window. */
1573 if (NILP (p->buffer)
1574 && NILP (p->hchild)
1575 && NILP (p->vchild))
1576 return;
1577
1578 parent = p->parent;
1579 if (NILP (parent))
1580 error ("Attempt to delete minibuffer or sole ordinary window");
1581 par = XWINDOW (parent);
1582
1583 windows_or_buffers_changed++;
1584 Vwindow_list = Qnil;
1585 f = XFRAME (WINDOW_FRAME (p));
1586 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
1587
1588 /* Are we trying to delete any frame's selected window? */
1589 {
1590 Lisp_Object swindow, pwindow;
1591
1592 /* See if the frame's selected window is either WINDOW
1593 or any subwindow of it, by finding all that window's parents
1594 and comparing each one with WINDOW. */
1595 swindow = FRAME_SELECTED_WINDOW (f);
1596
1597 while (1)
1598 {
1599 pwindow = swindow;
1600 while (!NILP (pwindow))
1601 {
1602 if (EQ (window, pwindow))
1603 break;
1604 pwindow = XWINDOW (pwindow)->parent;
1605 }
1606
1607 /* If the window being deleted is not a parent of SWINDOW,
1608 then SWINDOW is ok as the new selected window. */
1609 if (!EQ (window, pwindow))
1610 break;
1611 /* Otherwise, try another window for SWINDOW. */
1612 swindow = Fnext_window (swindow, Qlambda, Qnil);
1613
1614 /* If we get back to the frame's selected window,
1615 it means there was no acceptable alternative,
1616 so we cannot delete. */
1617 if (EQ (swindow, FRAME_SELECTED_WINDOW (f)))
1618 error ("Cannot delete window");
1619 }
1620
1621 /* If we need to change SWINDOW, do it. */
1622 if (! EQ (swindow, FRAME_SELECTED_WINDOW (f)))
1623 {
1624 /* If we're about to delete the selected window on the
1625 selected frame, then we should use Fselect_window to select
1626 the new window. On the other hand, if we're about to
1627 delete the selected window on any other frame, we shouldn't do
1628 anything but set the frame's selected_window slot. */
1629 if (EQ (FRAME_SELECTED_WINDOW (f), selected_window))
1630 Fselect_window (swindow, Qnil);
1631 else
1632 FRAME_SELECTED_WINDOW (f) = swindow;
1633 }
1634 }
1635
1636 /* Now we know we can delete this one. */
1637 window_deletion_count++;
1638
1639 tem = p->buffer;
1640 /* tem is null for dummy parent windows
1641 (which have inferiors but not any contents themselves) */
1642 if (!NILP (tem))
1643 {
1644 unshow_buffer (p);
1645 unchain_marker (XMARKER (p->pointm));
1646 unchain_marker (XMARKER (p->start));
1647 }
1648
1649 /* Free window glyph matrices. It is sure that they are allocated
1650 again when ADJUST_GLYPHS is called. Block input so that expose
1651 events and other events that access glyph matrices are not
1652 processed while we are changing them. */
1653 BLOCK_INPUT;
1654 free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (f)));
1655
1656 tem = p->next;
1657 if (!NILP (tem))
1658 XWINDOW (tem)->prev = p->prev;
1659
1660 tem = p->prev;
1661 if (!NILP (tem))
1662 XWINDOW (tem)->next = p->next;
1663
1664 if (EQ (window, par->hchild))
1665 par->hchild = p->next;
1666 if (EQ (window, par->vchild))
1667 par->vchild = p->next;
1668
1669 /* Find one of our siblings to give our space to. */
1670 sib = p->prev;
1671 if (NILP (sib))
1672 {
1673 /* If p gives its space to its next sibling, that sibling needs
1674 to have its top/left side pulled back to where p's is.
1675 set_window_{height,width} will re-position the sibling's
1676 children. */
1677 sib = p->next;
1678 XWINDOW (sib)->top_line = p->top_line;
1679 XWINDOW (sib)->left_col = p->left_col;
1680 }
1681
1682 /* Stretch that sibling. */
1683 if (!NILP (par->vchild))
1684 set_window_height (sib,
1685 XFASTINT (XWINDOW (sib)->total_lines) + XFASTINT (p->total_lines),
1686 1);
1687 if (!NILP (par->hchild))
1688 set_window_width (sib,
1689 XFASTINT (XWINDOW (sib)->total_cols) + XFASTINT (p->total_cols),
1690 1);
1691
1692 /* If parent now has only one child,
1693 put the child into the parent's place. */
1694 tem = par->hchild;
1695 if (NILP (tem))
1696 tem = par->vchild;
1697 if (NILP (XWINDOW (tem)->next)) {
1698 replace_window (parent, tem);
1699 par = XWINDOW (tem);
1700 }
1701
1702 /* Since we may be deleting combination windows, we must make sure that
1703 not only p but all its children have been marked as deleted. */
1704 if (! NILP (p->hchild))
1705 delete_all_subwindows (XWINDOW (p->hchild));
1706 else if (! NILP (p->vchild))
1707 delete_all_subwindows (XWINDOW (p->vchild));
1708
1709 /* Mark this window as deleted. */
1710 p->buffer = p->hchild = p->vchild = Qnil;
1711
1712 if (! NILP (par->parent))
1713 par = XWINDOW (par->parent);
1714
1715 /* Check if we have a v/hchild with a v/hchild. In that case remove
1716 one of them. */
1717
1718 if (! NILP (par->vchild) && ! NILP (XWINDOW (par->vchild)->vchild))
1719 {
1720 p = XWINDOW (par->vchild);
1721 par->vchild = p->vchild;
1722 tem = p->vchild;
1723 }
1724 else if (! NILP (par->hchild) && ! NILP (XWINDOW (par->hchild)->hchild))
1725 {
1726 p = XWINDOW (par->hchild);
1727 par->hchild = p->hchild;
1728 tem = p->hchild;
1729 }
1730 else
1731 p = 0;
1732
1733 if (p)
1734 {
1735 while (! NILP (tem)) {
1736 XWINDOW (tem)->parent = p->parent;
1737 if (NILP (XWINDOW (tem)->next))
1738 break;
1739 tem = XWINDOW (tem)->next;
1740 }
1741 if (! NILP (tem)) {
1742 /* The next of the v/hchild we are removing is now the next of the
1743 last child for the v/hchild:
1744 Before v/hchild -> v/hchild -> next1 -> next2
1745 |
1746 -> next3
1747 After: v/hchild -> next1 -> next2 -> next3
1748 */
1749 XWINDOW (tem)->next = p->next;
1750 if (! NILP (p->next))
1751 XWINDOW (p->next)->prev = tem;
1752 }
1753 p->next = p->prev = p->vchild = p->hchild = p->buffer = Qnil;
1754 }
1755
1756
1757 /* Adjust glyph matrices. */
1758 adjust_glyphs (f);
1759 UNBLOCK_INPUT;
1760 }
1761
1762
1763 \f
1764 /***********************************************************************
1765 Window List
1766 ***********************************************************************/
1767
1768 /* Add window W to *USER_DATA. USER_DATA is actually a Lisp_Object
1769 pointer. This is a callback function for foreach_window, used in
1770 function window_list. */
1771
1772 static int
1773 add_window_to_list (w, user_data)
1774 struct window *w;
1775 void *user_data;
1776 {
1777 Lisp_Object *list = (Lisp_Object *) user_data;
1778 Lisp_Object window;
1779 XSETWINDOW (window, w);
1780 *list = Fcons (window, *list);
1781 return 1;
1782 }
1783
1784
1785 /* Return a list of all windows, for use by next_window. If
1786 Vwindow_list is a list, return that list. Otherwise, build a new
1787 list, cache it in Vwindow_list, and return that. */
1788
1789 static Lisp_Object
1790 window_list ()
1791 {
1792 if (!CONSP (Vwindow_list))
1793 {
1794 Lisp_Object tail;
1795
1796 Vwindow_list = Qnil;
1797 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
1798 {
1799 Lisp_Object args[2];
1800
1801 /* We are visiting windows in canonical order, and add
1802 new windows at the front of args[1], which means we
1803 have to reverse this list at the end. */
1804 args[1] = Qnil;
1805 foreach_window (XFRAME (XCAR (tail)), add_window_to_list, &args[1]);
1806 args[0] = Vwindow_list;
1807 args[1] = Fnreverse (args[1]);
1808 Vwindow_list = Fnconc (2, args);
1809 }
1810 }
1811
1812 return Vwindow_list;
1813 }
1814
1815
1816 /* Value is non-zero if WINDOW satisfies the constraints given by
1817 OWINDOW, MINIBUF and ALL_FRAMES.
1818
1819 MINIBUF t means WINDOW may be minibuffer windows.
1820 `lambda' means WINDOW may not be a minibuffer window.
1821 a window means a specific minibuffer window
1822
1823 ALL_FRAMES t means search all frames,
1824 nil means search just current frame,
1825 `visible' means search just visible frames,
1826 0 means search visible and iconified frames,
1827 a window means search the frame that window belongs to,
1828 a frame means consider windows on that frame, only. */
1829
1830 static int
1831 candidate_window_p (window, owindow, minibuf, all_frames)
1832 Lisp_Object window, owindow, minibuf, all_frames;
1833 {
1834 struct window *w = XWINDOW (window);
1835 struct frame *f = XFRAME (w->frame);
1836 int candidate_p = 1;
1837
1838 if (!BUFFERP (w->buffer))
1839 candidate_p = 0;
1840 else if (MINI_WINDOW_P (w)
1841 && (EQ (minibuf, Qlambda)
1842 || (WINDOWP (minibuf) && !EQ (minibuf, window))))
1843 {
1844 /* If MINIBUF is `lambda' don't consider any mini-windows.
1845 If it is a window, consider only that one. */
1846 candidate_p = 0;
1847 }
1848 else if (EQ (all_frames, Qt))
1849 candidate_p = 1;
1850 else if (NILP (all_frames))
1851 {
1852 xassert (WINDOWP (owindow));
1853 candidate_p = EQ (w->frame, XWINDOW (owindow)->frame);
1854 }
1855 else if (EQ (all_frames, Qvisible))
1856 {
1857 FRAME_SAMPLE_VISIBILITY (f);
1858 candidate_p = FRAME_VISIBLE_P (f)
1859 && (FRAME_TERMINAL (XFRAME (w->frame))
1860 == FRAME_TERMINAL (XFRAME (selected_frame)));
1861
1862 }
1863 else if (INTEGERP (all_frames) && XINT (all_frames) == 0)
1864 {
1865 FRAME_SAMPLE_VISIBILITY (f);
1866 candidate_p = (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f)
1867 #ifdef HAVE_X_WINDOWS
1868 /* Yuck!! If we've just created the frame and the
1869 window-manager requested the user to place it
1870 manually, the window may still not be considered
1871 `visible'. I'd argue it should be at least
1872 something like `iconified', but don't know how to do
1873 that yet. --Stef */
1874 || (FRAME_X_P (f) && f->output_data.x->asked_for_visible
1875 && !f->output_data.x->has_been_visible)
1876 #endif
1877 )
1878 && (FRAME_TERMINAL (XFRAME (w->frame))
1879 == FRAME_TERMINAL (XFRAME (selected_frame)));
1880 }
1881 else if (WINDOWP (all_frames))
1882 candidate_p = (EQ (FRAME_MINIBUF_WINDOW (f), all_frames)
1883 || EQ (XWINDOW (all_frames)->frame, w->frame)
1884 || EQ (XWINDOW (all_frames)->frame, FRAME_FOCUS_FRAME (f)));
1885 else if (FRAMEP (all_frames))
1886 candidate_p = EQ (all_frames, w->frame);
1887
1888 return candidate_p;
1889 }
1890
1891
1892 /* Decode arguments as allowed by Fnext_window, Fprevious_window, and
1893 Fwindow_list. See there for the meaning of WINDOW, MINIBUF, and
1894 ALL_FRAMES. */
1895
1896 static void
1897 decode_next_window_args (window, minibuf, all_frames)
1898 Lisp_Object *window, *minibuf, *all_frames;
1899 {
1900 if (NILP (*window))
1901 *window = selected_window;
1902 else
1903 CHECK_LIVE_WINDOW (*window);
1904
1905 /* MINIBUF nil may or may not include minibuffers. Decide if it
1906 does. */
1907 if (NILP (*minibuf))
1908 *minibuf = minibuf_level ? minibuf_window : Qlambda;
1909 else if (!EQ (*minibuf, Qt))
1910 *minibuf = Qlambda;
1911
1912 /* Now *MINIBUF can be t => count all minibuffer windows, `lambda'
1913 => count none of them, or a specific minibuffer window (the
1914 active one) to count. */
1915
1916 /* ALL_FRAMES nil doesn't specify which frames to include. */
1917 if (NILP (*all_frames))
1918 *all_frames = (!EQ (*minibuf, Qlambda)
1919 ? FRAME_MINIBUF_WINDOW (XFRAME (XWINDOW (*window)->frame))
1920 : Qnil);
1921 else if (EQ (*all_frames, Qvisible))
1922 ;
1923 else if (EQ (*all_frames, make_number (0)))
1924 ;
1925 else if (FRAMEP (*all_frames))
1926 ;
1927 else if (!EQ (*all_frames, Qt))
1928 *all_frames = Qnil;
1929
1930 /* Now *ALL_FRAMES is t meaning search all frames, nil meaning
1931 search just current frame, `visible' meaning search just visible
1932 frames, 0 meaning search visible and iconified frames, or a
1933 window, meaning search the frame that window belongs to, or a
1934 frame, meaning consider windows on that frame, only. */
1935 }
1936
1937
1938 /* Return the next or previous window of WINDOW in cyclic ordering
1939 of windows. NEXT_P non-zero means return the next window. See the
1940 documentation string of next-window for the meaning of MINIBUF and
1941 ALL_FRAMES. */
1942
1943 static Lisp_Object
1944 next_window (window, minibuf, all_frames, next_p)
1945 Lisp_Object window, minibuf, all_frames;
1946 int next_p;
1947 {
1948 decode_next_window_args (&window, &minibuf, &all_frames);
1949
1950 /* If ALL_FRAMES is a frame, and WINDOW isn't on that frame, just
1951 return the first window on the frame. */
1952 if (FRAMEP (all_frames)
1953 && !EQ (all_frames, XWINDOW (window)->frame))
1954 return Fframe_first_window (all_frames);
1955
1956 if (next_p)
1957 {
1958 Lisp_Object list;
1959
1960 /* Find WINDOW in the list of all windows. */
1961 list = Fmemq (window, window_list ());
1962
1963 /* Scan forward from WINDOW to the end of the window list. */
1964 if (CONSP (list))
1965 for (list = XCDR (list); CONSP (list); list = XCDR (list))
1966 if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
1967 break;
1968
1969 /* Scan from the start of the window list up to WINDOW. */
1970 if (!CONSP (list))
1971 for (list = Vwindow_list;
1972 CONSP (list) && !EQ (XCAR (list), window);
1973 list = XCDR (list))
1974 if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
1975 break;
1976
1977 if (CONSP (list))
1978 window = XCAR (list);
1979 }
1980 else
1981 {
1982 Lisp_Object candidate, list;
1983
1984 /* Scan through the list of windows for candidates. If there are
1985 candidate windows in front of WINDOW, the last one of these
1986 is the one we want. If there are candidates following WINDOW
1987 in the list, again the last one of these is the one we want. */
1988 candidate = Qnil;
1989 for (list = window_list (); CONSP (list); list = XCDR (list))
1990 {
1991 if (EQ (XCAR (list), window))
1992 {
1993 if (WINDOWP (candidate))
1994 break;
1995 }
1996 else if (candidate_window_p (XCAR (list), window, minibuf,
1997 all_frames))
1998 candidate = XCAR (list);
1999 }
2000
2001 if (WINDOWP (candidate))
2002 window = candidate;
2003 }
2004
2005 return window;
2006 }
2007
2008
2009 DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
2010 doc: /* Return window following WINDOW in cyclic ordering of windows.
2011 WINDOW defaults to the selected window. The optional arguments
2012 MINIBUF and ALL-FRAMES specify the set of windows to consider.
2013
2014 MINIBUF t means consider the minibuffer window even if the
2015 minibuffer is not active. MINIBUF nil or omitted means consider
2016 the minibuffer window only if the minibuffer is active. Any
2017 other value means do not consider the minibuffer window even if
2018 the minibuffer is active.
2019
2020 Several frames may share a single minibuffer; if the minibuffer
2021 is active, all windows on all frames that share that minibuffer
2022 are considered too. Therefore, if you are using a separate
2023 minibuffer frame and the minibuffer is active and MINIBUF says it
2024 counts, `next-window' considers the windows in the frame from
2025 which you entered the minibuffer, as well as the minibuffer
2026 window.
2027
2028 ALL-FRAMES nil or omitted means consider all windows on WINDOW's
2029 frame, plus the minibuffer window if specified by the MINIBUF
2030 argument, see above. If the minibuffer counts, consider all
2031 windows on all frames that share that minibuffer too.
2032 ALL-FRAMES t means consider all windows on all existing frames.
2033 ALL-FRAMES `visible' means consider all windows on all visible
2034 frames.
2035 ALL-FRAMES 0 means consider all windows on all visible and
2036 iconified frames.
2037 ALL-FRAMES a frame means consider all windows on that frame only.
2038 Anything else means consider all windows on WINDOW's frame and no
2039 others.
2040
2041 If you use consistent values for MINIBUF and ALL-FRAMES, you can use
2042 `next-window' to iterate through the entire cycle of acceptable
2043 windows, eventually ending up back at the window you started with.
2044 `previous-window' traverses the same cycle, in the reverse order. */)
2045 (window, minibuf, all_frames)
2046 Lisp_Object window, minibuf, all_frames;
2047 {
2048 return next_window (window, minibuf, all_frames, 1);
2049 }
2050
2051
2052 DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
2053 doc: /* Return window preceding WINDOW in cyclic ordering of windows.
2054 WINDOW defaults to the selected window. The optional arguments
2055 MINIBUF and ALL-FRAMES specify the set of windows to consider.
2056 For the precise meaning of these arguments see `next-window'.
2057
2058 If you use consistent values for MINIBUF and ALL-FRAMES, you can
2059 use `previous-window' to iterate through the entire cycle of
2060 acceptable windows, eventually ending up back at the window you
2061 started with. `next-window' traverses the same cycle, in the
2062 reverse order. */)
2063 (window, minibuf, all_frames)
2064 Lisp_Object window, minibuf, all_frames;
2065 {
2066 return next_window (window, minibuf, all_frames, 0);
2067 }
2068
2069
2070 DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
2071 doc: /* Select another window in cyclic ordering of windows.
2072 COUNT specifies the number of windows to skip, starting with the
2073 selected window, before making the selection. If COUNT is
2074 positive, skip COUNT windows forwards. If COUNT is negative,
2075 skip -COUNT windows backwards. COUNT zero means do not skip any
2076 window, so select the selected window. In an interactive call,
2077 COUNT is the numeric prefix argument. Return nil.
2078
2079 This function uses `next-window' for finding the window to select.
2080 The argument ALL-FRAMES has the same meaning as in `next-window',
2081 but the MINIBUF argument of `next-window' is always effectively
2082 nil. */)
2083 (count, all_frames)
2084 Lisp_Object count, all_frames;
2085 {
2086 Lisp_Object window;
2087 int i;
2088
2089 CHECK_NUMBER (count);
2090 window = selected_window;
2091
2092 for (i = XINT (count); i > 0; --i)
2093 window = Fnext_window (window, Qnil, all_frames);
2094 for (; i < 0; ++i)
2095 window = Fprevious_window (window, Qnil, all_frames);
2096
2097 Fselect_window (window, Qnil);
2098 return Qnil;
2099 }
2100
2101
2102 DEFUN ("window-list", Fwindow_list, Swindow_list, 0, 3, 0,
2103 doc: /* Return a list of windows on FRAME, starting with WINDOW.
2104 FRAME nil or omitted means use the selected frame.
2105 WINDOW nil or omitted means use the selected window.
2106 MINIBUF t means include the minibuffer window, even if it isn't active.
2107 MINIBUF nil or omitted means include the minibuffer window only
2108 if it's active.
2109 MINIBUF neither nil nor t means never include the minibuffer window. */)
2110 (frame, minibuf, window)
2111 Lisp_Object frame, minibuf, window;
2112 {
2113 if (NILP (window))
2114 window = FRAMEP (frame) ? XFRAME (frame)->selected_window : selected_window;
2115 CHECK_WINDOW (window);
2116 if (NILP (frame))
2117 frame = selected_frame;
2118
2119 if (!EQ (frame, XWINDOW (window)->frame))
2120 error ("Window is on a different frame");
2121
2122 return window_list_1 (window, minibuf, frame);
2123 }
2124
2125
2126 /* Return a list of windows in cyclic ordering. Arguments are like
2127 for `next-window'. */
2128
2129 static Lisp_Object
2130 window_list_1 (window, minibuf, all_frames)
2131 Lisp_Object window, minibuf, all_frames;
2132 {
2133 Lisp_Object tail, list, rest;
2134
2135 decode_next_window_args (&window, &minibuf, &all_frames);
2136 list = Qnil;
2137
2138 for (tail = window_list (); CONSP (tail); tail = XCDR (tail))
2139 if (candidate_window_p (XCAR (tail), window, minibuf, all_frames))
2140 list = Fcons (XCAR (tail), list);
2141
2142 /* Rotate the list to start with WINDOW. */
2143 list = Fnreverse (list);
2144 rest = Fmemq (window, list);
2145 if (!NILP (rest) && !EQ (rest, list))
2146 {
2147 for (tail = list; !EQ (XCDR (tail), rest); tail = XCDR (tail))
2148 ;
2149 XSETCDR (tail, Qnil);
2150 list = nconc2 (rest, list);
2151 }
2152 return list;
2153 }
2154
2155
2156 \f
2157 /* Look at all windows, performing an operation specified by TYPE
2158 with argument OBJ.
2159 If FRAMES is Qt, look at all frames;
2160 Qnil, look at just the selected frame;
2161 Qvisible, look at visible frames;
2162 a frame, just look at windows on that frame.
2163 If MINI is non-zero, perform the operation on minibuffer windows too. */
2164
2165 enum window_loop
2166 {
2167 WINDOW_LOOP_UNUSED,
2168 GET_BUFFER_WINDOW, /* Arg is buffer */
2169 GET_LRU_WINDOW, /* Arg is t for full-width windows only */
2170 DELETE_OTHER_WINDOWS, /* Arg is window not to delete */
2171 DELETE_BUFFER_WINDOWS, /* Arg is buffer */
2172 GET_LARGEST_WINDOW,
2173 UNSHOW_BUFFER, /* Arg is buffer */
2174 REDISPLAY_BUFFER_WINDOWS, /* Arg is buffer */
2175 CHECK_ALL_WINDOWS
2176 };
2177
2178 static Lisp_Object
2179 window_loop (type, obj, mini, frames)
2180 enum window_loop type;
2181 Lisp_Object obj, frames;
2182 int mini;
2183 {
2184 Lisp_Object window, windows, best_window, frame_arg;
2185 struct frame *f;
2186 struct gcpro gcpro1;
2187
2188 /* If we're only looping through windows on a particular frame,
2189 frame points to that frame. If we're looping through windows
2190 on all frames, frame is 0. */
2191 if (FRAMEP (frames))
2192 f = XFRAME (frames);
2193 else if (NILP (frames))
2194 f = SELECTED_FRAME ();
2195 else
2196 f = NULL;
2197
2198 if (f)
2199 frame_arg = Qlambda;
2200 else if (EQ (frames, make_number (0)))
2201 frame_arg = frames;
2202 else if (EQ (frames, Qvisible))
2203 frame_arg = frames;
2204 else
2205 frame_arg = Qt;
2206
2207 /* frame_arg is Qlambda to stick to one frame,
2208 Qvisible to consider all visible frames,
2209 or Qt otherwise. */
2210
2211 /* Pick a window to start with. */
2212 if (WINDOWP (obj))
2213 window = obj;
2214 else if (f)
2215 window = FRAME_SELECTED_WINDOW (f);
2216 else
2217 window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
2218
2219 windows = window_list_1 (window, mini ? Qt : Qnil, frame_arg);
2220 GCPRO1 (windows);
2221 best_window = Qnil;
2222
2223 for (; CONSP (windows); windows = XCDR (windows))
2224 {
2225 struct window *w;
2226
2227 window = XCAR (windows);
2228 w = XWINDOW (window);
2229
2230 /* Note that we do not pay attention here to whether the frame
2231 is visible, since Fwindow_list skips non-visible frames if
2232 that is desired, under the control of frame_arg. */
2233 if (!MINI_WINDOW_P (w)
2234 /* For UNSHOW_BUFFER, we must always consider all windows. */
2235 || type == UNSHOW_BUFFER
2236 || (mini && minibuf_level > 0))
2237 switch (type)
2238 {
2239 case GET_BUFFER_WINDOW:
2240 if (EQ (w->buffer, obj)
2241 /* Don't find any minibuffer window
2242 except the one that is currently in use. */
2243 && (MINI_WINDOW_P (w)
2244 ? EQ (window, minibuf_window)
2245 : 1))
2246 {
2247 if (NILP (best_window))
2248 best_window = window;
2249 else if (EQ (window, selected_window))
2250 /* Prefer to return selected-window. */
2251 RETURN_UNGCPRO (window);
2252 else if (EQ (Fwindow_frame (window), selected_frame))
2253 /* Prefer windows on the current frame. */
2254 best_window = window;
2255 }
2256 break;
2257
2258 case GET_LRU_WINDOW:
2259 /* `obj' is an integer encoding a bitvector.
2260 `obj & 1' means consider only full-width windows.
2261 `obj & 2' means consider also dedicated windows. */
2262 if (((XINT (obj) & 1) && !WINDOW_FULL_WIDTH_P (w))
2263 || (!(XINT (obj) & 2) && !NILP (w->dedicated))
2264 /* Minibuffer windows are always ignored. */
2265 || MINI_WINDOW_P (w))
2266 break;
2267 if (NILP (best_window)
2268 || (XFASTINT (XWINDOW (best_window)->use_time)
2269 > XFASTINT (w->use_time)))
2270 best_window = window;
2271 break;
2272
2273 case DELETE_OTHER_WINDOWS:
2274 if (!EQ (window, obj))
2275 Fdelete_window (window);
2276 break;
2277
2278 case DELETE_BUFFER_WINDOWS:
2279 if (EQ (w->buffer, obj))
2280 {
2281 struct frame *f = XFRAME (WINDOW_FRAME (w));
2282
2283 /* If this window is dedicated, and in a frame of its own,
2284 kill the frame. */
2285 if (EQ (window, FRAME_ROOT_WINDOW (f))
2286 && !NILP (w->dedicated)
2287 && other_visible_frames (f))
2288 {
2289 /* Skip the other windows on this frame.
2290 There might be one, the minibuffer! */
2291 while (CONSP (XCDR (windows))
2292 && EQ (XWINDOW (XCAR (windows))->frame,
2293 XWINDOW (XCAR (XCDR (windows)))->frame))
2294 windows = XCDR (windows);
2295
2296 /* Now we can safely delete the frame. */
2297 delete_frame (w->frame, Qnil);
2298 }
2299 else if (NILP (w->parent))
2300 {
2301 /* If we're deleting the buffer displayed in the
2302 only window on the frame, find a new buffer to
2303 display there. */
2304 Lisp_Object buffer;
2305 buffer = Fother_buffer (obj, Qnil, w->frame);
2306 /* Reset dedicated state of window. */
2307 w->dedicated = Qnil;
2308 Fset_window_buffer (window, buffer, Qnil);
2309 if (EQ (window, selected_window))
2310 Fset_buffer (w->buffer);
2311 }
2312 else
2313 Fdelete_window (window);
2314 }
2315 break;
2316
2317 case GET_LARGEST_WINDOW:
2318 { /* nil `obj' means to ignore dedicated windows. */
2319 /* Ignore dedicated windows and minibuffers. */
2320 if (MINI_WINDOW_P (w) || (NILP (obj) && !NILP (w->dedicated)))
2321 break;
2322
2323 if (NILP (best_window))
2324 best_window = window;
2325 else
2326 {
2327 struct window *b = XWINDOW (best_window);
2328 if (XFASTINT (w->total_lines) * XFASTINT (w->total_cols)
2329 > XFASTINT (b->total_lines) * XFASTINT (b->total_cols))
2330 best_window = window;
2331 }
2332 }
2333 break;
2334
2335 case UNSHOW_BUFFER:
2336 if (EQ (w->buffer, obj))
2337 {
2338 Lisp_Object buffer;
2339 struct frame *f = XFRAME (w->frame);
2340
2341 /* Find another buffer to show in this window. */
2342 buffer = Fother_buffer (obj, Qnil, w->frame);
2343
2344 /* If this window is dedicated, and in a frame of its own,
2345 kill the frame. */
2346 if (EQ (window, FRAME_ROOT_WINDOW (f))
2347 && !NILP (w->dedicated)
2348 && other_visible_frames (f))
2349 {
2350 /* Skip the other windows on this frame.
2351 There might be one, the minibuffer! */
2352 while (CONSP (XCDR (windows))
2353 && EQ (XWINDOW (XCAR (windows))->frame,
2354 XWINDOW (XCAR (XCDR (windows)))->frame))
2355 windows = XCDR (windows);
2356
2357 /* Now we can safely delete the frame. */
2358 delete_frame (w->frame, Qnil);
2359 }
2360 else if (!NILP (w->dedicated) && !NILP (w->parent))
2361 {
2362 Lisp_Object window;
2363 XSETWINDOW (window, w);
2364 /* If this window is dedicated and not the only window
2365 in its frame, then kill it. */
2366 Fdelete_window (window);
2367 }
2368 else
2369 {
2370 /* Otherwise show a different buffer in the window. */
2371 w->dedicated = Qnil;
2372 Fset_window_buffer (window, buffer, Qnil);
2373 if (EQ (window, selected_window))
2374 Fset_buffer (w->buffer);
2375 }
2376 }
2377 break;
2378
2379 case REDISPLAY_BUFFER_WINDOWS:
2380 if (EQ (w->buffer, obj))
2381 {
2382 mark_window_display_accurate (window, 0);
2383 w->update_mode_line = Qt;
2384 XBUFFER (obj)->prevent_redisplay_optimizations_p = 1;
2385 ++update_mode_lines;
2386 best_window = window;
2387 }
2388 break;
2389
2390 /* Check for a window that has a killed buffer. */
2391 case CHECK_ALL_WINDOWS:
2392 if (! NILP (w->buffer)
2393 && NILP (XBUFFER (w->buffer)->name))
2394 abort ();
2395 break;
2396
2397 case WINDOW_LOOP_UNUSED:
2398 break;
2399 }
2400 }
2401
2402 UNGCPRO;
2403 return best_window;
2404 }
2405
2406 /* Used for debugging. Abort if any window has a dead buffer. */
2407
2408 void
2409 check_all_windows ()
2410 {
2411 window_loop (CHECK_ALL_WINDOWS, Qnil, 1, Qt);
2412 }
2413
2414 DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 2, 0,
2415 doc: /* Return the window least recently selected or used for display.
2416 \(LRU means Least Recently Used.)
2417
2418 Return a full-width window if possible.
2419 A minibuffer window is never a candidate.
2420 A dedicated window is never a candidate, unless DEDICATED is non-nil,
2421 so if all windows are dedicated, the value is nil.
2422 If optional argument FRAME is `visible', search all visible frames.
2423 If FRAME is 0, search all visible and iconified frames.
2424 If FRAME is t, search all frames.
2425 If FRAME is nil, search only the selected frame.
2426 If FRAME is a frame, search only that frame. */)
2427 (frame, dedicated)
2428 Lisp_Object frame, dedicated;
2429 {
2430 register Lisp_Object w;
2431 /* First try for a window that is full-width */
2432 w = window_loop (GET_LRU_WINDOW,
2433 NILP (dedicated) ? make_number (1) : make_number (3),
2434 0, frame);
2435 if (!NILP (w) && !EQ (w, selected_window))
2436 return w;
2437 /* If none of them, try the rest */
2438 return window_loop (GET_LRU_WINDOW,
2439 NILP (dedicated) ? make_number (0) : make_number (2),
2440 0, frame);
2441 }
2442
2443 DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 2, 0,
2444 doc: /* Return the largest window in area.
2445 A minibuffer window is never a candidate.
2446 A dedicated window is never a candidate unless DEDICATED is non-nil,
2447 so if all windows are dedicated, the value is nil.
2448 If optional argument FRAME is `visible', search all visible frames.
2449 If FRAME is 0, search all visible and iconified frames.
2450 If FRAME is t, search all frames.
2451 If FRAME is nil, search only the selected frame.
2452 If FRAME is a frame, search only that frame. */)
2453 (frame, dedicated)
2454 Lisp_Object frame, dedicated;
2455 {
2456 return window_loop (GET_LARGEST_WINDOW, dedicated, 0,
2457 frame);
2458 }
2459
2460 DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 0, 2, 0,
2461 doc: /* Return a window currently displaying BUFFER-OR-NAME, or nil if none.
2462 BUFFER-OR-NAME may be a buffer or a buffer name and defaults to the
2463 current buffer.
2464 If optional argument FRAME is `visible', search all visible frames.
2465 If optional argument FRAME is 0, search all visible and iconified frames.
2466 If FRAME is t, search all frames.
2467 If FRAME is nil, search only the selected frame.
2468 If FRAME is a frame, search only that frame. */)
2469 (buffer_or_name, frame)
2470 Lisp_Object buffer_or_name, frame;
2471 {
2472 Lisp_Object buffer;
2473
2474 if (NILP (buffer_or_name))
2475 buffer = Fcurrent_buffer ();
2476 else
2477 buffer = Fget_buffer (buffer_or_name);
2478
2479 if (BUFFERP (buffer))
2480 return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame);
2481 else
2482 return Qnil;
2483 }
2484
2485 DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
2486 0, 1, "",
2487 doc: /* Make WINDOW (or the selected window) fill its frame.
2488 Only the frame WINDOW is on is affected.
2489 This function tries to reduce display jumps by keeping the text
2490 previously visible in WINDOW in the same place on the frame. Doing this
2491 depends on the value of (window-start WINDOW), so if calling this
2492 function in a program gives strange scrolling, make sure the
2493 window-start value is reasonable when this function is called. */)
2494 (window)
2495 Lisp_Object window;
2496 {
2497 struct window *w;
2498 int startpos;
2499 int top, new_top;
2500
2501 if (NILP (window))
2502 window = selected_window;
2503 else
2504 CHECK_LIVE_WINDOW (window);
2505 w = XWINDOW (window);
2506
2507 startpos = marker_position (w->start);
2508 top = WINDOW_TOP_EDGE_LINE (w) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
2509
2510 if (MINI_WINDOW_P (w) && top > 0)
2511 error ("Can't expand minibuffer to full frame");
2512
2513 window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_FRAME (w));
2514
2515 /* Try to minimize scrolling, by setting the window start to the point
2516 will cause the text at the old window start to be at the same place
2517 on the frame. But don't try to do this if the window start is
2518 outside the visible portion (as might happen when the display is
2519 not current, due to typeahead). */
2520 new_top = WINDOW_TOP_EDGE_LINE (w) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
2521 if (new_top != top
2522 && startpos >= BUF_BEGV (XBUFFER (w->buffer))
2523 && startpos <= BUF_ZV (XBUFFER (w->buffer)))
2524 {
2525 struct position pos;
2526 struct buffer *obuf = current_buffer;
2527
2528 Fset_buffer (w->buffer);
2529 /* This computation used to temporarily move point, but that can
2530 have unwanted side effects due to text properties. */
2531 pos = *vmotion (startpos, -top, w);
2532
2533 set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
2534 w->window_end_valid = Qnil;
2535 w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
2536 || FETCH_BYTE (pos.bytepos - 1) == '\n') ? Qt
2537 : Qnil);
2538 /* We need to do this, so that the window-scroll-functions
2539 get called. */
2540 w->optional_new_start = Qt;
2541
2542 set_buffer_internal (obuf);
2543 }
2544
2545 return Qnil;
2546 }
2547
2548 DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
2549 0, 2, "bDelete windows on (buffer): ",
2550 doc: /* Delete all windows showing BUFFER-OR-NAME.
2551 BUFFER-OR-NAME may be a buffer or the name of an existing buffer and
2552 defaults to the current buffer.
2553
2554 Optional second argument FRAME controls which frames are affected.
2555 If optional argument FRAME is `visible', search all visible frames.
2556 If FRAME is 0, search all visible and iconified frames.
2557 If FRAME is nil, search all frames.
2558 If FRAME is t, search only the selected frame.
2559 If FRAME is a frame, search only that frame.
2560 When a window showing BUFFER-OR-NAME is dedicated and the only window of
2561 its frame, that frame is deleted when there are other frames left. */)
2562 (buffer_or_name, frame)
2563 Lisp_Object buffer_or_name, frame;
2564 {
2565 Lisp_Object buffer;
2566
2567 /* FRAME uses t and nil to mean the opposite of what window_loop
2568 expects. */
2569 if (NILP (frame))
2570 frame = Qt;
2571 else if (EQ (frame, Qt))
2572 frame = Qnil;
2573
2574 if (NILP (buffer_or_name))
2575 buffer = Fcurrent_buffer ();
2576 else
2577 {
2578 buffer = Fget_buffer (buffer_or_name);
2579 CHECK_BUFFER (buffer);
2580 }
2581
2582 window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
2583
2584 return Qnil;
2585 }
2586
2587 DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
2588 Sreplace_buffer_in_windows,
2589 0, 1, "bReplace buffer in windows: ",
2590 doc: /* Replace BUFFER-OR-NAME with some other buffer in all windows showing it.
2591 BUFFER-OR-NAME may be a buffer or the name of an existing buffer and
2592 defaults to the current buffer.
2593
2594 When a window showing BUFFER-OR-NAME is dedicated that window is
2595 deleted. If that window is the only window on its frame, that frame is
2596 deleted too when there are other frames left. If there are no other
2597 frames left, some other buffer is displayed in that window. */)
2598 (buffer_or_name)
2599 Lisp_Object buffer_or_name;
2600 {
2601 Lisp_Object buffer;
2602
2603 if (NILP (buffer_or_name))
2604 buffer = Fcurrent_buffer ();
2605 else
2606 {
2607 buffer = Fget_buffer (buffer_or_name);
2608 CHECK_BUFFER (buffer);
2609 }
2610
2611 window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
2612
2613 return Qnil;
2614 }
2615
2616 /* Replace BUFFER with some other buffer in all windows
2617 of all frames, even those on other keyboards. */
2618
2619 void
2620 replace_buffer_in_all_windows (buffer)
2621 Lisp_Object buffer;
2622 {
2623 Lisp_Object tail, frame;
2624
2625 /* A single call to window_loop won't do the job
2626 because it only considers frames on the current keyboard.
2627 So loop manually over frames, and handle each one. */
2628 FOR_EACH_FRAME (tail, frame)
2629 window_loop (UNSHOW_BUFFER, buffer, 1, frame);
2630 }
2631 \f
2632 /* Set the height of WINDOW and all its inferiors. */
2633
2634 /* The smallest acceptable dimensions for a window. Anything smaller
2635 might crash Emacs. */
2636
2637 #define MIN_SAFE_WINDOW_WIDTH (2)
2638 #define MIN_SAFE_WINDOW_HEIGHT (1)
2639
2640 /* For wp non-zero the total number of columns of window w. Otherwise
2641 the total number of lines of w. */
2642
2643 #define WINDOW_TOTAL_SIZE(w, wp) \
2644 (wp ? WINDOW_TOTAL_COLS (w) : WINDOW_TOTAL_LINES (w))
2645
2646 /* If *ROWS or *COLS are too small a size for FRAME, set them to the
2647 minimum allowable size. */
2648
2649 void
2650 check_frame_size (frame, rows, cols)
2651 FRAME_PTR frame;
2652 int *rows, *cols;
2653 {
2654 /* For height, we have to see:
2655 how many windows the frame has at minimum (one or two),
2656 and whether it has a menu bar or other special stuff at the top. */
2657 int min_height
2658 = ((FRAME_MINIBUF_ONLY_P (frame) || ! FRAME_HAS_MINIBUF_P (frame))
2659 ? MIN_SAFE_WINDOW_HEIGHT
2660 : 2 * MIN_SAFE_WINDOW_HEIGHT);
2661
2662 if (FRAME_TOP_MARGIN (frame) > 0)
2663 min_height += FRAME_TOP_MARGIN (frame);
2664
2665 if (*rows < min_height)
2666 *rows = min_height;
2667 if (*cols < MIN_SAFE_WINDOW_WIDTH)
2668 *cols = MIN_SAFE_WINDOW_WIDTH;
2669 }
2670
2671 /* Value is non-zero if window W is fixed-size. WIDTH_P non-zero means
2672 check if W's width can be changed, otherwise check W's height.
2673 CHECK_SIBLINGS_P non-zero means check resizablity of WINDOW's
2674 siblings, too. If none of the siblings is resizable, WINDOW isn't
2675 either. */
2676
2677 static int
2678 window_fixed_size_p (w, width_p, check_siblings_p)
2679 struct window *w;
2680 int width_p, check_siblings_p;
2681 {
2682 int fixed_p;
2683 struct window *c;
2684
2685 if (!NILP (w->hchild))
2686 {
2687 c = XWINDOW (w->hchild);
2688
2689 if (width_p)
2690 {
2691 /* A horizontal combination is fixed-width if all of if its
2692 children are. */
2693 while (c && window_fixed_size_p (c, width_p, 0))
2694 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2695 fixed_p = c == NULL;
2696 }
2697 else
2698 {
2699 /* A horizontal combination is fixed-height if one of if its
2700 children is. */
2701 while (c && !window_fixed_size_p (c, width_p, 0))
2702 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2703 fixed_p = c != NULL;
2704 }
2705 }
2706 else if (!NILP (w->vchild))
2707 {
2708 c = XWINDOW (w->vchild);
2709
2710 if (width_p)
2711 {
2712 /* A vertical combination is fixed-width if one of if its
2713 children is. */
2714 while (c && !window_fixed_size_p (c, width_p, 0))
2715 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2716 fixed_p = c != NULL;
2717 }
2718 else
2719 {
2720 /* A vertical combination is fixed-height if all of if its
2721 children are. */
2722 while (c && window_fixed_size_p (c, width_p, 0))
2723 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2724 fixed_p = c == NULL;
2725 }
2726 }
2727 else if (BUFFERP (w->buffer))
2728 {
2729 struct buffer *old = current_buffer;
2730 Lisp_Object val;
2731
2732 current_buffer = XBUFFER (w->buffer);
2733 val = find_symbol_value (Qwindow_size_fixed);
2734 current_buffer = old;
2735
2736 fixed_p = 0;
2737 if (!EQ (val, Qunbound))
2738 {
2739 fixed_p = !NILP (val);
2740
2741 if (fixed_p
2742 && ((EQ (val, Qheight) && width_p)
2743 || (EQ (val, Qwidth) && !width_p)))
2744 fixed_p = 0;
2745 }
2746
2747 /* Can't tell if this one is resizable without looking at
2748 siblings. If all siblings are fixed-size this one is too. */
2749 if (!fixed_p && check_siblings_p && WINDOWP (w->parent))
2750 {
2751 Lisp_Object child;
2752
2753 for (child = w->prev; WINDOWP (child); child = XWINDOW (child)->prev)
2754 if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
2755 break;
2756
2757 if (NILP (child))
2758 for (child = w->next; WINDOWP (child); child = XWINDOW (child)->next)
2759 if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
2760 break;
2761
2762 if (NILP (child))
2763 fixed_p = 1;
2764 }
2765 }
2766 else
2767 fixed_p = 1;
2768
2769 return fixed_p;
2770 }
2771
2772 /* Return minimum size of leaf window W. WIDTH_P non-zero means return
2773 the minimum width of W, WIDTH_P zero means return the minimum height
2774 of W. SAFE_P non-zero means ignore window-min-height|width but just
2775 return values that won't crash Emacs and don't hide components like
2776 fringes, scrollbars, or modelines. If WIDTH_P is zero and W is the
2777 minibuffer window, always return 1. */
2778
2779 static int
2780 window_min_size_2 (w, width_p, safe_p)
2781 struct window *w;
2782 int width_p, safe_p;
2783 {
2784 /* We should consider buffer-local values of window_min_height and
2785 window_min_width here. */
2786 if (width_p)
2787 {
2788 int safe_size = (MIN_SAFE_WINDOW_WIDTH
2789 + WINDOW_FRINGE_COLS (w)
2790 + WINDOW_SCROLL_BAR_COLS (w));
2791
2792 return safe_p ? safe_size : max (window_min_width, safe_size);
2793 }
2794 else if (MINI_WINDOW_P (w))
2795 return 1;
2796 else
2797 {
2798 int safe_size = (MIN_SAFE_WINDOW_HEIGHT
2799 + ((BUFFERP (w->buffer)
2800 && !NILP (XBUFFER (w->buffer)->mode_line_format))
2801 ? 1 : 0));
2802
2803 return safe_p ? safe_size : max (window_min_height, safe_size);
2804 }
2805 }
2806
2807 /* Return minimum size of window W, not taking fixed-width windows into
2808 account. WIDTH_P non-zero means return the minimum width, otherwise
2809 return the minimum height. SAFE_P non-zero means ignore
2810 window-min-height|width but just return values that won't crash Emacs
2811 and don't hide components like fringes, scrollbars, or modelines. If
2812 W is a combination window, compute the minimum size from the minimum
2813 sizes of W's children. */
2814
2815 static int
2816 window_min_size_1 (w, width_p, safe_p)
2817 struct window *w;
2818 int width_p, safe_p;
2819 {
2820 struct window *c;
2821 int size;
2822
2823 if (!NILP (w->hchild))
2824 {
2825 /* W is a horizontal combination. */
2826 c = XWINDOW (w->hchild);
2827 size = 0;
2828
2829 if (width_p)
2830 {
2831 /* The minimum width of a horizontal combination is the sum of
2832 the minimum widths of its children. */
2833 while (c)
2834 {
2835 size += window_min_size_1 (c, 1, safe_p);
2836 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2837 }
2838 }
2839 else
2840 {
2841 /* The minimum height of a horizontal combination is the
2842 maximum of the minimum heights of its children. */
2843 while (c)
2844 {
2845 size = max (window_min_size_1 (c, 0, safe_p), size);
2846 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2847 }
2848 }
2849 }
2850 else if (!NILP (w->vchild))
2851 {
2852 /* W is a vertical combination. */
2853 c = XWINDOW (w->vchild);
2854 size = 0;
2855
2856 if (width_p)
2857 {
2858 /* The minimum width of a vertical combination is the maximum
2859 of the minimum widths of its children. */
2860 while (c)
2861 {
2862 size = max (window_min_size_1 (c, 1, safe_p), size);
2863 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2864 }
2865 }
2866 else
2867 {
2868 /* The minimum height of a vertical combination is the sum of
2869 the minimum height of its children. */
2870 while (c)
2871 {
2872 size += window_min_size_1 (c, 0, safe_p);
2873 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2874 }
2875 }
2876 }
2877 else
2878 /* W is a leaf window. */
2879 size = window_min_size_2 (w, width_p, safe_p);
2880
2881 return size;
2882 }
2883
2884 /* Return the minimum size of window W, taking fixed-size windows into
2885 account. WIDTH_P non-zero means return the minimum width, otherwise
2886 return the minimum height. SAFE_P non-zero means ignore
2887 window-min-height|width but just return values that won't crash Emacs
2888 and don't hide components like fringes, scrollbars, or modelines.
2889 IGNORE_FIXED_P non-zero means ignore if W is fixed-size. Set *FIXED
2890 to 1 if W is fixed-size unless FIXED is null. */
2891
2892 static int
2893 window_min_size (w, width_p, safe_p, ignore_fixed_p, fixed)
2894 struct window *w;
2895 int width_p, safe_p, ignore_fixed_p, *fixed;
2896 {
2897 int size, fixed_p;
2898
2899 if (ignore_fixed_p)
2900 fixed_p = 0;
2901 else
2902 fixed_p = window_fixed_size_p (w, width_p, 1);
2903
2904 if (fixed)
2905 *fixed = fixed_p;
2906
2907 if (fixed_p)
2908 size = WINDOW_TOTAL_SIZE (w, width_p);
2909 else
2910 size = window_min_size_1 (w, width_p, safe_p);
2911
2912 return size;
2913 }
2914
2915
2916 /* Adjust the margins of window W if text area is too small.
2917 Return 1 if window width is ok after adjustment; 0 if window
2918 is still too narrow. */
2919
2920 static int
2921 adjust_window_margins (w)
2922 struct window *w;
2923 {
2924 int box_cols = (WINDOW_TOTAL_COLS (w)
2925 - WINDOW_FRINGE_COLS (w)
2926 - WINDOW_SCROLL_BAR_COLS (w));
2927 int margin_cols = (WINDOW_LEFT_MARGIN_COLS (w)
2928 + WINDOW_RIGHT_MARGIN_COLS (w));
2929
2930 if (box_cols - margin_cols >= MIN_SAFE_WINDOW_WIDTH)
2931 return 1;
2932
2933 if (margin_cols < 0 || box_cols < MIN_SAFE_WINDOW_WIDTH)
2934 return 0;
2935
2936 /* Window's text area is too narrow, but reducing the window
2937 margins will fix that. */
2938 margin_cols = box_cols - MIN_SAFE_WINDOW_WIDTH;
2939 if (WINDOW_RIGHT_MARGIN_COLS (w) > 0)
2940 {
2941 if (WINDOW_LEFT_MARGIN_COLS (w) > 0)
2942 w->left_margin_cols = w->right_margin_cols
2943 = make_number (margin_cols/2);
2944 else
2945 w->right_margin_cols = make_number (margin_cols);
2946 }
2947 else
2948 w->left_margin_cols = make_number (margin_cols);
2949 return 1;
2950 }
2951
2952 /* Calculate new sizes for windows in the list FORWARD when their
2953 compound size goes from TOTAL to SIZE. TOTAL must be greater than
2954 SIZE. The number of windows in FORWARD is NCHILDREN, and the number
2955 that can shrink is SHRINKABLE. Fixed-size windows may be shrunk if
2956 and only if RESIZE_FIXED_P is non-zero. WIDTH_P non-zero means
2957 shrink columns, otherwise shrink lines.
2958
2959 SAFE_P zero means windows may be sized down to window-min-height
2960 lines (window-min-window columns for WIDTH_P non-zero). SAFE_P
2961 non-zero means windows may be sized down to their minimum safe sizes
2962 taking into account the space needed to display modelines, fringes,
2963 and scrollbars.
2964
2965 This function returns an allocated array of new sizes that the caller
2966 must free. A size -1 means the window is fixed and RESIZE_FIXED_P is
2967 zero. A size zero means the window shall be deleted. Array index 0
2968 refers to the first window in FORWARD, 1 to the second, and so on.
2969
2970 This function resizes windows proportionally to their size. It also
2971 tries to preserve smaller windows by resizing larger windows before
2972 resizing any window to zero. If resize_proportionally is non-nil for
2973 a specific window, it will attempt to strictly resize that window
2974 proportionally, even at the expense of deleting smaller windows. */
2975 static int *
2976 shrink_windows (total, size, nchildren, shrinkable, resize_fixed_p,
2977 forward, width_p, safe_p)
2978 int total, size, nchildren, shrinkable;
2979 int resize_fixed_p, width_p, safe_p;
2980 Lisp_Object forward;
2981 {
2982 int available_resize = 0;
2983 int *new_sizes, *min_sizes;
2984 struct window *c;
2985 Lisp_Object child;
2986 int smallest = total;
2987 int total_removed = 0;
2988 int total_shrink = total - size;
2989 int i;
2990
2991 new_sizes = xmalloc (sizeof (*new_sizes) * nchildren);
2992 min_sizes = xmalloc (sizeof (*min_sizes) * nchildren);
2993
2994 for (i = 0, child = forward; !NILP (child); child = c->next, ++i)
2995 {
2996 int child_size;
2997
2998 c = XWINDOW (child);
2999 child_size = WINDOW_TOTAL_SIZE (c, width_p);
3000
3001 if (!resize_fixed_p && window_fixed_size_p (c, width_p, 0))
3002 new_sizes[i] = -1;
3003 else
3004 {
3005 new_sizes[i] = child_size;
3006 min_sizes[i] = window_min_size_1 (c, width_p, safe_p);
3007 if (child_size > min_sizes[i]
3008 && NILP (c->resize_proportionally))
3009 available_resize += child_size - min_sizes[i];
3010 }
3011 }
3012 /* We might need to shrink some windows to zero. Find the smallest
3013 windows and set them to 0 until we can fulfil the new size. */
3014
3015 while (shrinkable > 1 && size + available_resize < total)
3016 {
3017 for (i = 0; i < nchildren; ++i)
3018 if (new_sizes[i] > 0 && smallest > new_sizes[i])
3019 smallest = new_sizes[i];
3020
3021 for (i = 0; i < nchildren; ++i)
3022 if (new_sizes[i] == smallest)
3023 {
3024 /* Resize this window down to zero. */
3025 new_sizes[i] = 0;
3026 if (smallest > min_sizes[i])
3027 available_resize -= smallest - min_sizes[i];
3028 available_resize += smallest;
3029 --shrinkable;
3030 total_removed += smallest;
3031
3032 /* We don't know what the smallest is now. */
3033 smallest = total;
3034
3035 /* Out of for, just remove one window at the time and
3036 check again if we have enough space. */
3037 break;
3038 }
3039 }
3040
3041 /* Now, calculate the new sizes. Try to shrink each window
3042 proportional to its size. */
3043 for (i = 0; i < nchildren; ++i)
3044 {
3045 if (new_sizes[i] > min_sizes[i])
3046 {
3047 int to_shrink = total_shrink * new_sizes[i] / total;
3048
3049 if (new_sizes[i] - to_shrink < min_sizes[i])
3050 to_shrink = new_sizes[i] - min_sizes[i];
3051 new_sizes[i] -= to_shrink;
3052 total_removed += to_shrink;
3053 }
3054 }
3055
3056 /* Any reminder due to rounding, we just subtract from windows
3057 that are left and still can be shrunk. */
3058 while (total_shrink > total_removed)
3059 {
3060 int nonzero_sizes = 0;
3061 int nonzero_idx = -1;
3062
3063 for (i = 0; i < nchildren; ++i)
3064 if (new_sizes[i] > 0)
3065 {
3066 ++nonzero_sizes;
3067 nonzero_idx = i;
3068 }
3069
3070 for (i = 0; i < nchildren; ++i)
3071 if (new_sizes[i] > min_sizes[i])
3072 {
3073 --new_sizes[i];
3074 ++total_removed;
3075
3076 /* Out of for, just shrink one window at the time and
3077 check again if we have enough space. */
3078 break;
3079 }
3080
3081 /* Special case, only one window left. */
3082 if (nonzero_sizes == 1)
3083 break;
3084 }
3085
3086 /* Any surplus due to rounding, we add to windows that are left. */
3087 while (total_shrink < total_removed)
3088 {
3089 for (i = 0; i < nchildren; ++i)
3090 {
3091 if (new_sizes[i] != 0 && total_shrink < total_removed)
3092 {
3093 ++new_sizes[i];
3094 --total_removed;
3095 break;
3096 }
3097 }
3098 }
3099
3100 xfree (min_sizes);
3101
3102 return new_sizes;
3103 }
3104
3105 /* Set WINDOW's height or width to SIZE. WIDTH_P non-zero means set
3106 WINDOW's width. Resize WINDOW's children, if any, so that they keep
3107 their proportionate size relative to WINDOW.
3108
3109 If FIRST_ONLY is 1, change only the first of WINDOW's children when
3110 they are in series. If LAST_ONLY is 1, change only the last of
3111 WINDOW's children when they are in series.
3112
3113 Propagate WINDOW's top or left edge position to children. Delete
3114 windows that become too small unless NODELETE_P is 1. When
3115 NODELETE_P equals 2 do not honor settings for window-min-height and
3116 window-min-width when resizing windows but use safe defaults instead.
3117 This should give better behavior when resizing frames. */
3118
3119 static void
3120 size_window (window, size, width_p, nodelete_p, first_only, last_only)
3121 Lisp_Object window;
3122 int size, width_p, nodelete_p;
3123 int first_only, last_only;
3124 {
3125 struct window *w = XWINDOW (window);
3126 struct window *c;
3127 Lisp_Object child, *forward, *sideward;
3128 int old_size = WINDOW_TOTAL_SIZE (w, width_p);
3129
3130 size = max (0, size);
3131
3132 /* Delete WINDOW if it's too small. */
3133 if (nodelete_p != 1 && !NILP (w->parent)
3134 && size < window_min_size_1 (w, width_p, nodelete_p == 2))
3135 {
3136 delete_window (window);
3137 return;
3138 }
3139
3140 /* Set redisplay hints. */
3141 w->last_modified = make_number (0);
3142 w->last_overlay_modified = make_number (0);
3143 windows_or_buffers_changed++;
3144 FRAME_WINDOW_SIZES_CHANGED (XFRAME (w->frame)) = 1;
3145
3146 if (width_p)
3147 {
3148 sideward = &w->vchild;
3149 forward = &w->hchild;
3150 w->total_cols = make_number (size);
3151 adjust_window_margins (w);
3152 }
3153 else
3154 {
3155 sideward = &w->hchild;
3156 forward = &w->vchild;
3157 w->total_lines = make_number (size);
3158 w->orig_total_lines = Qnil;
3159 }
3160
3161 if (!NILP (*sideward))
3162 {
3163 /* We have a chain of parallel siblings whose size should all change. */
3164 for (child = *sideward; !NILP (child); child = c->next)
3165 {
3166 c = XWINDOW (child);
3167 if (width_p)
3168 c->left_col = w->left_col;
3169 else
3170 c->top_line = w->top_line;
3171 size_window (child, size, width_p, nodelete_p,
3172 first_only, last_only);
3173 }
3174 }
3175 else if (!NILP (*forward) && last_only)
3176 {
3177 /* Change the last in a series of siblings. */
3178 Lisp_Object last_child;
3179 int child_size;
3180
3181 for (child = *forward; !NILP (child); child = c->next)
3182 {
3183 c = XWINDOW (child);
3184 last_child = child;
3185 }
3186
3187 child_size = WINDOW_TOTAL_SIZE (c, width_p);
3188 size_window (last_child, size - old_size + child_size,
3189 width_p, nodelete_p, first_only, last_only);
3190 }
3191 else if (!NILP (*forward) && first_only)
3192 {
3193 /* Change the first in a series of siblings. */
3194 int child_size;
3195
3196 child = *forward;
3197 c = XWINDOW (child);
3198
3199 if (width_p)
3200 c->left_col = w->left_col;
3201 else
3202 c->top_line = w->top_line;
3203
3204 child_size = WINDOW_TOTAL_SIZE (c, width_p);
3205 size_window (child, size - old_size + child_size,
3206 width_p, nodelete_p, first_only, last_only);
3207 }
3208 else if (!NILP (*forward))
3209 {
3210 int fixed_size, each, extra, n;
3211 int resize_fixed_p, nfixed;
3212 int last_pos, first_pos, nchildren, total;
3213 int *new_sizes = NULL;
3214
3215 /* Determine the fixed-size portion of this window, and the
3216 number of child windows. */
3217 fixed_size = nchildren = nfixed = total = 0;
3218 for (child = *forward; !NILP (child); child = c->next, ++nchildren)
3219 {
3220 int child_size;
3221
3222 c = XWINDOW (child);
3223 child_size = WINDOW_TOTAL_SIZE (c, width_p);
3224 total += child_size;
3225
3226 if (window_fixed_size_p (c, width_p, 0))
3227 {
3228 fixed_size += child_size;
3229 ++nfixed;
3230 }
3231 }
3232
3233 /* If the new size is smaller than fixed_size, or if there
3234 aren't any resizable windows, allow resizing fixed-size
3235 windows. */
3236 resize_fixed_p = nfixed == nchildren || size < fixed_size;
3237
3238 /* Compute how many lines/columns to add/remove to each child. The
3239 value of extra takes care of rounding errors. */
3240 n = resize_fixed_p ? nchildren : nchildren - nfixed;
3241 if (size < total && n > 1)
3242 new_sizes = shrink_windows (total, size, nchildren, n,
3243 resize_fixed_p, *forward, width_p,
3244 nodelete_p == 2);
3245 else
3246 {
3247 each = (size - total) / n;
3248 extra = (size - total) - n * each;
3249 }
3250
3251 /* Compute new children heights and edge positions. */
3252 first_pos = width_p ? XINT (w->left_col) : XINT (w->top_line);
3253 last_pos = first_pos;
3254 for (n = 0, child = *forward; !NILP (child); child = c->next, ++n)
3255 {
3256 int new_size, old_size;
3257
3258 c = XWINDOW (child);
3259 old_size = WINDOW_TOTAL_SIZE (c, width_p);
3260 new_size = old_size;
3261
3262 /* The top or left edge position of this child equals the
3263 bottom or right edge of its predecessor. */
3264 if (width_p)
3265 c->left_col = make_number (last_pos);
3266 else
3267 c->top_line = make_number (last_pos);
3268
3269 /* If this child can be resized, do it. */
3270 if (resize_fixed_p || !window_fixed_size_p (c, width_p, 0))
3271 {
3272 new_size = new_sizes ? new_sizes[n] : old_size + each + extra;
3273 extra = 0;
3274 }
3275
3276 /* Set new size. Note that size_window also propagates
3277 edge positions to children, so it's not a no-op if we
3278 didn't change the child's size. */
3279 size_window (child, new_size, width_p, 1, first_only, last_only);
3280
3281 /* Remember the bottom/right edge position of this child; it
3282 will be used to set the top/left edge of the next child. */
3283 last_pos += new_size;
3284 }
3285
3286 xfree (new_sizes);
3287
3288 /* We should have covered the parent exactly with child windows. */
3289 xassert (size == last_pos - first_pos);
3290
3291 /* Now delete any children that became too small. */
3292 if (nodelete_p != 1)
3293 for (child = *forward; !NILP (child); child = c->next)
3294 {
3295 int child_size;
3296
3297 c = XWINDOW (child);
3298 child_size = WINDOW_TOTAL_SIZE (c, width_p);
3299 size_window (child, child_size, width_p, nodelete_p,
3300 first_only, last_only);
3301 }
3302 }
3303 }
3304
3305 /* Set WINDOW's height to HEIGHT, and recursively change the height of
3306 WINDOW's children. NODELETE zero means windows that have become
3307 smaller than window-min-height in the process may be deleted.
3308 NODELETE 1 means never delete windows that become too small in the
3309 process. (The caller should check later and do so if appropriate.)
3310 NODELETE 2 means delete only windows that have become too small to be
3311 displayed correctly. */
3312
3313 void
3314 set_window_height (window, height, nodelete)
3315 Lisp_Object window;
3316 int height;
3317 int nodelete;
3318 {
3319 size_window (window, height, 0, nodelete, 0, 0);
3320 }
3321
3322 /* Set WINDOW's width to WIDTH, and recursively change the width of
3323 WINDOW's children. NODELETE zero means windows that have become
3324 smaller than window-min-width in the process may be deleted.
3325 NODELETE 1 means never delete windows that become too small in the
3326 process. (The caller should check later and do so if appropriate.)
3327 NODELETE 2 means delete only windows that have become too small to be
3328 displayed correctly. */
3329
3330 void
3331 set_window_width (window, width, nodelete)
3332 Lisp_Object window;
3333 int width;
3334 int nodelete;
3335 {
3336 size_window (window, width, 1, nodelete, 0, 0);
3337 }
3338
3339 /* Change window heights in windows rooted in WINDOW by N lines. */
3340
3341 void
3342 change_window_heights (window, n)
3343 Lisp_Object window;
3344 int n;
3345 {
3346 struct window *w = XWINDOW (window);
3347
3348 XSETFASTINT (w->top_line, XFASTINT (w->top_line) + n);
3349 XSETFASTINT (w->total_lines, XFASTINT (w->total_lines) - n);
3350
3351 if (INTEGERP (w->orig_top_line))
3352 XSETFASTINT (w->orig_top_line, XFASTINT (w->orig_top_line) + n);
3353 if (INTEGERP (w->orig_total_lines))
3354 XSETFASTINT (w->orig_total_lines, XFASTINT (w->orig_total_lines) - n);
3355
3356 /* Handle just the top child in a vertical split. */
3357 if (!NILP (w->vchild))
3358 change_window_heights (w->vchild, n);
3359
3360 /* Adjust all children in a horizontal split. */
3361 for (window = w->hchild; !NILP (window); window = w->next)
3362 {
3363 w = XWINDOW (window);
3364 change_window_heights (window, n);
3365 }
3366 }
3367
3368 \f
3369 int window_select_count;
3370
3371 EXFUN (Fset_window_fringes, 4);
3372 EXFUN (Fset_window_scroll_bars, 4);
3373
3374 static void
3375 run_funs (Lisp_Object funs)
3376 {
3377 for (; CONSP (funs); funs = XCDR (funs))
3378 if (!EQ (XCAR (funs), Qt))
3379 call0 (XCAR (funs));
3380 }
3381
3382 static Lisp_Object select_window_norecord (Lisp_Object window);
3383 static Lisp_Object select_frame_norecord (Lisp_Object frame);
3384
3385 void
3386 run_window_configuration_change_hook (struct frame *f)
3387 {
3388 int count = SPECPDL_INDEX ();
3389 Lisp_Object frame, global_wcch
3390 = Fdefault_value (Qwindow_configuration_change_hook);
3391 XSETFRAME (frame, f);
3392
3393 if (NILP (Vrun_hooks))
3394 return;
3395
3396 if (SELECTED_FRAME () != f)
3397 {
3398 record_unwind_protect (select_frame_norecord, Fselected_frame ());
3399 Fselect_frame (frame, Qt);
3400 }
3401
3402 /* Use the right buffer. Matters when running the local hooks. */
3403 if (current_buffer != XBUFFER (Fwindow_buffer (Qnil)))
3404 {
3405 record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
3406 Fset_buffer (Fwindow_buffer (Qnil));
3407 }
3408
3409 /* Look for buffer-local values. */
3410 {
3411 Lisp_Object windows = Fwindow_list (frame, Qlambda, Qnil);
3412 for (; CONSP (windows); windows = XCDR (windows))
3413 {
3414 Lisp_Object window = XCAR (windows);
3415 Lisp_Object buffer = Fwindow_buffer (window);
3416 if (!NILP (Flocal_variable_p (Qwindow_configuration_change_hook,
3417 buffer)))
3418 {
3419 int count = SPECPDL_INDEX ();
3420 record_unwind_protect (select_window_norecord, Fselected_window ());
3421 select_window_norecord (window);
3422 run_funs (Fbuffer_local_value (Qwindow_configuration_change_hook,
3423 buffer));
3424 unbind_to (count, Qnil);
3425 }
3426 }
3427 }
3428
3429 run_funs (global_wcch);
3430 unbind_to (count, Qnil);
3431 }
3432
3433 /* Make WINDOW display BUFFER as its contents. RUN_HOOKS_P non-zero
3434 means it's allowed to run hooks. See make_frame for a case where
3435 it's not allowed. KEEP_MARGINS_P non-zero means that the current
3436 margins, fringes, and scroll-bar settings of the window are not
3437 reset from the buffer's local settings. */
3438
3439 void
3440 set_window_buffer (window, buffer, run_hooks_p, keep_margins_p)
3441 Lisp_Object window, buffer;
3442 int run_hooks_p, keep_margins_p;
3443 {
3444 struct window *w = XWINDOW (window);
3445 struct buffer *b = XBUFFER (buffer);
3446 int count = SPECPDL_INDEX ();
3447 int samebuf = EQ (buffer, w->buffer);
3448
3449 w->buffer = buffer;
3450
3451 if (EQ (window, selected_window))
3452 b->last_selected_window = window;
3453
3454 /* Let redisplay errors through. */
3455 b->display_error_modiff = 0;
3456
3457 /* Update time stamps of buffer display. */
3458 if (INTEGERP (b->display_count))
3459 XSETINT (b->display_count, XINT (b->display_count) + 1);
3460 b->display_time = Fcurrent_time ();
3461
3462 XSETFASTINT (w->window_end_pos, 0);
3463 XSETFASTINT (w->window_end_vpos, 0);
3464 bzero (&w->last_cursor, sizeof w->last_cursor);
3465 w->window_end_valid = Qnil;
3466 if (!(keep_margins_p && samebuf))
3467 { /* If we're not actually changing the buffer, don't reset hscroll and
3468 vscroll. This case happens for example when called from
3469 change_frame_size_1, where we use a dummy call to
3470 Fset_window_buffer on the frame's selected window (and no other)
3471 just in order to run window-configuration-change-hook.
3472 Resetting hscroll and vscroll here is problematic for things like
3473 image-mode and doc-view-mode since it resets the image's position
3474 whenever we resize the frame. */
3475 w->hscroll = w->min_hscroll = make_number (0);
3476 w->vscroll = 0;
3477 set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
3478 set_marker_restricted (w->start,
3479 make_number (b->last_window_start),
3480 buffer);
3481 w->start_at_line_beg = Qnil;
3482 w->force_start = Qnil;
3483 XSETFASTINT (w->last_modified, 0);
3484 XSETFASTINT (w->last_overlay_modified, 0);
3485 }
3486 /* Maybe we could move this into the `if' but it's not obviously safe and
3487 I doubt it's worth the trouble. */
3488 windows_or_buffers_changed++;
3489
3490 /* We must select BUFFER for running the window-scroll-functions. */
3491 /* We can't check ! NILP (Vwindow_scroll_functions) here
3492 because that might itself be a local variable. */
3493 if (window_initialized)
3494 {
3495 record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
3496 Fset_buffer (buffer);
3497 }
3498
3499 XMARKER (w->pointm)->insertion_type = !NILP (Vwindow_point_insertion_type);
3500
3501 if (!keep_margins_p)
3502 {
3503 /* Set left and right marginal area width etc. from buffer. */
3504
3505 /* This may call adjust_window_margins three times, so
3506 temporarily disable window margins. */
3507 Lisp_Object save_left = w->left_margin_cols;
3508 Lisp_Object save_right = w->right_margin_cols;
3509
3510 w->left_margin_cols = w->right_margin_cols = Qnil;
3511
3512 Fset_window_fringes (window,
3513 b->left_fringe_width, b->right_fringe_width,
3514 b->fringes_outside_margins);
3515
3516 Fset_window_scroll_bars (window,
3517 b->scroll_bar_width,
3518 b->vertical_scroll_bar_type, Qnil);
3519
3520 w->left_margin_cols = save_left;
3521 w->right_margin_cols = save_right;
3522
3523 Fset_window_margins (window,
3524 b->left_margin_cols, b->right_margin_cols);
3525 }
3526
3527 if (run_hooks_p)
3528 {
3529 if (! NILP (Vwindow_scroll_functions))
3530 run_hook_with_args_2 (Qwindow_scroll_functions, window,
3531 Fmarker_position (w->start));
3532 run_window_configuration_change_hook (XFRAME (WINDOW_FRAME (w)));
3533 }
3534
3535 unbind_to (count, Qnil);
3536 }
3537
3538
3539 DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 3, 0,
3540 doc: /* Make WINDOW display BUFFER-OR-NAME as its contents.
3541 WINDOW defaults to the selected window. BUFFER-OR-NAME must be a buffer
3542 or the name of an existing buffer. Optional third argument KEEP-MARGINS
3543 non-nil means that WINDOW's current display margins, fringe widths, and
3544 scroll bar settings are preserved; the default is to reset these from
3545 the local settings for BUFFER-OR-NAME or the frame defaults. Return nil.
3546
3547 This function throws an error when WINDOW is strongly dedicated to its
3548 buffer (that is `window-dedicated-p' returns t for WINDOW) and does not
3549 already display BUFFER-OR-NAME.
3550
3551 This function runs `window-scroll-functions' before running
3552 `window-configuration-change-hook'. */)
3553 (window, buffer_or_name, keep_margins)
3554 register Lisp_Object window, buffer_or_name, keep_margins;
3555 {
3556 register Lisp_Object tem, buffer;
3557 register struct window *w = decode_window (window);
3558
3559 XSETWINDOW (window, w);
3560 buffer = Fget_buffer (buffer_or_name);
3561 CHECK_BUFFER (buffer);
3562 if (NILP (XBUFFER (buffer)->name))
3563 error ("Attempt to display deleted buffer");
3564
3565 tem = w->buffer;
3566 if (NILP (tem))
3567 error ("Window is deleted");
3568 else if (!EQ (tem, Qt))
3569 /* w->buffer is t when the window is first being set up. */
3570 {
3571 if (!EQ (tem, buffer))
3572 if (EQ (w->dedicated, Qt))
3573 error ("Window is dedicated to `%s'", SDATA (XBUFFER (tem)->name));
3574 else
3575 w->dedicated = Qnil;
3576
3577 unshow_buffer (w);
3578 }
3579
3580 set_window_buffer (window, buffer, 1, !NILP (keep_margins));
3581 return Qnil;
3582 }
3583
3584 /* If select_window is called with inhibit_point_swap non-zero it will
3585 not store point of the old selected window's buffer back into that
3586 window's pointm slot. This is needed by Fset_window_configuration to
3587 avoid that the display routine is called with selected_window set to
3588 Qnil causing a subsequent crash. */
3589
3590 static Lisp_Object
3591 select_window (window, norecord, inhibit_point_swap)
3592 Lisp_Object window, norecord;
3593 int inhibit_point_swap;
3594 {
3595 register struct window *w;
3596 register struct window *ow;
3597 struct frame *sf;
3598
3599 CHECK_LIVE_WINDOW (window);
3600
3601 w = XWINDOW (window);
3602 w->frozen_window_start_p = 0;
3603
3604 if (NILP (norecord))
3605 {
3606 ++window_select_count;
3607 XSETFASTINT (w->use_time, window_select_count);
3608 }
3609
3610 if (EQ (window, selected_window) && !inhibit_point_swap)
3611 return window;
3612
3613 sf = SELECTED_FRAME ();
3614 if (XFRAME (WINDOW_FRAME (w)) != sf)
3615 {
3616 XFRAME (WINDOW_FRAME (w))->selected_window = window;
3617 /* Use this rather than Fhandle_switch_frame
3618 so that FRAME_FOCUS_FRAME is moved appropriately as we
3619 move around in the state where a minibuffer in a separate
3620 frame is active. */
3621 Fselect_frame (WINDOW_FRAME (w), norecord);
3622 /* Fselect_frame called us back so we've done all the work already. */
3623 eassert (EQ (window, selected_window));
3624 return window;
3625 }
3626 else
3627 sf->selected_window = window;
3628
3629 /* Store the current buffer's actual point into the
3630 old selected window. It belongs to that window,
3631 and when the window is not selected, must be in the window. */
3632 if (!inhibit_point_swap)
3633 {
3634 ow = XWINDOW (selected_window);
3635 if (! NILP (ow->buffer))
3636 set_marker_both (ow->pointm, ow->buffer,
3637 BUF_PT (XBUFFER (ow->buffer)),
3638 BUF_PT_BYTE (XBUFFER (ow->buffer)));
3639 }
3640
3641 selected_window = window;
3642
3643 if (NILP (norecord))
3644 record_buffer (w->buffer);
3645 Fset_buffer (w->buffer);
3646
3647 XBUFFER (w->buffer)->last_selected_window = window;
3648
3649 /* Go to the point recorded in the window.
3650 This is important when the buffer is in more
3651 than one window. It also matters when
3652 redisplay_window has altered point after scrolling,
3653 because it makes the change only in the window. */
3654 {
3655 register int new_point = marker_position (w->pointm);
3656 if (new_point < BEGV)
3657 SET_PT (BEGV);
3658 else if (new_point > ZV)
3659 SET_PT (ZV);
3660 else
3661 SET_PT (new_point);
3662 }
3663
3664 windows_or_buffers_changed++;
3665 return window;
3666 }
3667
3668
3669 /* Note that selected_window can be nil when this is called from
3670 Fset_window_configuration. */
3671
3672 DEFUN ("select-window", Fselect_window, Sselect_window, 1, 2, 0,
3673 doc: /* Select WINDOW. Most editing will apply to WINDOW's buffer.
3674 If WINDOW is not already selected, make WINDOW's buffer current
3675 and make WINDOW the frame's selected window. Return WINDOW.
3676 Optional second arg NORECORD non-nil means do not put this buffer
3677 at the front of the list of recently selected ones and do not
3678 make this window the most recently selected one.
3679
3680 Note that the main editor command loop selects the buffer of the
3681 selected window before each command. */)
3682 (window, norecord)
3683 register Lisp_Object window, norecord;
3684 {
3685 return select_window (window, norecord, 0);
3686 }
3687
3688 static Lisp_Object
3689 select_window_norecord (window)
3690 Lisp_Object window;
3691 {
3692 return WINDOW_LIVE_P (window)
3693 ? Fselect_window (window, Qt) : selected_window;
3694 }
3695
3696 static Lisp_Object
3697 select_frame_norecord (frame)
3698 Lisp_Object frame;
3699 {
3700 return FRAME_LIVE_P (XFRAME (frame))
3701 ? Fselect_frame (frame, Qt) : selected_frame;
3702 }
3703 \f
3704 Lisp_Object
3705 display_buffer (buffer, not_this_window_p, override_frame)
3706 Lisp_Object buffer, not_this_window_p, override_frame;
3707 {
3708 return call3 (Qdisplay_buffer, buffer, not_this_window_p, override_frame);
3709 }
3710
3711 DEFUN ("force-window-update", Fforce_window_update, Sforce_window_update,
3712 0, 1, 0,
3713 doc: /* Force all windows to be updated on next redisplay.
3714 If optional arg OBJECT is a window, force redisplay of that window only.
3715 If OBJECT is a buffer or buffer name, force redisplay of all windows
3716 displaying that buffer. */)
3717 (object)
3718 Lisp_Object object;
3719 {
3720 if (NILP (object))
3721 {
3722 windows_or_buffers_changed++;
3723 update_mode_lines++;
3724 return Qt;
3725 }
3726
3727 if (WINDOWP (object))
3728 {
3729 struct window *w = XWINDOW (object);
3730 mark_window_display_accurate (object, 0);
3731 w->update_mode_line = Qt;
3732 if (BUFFERP (w->buffer))
3733 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
3734 ++update_mode_lines;
3735 return Qt;
3736 }
3737
3738 if (STRINGP (object))
3739 object = Fget_buffer (object);
3740 if (BUFFERP (object) && !NILP (XBUFFER (object)->name))
3741 {
3742 /* Walk all windows looking for buffer, and force update
3743 of each of those windows. */
3744
3745 object = window_loop (REDISPLAY_BUFFER_WINDOWS, object, 0, Qvisible);
3746 return NILP (object) ? Qnil : Qt;
3747 }
3748
3749 /* If nothing suitable was found, just return.
3750 We could signal an error, but this feature will typically be used
3751 asynchronously in timers or process sentinels, so we don't. */
3752 return Qnil;
3753 }
3754
3755
3756 void
3757 temp_output_buffer_show (buf)
3758 register Lisp_Object buf;
3759 {
3760 register struct buffer *old = current_buffer;
3761 register Lisp_Object window;
3762 register struct window *w;
3763
3764 XBUFFER (buf)->directory = current_buffer->directory;
3765
3766 Fset_buffer (buf);
3767 BUF_SAVE_MODIFF (XBUFFER (buf)) = MODIFF;
3768 BEGV = BEG;
3769 ZV = Z;
3770 SET_PT (BEG);
3771 #if 0 /* rms: there should be no reason for this. */
3772 XBUFFER (buf)->prevent_redisplay_optimizations_p = 1;
3773 #endif
3774 set_buffer_internal (old);
3775
3776 if (!NILP (Vtemp_buffer_show_function))
3777 call1 (Vtemp_buffer_show_function, buf);
3778 else
3779 {
3780 window = display_buffer (buf, Qnil, Qnil);
3781
3782 if (!EQ (XWINDOW (window)->frame, selected_frame))
3783 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
3784 Vminibuf_scroll_window = window;
3785 w = XWINDOW (window);
3786 XSETFASTINT (w->hscroll, 0);
3787 XSETFASTINT (w->min_hscroll, 0);
3788 set_marker_restricted_both (w->start, buf, BEG, BEG);
3789 set_marker_restricted_both (w->pointm, buf, BEG, BEG);
3790
3791 /* Run temp-buffer-show-hook, with the chosen window selected
3792 and its buffer current. */
3793
3794 if (!NILP (Vrun_hooks)
3795 && !NILP (Fboundp (Qtemp_buffer_show_hook))
3796 && !NILP (Fsymbol_value (Qtemp_buffer_show_hook)))
3797 {
3798 int count = SPECPDL_INDEX ();
3799 Lisp_Object prev_window, prev_buffer;
3800 prev_window = selected_window;
3801 XSETBUFFER (prev_buffer, old);
3802
3803 /* Select the window that was chosen, for running the hook.
3804 Note: Both Fselect_window and select_window_norecord may
3805 set-buffer to the buffer displayed in the window,
3806 so we need to save the current buffer. --stef */
3807 record_unwind_protect (Fset_buffer, prev_buffer);
3808 record_unwind_protect (select_window_norecord, prev_window);
3809 Fselect_window (window, Qt);
3810 Fset_buffer (w->buffer);
3811 call1 (Vrun_hooks, Qtemp_buffer_show_hook);
3812 unbind_to (count, Qnil);
3813 }
3814 }
3815 }
3816 \f
3817 static void
3818 make_dummy_parent (window)
3819 Lisp_Object window;
3820 {
3821 Lisp_Object new;
3822 register struct window *o, *p;
3823 int i;
3824
3825 o = XWINDOW (window);
3826 p = allocate_window ();
3827 for (i = 0; i < VECSIZE (struct window); ++i)
3828 ((struct Lisp_Vector *) p)->contents[i]
3829 = ((struct Lisp_Vector *)o)->contents[i];
3830 XSETWINDOW (new, p);
3831
3832 ++sequence_number;
3833 XSETFASTINT (p->sequence_number, sequence_number);
3834
3835 /* Put new into window structure in place of window */
3836 replace_window (window, new);
3837
3838 o->next = Qnil;
3839 o->prev = Qnil;
3840 o->vchild = Qnil;
3841 o->hchild = Qnil;
3842 o->parent = new;
3843
3844 p->start = Qnil;
3845 p->pointm = Qnil;
3846 p->buffer = Qnil;
3847 }
3848
3849 DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
3850 doc: /* Split WINDOW, putting SIZE lines in the first of the pair.
3851 WINDOW defaults to selected one and SIZE to half its size.
3852 If optional third arg HORIZONTAL is non-nil, split side by side and put
3853 SIZE columns in the first of the pair. In that case, SIZE includes that
3854 window's scroll bar, or the divider column to its right.
3855 Interactively, all arguments are nil.
3856 Returns the newly created window (which is the lower or rightmost one).
3857 The upper or leftmost window is the original one, and remains selected
3858 if it was selected before.
3859
3860 See Info node `(elisp)Splitting Windows' for more details and examples. */)
3861 (window, size, horizontal)
3862 Lisp_Object window, size, horizontal;
3863 {
3864 register Lisp_Object new;
3865 register struct window *o, *p;
3866 FRAME_PTR fo;
3867 register int size_int;
3868
3869 if (NILP (window))
3870 window = selected_window;
3871 else
3872 CHECK_LIVE_WINDOW (window);
3873
3874 o = XWINDOW (window);
3875 fo = XFRAME (WINDOW_FRAME (o));
3876
3877 if (NILP (size))
3878 {
3879 if (!NILP (horizontal))
3880 /* Calculate the size of the left-hand window, by dividing
3881 the usable space in columns by two.
3882 We round up, since the left-hand window may include
3883 a dividing line, while the right-hand may not. */
3884 size_int = (XFASTINT (o->total_cols) + 1) >> 1;
3885 else
3886 size_int = XFASTINT (o->total_lines) >> 1;
3887 }
3888 else
3889 {
3890 CHECK_NUMBER (size);
3891 size_int = XINT (size);
3892 }
3893
3894 if (MINI_WINDOW_P (o))
3895 error ("Attempt to split minibuffer window");
3896 else if (window_fixed_size_p (o, !NILP (horizontal), 0))
3897 error ("Attempt to split fixed-size window");
3898
3899 if (NILP (horizontal))
3900 {
3901 int window_safe_height = window_min_size_2 (o, 0, 0);
3902
3903 if (size_int < window_safe_height)
3904 error ("Window height %d too small (after splitting)", size_int);
3905 if (size_int + window_safe_height > XFASTINT (o->total_lines))
3906 error ("Window height %d too small (after splitting)",
3907 XFASTINT (o->total_lines) - size_int);
3908 if (NILP (o->parent)
3909 || NILP (XWINDOW (o->parent)->vchild))
3910 {
3911 make_dummy_parent (window);
3912 new = o->parent;
3913 XWINDOW (new)->vchild = window;
3914 }
3915 }
3916 else
3917 {
3918 int window_safe_width = window_min_size_2 (o, 1, 0);
3919
3920 if (size_int < window_safe_width)
3921 error ("Window width %d too small (after splitting)", size_int);
3922 if (size_int + window_safe_width > XFASTINT (o->total_cols))
3923 error ("Window width %d too small (after splitting)",
3924 XFASTINT (o->total_cols) - size_int);
3925 if (NILP (o->parent)
3926 || NILP (XWINDOW (o->parent)->hchild))
3927 {
3928 make_dummy_parent (window);
3929 new = o->parent;
3930 XWINDOW (new)->hchild = window;
3931 }
3932 }
3933
3934 /* Now we know that window's parent is a vertical combination
3935 if we are dividing vertically, or a horizontal combination
3936 if we are making side-by-side windows */
3937
3938 windows_or_buffers_changed++;
3939 FRAME_WINDOW_SIZES_CHANGED (fo) = 1;
3940 new = make_window ();
3941 p = XWINDOW (new);
3942
3943 p->frame = o->frame;
3944 p->next = o->next;
3945 if (!NILP (p->next))
3946 XWINDOW (p->next)->prev = new;
3947 p->prev = window;
3948 o->next = new;
3949 p->parent = o->parent;
3950 p->buffer = Qt;
3951 p->window_end_valid = Qnil;
3952 bzero (&p->last_cursor, sizeof p->last_cursor);
3953
3954 /* Duplicate special geometry settings. */
3955
3956 p->left_margin_cols = o->left_margin_cols;
3957 p->right_margin_cols = o->right_margin_cols;
3958 p->left_fringe_width = o->left_fringe_width;
3959 p->right_fringe_width = o->right_fringe_width;
3960 p->fringes_outside_margins = o->fringes_outside_margins;
3961 p->scroll_bar_width = o->scroll_bar_width;
3962 p->vertical_scroll_bar_type = o->vertical_scroll_bar_type;
3963
3964 /* Apportion the available frame space among the two new windows */
3965
3966 if (!NILP (horizontal))
3967 {
3968 p->total_lines = o->total_lines;
3969 p->top_line = o->top_line;
3970 XSETFASTINT (p->total_cols, XFASTINT (o->total_cols) - size_int);
3971 XSETFASTINT (o->total_cols, size_int);
3972 XSETFASTINT (p->left_col, XFASTINT (o->left_col) + size_int);
3973 adjust_window_margins (p);
3974 adjust_window_margins (o);
3975 }
3976 else
3977 {
3978 p->left_col = o->left_col;
3979 p->total_cols = o->total_cols;
3980 XSETFASTINT (p->total_lines, XFASTINT (o->total_lines) - size_int);
3981 XSETFASTINT (o->total_lines, size_int);
3982 XSETFASTINT (p->top_line, XFASTINT (o->top_line) + size_int);
3983 }
3984
3985 /* Adjust glyph matrices. */
3986 adjust_glyphs (fo);
3987
3988 Fset_window_buffer (new, o->buffer, Qt);
3989 return new;
3990 }
3991 \f
3992 DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
3993 doc: /* Make selected window SIZE lines taller.
3994 Interactively, if no argument is given, make the selected window one
3995 line taller. If optional argument HORIZONTAL is non-nil, make selected
3996 window wider by SIZE columns. If SIZE is negative, shrink the window by
3997 -SIZE lines or columns. Return nil.
3998
3999 This function can delete windows if they get too small. The size of
4000 fixed size windows is not altered by this function. */)
4001 (size, horizontal)
4002 Lisp_Object size, horizontal;
4003 {
4004 CHECK_NUMBER (size);
4005 enlarge_window (selected_window, XINT (size), !NILP (horizontal));
4006
4007 run_window_configuration_change_hook (SELECTED_FRAME ());
4008
4009 return Qnil;
4010 }
4011
4012 DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
4013 doc: /* Make selected window SIZE lines smaller.
4014 Interactively, if no argument is given, make the selected window one
4015 line smaller. If optional argument HORIZONTAL is non-nil, make the
4016 window narrower by SIZE columns. If SIZE is negative, enlarge selected
4017 window by -SIZE lines or columns. Return nil.
4018
4019 This function can delete windows if they get too small. The size of
4020 fixed size windows is not altered by this function. */)
4021 (size, horizontal)
4022 Lisp_Object size, horizontal;
4023 {
4024 CHECK_NUMBER (size);
4025 enlarge_window (selected_window, -XINT (size), !NILP (horizontal));
4026
4027 run_window_configuration_change_hook (SELECTED_FRAME ());
4028
4029 return Qnil;
4030 }
4031
4032 int
4033 window_height (window)
4034 Lisp_Object window;
4035 {
4036 register struct window *p = XWINDOW (window);
4037 return WINDOW_TOTAL_LINES (p);
4038 }
4039
4040 int
4041 window_width (window)
4042 Lisp_Object window;
4043 {
4044 register struct window *p = XWINDOW (window);
4045 return WINDOW_TOTAL_COLS (p);
4046 }
4047
4048
4049 #define CURBEG(w) \
4050 *(horiz_flag ? &(XWINDOW (w)->left_col) : &(XWINDOW (w)->top_line))
4051
4052 #define CURSIZE(w) \
4053 *(horiz_flag ? &(XWINDOW (w)->total_cols) : &(XWINDOW (w)->total_lines))
4054
4055
4056 /* Enlarge WINDOW by DELTA. HORIZ_FLAG nonzero means enlarge it
4057 horizontally; zero means do it vertically.
4058
4059 Siblings of the selected window are resized to fulfill the size
4060 request. If they become too small in the process, they may be
4061 deleted. */
4062
4063 static void
4064 enlarge_window (window, delta, horiz_flag)
4065 Lisp_Object window;
4066 int delta, horiz_flag;
4067 {
4068 Lisp_Object parent, next, prev;
4069 struct window *p;
4070 Lisp_Object *sizep;
4071 int maximum;
4072 int (*sizefun) P_ ((Lisp_Object))
4073 = horiz_flag ? window_width : window_height;
4074 void (*setsizefun) P_ ((Lisp_Object, int, int))
4075 = (horiz_flag ? set_window_width : set_window_height);
4076
4077 /* Give up if this window cannot be resized. */
4078 if (window_fixed_size_p (XWINDOW (window), horiz_flag, 1))
4079 error ("Window is not resizable");
4080
4081 /* Find the parent of the selected window. */
4082 while (1)
4083 {
4084 p = XWINDOW (window);
4085 parent = p->parent;
4086
4087 if (NILP (parent))
4088 {
4089 if (horiz_flag)
4090 error ("No other window to side of this one");
4091 break;
4092 }
4093
4094 if (horiz_flag
4095 ? !NILP (XWINDOW (parent)->hchild)
4096 : !NILP (XWINDOW (parent)->vchild))
4097 break;
4098
4099 window = parent;
4100 }
4101
4102 sizep = &CURSIZE (window);
4103
4104 {
4105 register int maxdelta;
4106
4107 /* Compute the maximum size increment this window can have. */
4108
4109 maxdelta = (!NILP (parent) ? (*sizefun) (parent) - XINT (*sizep)
4110 /* This is a main window followed by a minibuffer. */
4111 : !NILP (p->next) ? ((*sizefun) (p->next)
4112 - window_min_size (XWINDOW (p->next),
4113 horiz_flag, 0, 0, 0))
4114 /* This is a minibuffer following a main window. */
4115 : !NILP (p->prev) ? ((*sizefun) (p->prev)
4116 - window_min_size (XWINDOW (p->prev),
4117 horiz_flag, 0, 0, 0))
4118 /* This is a frame with only one window, a minibuffer-only
4119 or a minibufferless frame. */
4120 : (delta = 0));
4121
4122 if (delta > maxdelta)
4123 /* This case traps trying to make the minibuffer
4124 the full frame, or make the only window aside from the
4125 minibuffer the full frame. */
4126 delta = maxdelta;
4127 }
4128
4129 if (XINT (*sizep) + delta < window_min_size (XWINDOW (window),
4130 horiz_flag, 0, 0, 0))
4131 {
4132 delete_window (window);
4133 return;
4134 }
4135
4136 if (delta == 0)
4137 return;
4138
4139 /* Find the total we can get from other siblings without deleting them. */
4140 maximum = 0;
4141 for (next = p->next; WINDOWP (next); next = XWINDOW (next)->next)
4142 maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
4143 horiz_flag, 0, 0, 0);
4144 for (prev = p->prev; WINDOWP (prev); prev = XWINDOW (prev)->prev)
4145 maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
4146 horiz_flag, 0, 0, 0);
4147
4148 /* If we can get it all from them without deleting them, do so. */
4149 if (delta <= maximum)
4150 {
4151 Lisp_Object first_unaffected;
4152 Lisp_Object first_affected;
4153 int fixed_p;
4154
4155 next = p->next;
4156 prev = p->prev;
4157 first_affected = window;
4158 /* Look at one sibling at a time,
4159 moving away from this window in both directions alternately,
4160 and take as much as we can get without deleting that sibling. */
4161 while (delta != 0
4162 && (!NILP (next) || !NILP (prev)))
4163 {
4164 if (! NILP (next))
4165 {
4166 int this_one = ((*sizefun) (next)
4167 - window_min_size (XWINDOW (next), horiz_flag,
4168 0, 0, &fixed_p));
4169 if (!fixed_p)
4170 {
4171 if (this_one > delta)
4172 this_one = delta;
4173
4174 (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
4175 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
4176
4177 delta -= this_one;
4178 }
4179
4180 next = XWINDOW (next)->next;
4181 }
4182
4183 if (delta == 0)
4184 break;
4185
4186 if (! NILP (prev))
4187 {
4188 int this_one = ((*sizefun) (prev)
4189 - window_min_size (XWINDOW (prev), horiz_flag,
4190 0, 0, &fixed_p));
4191 if (!fixed_p)
4192 {
4193 if (this_one > delta)
4194 this_one = delta;
4195
4196 first_affected = prev;
4197
4198 (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
4199 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
4200
4201 delta -= this_one;
4202 }
4203
4204 prev = XWINDOW (prev)->prev;
4205 }
4206 }
4207
4208 xassert (delta == 0);
4209
4210 /* Now recalculate the edge positions of all the windows affected,
4211 based on the new sizes. */
4212 first_unaffected = next;
4213 prev = first_affected;
4214 for (next = XWINDOW (prev)->next; ! EQ (next, first_unaffected);
4215 prev = next, next = XWINDOW (next)->next)
4216 {
4217 XSETINT (CURBEG (next), XINT (CURBEG (prev)) + (*sizefun) (prev));
4218 /* This does not change size of NEXT,
4219 but it propagates the new top edge to its children */
4220 (*setsizefun) (next, (*sizefun) (next), 0);
4221 }
4222 }
4223 else
4224 {
4225 register int delta1;
4226 register int opht = (*sizefun) (parent);
4227
4228 if (opht <= XINT (*sizep) + delta)
4229 {
4230 /* If trying to grow this window to or beyond size of the parent,
4231 just delete all the sibling windows. */
4232 Lisp_Object start, tem, next;
4233
4234 start = XWINDOW (parent)->vchild;
4235 if (NILP (start))
4236 start = XWINDOW (parent)->hchild;
4237
4238 /* Delete any siblings that come after WINDOW. */
4239 tem = XWINDOW (window)->next;
4240 while (! NILP (tem))
4241 {
4242 next = XWINDOW (tem)->next;
4243 delete_window (tem);
4244 tem = next;
4245 }
4246
4247 /* Delete any siblings that come after WINDOW.
4248 Note that if START is not WINDOW, then WINDOW still
4249 has siblings, so WINDOW has not yet replaced its parent. */
4250 tem = start;
4251 while (! EQ (tem, window))
4252 {
4253 next = XWINDOW (tem)->next;
4254 delete_window (tem);
4255 tem = next;
4256 }
4257 }
4258 else
4259 {
4260 /* Otherwise, make delta1 just right so that if we add
4261 delta1 lines to this window and to the parent, and then
4262 shrink the parent back to its original size, the new
4263 proportional size of this window will increase by delta.
4264
4265 The function size_window will compute the new height h'
4266 of the window from delta1 as:
4267
4268 e = delta1/n
4269 x = delta1 - delta1/n * n for the 1st resizable child
4270 h' = h + e + x
4271
4272 where n is the number of children that can be resized.
4273 We can ignore x by choosing a delta1 that is a multiple of
4274 n. We want the height of this window to come out as
4275
4276 h' = h + delta
4277
4278 So, delta1 must be
4279
4280 h + e = h + delta
4281 delta1/n = delta
4282 delta1 = n * delta.
4283
4284 The number of children n equals the number of resizable
4285 children of this window + 1 because we know window itself
4286 is resizable (otherwise we would have signaled an error).
4287
4288 This reasoning is not correct when other windows become too
4289 small and shrink_windows refuses to delete them. Below we
4290 use resize_proportionally to work around this problem. */
4291
4292 struct window *w = XWINDOW (window);
4293 Lisp_Object s;
4294 int n = 1;
4295
4296 for (s = w->next; WINDOWP (s); s = XWINDOW (s)->next)
4297 if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
4298 ++n;
4299 for (s = w->prev; WINDOWP (s); s = XWINDOW (s)->prev)
4300 if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
4301 ++n;
4302
4303 delta1 = n * delta;
4304
4305 /* Add delta1 lines or columns to this window, and to the parent,
4306 keeping things consistent while not affecting siblings. */
4307 XSETINT (CURSIZE (parent), opht + delta1);
4308 (*setsizefun) (window, XINT (*sizep) + delta1, 0);
4309
4310 /* Squeeze out delta1 lines or columns from our parent,
4311 shrinking this window and siblings proportionately. This
4312 brings parent back to correct size. Delta1 was calculated
4313 so this makes this window the desired size, taking it all
4314 out of the siblings.
4315
4316 Temporarily set resize_proportionally to Qt to assure that,
4317 if necessary, shrink_windows deletes smaller windows rather
4318 than shrink this window. */
4319 w->resize_proportionally = Qt;
4320 (*setsizefun) (parent, opht, 0);
4321 w->resize_proportionally = Qnil;
4322 }
4323 }
4324
4325 XSETFASTINT (p->last_modified, 0);
4326 XSETFASTINT (p->last_overlay_modified, 0);
4327
4328 /* Adjust glyph matrices. */
4329 adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
4330 }
4331
4332
4333 /* Adjust the size of WINDOW by DELTA, moving only its trailing edge.
4334 HORIZ_FLAG nonzero means adjust the width, moving the right edge.
4335 zero means adjust the height, moving the bottom edge.
4336
4337 Following siblings of the selected window are resized to fulfill
4338 the size request. If they become too small in the process, they
4339 are not deleted; instead, we signal an error. */
4340
4341 static void
4342 adjust_window_trailing_edge (window, delta, horiz_flag)
4343 Lisp_Object window;
4344 int delta, horiz_flag;
4345 {
4346 Lisp_Object parent, child;
4347 struct window *p;
4348 Lisp_Object old_config = Fcurrent_window_configuration (Qnil);
4349 int delcount = window_deletion_count;
4350
4351 CHECK_WINDOW (window);
4352
4353 /* Give up if this window cannot be resized. */
4354 if (window_fixed_size_p (XWINDOW (window), horiz_flag, 1))
4355 error ("Window is not resizable");
4356
4357 while (1)
4358 {
4359 Lisp_Object first_parallel = Qnil;
4360
4361 if (NILP (window))
4362 {
4363 /* This happens if WINDOW on the previous iteration was
4364 at top level of the window tree. */
4365 Fset_window_configuration (old_config);
4366 error ("Specified window edge is fixed");
4367 }
4368
4369 p = XWINDOW (window);
4370 parent = p->parent;
4371
4372 /* See if this level has windows in parallel in the specified
4373 direction. If so, set FIRST_PARALLEL to the first one. */
4374 if (horiz_flag)
4375 {
4376 if (! NILP (parent) && !NILP (XWINDOW (parent)->vchild))
4377 first_parallel = XWINDOW (parent)->vchild;
4378 else if (NILP (parent) && !NILP (p->next))
4379 {
4380 /* Handle the vertical chain of main window and minibuffer
4381 which has no parent. */
4382 first_parallel = window;
4383 while (! NILP (XWINDOW (first_parallel)->prev))
4384 first_parallel = XWINDOW (first_parallel)->prev;
4385 }
4386 }
4387 else
4388 {
4389 if (! NILP (parent) && !NILP (XWINDOW (parent)->hchild))
4390 first_parallel = XWINDOW (parent)->hchild;
4391 }
4392
4393 /* If this level's succession is in the desired dimension,
4394 and this window is the last one, and there is no higher level,
4395 its trailing edge is fixed. */
4396 if (NILP (XWINDOW (window)->next) && NILP (first_parallel)
4397 && NILP (parent))
4398 {
4399 Fset_window_configuration (old_config);
4400 error ("Specified window edge is fixed");
4401 }
4402
4403 /* Don't make this window too small. */
4404 if (XINT (CURSIZE (window)) + delta
4405 < window_min_size_2 (XWINDOW (window), horiz_flag, 0))
4406 {
4407 Fset_window_configuration (old_config);
4408 error ("Cannot adjust window size as specified");
4409 }
4410
4411 /* Clear out some redisplay caches. */
4412 XSETFASTINT (p->last_modified, 0);
4413 XSETFASTINT (p->last_overlay_modified, 0);
4414
4415 /* Adjust this window's edge. */
4416 XSETINT (CURSIZE (window),
4417 XINT (CURSIZE (window)) + delta);
4418
4419 /* If this window has following siblings in the desired dimension,
4420 make them smaller, and exit the loop.
4421
4422 (If we reach the top of the tree and can never do this,
4423 we will fail and report an error, above.) */
4424 if (NILP (first_parallel))
4425 {
4426 if (!NILP (p->next))
4427 {
4428 /* This may happen for the minibuffer. In that case
4429 the window_deletion_count check below does not work. */
4430 if (XINT (CURSIZE (p->next)) - delta <= 0)
4431 {
4432 Fset_window_configuration (old_config);
4433 error ("Cannot adjust window size as specified");
4434 }
4435
4436 XSETINT (CURBEG (p->next),
4437 XINT (CURBEG (p->next)) + delta);
4438 size_window (p->next, XINT (CURSIZE (p->next)) - delta,
4439 horiz_flag, 0, 1, 0);
4440 break;
4441 }
4442 }
4443 else
4444 /* Here we have a chain of parallel siblings, in the other dimension.
4445 Change the size of the other siblings. */
4446 for (child = first_parallel;
4447 ! NILP (child);
4448 child = XWINDOW (child)->next)
4449 if (! EQ (child, window))
4450 size_window (child, XINT (CURSIZE (child)) + delta,
4451 horiz_flag, 0, 0, 1);
4452
4453 window = parent;
4454 }
4455
4456 /* If we made a window so small it got deleted,
4457 we failed. Report failure. */
4458 if (delcount != window_deletion_count)
4459 {
4460 Fset_window_configuration (old_config);
4461 error ("Cannot adjust window size as specified");
4462 }
4463
4464 /* Adjust glyph matrices. */
4465 adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
4466 }
4467
4468 #undef CURBEG
4469 #undef CURSIZE
4470
4471 DEFUN ("adjust-window-trailing-edge", Fadjust_window_trailing_edge,
4472 Sadjust_window_trailing_edge, 3, 3, 0,
4473 doc: /* Adjust the bottom or right edge of WINDOW by DELTA.
4474 If HORIZONTAL is non-nil, that means adjust the width, moving the right edge.
4475 Otherwise, adjust the height, moving the bottom edge.
4476
4477 Following siblings of the selected window are resized to fulfill
4478 the size request. If they become too small in the process, they
4479 are not deleted; instead, we signal an error. */)
4480 (window, delta, horizontal)
4481 Lisp_Object window, delta, horizontal;
4482 {
4483 CHECK_NUMBER (delta);
4484 if (NILP (window))
4485 window = selected_window;
4486 adjust_window_trailing_edge (window, XINT (delta), !NILP (horizontal));
4487
4488 run_window_configuration_change_hook
4489 (XFRAME (WINDOW_FRAME (XWINDOW (window))));
4490
4491 return Qnil;
4492 }
4493
4494
4495 \f
4496 /***********************************************************************
4497 Resizing Mini-Windows
4498 ***********************************************************************/
4499
4500 static void shrink_window_lowest_first P_ ((struct window *, int));
4501
4502 enum save_restore_action
4503 {
4504 CHECK_ORIG_SIZES,
4505 SAVE_ORIG_SIZES,
4506 RESTORE_ORIG_SIZES
4507 };
4508
4509 static int save_restore_orig_size P_ ((struct window *,
4510 enum save_restore_action));
4511
4512 /* Shrink windows rooted in window W to HEIGHT. Take the space needed
4513 from lowest windows first. */
4514
4515 static void
4516 shrink_window_lowest_first (w, height)
4517 struct window *w;
4518 int height;
4519 {
4520 struct window *c;
4521 Lisp_Object child;
4522 int old_height;
4523
4524 xassert (!MINI_WINDOW_P (w));
4525
4526 /* Set redisplay hints. */
4527 XSETFASTINT (w->last_modified, 0);
4528 XSETFASTINT (w->last_overlay_modified, 0);
4529 windows_or_buffers_changed++;
4530 FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
4531
4532 old_height = XFASTINT (w->total_lines);
4533 XSETFASTINT (w->total_lines, height);
4534
4535 if (!NILP (w->hchild))
4536 {
4537 for (child = w->hchild; !NILP (child); child = c->next)
4538 {
4539 c = XWINDOW (child);
4540 c->top_line = w->top_line;
4541 shrink_window_lowest_first (c, height);
4542 }
4543 }
4544 else if (!NILP (w->vchild))
4545 {
4546 Lisp_Object last_child;
4547 int delta = old_height - height;
4548 int last_top;
4549
4550 last_child = Qnil;
4551
4552 /* Find the last child. We are taking space from lowest windows
4553 first, so we iterate over children from the last child
4554 backwards. */
4555 for (child = w->vchild; WINDOWP (child); child = XWINDOW (child)->next)
4556 last_child = child;
4557
4558 /* Size children down to their safe heights. */
4559 for (child = last_child; delta && !NILP (child); child = c->prev)
4560 {
4561 int this_one;
4562
4563 c = XWINDOW (child);
4564 this_one = XFASTINT (c->total_lines) - window_min_size_1 (c, 0, 1);
4565
4566 if (this_one > delta)
4567 this_one = delta;
4568
4569 shrink_window_lowest_first (c, XFASTINT (c->total_lines) - this_one);
4570 delta -= this_one;
4571 }
4572
4573 /* Compute new positions. */
4574 last_top = XINT (w->top_line);
4575 for (child = w->vchild; !NILP (child); child = c->next)
4576 {
4577 c = XWINDOW (child);
4578 c->top_line = make_number (last_top);
4579 shrink_window_lowest_first (c, XFASTINT (c->total_lines));
4580 last_top += XFASTINT (c->total_lines);
4581 }
4582 }
4583 }
4584
4585
4586 /* Save, restore, or check positions and sizes in the window tree
4587 rooted at W. ACTION says what to do.
4588
4589 If ACTION is CHECK_ORIG_SIZES, check if orig_top_line and
4590 orig_total_lines members are valid for all windows in the window
4591 tree. Value is non-zero if they are valid.
4592
4593 If ACTION is SAVE_ORIG_SIZES, save members top and height in
4594 orig_top_line and orig_total_lines for all windows in the tree.
4595
4596 If ACTION is RESTORE_ORIG_SIZES, restore top and height from values
4597 stored in orig_top_line and orig_total_lines for all windows. */
4598
4599 static int
4600 save_restore_orig_size (w, action)
4601 struct window *w;
4602 enum save_restore_action action;
4603 {
4604 int success_p = 1;
4605
4606 while (w)
4607 {
4608 if (!NILP (w->hchild))
4609 {
4610 if (!save_restore_orig_size (XWINDOW (w->hchild), action))
4611 success_p = 0;
4612 }
4613 else if (!NILP (w->vchild))
4614 {
4615 if (!save_restore_orig_size (XWINDOW (w->vchild), action))
4616 success_p = 0;
4617 }
4618
4619 switch (action)
4620 {
4621 case CHECK_ORIG_SIZES:
4622 if (!INTEGERP (w->orig_top_line) || !INTEGERP (w->orig_total_lines))
4623 return 0;
4624 break;
4625
4626 case SAVE_ORIG_SIZES:
4627 w->orig_top_line = w->top_line;
4628 w->orig_total_lines = w->total_lines;
4629 XSETFASTINT (w->last_modified, 0);
4630 XSETFASTINT (w->last_overlay_modified, 0);
4631 break;
4632
4633 case RESTORE_ORIG_SIZES:
4634 xassert (INTEGERP (w->orig_top_line) && INTEGERP (w->orig_total_lines));
4635 w->top_line = w->orig_top_line;
4636 w->total_lines = w->orig_total_lines;
4637 w->orig_total_lines = w->orig_top_line = Qnil;
4638 XSETFASTINT (w->last_modified, 0);
4639 XSETFASTINT (w->last_overlay_modified, 0);
4640 break;
4641
4642 default:
4643 abort ();
4644 }
4645
4646 w = NILP (w->next) ? NULL : XWINDOW (w->next);
4647 }
4648
4649 return success_p;
4650 }
4651
4652
4653 /* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we can
4654 without deleting other windows. */
4655
4656 void
4657 grow_mini_window (w, delta)
4658 struct window *w;
4659 int delta;
4660 {
4661 struct frame *f = XFRAME (w->frame);
4662 struct window *root;
4663
4664 xassert (MINI_WINDOW_P (w));
4665 /* Commenting out the following assertion goes against the stated interface
4666 of the function, but it currently does not seem to do anything useful.
4667 See discussion of this issue in the thread for bug#4534.
4668 xassert (delta >= 0); */
4669
4670 /* Compute how much we can enlarge the mini-window without deleting
4671 other windows. */
4672 root = XWINDOW (FRAME_ROOT_WINDOW (f));
4673 if (delta > 0)
4674 {
4675 int min_height = window_min_size (root, 0, 0, 0, 0);
4676 if (XFASTINT (root->total_lines) - delta < min_height)
4677 /* Note that the root window may already be smaller than
4678 min_height. */
4679 delta = max (0, XFASTINT (root->total_lines) - min_height);
4680 }
4681
4682 if (delta)
4683 {
4684 /* Save original window sizes and positions, if not already done. */
4685 if (!save_restore_orig_size (root, CHECK_ORIG_SIZES))
4686 save_restore_orig_size (root, SAVE_ORIG_SIZES);
4687
4688 /* Shrink other windows. */
4689 shrink_window_lowest_first (root, XFASTINT (root->total_lines) - delta);
4690
4691 /* Grow the mini-window. */
4692 w->top_line = make_number (XFASTINT (root->top_line) + XFASTINT (root->total_lines));
4693 w->total_lines = make_number (XFASTINT (w->total_lines) + delta);
4694 XSETFASTINT (w->last_modified, 0);
4695 XSETFASTINT (w->last_overlay_modified, 0);
4696
4697 adjust_glyphs (f);
4698 }
4699 }
4700
4701
4702 /* Shrink mini-window W. If there is recorded info about window sizes
4703 before a call to grow_mini_window, restore recorded window sizes.
4704 Otherwise, if the mini-window is higher than 1 line, resize it to 1
4705 line. */
4706
4707 void
4708 shrink_mini_window (w)
4709 struct window *w;
4710 {
4711 struct frame *f = XFRAME (w->frame);
4712 struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
4713
4714 if (save_restore_orig_size (root, CHECK_ORIG_SIZES))
4715 {
4716 save_restore_orig_size (root, RESTORE_ORIG_SIZES);
4717 adjust_glyphs (f);
4718 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
4719 windows_or_buffers_changed = 1;
4720 }
4721 else if (XFASTINT (w->total_lines) > 1)
4722 {
4723 /* Distribute the additional lines of the mini-window
4724 among the other windows. */
4725 Lisp_Object window;
4726 XSETWINDOW (window, w);
4727 enlarge_window (window, 1 - XFASTINT (w->total_lines), 0);
4728 }
4729 }
4730
4731
4732 \f
4733 /* Mark window cursors off for all windows in the window tree rooted
4734 at W by setting their phys_cursor_on_p flag to zero. Called from
4735 xterm.c, e.g. when a frame is cleared and thereby all cursors on
4736 the frame are cleared. */
4737
4738 void
4739 mark_window_cursors_off (w)
4740 struct window *w;
4741 {
4742 while (w)
4743 {
4744 if (!NILP (w->hchild))
4745 mark_window_cursors_off (XWINDOW (w->hchild));
4746 else if (!NILP (w->vchild))
4747 mark_window_cursors_off (XWINDOW (w->vchild));
4748 else
4749 w->phys_cursor_on_p = 0;
4750
4751 w = NILP (w->next) ? 0 : XWINDOW (w->next);
4752 }
4753 }
4754
4755
4756 /* Return number of lines of text (not counting mode lines) in W. */
4757
4758 int
4759 window_internal_height (w)
4760 struct window *w;
4761 {
4762 int ht = XFASTINT (w->total_lines);
4763
4764 if (!MINI_WINDOW_P (w))
4765 {
4766 if (!NILP (w->parent)
4767 || !NILP (w->vchild)
4768 || !NILP (w->hchild)
4769 || !NILP (w->next)
4770 || !NILP (w->prev)
4771 || WINDOW_WANTS_MODELINE_P (w))
4772 --ht;
4773
4774 if (WINDOW_WANTS_HEADER_LINE_P (w))
4775 --ht;
4776 }
4777
4778 return ht;
4779 }
4780
4781
4782 /* Return the number of columns in W.
4783 Don't count columns occupied by scroll bars or the vertical bar
4784 separating W from the sibling to its right. */
4785
4786 int
4787 window_box_text_cols (w)
4788 struct window *w;
4789 {
4790 struct frame *f = XFRAME (WINDOW_FRAME (w));
4791 int width = XINT (w->total_cols);
4792
4793 if (WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
4794 /* Scroll bars occupy a few columns. */
4795 width -= WINDOW_CONFIG_SCROLL_BAR_COLS (w);
4796 else if (!FRAME_WINDOW_P (f)
4797 && !WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
4798 /* The column of `|' characters separating side-by-side windows
4799 occupies one column only. */
4800 width -= 1;
4801
4802 if (FRAME_WINDOW_P (f))
4803 /* On window-systems, fringes and display margins cannot be
4804 used for normal text. */
4805 width -= (WINDOW_FRINGE_COLS (w)
4806 + WINDOW_LEFT_MARGIN_COLS (w)
4807 + WINDOW_RIGHT_MARGIN_COLS (w));
4808
4809 return width;
4810 }
4811
4812 \f
4813 /************************************************************************
4814 Window Scrolling
4815 ***********************************************************************/
4816
4817 /* Scroll contents of window WINDOW up. If WHOLE is non-zero, scroll
4818 N screen-fulls, which is defined as the height of the window minus
4819 next_screen_context_lines. If WHOLE is zero, scroll up N lines
4820 instead. Negative values of N mean scroll down. NOERROR non-zero
4821 means don't signal an error if we try to move over BEGV or ZV,
4822 respectively. */
4823
4824 static void
4825 window_scroll (window, n, whole, noerror)
4826 Lisp_Object window;
4827 int n;
4828 int whole;
4829 int noerror;
4830 {
4831 immediate_quit = 1;
4832
4833 /* If we must, use the pixel-based version which is much slower than
4834 the line-based one but can handle varying line heights. */
4835 if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
4836 window_scroll_pixel_based (window, n, whole, noerror);
4837 else
4838 window_scroll_line_based (window, n, whole, noerror);
4839
4840 immediate_quit = 0;
4841 }
4842
4843
4844 /* Implementation of window_scroll that works based on pixel line
4845 heights. See the comment of window_scroll for parameter
4846 descriptions. */
4847
4848 static void
4849 window_scroll_pixel_based (window, n, whole, noerror)
4850 Lisp_Object window;
4851 int n;
4852 int whole;
4853 int noerror;
4854 {
4855 struct it it;
4856 struct window *w = XWINDOW (window);
4857 struct text_pos start;
4858 int this_scroll_margin;
4859 /* True if we fiddled the window vscroll field without really scrolling. */
4860 int vscrolled = 0;
4861 int x, y, rtop, rbot, rowh, vpos;
4862
4863 SET_TEXT_POS_FROM_MARKER (start, w->start);
4864
4865 /* If PT is not visible in WINDOW, move back one half of
4866 the screen. Allow PT to be partially visible, otherwise
4867 something like (scroll-down 1) with PT in the line before
4868 the partially visible one would recenter. */
4869
4870 if (!pos_visible_p (w, PT, &x, &y, &rtop, &rbot, &rowh, &vpos))
4871 {
4872 /* Move backward half the height of the window. Performance note:
4873 vmotion used here is about 10% faster, but would give wrong
4874 results for variable height lines. */
4875 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
4876 it.current_y = it.last_visible_y;
4877 move_it_vertically_backward (&it, window_box_height (w) / 2);
4878
4879 /* The function move_iterator_vertically may move over more than
4880 the specified y-distance. If it->w is small, e.g. a
4881 mini-buffer window, we may end up in front of the window's
4882 display area. This is the case when Start displaying at the
4883 start of the line containing PT in this case. */
4884 if (it.current_y <= 0)
4885 {
4886 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
4887 move_it_vertically_backward (&it, 0);
4888 it.current_y = 0;
4889 }
4890
4891 start = it.current.pos;
4892 }
4893 else if (auto_window_vscroll_p)
4894 {
4895 if (rtop || rbot) /* partially visible */
4896 {
4897 int px;
4898 int dy = WINDOW_FRAME_LINE_HEIGHT (w);
4899 if (whole)
4900 dy = max ((window_box_height (w)
4901 - next_screen_context_lines * dy),
4902 dy);
4903 dy *= n;
4904
4905 if (n < 0)
4906 {
4907 /* Only vscroll backwards if already vscrolled forwards. */
4908 if (w->vscroll < 0 && rtop > 0)
4909 {
4910 px = max (0, -w->vscroll - min (rtop, -dy));
4911 Fset_window_vscroll (window, make_number (px), Qt);
4912 return;
4913 }
4914 }
4915 if (n > 0)
4916 {
4917 /* Do vscroll if already vscrolled or only display line. */
4918 if (rbot > 0 && (w->vscroll < 0 || vpos == 0))
4919 {
4920 px = max (0, -w->vscroll + min (rbot, dy));
4921 Fset_window_vscroll (window, make_number (px), Qt);
4922 return;
4923 }
4924
4925 /* Maybe modify window start instead of scrolling. */
4926 if (rbot > 0 || w->vscroll < 0)
4927 {
4928 int spos;
4929
4930 Fset_window_vscroll (window, make_number (0), Qt);
4931 /* If there are other text lines above the current row,
4932 move window start to current row. Else to next row. */
4933 if (rbot > 0)
4934 spos = XINT (Fline_beginning_position (Qnil));
4935 else
4936 spos = min (XINT (Fline_end_position (Qnil)) + 1, ZV);
4937 set_marker_restricted (w->start, make_number (spos),
4938 w->buffer);
4939 w->start_at_line_beg = Qt;
4940 w->update_mode_line = Qt;
4941 XSETFASTINT (w->last_modified, 0);
4942 XSETFASTINT (w->last_overlay_modified, 0);
4943 /* Set force_start so that redisplay_window will run the
4944 window-scroll-functions. */
4945 w->force_start = Qt;
4946 return;
4947 }
4948 }
4949 }
4950 /* Cancel previous vscroll. */
4951 Fset_window_vscroll (window, make_number (0), Qt);
4952 }
4953
4954 /* If scroll_preserve_screen_position is non-nil, we try to set
4955 point in the same window line as it is now, so get that line. */
4956 if (!NILP (Vscroll_preserve_screen_position))
4957 {
4958 /* We preserve the goal pixel coordinate across consecutive
4959 calls to scroll-up or scroll-down. This avoids the
4960 possibility of point becoming "stuck" on a tall line when
4961 scrolling by one line. */
4962 if (window_scroll_pixel_based_preserve_y < 0
4963 || (!EQ (current_kboard->Vlast_command, Qscroll_up)
4964 && !EQ (current_kboard->Vlast_command, Qscroll_down)))
4965 {
4966 start_display (&it, w, start);
4967 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
4968 window_scroll_pixel_based_preserve_y = it.current_y;
4969 window_scroll_pixel_based_preserve_x = it.current_x;
4970 }
4971 }
4972 else
4973 window_scroll_pixel_based_preserve_y
4974 = window_scroll_pixel_based_preserve_x = -1;
4975
4976 /* Move iterator it from start the specified distance forward or
4977 backward. The result is the new window start. */
4978 start_display (&it, w, start);
4979 if (whole)
4980 {
4981 int start_pos = IT_CHARPOS (it);
4982 int dy = WINDOW_FRAME_LINE_HEIGHT (w);
4983 dy = max ((window_box_height (w)
4984 - next_screen_context_lines * dy),
4985 dy) * n;
4986
4987 /* Note that move_it_vertically always moves the iterator to the
4988 start of a line. So, if the last line doesn't have a newline,
4989 we would end up at the start of the line ending at ZV. */
4990 if (dy <= 0)
4991 {
4992 move_it_vertically_backward (&it, -dy);
4993 /* Ensure we actually do move, e.g. in case we are currently
4994 looking at an image that is taller that the window height. */
4995 while (start_pos == IT_CHARPOS (it)
4996 && start_pos > BEGV)
4997 move_it_by_lines (&it, -1, 1);
4998 }
4999 else if (dy > 0)
5000 {
5001 move_it_to (&it, ZV, -1, it.current_y + dy, -1,
5002 MOVE_TO_POS | MOVE_TO_Y);
5003 /* Ensure we actually do move, e.g. in case we are currently
5004 looking at an image that is taller that the window height. */
5005 while (start_pos == IT_CHARPOS (it)
5006 && start_pos < ZV)
5007 move_it_by_lines (&it, 1, 1);
5008 }
5009 }
5010 else
5011 move_it_by_lines (&it, n, 1);
5012
5013 /* We failed if we find ZV is already on the screen (scrolling up,
5014 means there's nothing past the end), or if we can't start any
5015 earlier (scrolling down, means there's nothing past the top). */
5016 if ((n > 0 && IT_CHARPOS (it) == ZV)
5017 || (n < 0 && IT_CHARPOS (it) == CHARPOS (start)))
5018 {
5019 if (IT_CHARPOS (it) == ZV)
5020 {
5021 if (it.current_y < it.last_visible_y
5022 && (it.current_y + it.max_ascent + it.max_descent
5023 > it.last_visible_y))
5024 {
5025 /* The last line was only partially visible, make it fully
5026 visible. */
5027 w->vscroll = (it.last_visible_y
5028 - it.current_y + it.max_ascent + it.max_descent);
5029 adjust_glyphs (it.f);
5030 }
5031 else if (noerror)
5032 return;
5033 else if (n < 0) /* could happen with empty buffers */
5034 xsignal0 (Qbeginning_of_buffer);
5035 else
5036 xsignal0 (Qend_of_buffer);
5037 }
5038 else
5039 {
5040 if (w->vscroll != 0)
5041 /* The first line was only partially visible, make it fully
5042 visible. */
5043 w->vscroll = 0;
5044 else if (noerror)
5045 return;
5046 else
5047 xsignal0 (Qbeginning_of_buffer);
5048 }
5049
5050 /* If control gets here, then we vscrolled. */
5051
5052 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
5053
5054 /* Don't try to change the window start below. */
5055 vscrolled = 1;
5056 }
5057
5058 if (! vscrolled)
5059 {
5060 int pos = IT_CHARPOS (it);
5061 int bytepos;
5062
5063 /* If in the middle of a multi-glyph character move forward to
5064 the next character. */
5065 if (in_display_vector_p (&it))
5066 {
5067 ++pos;
5068 move_it_to (&it, pos, -1, -1, -1, MOVE_TO_POS);
5069 }
5070
5071 /* Set the window start, and set up the window for redisplay. */
5072 set_marker_restricted (w->start, make_number (pos),
5073 w->buffer);
5074 bytepos = XMARKER (w->start)->bytepos;
5075 w->start_at_line_beg = ((pos == BEGV || FETCH_BYTE (bytepos - 1) == '\n')
5076 ? Qt : Qnil);
5077 w->update_mode_line = Qt;
5078 XSETFASTINT (w->last_modified, 0);
5079 XSETFASTINT (w->last_overlay_modified, 0);
5080 /* Set force_start so that redisplay_window will run the
5081 window-scroll-functions. */
5082 w->force_start = Qt;
5083 }
5084
5085 /* The rest of this function uses current_y in a nonstandard way,
5086 not including the height of the header line if any. */
5087 it.current_y = it.vpos = 0;
5088
5089 /* Move PT out of scroll margins.
5090 This code wants current_y to be zero at the window start position
5091 even if there is a header line. */
5092 this_scroll_margin = max (0, scroll_margin);
5093 this_scroll_margin = min (this_scroll_margin, XFASTINT (w->total_lines) / 4);
5094 this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
5095
5096 if (n > 0)
5097 {
5098 /* We moved the window start towards ZV, so PT may be now
5099 in the scroll margin at the top. */
5100 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
5101 if (IT_CHARPOS (it) == PT && it.current_y >= this_scroll_margin
5102 && (NILP (Vscroll_preserve_screen_position)
5103 || EQ (Vscroll_preserve_screen_position, Qt)))
5104 /* We found PT at a legitimate height. Leave it alone. */
5105 ;
5106 else if (window_scroll_pixel_based_preserve_y >= 0)
5107 {
5108 /* If we have a header line, take account of it.
5109 This is necessary because we set it.current_y to 0, above. */
5110 move_it_to (&it, -1,
5111 window_scroll_pixel_based_preserve_x,
5112 window_scroll_pixel_based_preserve_y
5113 - (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0 ),
5114 -1, MOVE_TO_Y | MOVE_TO_X);
5115 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5116 }
5117 else
5118 {
5119 while (it.current_y < this_scroll_margin)
5120 {
5121 int prev = it.current_y;
5122 move_it_by_lines (&it, 1, 1);
5123 if (prev == it.current_y)
5124 break;
5125 }
5126 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5127 }
5128 }
5129 else if (n < 0)
5130 {
5131 int charpos, bytepos;
5132 int partial_p;
5133
5134 /* Save our position, for the
5135 window_scroll_pixel_based_preserve_y case. */
5136 charpos = IT_CHARPOS (it);
5137 bytepos = IT_BYTEPOS (it);
5138
5139 /* We moved the window start towards BEGV, so PT may be now
5140 in the scroll margin at the bottom. */
5141 move_it_to (&it, PT, -1,
5142 (it.last_visible_y - CURRENT_HEADER_LINE_HEIGHT (w)
5143 - this_scroll_margin - 1),
5144 -1,
5145 MOVE_TO_POS | MOVE_TO_Y);
5146
5147 /* Save our position, in case it's correct. */
5148 charpos = IT_CHARPOS (it);
5149 bytepos = IT_BYTEPOS (it);
5150
5151 /* See if point is on a partially visible line at the end. */
5152 if (it.what == IT_EOB)
5153 partial_p = it.current_y + it.ascent + it.descent > it.last_visible_y;
5154 else
5155 {
5156 move_it_by_lines (&it, 1, 1);
5157 partial_p = it.current_y > it.last_visible_y;
5158 }
5159
5160 if (charpos == PT && !partial_p
5161 && (NILP (Vscroll_preserve_screen_position)
5162 || EQ (Vscroll_preserve_screen_position, Qt)))
5163 /* We found PT before we found the display margin, so PT is ok. */
5164 ;
5165 else if (window_scroll_pixel_based_preserve_y >= 0)
5166 {
5167 SET_TEXT_POS_FROM_MARKER (start, w->start);
5168 start_display (&it, w, start);
5169 /* It would be wrong to subtract CURRENT_HEADER_LINE_HEIGHT
5170 here because we called start_display again and did not
5171 alter it.current_y this time. */
5172 move_it_to (&it, -1, window_scroll_pixel_based_preserve_x,
5173 window_scroll_pixel_based_preserve_y, -1,
5174 MOVE_TO_Y | MOVE_TO_X);
5175 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5176 }
5177 else
5178 {
5179 if (partial_p)
5180 /* The last line was only partially visible, so back up two
5181 lines to make sure we're on a fully visible line. */
5182 {
5183 move_it_by_lines (&it, -2, 0);
5184 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5185 }
5186 else
5187 /* No, the position we saved is OK, so use it. */
5188 SET_PT_BOTH (charpos, bytepos);
5189 }
5190 }
5191 }
5192
5193
5194 /* Implementation of window_scroll that works based on screen lines.
5195 See the comment of window_scroll for parameter descriptions. */
5196
5197 static void
5198 window_scroll_line_based (window, n, whole, noerror)
5199 Lisp_Object window;
5200 int n;
5201 int whole;
5202 int noerror;
5203 {
5204 register struct window *w = XWINDOW (window);
5205 register int opoint = PT, opoint_byte = PT_BYTE;
5206 register int pos, pos_byte;
5207 register int ht = window_internal_height (w);
5208 register Lisp_Object tem;
5209 int lose;
5210 Lisp_Object bolp;
5211 int startpos;
5212 Lisp_Object original_pos = Qnil;
5213
5214 /* If scrolling screen-fulls, compute the number of lines to
5215 scroll from the window's height. */
5216 if (whole)
5217 n *= max (1, ht - next_screen_context_lines);
5218
5219 startpos = marker_position (w->start);
5220
5221 if (!NILP (Vscroll_preserve_screen_position))
5222 {
5223 if (window_scroll_preserve_vpos <= 0
5224 || (!EQ (current_kboard->Vlast_command, Qscroll_up)
5225 && !EQ (current_kboard->Vlast_command, Qscroll_down)))
5226 {
5227 struct position posit
5228 = *compute_motion (startpos, 0, 0, 0,
5229 PT, ht, 0,
5230 -1, XINT (w->hscroll),
5231 0, w);
5232 window_scroll_preserve_vpos = posit.vpos;
5233 window_scroll_preserve_hpos = posit.hpos + XINT (w->hscroll);
5234 }
5235
5236 original_pos = Fcons (make_number (window_scroll_preserve_hpos),
5237 make_number (window_scroll_preserve_vpos));
5238 }
5239
5240 XSETFASTINT (tem, PT);
5241 tem = Fpos_visible_in_window_p (tem, window, Qnil);
5242
5243 if (NILP (tem))
5244 {
5245 Fvertical_motion (make_number (- (ht / 2)), window);
5246 startpos = PT;
5247 }
5248
5249 SET_PT (startpos);
5250 lose = n < 0 && PT == BEGV;
5251 Fvertical_motion (make_number (n), window);
5252 pos = PT;
5253 pos_byte = PT_BYTE;
5254 bolp = Fbolp ();
5255 SET_PT_BOTH (opoint, opoint_byte);
5256
5257 if (lose)
5258 {
5259 if (noerror)
5260 return;
5261 else
5262 xsignal0 (Qbeginning_of_buffer);
5263 }
5264
5265 if (pos < ZV)
5266 {
5267 int this_scroll_margin = scroll_margin;
5268
5269 /* Don't use a scroll margin that is negative or too large. */
5270 if (this_scroll_margin < 0)
5271 this_scroll_margin = 0;
5272
5273 if (XINT (w->total_lines) < 4 * scroll_margin)
5274 this_scroll_margin = XINT (w->total_lines) / 4;
5275
5276 set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
5277 w->start_at_line_beg = bolp;
5278 w->update_mode_line = Qt;
5279 XSETFASTINT (w->last_modified, 0);
5280 XSETFASTINT (w->last_overlay_modified, 0);
5281 /* Set force_start so that redisplay_window will run
5282 the window-scroll-functions. */
5283 w->force_start = Qt;
5284
5285 if (!NILP (Vscroll_preserve_screen_position)
5286 && (whole || !EQ (Vscroll_preserve_screen_position, Qt)))
5287 {
5288 SET_PT_BOTH (pos, pos_byte);
5289 Fvertical_motion (original_pos, window);
5290 }
5291 /* If we scrolled forward, put point enough lines down
5292 that it is outside the scroll margin. */
5293 else if (n > 0)
5294 {
5295 int top_margin;
5296
5297 if (this_scroll_margin > 0)
5298 {
5299 SET_PT_BOTH (pos, pos_byte);
5300 Fvertical_motion (make_number (this_scroll_margin), window);
5301 top_margin = PT;
5302 }
5303 else
5304 top_margin = pos;
5305
5306 if (top_margin <= opoint)
5307 SET_PT_BOTH (opoint, opoint_byte);
5308 else if (!NILP (Vscroll_preserve_screen_position))
5309 {
5310 SET_PT_BOTH (pos, pos_byte);
5311 Fvertical_motion (original_pos, window);
5312 }
5313 else
5314 SET_PT (top_margin);
5315 }
5316 else if (n < 0)
5317 {
5318 int bottom_margin;
5319
5320 /* If we scrolled backward, put point near the end of the window
5321 but not within the scroll margin. */
5322 SET_PT_BOTH (pos, pos_byte);
5323 tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
5324 if (XFASTINT (tem) == ht - this_scroll_margin)
5325 bottom_margin = PT;
5326 else
5327 bottom_margin = PT + 1;
5328
5329 if (bottom_margin > opoint)
5330 SET_PT_BOTH (opoint, opoint_byte);
5331 else
5332 {
5333 if (!NILP (Vscroll_preserve_screen_position))
5334 {
5335 SET_PT_BOTH (pos, pos_byte);
5336 Fvertical_motion (original_pos, window);
5337 }
5338 else
5339 Fvertical_motion (make_number (-1), window);
5340 }
5341 }
5342 }
5343 else
5344 {
5345 if (noerror)
5346 return;
5347 else
5348 xsignal0 (Qend_of_buffer);
5349 }
5350 }
5351
5352
5353 /* Scroll selected_window up or down. If N is nil, scroll a
5354 screen-full which is defined as the height of the window minus
5355 next_screen_context_lines. If N is the symbol `-', scroll.
5356 DIRECTION may be 1 meaning to scroll down, or -1 meaning to scroll
5357 up. This is the guts of Fscroll_up and Fscroll_down. */
5358
5359 static void
5360 scroll_command (n, direction)
5361 Lisp_Object n;
5362 int direction;
5363 {
5364 int count = SPECPDL_INDEX ();
5365
5366 xassert (eabs (direction) == 1);
5367
5368 /* If selected window's buffer isn't current, make it current for
5369 the moment. But don't screw up if window_scroll gets an error. */
5370 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
5371 {
5372 record_unwind_protect (save_excursion_restore, save_excursion_save ());
5373 Fset_buffer (XWINDOW (selected_window)->buffer);
5374
5375 /* Make redisplay consider other windows than just selected_window. */
5376 ++windows_or_buffers_changed;
5377 }
5378
5379 if (NILP (n))
5380 window_scroll (selected_window, direction, 1, 0);
5381 else if (EQ (n, Qminus))
5382 window_scroll (selected_window, -direction, 1, 0);
5383 else
5384 {
5385 n = Fprefix_numeric_value (n);
5386 window_scroll (selected_window, XINT (n) * direction, 0, 0);
5387 }
5388
5389 unbind_to (count, Qnil);
5390 }
5391
5392 DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "^P",
5393 doc: /* Scroll text of selected window upward ARG lines.
5394 If ARG is omitted or nil, scroll upward by a near full screen.
5395 A near full screen is `next-screen-context-lines' less than a full screen.
5396 Negative ARG means scroll downward.
5397 If ARG is the atom `-', scroll downward by nearly full screen.
5398 When calling from a program, supply as argument a number, nil, or `-'. */)
5399 (arg)
5400 Lisp_Object arg;
5401 {
5402 scroll_command (arg, 1);
5403 return Qnil;
5404 }
5405
5406 DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "^P",
5407 doc: /* Scroll text of selected window down ARG lines.
5408 If ARG is omitted or nil, scroll down by a near full screen.
5409 A near full screen is `next-screen-context-lines' less than a full screen.
5410 Negative ARG means scroll upward.
5411 If ARG is the atom `-', scroll upward by nearly full screen.
5412 When calling from a program, supply as argument a number, nil, or `-'. */)
5413 (arg)
5414 Lisp_Object arg;
5415 {
5416 scroll_command (arg, -1);
5417 return Qnil;
5418 }
5419 \f
5420 DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0,
5421 doc: /* Return the other window for \"other window scroll\" commands.
5422 If `other-window-scroll-buffer' is non-nil, a window
5423 showing that buffer is used.
5424 If in the minibuffer, `minibuffer-scroll-window' if non-nil
5425 specifies the window. This takes precedence over
5426 `other-window-scroll-buffer'. */)
5427 ()
5428 {
5429 Lisp_Object window;
5430
5431 if (MINI_WINDOW_P (XWINDOW (selected_window))
5432 && !NILP (Vminibuf_scroll_window))
5433 window = Vminibuf_scroll_window;
5434 /* If buffer is specified, scroll that buffer. */
5435 else if (!NILP (Vother_window_scroll_buffer))
5436 {
5437 window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
5438 if (NILP (window))
5439 window = display_buffer (Vother_window_scroll_buffer, Qt, Qnil);
5440 }
5441 else
5442 {
5443 /* Nothing specified; look for a neighboring window on the same
5444 frame. */
5445 window = Fnext_window (selected_window, Qnil, Qnil);
5446
5447 if (EQ (window, selected_window))
5448 /* That didn't get us anywhere; look for a window on another
5449 visible frame. */
5450 do
5451 window = Fnext_window (window, Qnil, Qt);
5452 while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
5453 && ! EQ (window, selected_window));
5454 }
5455
5456 CHECK_LIVE_WINDOW (window);
5457
5458 if (EQ (window, selected_window))
5459 error ("There is no other window");
5460
5461 return window;
5462 }
5463
5464 DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
5465 doc: /* Scroll next window upward ARG lines; or near full screen if no ARG.
5466 A near full screen is `next-screen-context-lines' less than a full screen.
5467 The next window is the one below the current one; or the one at the top
5468 if the current one is at the bottom. Negative ARG means scroll downward.
5469 If ARG is the atom `-', scroll downward by nearly full screen.
5470 When calling from a program, supply as argument a number, nil, or `-'.
5471
5472 If `other-window-scroll-buffer' is non-nil, scroll the window
5473 showing that buffer, popping the buffer up if necessary.
5474 If in the minibuffer, `minibuffer-scroll-window' if non-nil
5475 specifies the window to scroll. This takes precedence over
5476 `other-window-scroll-buffer'. */)
5477 (arg)
5478 Lisp_Object arg;
5479 {
5480 Lisp_Object window;
5481 struct window *w;
5482 int count = SPECPDL_INDEX ();
5483
5484 window = Fother_window_for_scrolling ();
5485 w = XWINDOW (window);
5486
5487 /* Don't screw up if window_scroll gets an error. */
5488 record_unwind_protect (save_excursion_restore, save_excursion_save ());
5489 ++windows_or_buffers_changed;
5490
5491 Fset_buffer (w->buffer);
5492 SET_PT (marker_position (w->pointm));
5493
5494 if (NILP (arg))
5495 window_scroll (window, 1, 1, 1);
5496 else if (EQ (arg, Qminus))
5497 window_scroll (window, -1, 1, 1);
5498 else
5499 {
5500 if (CONSP (arg))
5501 arg = Fcar (arg);
5502 CHECK_NUMBER (arg);
5503 window_scroll (window, XINT (arg), 0, 1);
5504 }
5505
5506 set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
5507 unbind_to (count, Qnil);
5508
5509 return Qnil;
5510 }
5511 \f
5512 DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 2, "^P\np",
5513 doc: /* Scroll selected window display ARG columns left.
5514 Default for ARG is window width minus 2.
5515 Value is the total amount of leftward horizontal scrolling in
5516 effect after the change.
5517 If SET-MINIMUM is non-nil, the new scroll amount becomes the
5518 lower bound for automatic scrolling, i.e. automatic scrolling
5519 will not scroll a window to a column less than the value returned
5520 by this function. This happens in an interactive call. */)
5521 (arg, set_minimum)
5522 register Lisp_Object arg, set_minimum;
5523 {
5524 Lisp_Object result;
5525 int hscroll;
5526 struct window *w = XWINDOW (selected_window);
5527
5528 if (NILP (arg))
5529 XSETFASTINT (arg, window_box_text_cols (w) - 2);
5530 else
5531 arg = Fprefix_numeric_value (arg);
5532
5533 hscroll = XINT (w->hscroll) + XINT (arg);
5534 result = Fset_window_hscroll (selected_window, make_number (hscroll));
5535
5536 if (!NILP (set_minimum))
5537 w->min_hscroll = w->hscroll;
5538
5539 return result;
5540 }
5541
5542 DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 2, "^P\np",
5543 doc: /* Scroll selected window display ARG columns right.
5544 Default for ARG is window width minus 2.
5545 Value is the total amount of leftward horizontal scrolling in
5546 effect after the change.
5547 If SET-MINIMUM is non-nil, the new scroll amount becomes the
5548 lower bound for automatic scrolling, i.e. automatic scrolling
5549 will not scroll a window to a column less than the value returned
5550 by this function. This happens in an interactive call. */)
5551 (arg, set_minimum)
5552 register Lisp_Object arg, set_minimum;
5553 {
5554 Lisp_Object result;
5555 int hscroll;
5556 struct window *w = XWINDOW (selected_window);
5557
5558 if (NILP (arg))
5559 XSETFASTINT (arg, window_box_text_cols (w) - 2);
5560 else
5561 arg = Fprefix_numeric_value (arg);
5562
5563 hscroll = XINT (w->hscroll) - XINT (arg);
5564 result = Fset_window_hscroll (selected_window, make_number (hscroll));
5565
5566 if (!NILP (set_minimum))
5567 w->min_hscroll = w->hscroll;
5568
5569 return result;
5570 }
5571
5572 DEFUN ("minibuffer-selected-window", Fminibuffer_selected_window, Sminibuffer_selected_window, 0, 0, 0,
5573 doc: /* Return the window which was selected when entering the minibuffer.
5574 Returns nil, if selected window is not a minibuffer window. */)
5575 ()
5576 {
5577 if (minibuf_level > 0
5578 && MINI_WINDOW_P (XWINDOW (selected_window))
5579 && WINDOW_LIVE_P (minibuf_selected_window))
5580 return minibuf_selected_window;
5581
5582 return Qnil;
5583 }
5584
5585 /* Value is the number of lines actually displayed in window W,
5586 as opposed to its height. */
5587
5588 static int
5589 displayed_window_lines (w)
5590 struct window *w;
5591 {
5592 struct it it;
5593 struct text_pos start;
5594 int height = window_box_height (w);
5595 struct buffer *old_buffer;
5596 int bottom_y;
5597
5598 if (XBUFFER (w->buffer) != current_buffer)
5599 {
5600 old_buffer = current_buffer;
5601 set_buffer_internal (XBUFFER (w->buffer));
5602 }
5603 else
5604 old_buffer = NULL;
5605
5606 /* In case W->start is out of the accessible range, do something
5607 reasonable. This happens in Info mode when Info-scroll-down
5608 calls (recenter -1) while W->start is 1. */
5609 if (XMARKER (w->start)->charpos < BEGV)
5610 SET_TEXT_POS (start, BEGV, BEGV_BYTE);
5611 else if (XMARKER (w->start)->charpos > ZV)
5612 SET_TEXT_POS (start, ZV, ZV_BYTE);
5613 else
5614 SET_TEXT_POS_FROM_MARKER (start, w->start);
5615
5616 start_display (&it, w, start);
5617 move_it_vertically (&it, height);
5618 bottom_y = line_bottom_y (&it);
5619
5620 /* rms: On a non-window display,
5621 the value of it.vpos at the bottom of the screen
5622 seems to be 1 larger than window_box_height (w).
5623 This kludge fixes a bug whereby (move-to-window-line -1)
5624 when ZV is on the last screen line
5625 moves to the previous screen line instead of the last one. */
5626 if (! FRAME_WINDOW_P (XFRAME (w->frame)))
5627 height++;
5628
5629 /* Add in empty lines at the bottom of the window. */
5630 if (bottom_y < height)
5631 {
5632 int uy = FRAME_LINE_HEIGHT (it.f);
5633 it.vpos += (height - bottom_y + uy - 1) / uy;
5634 }
5635
5636 if (old_buffer)
5637 set_buffer_internal (old_buffer);
5638
5639 return it.vpos;
5640 }
5641
5642
5643 DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
5644 doc: /* Center point in selected window and maybe redisplay frame.
5645 With prefix argument ARG, recenter putting point on screen line ARG
5646 relative to the selected window. If ARG is negative, it counts up from the
5647 bottom of the window. (ARG should be less than the height of the window.)
5648
5649 If ARG is omitted or nil, then recenter with point on the middle line of
5650 the selected window; if the variable `recenter-redisplay' is non-nil,
5651 also erase the entire frame and redraw it (when `auto-resize-tool-bars'
5652 is set to `grow-only', this resets the tool-bar's height to the minimum
5653 height needed); if `recenter-redisplay' has the special value `tty',
5654 then only tty frame are redrawn.
5655
5656 Just C-u as prefix means put point in the center of the window
5657 and redisplay normally--don't erase and redraw the frame. */)
5658 (arg)
5659 register Lisp_Object arg;
5660 {
5661 struct window *w = XWINDOW (selected_window);
5662 struct buffer *buf = XBUFFER (w->buffer);
5663 struct buffer *obuf = current_buffer;
5664 int center_p = 0;
5665 int charpos, bytepos;
5666 int iarg;
5667 int this_scroll_margin;
5668
5669 /* If redisplay is suppressed due to an error, try again. */
5670 obuf->display_error_modiff = 0;
5671
5672 if (NILP (arg))
5673 {
5674 if (!NILP (Vrecenter_redisplay)
5675 && (!EQ (Vrecenter_redisplay, Qtty)
5676 || !NILP (Ftty_type (selected_frame))))
5677 {
5678 int i;
5679
5680 /* Invalidate pixel data calculated for all compositions. */
5681 for (i = 0; i < n_compositions; i++)
5682 composition_table[i]->font = NULL;
5683
5684 WINDOW_XFRAME (w)->minimize_tool_bar_window_p = 1;
5685
5686 Fredraw_frame (WINDOW_FRAME (w));
5687 SET_FRAME_GARBAGED (WINDOW_XFRAME (w));
5688 }
5689
5690 center_p = 1;
5691 }
5692 else if (CONSP (arg)) /* Just C-u. */
5693 center_p = 1;
5694 else
5695 {
5696 arg = Fprefix_numeric_value (arg);
5697 CHECK_NUMBER (arg);
5698 iarg = XINT (arg);
5699 }
5700
5701 set_buffer_internal (buf);
5702
5703 /* Do this after making BUF current
5704 in case scroll_margin is buffer-local. */
5705 this_scroll_margin = max (0, scroll_margin);
5706 this_scroll_margin = min (this_scroll_margin,
5707 XFASTINT (w->total_lines) / 4);
5708
5709 /* Handle centering on a graphical frame specially. Such frames can
5710 have variable-height lines and centering point on the basis of
5711 line counts would lead to strange effects. */
5712 if (FRAME_WINDOW_P (XFRAME (w->frame)))
5713 {
5714 if (center_p)
5715 {
5716 struct it it;
5717 struct text_pos pt;
5718
5719 SET_TEXT_POS (pt, PT, PT_BYTE);
5720 start_display (&it, w, pt);
5721 move_it_vertically_backward (&it, window_box_height (w) / 2);
5722 charpos = IT_CHARPOS (it);
5723 bytepos = IT_BYTEPOS (it);
5724 }
5725 else if (iarg < 0)
5726 {
5727 struct it it;
5728 struct text_pos pt;
5729 int nlines = -iarg;
5730 int extra_line_spacing;
5731 int h = window_box_height (w);
5732
5733 iarg = - max (-iarg, this_scroll_margin);
5734
5735 SET_TEXT_POS (pt, PT, PT_BYTE);
5736 start_display (&it, w, pt);
5737
5738 /* Be sure we have the exact height of the full line containing PT. */
5739 move_it_by_lines (&it, 0, 1);
5740
5741 /* The amount of pixels we have to move back is the window
5742 height minus what's displayed in the line containing PT,
5743 and the lines below. */
5744 it.current_y = 0;
5745 it.vpos = 0;
5746 move_it_by_lines (&it, nlines, 1);
5747
5748 if (it.vpos == nlines)
5749 h -= it.current_y;
5750 else
5751 {
5752 /* Last line has no newline */
5753 h -= line_bottom_y (&it);
5754 it.vpos++;
5755 }
5756
5757 /* Don't reserve space for extra line spacing of last line. */
5758 extra_line_spacing = it.max_extra_line_spacing;
5759
5760 /* If we can't move down NLINES lines because we hit
5761 the end of the buffer, count in some empty lines. */
5762 if (it.vpos < nlines)
5763 {
5764 nlines -= it.vpos;
5765 extra_line_spacing = it.extra_line_spacing;
5766 h -= nlines * (FRAME_LINE_HEIGHT (it.f) + extra_line_spacing);
5767 }
5768 if (h <= 0)
5769 return Qnil;
5770
5771 /* Now find the new top line (starting position) of the window. */
5772 start_display (&it, w, pt);
5773 it.current_y = 0;
5774 move_it_vertically_backward (&it, h);
5775
5776 /* If extra line spacing is present, we may move too far
5777 back. This causes the last line to be only partially
5778 visible (which triggers redisplay to recenter that line
5779 in the middle), so move forward.
5780 But ignore extra line spacing on last line, as it is not
5781 considered to be part of the visible height of the line.
5782 */
5783 h += extra_line_spacing;
5784 while (-it.current_y > h)
5785 move_it_by_lines (&it, 1, 1);
5786
5787 charpos = IT_CHARPOS (it);
5788 bytepos = IT_BYTEPOS (it);
5789 }
5790 else
5791 {
5792 struct position pos;
5793
5794 iarg = max (iarg, this_scroll_margin);
5795
5796 pos = *vmotion (PT, -iarg, w);
5797 charpos = pos.bufpos;
5798 bytepos = pos.bytepos;
5799 }
5800 }
5801 else
5802 {
5803 struct position pos;
5804 int ht = window_internal_height (w);
5805
5806 if (center_p)
5807 iarg = ht / 2;
5808 else if (iarg < 0)
5809 iarg += ht;
5810
5811 /* Don't let it get into the margin at either top or bottom. */
5812 iarg = max (iarg, this_scroll_margin);
5813 iarg = min (iarg, ht - this_scroll_margin - 1);
5814
5815 pos = *vmotion (PT, - iarg, w);
5816 charpos = pos.bufpos;
5817 bytepos = pos.bytepos;
5818 }
5819
5820 /* Set the new window start. */
5821 set_marker_both (w->start, w->buffer, charpos, bytepos);
5822 w->window_end_valid = Qnil;
5823
5824 w->optional_new_start = Qt;
5825
5826 if (bytepos == BEGV_BYTE || FETCH_BYTE (bytepos - 1) == '\n')
5827 w->start_at_line_beg = Qt;
5828 else
5829 w->start_at_line_beg = Qnil;
5830
5831 set_buffer_internal (obuf);
5832 return Qnil;
5833 }
5834
5835
5836 DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height,
5837 0, 1, 0,
5838 doc: /* Return the height in lines of the text display area of WINDOW.
5839 WINDOW defaults to the selected window.
5840
5841 The return value does not include the mode line, any header line, nor
5842 any partial-height lines in the text display area. */)
5843 (window)
5844 Lisp_Object window;
5845 {
5846 struct window *w = decode_window (window);
5847 int pixel_height = window_box_height (w);
5848 int line_height = pixel_height / FRAME_LINE_HEIGHT (XFRAME (w->frame));
5849 return make_number (line_height);
5850 }
5851
5852
5853 \f
5854 DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
5855 1, 1, "P",
5856 doc: /* Position point relative to window.
5857 With no argument, position point at center of window.
5858 An argument specifies vertical position within the window;
5859 zero means top of window, negative means relative to bottom of window. */)
5860 (arg)
5861 Lisp_Object arg;
5862 {
5863 struct window *w = XWINDOW (selected_window);
5864 int lines, start;
5865 Lisp_Object window;
5866 #if 0
5867 int this_scroll_margin;
5868 #endif
5869
5870 if (!(BUFFERP (w->buffer)
5871 && XBUFFER (w->buffer) == current_buffer))
5872 /* This test is needed to make sure PT/PT_BYTE make sense in w->buffer
5873 when passed below to set_marker_both. */
5874 error ("move-to-window-line called from unrelated buffer");
5875
5876 window = selected_window;
5877 start = marker_position (w->start);
5878 if (start < BEGV || start > ZV)
5879 {
5880 int height = window_internal_height (w);
5881 Fvertical_motion (make_number (- (height / 2)), window);
5882 set_marker_both (w->start, w->buffer, PT, PT_BYTE);
5883 w->start_at_line_beg = Fbolp ();
5884 w->force_start = Qt;
5885 }
5886 else
5887 Fgoto_char (w->start);
5888
5889 lines = displayed_window_lines (w);
5890
5891 #if 0
5892 this_scroll_margin = max (0, scroll_margin);
5893 this_scroll_margin = min (this_scroll_margin, lines / 4);
5894 #endif
5895
5896 if (NILP (arg))
5897 XSETFASTINT (arg, lines / 2);
5898 else
5899 {
5900 int iarg = XINT (Fprefix_numeric_value (arg));
5901
5902 if (iarg < 0)
5903 iarg = iarg + lines;
5904
5905 #if 0 /* This code would prevent move-to-window-line from moving point
5906 to a place inside the scroll margins (which would cause the
5907 next redisplay to scroll). I wrote this code, but then concluded
5908 it is probably better not to install it. However, it is here
5909 inside #if 0 so as not to lose it. -- rms. */
5910
5911 /* Don't let it get into the margin at either top or bottom. */
5912 iarg = max (iarg, this_scroll_margin);
5913 iarg = min (iarg, lines - this_scroll_margin - 1);
5914 #endif
5915
5916 arg = make_number (iarg);
5917 }
5918
5919 /* Skip past a partially visible first line. */
5920 if (w->vscroll)
5921 XSETINT (arg, XINT (arg) + 1);
5922
5923 return Fvertical_motion (arg, window);
5924 }
5925
5926
5927 \f
5928 /***********************************************************************
5929 Window Configuration
5930 ***********************************************************************/
5931
5932 struct save_window_data
5933 {
5934 struct vectorlike_header header;
5935 Lisp_Object selected_frame;
5936 Lisp_Object current_window;
5937 Lisp_Object current_buffer;
5938 Lisp_Object minibuf_scroll_window;
5939 Lisp_Object minibuf_selected_window;
5940 Lisp_Object root_window;
5941 Lisp_Object focus_frame;
5942 /* A vector, each of whose elements is a struct saved_window
5943 for one window. */
5944 Lisp_Object saved_windows;
5945
5946 /* All fields above are traced by the GC.
5947 From `fame-cols' down, the fields are ignored by the GC. */
5948
5949 int frame_cols, frame_lines, frame_menu_bar_lines;
5950 int frame_tool_bar_lines;
5951 };
5952
5953 /* This is saved as a Lisp_Vector */
5954 struct saved_window
5955 {
5956 struct vectorlike_header header;
5957 Lisp_Object window;
5958 Lisp_Object buffer, start, pointm, mark;
5959 Lisp_Object left_col, top_line, total_cols, total_lines;
5960 Lisp_Object hscroll, min_hscroll;
5961 Lisp_Object parent, prev;
5962 Lisp_Object start_at_line_beg;
5963 Lisp_Object display_table;
5964 Lisp_Object orig_top_line, orig_total_lines;
5965 Lisp_Object left_margin_cols, right_margin_cols;
5966 Lisp_Object left_fringe_width, right_fringe_width, fringes_outside_margins;
5967 Lisp_Object scroll_bar_width, vertical_scroll_bar_type;
5968 Lisp_Object dedicated, resize_proportionally;
5969 };
5970
5971 #define SAVED_WINDOW_N(swv,n) \
5972 ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
5973
5974 DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
5975 doc: /* Return t if OBJECT is a window-configuration object. */)
5976 (object)
5977 Lisp_Object object;
5978 {
5979 return WINDOW_CONFIGURATIONP (object) ? Qt : Qnil;
5980 }
5981
5982 DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
5983 doc: /* Return the frame that CONFIG, a window-configuration object, is about. */)
5984 (config)
5985 Lisp_Object config;
5986 {
5987 register struct save_window_data *data;
5988 struct Lisp_Vector *saved_windows;
5989
5990 CHECK_WINDOW_CONFIGURATION (config);
5991
5992 data = (struct save_window_data *) XVECTOR (config);
5993 saved_windows = XVECTOR (data->saved_windows);
5994 return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
5995 }
5996
5997 DEFUN ("set-window-configuration", Fset_window_configuration,
5998 Sset_window_configuration, 1, 1, 0,
5999 doc: /* Set the configuration of windows and buffers as specified by CONFIGURATION.
6000 CONFIGURATION must be a value previously returned
6001 by `current-window-configuration' (which see).
6002 If CONFIGURATION was made from a frame that is now deleted,
6003 only frame-independent values can be restored. In this case,
6004 the return value is nil. Otherwise the value is t. */)
6005 (configuration)
6006 Lisp_Object configuration;
6007 {
6008 register struct save_window_data *data;
6009 struct Lisp_Vector *saved_windows;
6010 Lisp_Object new_current_buffer;
6011 Lisp_Object frame;
6012 FRAME_PTR f;
6013 int old_point = -1;
6014
6015 CHECK_WINDOW_CONFIGURATION (configuration);
6016
6017 data = (struct save_window_data *) XVECTOR (configuration);
6018 saved_windows = XVECTOR (data->saved_windows);
6019
6020 new_current_buffer = data->current_buffer;
6021 if (NILP (XBUFFER (new_current_buffer)->name))
6022 new_current_buffer = Qnil;
6023 else
6024 {
6025 if (XBUFFER (new_current_buffer) == current_buffer)
6026 /* The code further down "preserves point" by saving here PT in
6027 old_point and then setting it later back into PT. When the
6028 current-selected-window and the final-selected-window both show
6029 the current buffer, this suffers from the problem that the
6030 current PT is the window-point of the current-selected-window,
6031 while the final PT is the point of the final-selected-window, so
6032 this copy from one PT to the other would end up moving the
6033 window-point of the final-selected-window to the window-point of
6034 the current-selected-window. So we have to be careful which
6035 point of the current-buffer we copy into old_point. */
6036 if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer)
6037 && WINDOWP (selected_window)
6038 && EQ (XWINDOW (selected_window)->buffer, new_current_buffer)
6039 && !EQ (selected_window, data->current_window))
6040 old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos;
6041 else
6042 old_point = PT;
6043 else
6044 /* BUF_PT (XBUFFER (new_current_buffer)) gives us the position of
6045 point in new_current_buffer as of the last time this buffer was
6046 used. This can be non-deterministic since it can be changed by
6047 things like jit-lock by mere temporary selection of some random
6048 window that happens to show this buffer.
6049 So if possible we want this arbitrary choice of "which point" to
6050 be the one from the to-be-selected-window so as to prevent this
6051 window's cursor from being copied from another window. */
6052 if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer)
6053 /* If current_window = selected_window, its point is in BUF_PT. */
6054 && !EQ (selected_window, data->current_window))
6055 old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos;
6056 else
6057 old_point = BUF_PT (XBUFFER (new_current_buffer));
6058 }
6059
6060 frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
6061 f = XFRAME (frame);
6062
6063 /* If f is a dead frame, don't bother rebuilding its window tree.
6064 However, there is other stuff we should still try to do below. */
6065 if (FRAME_LIVE_P (f))
6066 {
6067 register struct window *w;
6068 register struct saved_window *p;
6069 struct window *root_window;
6070 struct window **leaf_windows;
6071 int n_leaf_windows;
6072 int k, i, n;
6073
6074 /* If the frame has been resized since this window configuration was
6075 made, we change the frame to the size specified in the
6076 configuration, restore the configuration, and then resize it
6077 back. We keep track of the prevailing height in these variables. */
6078 int previous_frame_lines = FRAME_LINES (f);
6079 int previous_frame_cols = FRAME_COLS (f);
6080 int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
6081 int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
6082
6083 /* The mouse highlighting code could get screwed up
6084 if it runs during this. */
6085 BLOCK_INPUT;
6086
6087 if (data->frame_lines != previous_frame_lines
6088 || data->frame_cols != previous_frame_cols)
6089 change_frame_size (f, data->frame_lines,
6090 data->frame_cols, 0, 0, 0);
6091 #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
6092 if (data->frame_menu_bar_lines
6093 != previous_frame_menu_bar_lines)
6094 x_set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines),
6095 make_number (0));
6096 #ifdef HAVE_WINDOW_SYSTEM
6097 if (data->frame_tool_bar_lines
6098 != previous_frame_tool_bar_lines)
6099 x_set_tool_bar_lines (f, make_number (data->frame_tool_bar_lines),
6100 make_number (0));
6101 #endif
6102 #endif
6103
6104 /* "Swap out" point from the selected window's buffer
6105 into the window itself. (Normally the pointm of the selected
6106 window holds garbage.) We do this now, before
6107 restoring the window contents, and prevent it from
6108 being done later on when we select a new window. */
6109 if (! NILP (XWINDOW (selected_window)->buffer))
6110 {
6111 w = XWINDOW (selected_window);
6112 set_marker_both (w->pointm,
6113 w->buffer,
6114 BUF_PT (XBUFFER (w->buffer)),
6115 BUF_PT_BYTE (XBUFFER (w->buffer)));
6116 }
6117
6118 windows_or_buffers_changed++;
6119 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
6120
6121 /* Problem: Freeing all matrices and later allocating them again
6122 is a serious redisplay flickering problem. What we would
6123 really like to do is to free only those matrices not reused
6124 below. */
6125 root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
6126 leaf_windows
6127 = (struct window **) alloca (count_windows (root_window)
6128 * sizeof (struct window *));
6129 n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
6130
6131 /* Kludge Alert!
6132 Mark all windows now on frame as "deleted".
6133 Restoring the new configuration "undeletes" any that are in it.
6134
6135 Save their current buffers in their height fields, since we may
6136 need it later, if a buffer saved in the configuration is now
6137 dead. */
6138 delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
6139
6140 for (k = 0; k < saved_windows->header.size; k++)
6141 {
6142 p = SAVED_WINDOW_N (saved_windows, k);
6143 w = XWINDOW (p->window);
6144 w->next = Qnil;
6145
6146 if (!NILP (p->parent))
6147 w->parent = SAVED_WINDOW_N (saved_windows,
6148 XFASTINT (p->parent))->window;
6149 else
6150 w->parent = Qnil;
6151
6152 if (!NILP (p->prev))
6153 {
6154 w->prev = SAVED_WINDOW_N (saved_windows,
6155 XFASTINT (p->prev))->window;
6156 XWINDOW (w->prev)->next = p->window;
6157 }
6158 else
6159 {
6160 w->prev = Qnil;
6161 if (!NILP (w->parent))
6162 {
6163 if (EQ (p->total_cols, XWINDOW (w->parent)->total_cols))
6164 {
6165 XWINDOW (w->parent)->vchild = p->window;
6166 XWINDOW (w->parent)->hchild = Qnil;
6167 }
6168 else
6169 {
6170 XWINDOW (w->parent)->hchild = p->window;
6171 XWINDOW (w->parent)->vchild = Qnil;
6172 }
6173 }
6174 }
6175
6176 /* If we squirreled away the buffer in the window's height,
6177 restore it now. */
6178 if (BUFFERP (w->total_lines))
6179 w->buffer = w->total_lines;
6180 w->left_col = p->left_col;
6181 w->top_line = p->top_line;
6182 w->total_cols = p->total_cols;
6183 w->total_lines = p->total_lines;
6184 w->hscroll = p->hscroll;
6185 w->min_hscroll = p->min_hscroll;
6186 w->display_table = p->display_table;
6187 w->orig_top_line = p->orig_top_line;
6188 w->orig_total_lines = p->orig_total_lines;
6189 w->left_margin_cols = p->left_margin_cols;
6190 w->right_margin_cols = p->right_margin_cols;
6191 w->left_fringe_width = p->left_fringe_width;
6192 w->right_fringe_width = p->right_fringe_width;
6193 w->fringes_outside_margins = p->fringes_outside_margins;
6194 w->scroll_bar_width = p->scroll_bar_width;
6195 w->vertical_scroll_bar_type = p->vertical_scroll_bar_type;
6196 w->dedicated = p->dedicated;
6197 w->resize_proportionally = p->resize_proportionally;
6198 XSETFASTINT (w->last_modified, 0);
6199 XSETFASTINT (w->last_overlay_modified, 0);
6200
6201 /* Reinstall the saved buffer and pointers into it. */
6202 if (NILP (p->buffer))
6203 w->buffer = p->buffer;
6204 else
6205 {
6206 if (!NILP (XBUFFER (p->buffer)->name))
6207 /* If saved buffer is alive, install it. */
6208 {
6209 w->buffer = p->buffer;
6210 w->start_at_line_beg = p->start_at_line_beg;
6211 set_marker_restricted (w->start, p->start, w->buffer);
6212 set_marker_restricted (w->pointm, p->pointm, w->buffer);
6213 Fset_marker (XBUFFER (w->buffer)->mark,
6214 p->mark, w->buffer);
6215
6216 /* As documented in Fcurrent_window_configuration, don't
6217 restore the location of point in the buffer which was
6218 current when the window configuration was recorded. */
6219 if (!EQ (p->buffer, new_current_buffer)
6220 && XBUFFER (p->buffer) == current_buffer)
6221 Fgoto_char (w->pointm);
6222 }
6223 else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
6224 /* Else unless window has a live buffer, get one. */
6225 {
6226 w->buffer = Fcdr (Fcar (Vbuffer_alist));
6227 /* This will set the markers to beginning of visible
6228 range. */
6229 set_marker_restricted (w->start, make_number (0), w->buffer);
6230 set_marker_restricted (w->pointm, make_number (0),w->buffer);
6231 w->start_at_line_beg = Qt;
6232 }
6233 else
6234 /* Keeping window's old buffer; make sure the markers
6235 are real. */
6236 {
6237 /* Set window markers at start of visible range. */
6238 if (XMARKER (w->start)->buffer == 0)
6239 set_marker_restricted (w->start, make_number (0),
6240 w->buffer);
6241 if (XMARKER (w->pointm)->buffer == 0)
6242 set_marker_restricted_both (w->pointm, w->buffer,
6243 BUF_PT (XBUFFER (w->buffer)),
6244 BUF_PT_BYTE (XBUFFER (w->buffer)));
6245 w->start_at_line_beg = Qt;
6246 }
6247 }
6248 }
6249
6250 FRAME_ROOT_WINDOW (f) = data->root_window;
6251
6252 /* Arrange *not* to restore point in the buffer that was
6253 current when the window configuration was saved. */
6254 if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer))
6255 set_marker_restricted (XWINDOW (data->current_window)->pointm,
6256 make_number (old_point),
6257 XWINDOW (data->current_window)->buffer);
6258
6259 /* In the following call to `select-window, prevent "swapping
6260 out point" in the old selected window using the buffer that
6261 has been restored into it. We already swapped out that point
6262 from that window's old buffer. */
6263 select_window (data->current_window, Qnil, 1);
6264 XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
6265 = selected_window;
6266
6267 if (NILP (data->focus_frame)
6268 || (FRAMEP (data->focus_frame)
6269 && FRAME_LIVE_P (XFRAME (data->focus_frame))))
6270 Fredirect_frame_focus (frame, data->focus_frame);
6271
6272 /* Set the screen height to the value it had before this function. */
6273 if (previous_frame_lines != FRAME_LINES (f)
6274 || previous_frame_cols != FRAME_COLS (f))
6275 change_frame_size (f, previous_frame_lines, previous_frame_cols,
6276 0, 0, 0);
6277 #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
6278 if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
6279 x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
6280 make_number (0));
6281 #ifdef HAVE_WINDOW_SYSTEM
6282 if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
6283 x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
6284 make_number (0));
6285 #endif
6286 #endif
6287
6288 /* Now, free glyph matrices in windows that were not reused. */
6289 for (i = n = 0; i < n_leaf_windows; ++i)
6290 {
6291 if (NILP (leaf_windows[i]->buffer))
6292 {
6293 /* Assert it's not reused as a combination. */
6294 xassert (NILP (leaf_windows[i]->hchild)
6295 && NILP (leaf_windows[i]->vchild));
6296 free_window_matrices (leaf_windows[i]);
6297 }
6298 else if (EQ (leaf_windows[i]->buffer, new_current_buffer))
6299 ++n;
6300 }
6301
6302 adjust_glyphs (f);
6303
6304 UNBLOCK_INPUT;
6305
6306 /* Fselect_window will have made f the selected frame, so we
6307 reselect the proper frame here. Fhandle_switch_frame will change the
6308 selected window too, but that doesn't make the call to
6309 Fselect_window above totally superfluous; it still sets f's
6310 selected window. */
6311 if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
6312 do_switch_frame (data->selected_frame, 0, 0, Qnil);
6313
6314 run_window_configuration_change_hook (f);
6315 }
6316
6317 if (!NILP (new_current_buffer))
6318 Fset_buffer (new_current_buffer);
6319
6320 Vminibuf_scroll_window = data->minibuf_scroll_window;
6321 minibuf_selected_window = data->minibuf_selected_window;
6322
6323 return (FRAME_LIVE_P (f) ? Qt : Qnil);
6324 }
6325
6326 /* Mark all windows now on frame as deleted
6327 by setting their buffers to nil. */
6328
6329 void
6330 delete_all_subwindows (w)
6331 register struct window *w;
6332 {
6333 if (!NILP (w->next))
6334 delete_all_subwindows (XWINDOW (w->next));
6335 if (!NILP (w->vchild))
6336 delete_all_subwindows (XWINDOW (w->vchild));
6337 if (!NILP (w->hchild))
6338 delete_all_subwindows (XWINDOW (w->hchild));
6339
6340 w->total_lines = w->buffer; /* See Fset_window_configuration for excuse. */
6341
6342 if (!NILP (w->buffer))
6343 unshow_buffer (w);
6344
6345 /* We set all three of these fields to nil, to make sure that we can
6346 distinguish this dead window from any live window. Live leaf
6347 windows will have buffer set, and combination windows will have
6348 vchild or hchild set. */
6349 w->buffer = Qnil;
6350 w->vchild = Qnil;
6351 w->hchild = Qnil;
6352
6353 Vwindow_list = Qnil;
6354 }
6355 \f
6356 static int
6357 count_windows (window)
6358 register struct window *window;
6359 {
6360 register int count = 1;
6361 if (!NILP (window->next))
6362 count += count_windows (XWINDOW (window->next));
6363 if (!NILP (window->vchild))
6364 count += count_windows (XWINDOW (window->vchild));
6365 if (!NILP (window->hchild))
6366 count += count_windows (XWINDOW (window->hchild));
6367 return count;
6368 }
6369
6370
6371 /* Fill vector FLAT with leaf windows under W, starting at index I.
6372 Value is last index + 1. */
6373
6374 static int
6375 get_leaf_windows (w, flat, i)
6376 struct window *w;
6377 struct window **flat;
6378 int i;
6379 {
6380 while (w)
6381 {
6382 if (!NILP (w->hchild))
6383 i = get_leaf_windows (XWINDOW (w->hchild), flat, i);
6384 else if (!NILP (w->vchild))
6385 i = get_leaf_windows (XWINDOW (w->vchild), flat, i);
6386 else
6387 flat[i++] = w;
6388
6389 w = NILP (w->next) ? 0 : XWINDOW (w->next);
6390 }
6391
6392 return i;
6393 }
6394
6395
6396 /* Return a pointer to the glyph W's physical cursor is on. Value is
6397 null if W's current matrix is invalid, so that no meaningfull glyph
6398 can be returned. */
6399
6400 struct glyph *
6401 get_phys_cursor_glyph (w)
6402 struct window *w;
6403 {
6404 struct glyph_row *row;
6405 struct glyph *glyph;
6406
6407 if (w->phys_cursor.vpos >= 0
6408 && w->phys_cursor.vpos < w->current_matrix->nrows
6409 && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
6410 row->enabled_p)
6411 && row->used[TEXT_AREA] > w->phys_cursor.hpos)
6412 glyph = row->glyphs[TEXT_AREA] + w->phys_cursor.hpos;
6413 else
6414 glyph = NULL;
6415
6416 return glyph;
6417 }
6418
6419
6420 static int
6421 save_window_save (window, vector, i)
6422 Lisp_Object window;
6423 struct Lisp_Vector *vector;
6424 int i;
6425 {
6426 register struct saved_window *p;
6427 register struct window *w;
6428 register Lisp_Object tem;
6429
6430 for (;!NILP (window); window = w->next)
6431 {
6432 p = SAVED_WINDOW_N (vector, i);
6433 w = XWINDOW (window);
6434
6435 XSETFASTINT (w->temslot, i); i++;
6436 p->window = window;
6437 p->buffer = w->buffer;
6438 p->left_col = w->left_col;
6439 p->top_line = w->top_line;
6440 p->total_cols = w->total_cols;
6441 p->total_lines = w->total_lines;
6442 p->hscroll = w->hscroll;
6443 p->min_hscroll = w->min_hscroll;
6444 p->display_table = w->display_table;
6445 p->orig_top_line = w->orig_top_line;
6446 p->orig_total_lines = w->orig_total_lines;
6447 p->left_margin_cols = w->left_margin_cols;
6448 p->right_margin_cols = w->right_margin_cols;
6449 p->left_fringe_width = w->left_fringe_width;
6450 p->right_fringe_width = w->right_fringe_width;
6451 p->fringes_outside_margins = w->fringes_outside_margins;
6452 p->scroll_bar_width = w->scroll_bar_width;
6453 p->vertical_scroll_bar_type = w->vertical_scroll_bar_type;
6454 p->dedicated = w->dedicated;
6455 p->resize_proportionally = w->resize_proportionally;
6456 if (!NILP (w->buffer))
6457 {
6458 /* Save w's value of point in the window configuration.
6459 If w is the selected window, then get the value of point
6460 from the buffer; pointm is garbage in the selected window. */
6461 if (EQ (window, selected_window))
6462 {
6463 p->pointm = Fmake_marker ();
6464 set_marker_both (p->pointm, w->buffer,
6465 BUF_PT (XBUFFER (w->buffer)),
6466 BUF_PT_BYTE (XBUFFER (w->buffer)));
6467 }
6468 else
6469 p->pointm = Fcopy_marker (w->pointm, Qnil);
6470
6471 p->start = Fcopy_marker (w->start, Qnil);
6472 p->start_at_line_beg = w->start_at_line_beg;
6473
6474 tem = XBUFFER (w->buffer)->mark;
6475 p->mark = Fcopy_marker (tem, Qnil);
6476 }
6477 else
6478 {
6479 p->pointm = Qnil;
6480 p->start = Qnil;
6481 p->mark = Qnil;
6482 p->start_at_line_beg = Qnil;
6483 }
6484
6485 if (NILP (w->parent))
6486 p->parent = Qnil;
6487 else
6488 p->parent = XWINDOW (w->parent)->temslot;
6489
6490 if (NILP (w->prev))
6491 p->prev = Qnil;
6492 else
6493 p->prev = XWINDOW (w->prev)->temslot;
6494
6495 if (!NILP (w->vchild))
6496 i = save_window_save (w->vchild, vector, i);
6497 if (!NILP (w->hchild))
6498 i = save_window_save (w->hchild, vector, i);
6499 }
6500
6501 return i;
6502 }
6503
6504 DEFUN ("current-window-configuration", Fcurrent_window_configuration,
6505 Scurrent_window_configuration, 0, 1, 0,
6506 doc: /* Return an object representing the current window configuration of FRAME.
6507 If FRAME is nil or omitted, use the selected frame.
6508 This describes the number of windows, their sizes and current buffers,
6509 and for each displayed buffer, where display starts, and the positions of
6510 point and mark. An exception is made for point in the current buffer:
6511 its value is -not- saved.
6512 This also records the currently selected frame, and FRAME's focus
6513 redirection (see `redirect-frame-focus'). */)
6514 (frame)
6515 Lisp_Object frame;
6516 {
6517 register Lisp_Object tem;
6518 register int n_windows;
6519 register struct save_window_data *data;
6520 register int i;
6521 FRAME_PTR f;
6522
6523 if (NILP (frame))
6524 frame = selected_frame;
6525 CHECK_LIVE_FRAME (frame);
6526 f = XFRAME (frame);
6527
6528 n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
6529 data = ALLOCATE_PSEUDOVECTOR (struct save_window_data, frame_cols,
6530 PVEC_WINDOW_CONFIGURATION);
6531
6532 data->frame_cols = FRAME_COLS (f);
6533 data->frame_lines = FRAME_LINES (f);
6534 data->frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
6535 data->frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
6536 data->selected_frame = selected_frame;
6537 data->current_window = FRAME_SELECTED_WINDOW (f);
6538 XSETBUFFER (data->current_buffer, current_buffer);
6539 data->minibuf_scroll_window = minibuf_level > 0 ? Vminibuf_scroll_window : Qnil;
6540 data->minibuf_selected_window = minibuf_level > 0 ? minibuf_selected_window : Qnil;
6541 data->root_window = FRAME_ROOT_WINDOW (f);
6542 data->focus_frame = FRAME_FOCUS_FRAME (f);
6543 tem = Fmake_vector (make_number (n_windows), Qnil);
6544 data->saved_windows = tem;
6545 for (i = 0; i < n_windows; i++)
6546 XVECTOR (tem)->contents[i]
6547 = Fmake_vector (make_number (VECSIZE (struct saved_window)), Qnil);
6548 save_window_save (FRAME_ROOT_WINDOW (f), XVECTOR (tem), 0);
6549 XSETWINDOW_CONFIGURATION (tem, data);
6550 return (tem);
6551 }
6552
6553 DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
6554 0, UNEVALLED, 0,
6555 doc: /* Execute BODY, preserving window sizes and contents.
6556 Return the value of the last form in BODY.
6557 Restore which buffer appears in which window, where display starts,
6558 and the value of point and mark for each window.
6559 Also restore the choice of selected window.
6560 Also restore which buffer is current.
6561 Does not restore the value of point in current buffer.
6562 usage: (save-window-excursion BODY...) */)
6563 (args)
6564 Lisp_Object args;
6565 {
6566 register Lisp_Object val;
6567 register int count = SPECPDL_INDEX ();
6568
6569 record_unwind_protect (Fset_window_configuration,
6570 Fcurrent_window_configuration (Qnil));
6571 val = Fprogn (args);
6572 return unbind_to (count, val);
6573 }
6574
6575
6576 \f
6577 /***********************************************************************
6578 Window Split Tree
6579 ***********************************************************************/
6580
6581 static Lisp_Object
6582 window_tree (w)
6583 struct window *w;
6584 {
6585 Lisp_Object tail = Qnil;
6586 Lisp_Object result = Qnil;
6587
6588 while (w)
6589 {
6590 Lisp_Object wn;
6591
6592 XSETWINDOW (wn, w);
6593 if (!NILP (w->hchild))
6594 wn = Fcons (Qnil, Fcons (Fwindow_edges (wn),
6595 window_tree (XWINDOW (w->hchild))));
6596 else if (!NILP (w->vchild))
6597 wn = Fcons (Qt, Fcons (Fwindow_edges (wn),
6598 window_tree (XWINDOW (w->vchild))));
6599
6600 if (NILP (result))
6601 {
6602 result = tail = Fcons (wn, Qnil);
6603 }
6604 else
6605 {
6606 XSETCDR (tail, Fcons (wn, Qnil));
6607 tail = XCDR (tail);
6608 }
6609
6610 w = NILP (w->next) ? 0 : XWINDOW (w->next);
6611 }
6612
6613 return result;
6614 }
6615
6616
6617
6618 DEFUN ("window-tree", Fwindow_tree, Swindow_tree,
6619 0, 1, 0,
6620 doc: /* Return the window tree for frame FRAME.
6621
6622 The return value is a list of the form (ROOT MINI), where ROOT
6623 represents the window tree of the frame's root window, and MINI
6624 is the frame's minibuffer window.
6625
6626 If the root window is not split, ROOT is the root window itself.
6627 Otherwise, ROOT is a list (DIR EDGES W1 W2 ...) where DIR is nil for a
6628 horizontal split, and t for a vertical split, EDGES gives the combined
6629 size and position of the subwindows in the split, and the rest of the
6630 elements are the subwindows in the split. Each of the subwindows may
6631 again be a window or a list representing a window split, and so on.
6632 EDGES is a list \(LEFT TOP RIGHT BOTTOM) as returned by `window-edges'.
6633
6634 If FRAME is nil or omitted, return information on the currently
6635 selected frame. */)
6636 (frame)
6637 Lisp_Object frame;
6638 {
6639 FRAME_PTR f;
6640
6641 if (NILP (frame))
6642 frame = selected_frame;
6643
6644 CHECK_FRAME (frame);
6645 f = XFRAME (frame);
6646
6647 if (!FRAME_LIVE_P (f))
6648 return Qnil;
6649
6650 return window_tree (XWINDOW (FRAME_ROOT_WINDOW (f)));
6651 }
6652
6653 \f
6654 /***********************************************************************
6655 Marginal Areas
6656 ***********************************************************************/
6657
6658 DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
6659 2, 3, 0,
6660 doc: /* Set width of marginal areas of window WINDOW.
6661 If WINDOW is nil, set margins of the currently selected window.
6662 Second arg LEFT-WIDTH specifies the number of character cells to
6663 reserve for the left marginal area. Optional third arg RIGHT-WIDTH
6664 does the same for the right marginal area. A nil width parameter
6665 means no margin. */)
6666 (window, left_width, right_width)
6667 Lisp_Object window, left_width, right_width;
6668 {
6669 struct window *w = decode_window (window);
6670
6671 /* Translate negative or zero widths to nil.
6672 Margins that are too wide have to be checked elsewhere. */
6673
6674 if (!NILP (left_width))
6675 {
6676 CHECK_NUMBER (left_width);
6677 if (XINT (left_width) <= 0)
6678 left_width = Qnil;
6679 }
6680
6681 if (!NILP (right_width))
6682 {
6683 CHECK_NUMBER (right_width);
6684 if (XINT (right_width) <= 0)
6685 right_width = Qnil;
6686 }
6687
6688 if (!EQ (w->left_margin_cols, left_width)
6689 || !EQ (w->right_margin_cols, right_width))
6690 {
6691 w->left_margin_cols = left_width;
6692 w->right_margin_cols = right_width;
6693
6694 adjust_window_margins (w);
6695
6696 ++windows_or_buffers_changed;
6697 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6698 }
6699
6700 return Qnil;
6701 }
6702
6703
6704 DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
6705 0, 1, 0,
6706 doc: /* Get width of marginal areas of window WINDOW.
6707 If WINDOW is omitted or nil, use the currently selected window.
6708 Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).
6709 If a marginal area does not exist, its width will be returned
6710 as nil. */)
6711 (window)
6712 Lisp_Object window;
6713 {
6714 struct window *w = decode_window (window);
6715 return Fcons (w->left_margin_cols, w->right_margin_cols);
6716 }
6717
6718
6719 \f
6720 /***********************************************************************
6721 Fringes
6722 ***********************************************************************/
6723
6724 DEFUN ("set-window-fringes", Fset_window_fringes, Sset_window_fringes,
6725 2, 4, 0,
6726 doc: /* Set the fringe widths of window WINDOW.
6727 If WINDOW is nil, set the fringe widths of the currently selected
6728 window.
6729 Second arg LEFT-WIDTH specifies the number of pixels to reserve for
6730 the left fringe. Optional third arg RIGHT-WIDTH specifies the right
6731 fringe width. If a fringe width arg is nil, that means to use the
6732 frame's default fringe width. Default fringe widths can be set with
6733 the command `set-fringe-style'.
6734 If optional fourth arg OUTSIDE-MARGINS is non-nil, draw the fringes
6735 outside of the display margins. By default, fringes are drawn between
6736 display marginal areas and the text area. */)
6737 (window, left_width, right_width, outside_margins)
6738 Lisp_Object window, left_width, right_width, outside_margins;
6739 {
6740 struct window *w = decode_window (window);
6741
6742 if (!NILP (left_width))
6743 CHECK_NATNUM (left_width);
6744 if (!NILP (right_width))
6745 CHECK_NATNUM (right_width);
6746
6747 /* Do nothing on a tty. */
6748 if (FRAME_WINDOW_P (WINDOW_XFRAME (w))
6749 && (!EQ (w->left_fringe_width, left_width)
6750 || !EQ (w->right_fringe_width, right_width)
6751 || !EQ (w->fringes_outside_margins, outside_margins)))
6752 {
6753 w->left_fringe_width = left_width;
6754 w->right_fringe_width = right_width;
6755 w->fringes_outside_margins = outside_margins;
6756
6757 adjust_window_margins (w);
6758
6759 clear_glyph_matrix (w->current_matrix);
6760 w->window_end_valid = Qnil;
6761
6762 ++windows_or_buffers_changed;
6763 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6764 }
6765
6766 return Qnil;
6767 }
6768
6769
6770 DEFUN ("window-fringes", Fwindow_fringes, Swindow_fringes,
6771 0, 1, 0,
6772 doc: /* Get width of fringes of window WINDOW.
6773 If WINDOW is omitted or nil, use the currently selected window.
6774 Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS). */)
6775 (window)
6776 Lisp_Object window;
6777 {
6778 struct window *w = decode_window (window);
6779
6780 return Fcons (make_number (WINDOW_LEFT_FRINGE_WIDTH (w)),
6781 Fcons (make_number (WINDOW_RIGHT_FRINGE_WIDTH (w)),
6782 Fcons ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
6783 ? Qt : Qnil), Qnil)));
6784 }
6785
6786
6787 \f
6788 /***********************************************************************
6789 Scroll bars
6790 ***********************************************************************/
6791
6792 DEFUN ("set-window-scroll-bars", Fset_window_scroll_bars, Sset_window_scroll_bars,
6793 2, 4, 0,
6794 doc: /* Set width and type of scroll bars of window WINDOW.
6795 If window is nil, set scroll bars of the currently selected window.
6796 Second parameter WIDTH specifies the pixel width for the scroll bar;
6797 this is automatically adjusted to a multiple of the frame column width.
6798 Third parameter VERTICAL-TYPE specifies the type of the vertical scroll
6799 bar: left, right, or nil.
6800 If WIDTH is nil, use the frame's scroll-bar width.
6801 If VERTICAL-TYPE is t, use the frame's scroll-bar type.
6802 Fourth parameter HORIZONTAL-TYPE is currently unused. */)
6803 (window, width, vertical_type, horizontal_type)
6804 Lisp_Object window, width, vertical_type, horizontal_type;
6805 {
6806 struct window *w = decode_window (window);
6807
6808 if (!NILP (width))
6809 {
6810 CHECK_NATNUM (width);
6811
6812 if (XINT (width) == 0)
6813 vertical_type = Qnil;
6814 }
6815
6816 if (!(NILP (vertical_type)
6817 || EQ (vertical_type, Qleft)
6818 || EQ (vertical_type, Qright)
6819 || EQ (vertical_type, Qt)))
6820 error ("Invalid type of vertical scroll bar");
6821
6822 if (!EQ (w->scroll_bar_width, width)
6823 || !EQ (w->vertical_scroll_bar_type, vertical_type))
6824 {
6825 w->scroll_bar_width = width;
6826 w->vertical_scroll_bar_type = vertical_type;
6827
6828 adjust_window_margins (w);
6829
6830 clear_glyph_matrix (w->current_matrix);
6831 w->window_end_valid = Qnil;
6832
6833 ++windows_or_buffers_changed;
6834 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
6835 }
6836
6837 return Qnil;
6838 }
6839
6840
6841 DEFUN ("window-scroll-bars", Fwindow_scroll_bars, Swindow_scroll_bars,
6842 0, 1, 0,
6843 doc: /* Get width and type of scroll bars of window WINDOW.
6844 If WINDOW is omitted or nil, use the currently selected window.
6845 Value is a list of the form (WIDTH COLS VERTICAL-TYPE HORIZONTAL-TYPE).
6846 If WIDTH is nil or TYPE is t, the window is using the frame's corresponding
6847 value. */)
6848 (window)
6849 Lisp_Object window;
6850 {
6851 struct window *w = decode_window (window);
6852 return Fcons (make_number ((WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
6853 ? WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
6854 : WINDOW_SCROLL_BAR_AREA_WIDTH (w))),
6855 Fcons (make_number (WINDOW_SCROLL_BAR_COLS (w)),
6856 Fcons (w->vertical_scroll_bar_type,
6857 Fcons (Qnil, Qnil))));
6858 }
6859
6860
6861 \f
6862 /***********************************************************************
6863 Smooth scrolling
6864 ***********************************************************************/
6865
6866 DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 2, 0,
6867 doc: /* Return the amount by which WINDOW is scrolled vertically.
6868 Use the selected window if WINDOW is nil or omitted.
6869 Normally, value is a multiple of the canonical character height of WINDOW;
6870 optional second arg PIXELS-P means value is measured in pixels. */)
6871 (window, pixels_p)
6872 Lisp_Object window, pixels_p;
6873 {
6874 Lisp_Object result;
6875 struct frame *f;
6876 struct window *w;
6877
6878 if (NILP (window))
6879 window = selected_window;
6880 else
6881 CHECK_WINDOW (window);
6882 w = XWINDOW (window);
6883 f = XFRAME (w->frame);
6884
6885 if (FRAME_WINDOW_P (f))
6886 result = (NILP (pixels_p)
6887 ? FRAME_CANON_Y_FROM_PIXEL_Y (f, -w->vscroll)
6888 : make_number (-w->vscroll));
6889 else
6890 result = make_number (0);
6891 return result;
6892 }
6893
6894
6895 DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
6896 2, 3, 0,
6897 doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL.
6898 WINDOW nil means use the selected window. Normally, VSCROLL is a
6899 non-negative multiple of the canonical character height of WINDOW;
6900 optional third arg PIXELS-P non-nil means that VSCROLL is in pixels.
6901 If PIXELS-P is nil, VSCROLL may have to be rounded so that it
6902 corresponds to an integral number of pixels. The return value is the
6903 result of this rounding.
6904 If PIXELS-P is non-nil, the return value is VSCROLL. */)
6905 (window, vscroll, pixels_p)
6906 Lisp_Object window, vscroll, pixels_p;
6907 {
6908 struct window *w;
6909 struct frame *f;
6910
6911 if (NILP (window))
6912 window = selected_window;
6913 else
6914 CHECK_WINDOW (window);
6915 CHECK_NUMBER_OR_FLOAT (vscroll);
6916
6917 w = XWINDOW (window);
6918 f = XFRAME (w->frame);
6919
6920 if (FRAME_WINDOW_P (f))
6921 {
6922 int old_dy = w->vscroll;
6923
6924 w->vscroll = - (NILP (pixels_p)
6925 ? FRAME_LINE_HEIGHT (f) * XFLOATINT (vscroll)
6926 : XFLOATINT (vscroll));
6927 w->vscroll = min (w->vscroll, 0);
6928
6929 if (w->vscroll != old_dy)
6930 {
6931 /* Adjust glyph matrix of the frame if the virtual display
6932 area becomes larger than before. */
6933 if (w->vscroll < 0 && w->vscroll < old_dy)
6934 adjust_glyphs (f);
6935
6936 /* Prevent redisplay shortcuts. */
6937 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
6938 }
6939 }
6940
6941 return Fwindow_vscroll (window, pixels_p);
6942 }
6943
6944 \f
6945 /* Call FN for all leaf windows on frame F. FN is called with the
6946 first argument being a pointer to the leaf window, and with
6947 additional argument USER_DATA. Stops when FN returns 0. */
6948
6949 void
6950 foreach_window (f, fn, user_data)
6951 struct frame *f;
6952 int (* fn) P_ ((struct window *, void *));
6953 void *user_data;
6954 {
6955 /* delete_frame may set FRAME_ROOT_WINDOW (f) to Qnil. */
6956 if (WINDOWP (FRAME_ROOT_WINDOW (f)))
6957 foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data);
6958 }
6959
6960
6961 /* Helper function for foreach_window. Call FN for all leaf windows
6962 reachable from W. FN is called with the first argument being a
6963 pointer to the leaf window, and with additional argument USER_DATA.
6964 Stop when FN returns 0. Value is 0 if stopped by FN. */
6965
6966 static int
6967 foreach_window_1 (w, fn, user_data)
6968 struct window *w;
6969 int (* fn) P_ ((struct window *, void *));
6970 void *user_data;
6971 {
6972 int cont;
6973
6974 for (cont = 1; w && cont;)
6975 {
6976 if (!NILP (w->hchild))
6977 cont = foreach_window_1 (XWINDOW (w->hchild), fn, user_data);
6978 else if (!NILP (w->vchild))
6979 cont = foreach_window_1 (XWINDOW (w->vchild), fn, user_data);
6980 else
6981 cont = fn (w, user_data);
6982
6983 w = NILP (w->next) ? 0 : XWINDOW (w->next);
6984 }
6985
6986 return cont;
6987 }
6988
6989
6990 /* Freeze or unfreeze the window start of W unless it is a
6991 mini-window or the selected window. FREEZE_P non-null means freeze
6992 the window start. */
6993
6994 static int
6995 freeze_window_start (w, freeze_p)
6996 struct window *w;
6997 void *freeze_p;
6998 {
6999 if (MINI_WINDOW_P (w)
7000 || (WINDOWP (selected_window) /* Can be nil in corner cases. */
7001 && (w == XWINDOW (selected_window)
7002 || (MINI_WINDOW_P (XWINDOW (selected_window))
7003 && ! NILP (Vminibuf_scroll_window)
7004 && w == XWINDOW (Vminibuf_scroll_window)))))
7005 freeze_p = NULL;
7006
7007 w->frozen_window_start_p = freeze_p != NULL;
7008 return 1;
7009 }
7010
7011
7012 /* Freeze or unfreeze the window starts of all leaf windows on frame
7013 F, except the selected window and a mini-window. FREEZE_P non-zero
7014 means freeze the window start. */
7015
7016 void
7017 freeze_window_starts (f, freeze_p)
7018 struct frame *f;
7019 int freeze_p;
7020 {
7021 foreach_window (f, freeze_window_start, (void *) (freeze_p ? f : 0));
7022 }
7023
7024 \f
7025 /***********************************************************************
7026 Initialization
7027 ***********************************************************************/
7028
7029 /* Return 1 if window configurations C1 and C2
7030 describe the same state of affairs. This is used by Fequal. */
7031
7032 int
7033 compare_window_configurations (c1, c2, ignore_positions)
7034 Lisp_Object c1, c2;
7035 int ignore_positions;
7036 {
7037 register struct save_window_data *d1, *d2;
7038 struct Lisp_Vector *sw1, *sw2;
7039 int i;
7040
7041 CHECK_WINDOW_CONFIGURATION (c1);
7042 CHECK_WINDOW_CONFIGURATION (c2);
7043
7044 d1 = (struct save_window_data *) XVECTOR (c1);
7045 d2 = (struct save_window_data *) XVECTOR (c2);
7046 sw1 = XVECTOR (d1->saved_windows);
7047 sw2 = XVECTOR (d2->saved_windows);
7048
7049 if (d1->frame_cols != d2->frame_cols)
7050 return 0;
7051 if (d1->frame_lines != d2->frame_lines)
7052 return 0;
7053 if (d1->frame_menu_bar_lines != d2->frame_menu_bar_lines)
7054 return 0;
7055 if (! EQ (d1->selected_frame, d2->selected_frame))
7056 return 0;
7057 /* Don't compare the current_window field directly.
7058 Instead see w1_is_current and w2_is_current, below. */
7059 if (! EQ (d1->current_buffer, d2->current_buffer))
7060 return 0;
7061 if (! ignore_positions)
7062 {
7063 if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
7064 return 0;
7065 if (! EQ (d1->minibuf_selected_window, d2->minibuf_selected_window))
7066 return 0;
7067 }
7068 /* Don't compare the root_window field.
7069 We don't require the two configurations
7070 to use the same window object,
7071 and the two root windows must be equivalent
7072 if everything else compares equal. */
7073 if (! EQ (d1->focus_frame, d2->focus_frame))
7074 return 0;
7075
7076 /* Verify that the two confis have the same number of windows. */
7077 if (sw1->header.size != sw2->header.size)
7078 return 0;
7079
7080 for (i = 0; i < sw1->header.size; i++)
7081 {
7082 struct saved_window *p1, *p2;
7083 int w1_is_current, w2_is_current;
7084
7085 p1 = SAVED_WINDOW_N (sw1, i);
7086 p2 = SAVED_WINDOW_N (sw2, i);
7087
7088 /* Verify that the current windows in the two
7089 configurations correspond to each other. */
7090 w1_is_current = EQ (d1->current_window, p1->window);
7091 w2_is_current = EQ (d2->current_window, p2->window);
7092
7093 if (w1_is_current != w2_is_current)
7094 return 0;
7095
7096 /* Verify that the corresponding windows do match. */
7097 if (! EQ (p1->buffer, p2->buffer))
7098 return 0;
7099 if (! EQ (p1->left_col, p2->left_col))
7100 return 0;
7101 if (! EQ (p1->top_line, p2->top_line))
7102 return 0;
7103 if (! EQ (p1->total_cols, p2->total_cols))
7104 return 0;
7105 if (! EQ (p1->total_lines, p2->total_lines))
7106 return 0;
7107 if (! EQ (p1->display_table, p2->display_table))
7108 return 0;
7109 if (! EQ (p1->parent, p2->parent))
7110 return 0;
7111 if (! EQ (p1->prev, p2->prev))
7112 return 0;
7113 if (! ignore_positions)
7114 {
7115 if (! EQ (p1->hscroll, p2->hscroll))
7116 return 0;
7117 if (!EQ (p1->min_hscroll, p2->min_hscroll))
7118 return 0;
7119 if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
7120 return 0;
7121 if (NILP (Fequal (p1->start, p2->start)))
7122 return 0;
7123 if (NILP (Fequal (p1->pointm, p2->pointm)))
7124 return 0;
7125 if (NILP (Fequal (p1->mark, p2->mark)))
7126 return 0;
7127 }
7128 if (! EQ (p1->left_margin_cols, p2->left_margin_cols))
7129 return 0;
7130 if (! EQ (p1->right_margin_cols, p2->right_margin_cols))
7131 return 0;
7132 if (! EQ (p1->left_fringe_width, p2->left_fringe_width))
7133 return 0;
7134 if (! EQ (p1->right_fringe_width, p2->right_fringe_width))
7135 return 0;
7136 if (! EQ (p1->fringes_outside_margins, p2->fringes_outside_margins))
7137 return 0;
7138 if (! EQ (p1->scroll_bar_width, p2->scroll_bar_width))
7139 return 0;
7140 if (! EQ (p1->vertical_scroll_bar_type, p2->vertical_scroll_bar_type))
7141 return 0;
7142 }
7143
7144 return 1;
7145 }
7146
7147 DEFUN ("compare-window-configurations", Fcompare_window_configurations,
7148 Scompare_window_configurations, 2, 2, 0,
7149 doc: /* Compare two window configurations as regards the structure of windows.
7150 This function ignores details such as the values of point and mark
7151 and scrolling positions. */)
7152 (x, y)
7153 Lisp_Object x, y;
7154 {
7155 if (compare_window_configurations (x, y, 1))
7156 return Qt;
7157 return Qnil;
7158 }
7159 \f
7160 void
7161 init_window_once ()
7162 {
7163 struct frame *f = make_initial_frame ();
7164 XSETFRAME (selected_frame, f);
7165 Vterminal_frame = selected_frame;
7166 minibuf_window = f->minibuffer_window;
7167 selected_window = f->selected_window;
7168 last_nonminibuf_frame = f;
7169
7170 window_initialized = 1;
7171 }
7172
7173 void
7174 init_window ()
7175 {
7176 Vwindow_list = Qnil;
7177 }
7178
7179 void
7180 syms_of_window ()
7181 {
7182 Qscroll_up = intern_c_string ("scroll-up");
7183 staticpro (&Qscroll_up);
7184
7185 Qscroll_down = intern_c_string ("scroll-down");
7186 staticpro (&Qscroll_down);
7187
7188 Qwindow_size_fixed = intern_c_string ("window-size-fixed");
7189 staticpro (&Qwindow_size_fixed);
7190 Fset (Qwindow_size_fixed, Qnil);
7191
7192 staticpro (&Qwindow_configuration_change_hook);
7193 Qwindow_configuration_change_hook
7194 = intern_c_string ("window-configuration-change-hook");
7195
7196 Qwindowp = intern_c_string ("windowp");
7197 staticpro (&Qwindowp);
7198
7199 Qwindow_configuration_p = intern_c_string ("window-configuration-p");
7200 staticpro (&Qwindow_configuration_p);
7201
7202 Qwindow_live_p = intern_c_string ("window-live-p");
7203 staticpro (&Qwindow_live_p);
7204
7205 Qdisplay_buffer = intern_c_string ("display-buffer");
7206 staticpro (&Qdisplay_buffer);
7207
7208 Qtemp_buffer_show_hook = intern_c_string ("temp-buffer-show-hook");
7209 staticpro (&Qtemp_buffer_show_hook);
7210
7211 staticpro (&Vwindow_list);
7212
7213 minibuf_selected_window = Qnil;
7214 staticpro (&minibuf_selected_window);
7215
7216 window_scroll_pixel_based_preserve_x = -1;
7217 window_scroll_pixel_based_preserve_y = -1;
7218 window_scroll_preserve_hpos = -1;
7219 window_scroll_preserve_vpos = -1;
7220
7221 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
7222 doc: /* Non-nil means call as function to display a help buffer.
7223 The function is called with one argument, the buffer to be displayed.
7224 Used by `with-output-to-temp-buffer'.
7225 If this function is used, then it must do the entire job of showing
7226 the buffer; `temp-buffer-show-hook' is not run unless this function runs it. */);
7227 Vtemp_buffer_show_function = Qnil;
7228
7229 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
7230 doc: /* Non-nil means it is the window that C-M-v in minibuffer should scroll. */);
7231 Vminibuf_scroll_window = Qnil;
7232
7233 DEFVAR_BOOL ("mode-line-in-non-selected-windows", &mode_line_in_non_selected_windows,
7234 doc: /* Non-nil means to use `mode-line-inactive' face in non-selected windows.
7235 If the minibuffer is active, the `minibuffer-scroll-window' mode line
7236 is displayed in the `mode-line' face. */);
7237 mode_line_in_non_selected_windows = 1;
7238
7239 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
7240 doc: /* If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window. */);
7241 Vother_window_scroll_buffer = Qnil;
7242
7243 DEFVAR_BOOL ("auto-window-vscroll", &auto_window_vscroll_p,
7244 doc: /* *Non-nil means to automatically adjust `window-vscroll' to view tall lines. */);
7245 auto_window_vscroll_p = 1;
7246
7247 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
7248 doc: /* *Number of lines of continuity when scrolling by screenfuls. */);
7249 next_screen_context_lines = 2;
7250
7251 DEFVAR_INT ("window-min-height", &window_min_height,
7252 doc: /* Allow deleting windows less than this tall.
7253 The value is measured in line units. If a window wants a modeline it
7254 is counted as one line.
7255
7256 Emacs honors settings of this variable when enlarging or shrinking
7257 windows vertically. A value less than 1 is invalid. */);
7258 window_min_height = 4;
7259
7260 DEFVAR_INT ("window-min-width", &window_min_width,
7261 doc: /* Allow deleting windows less than this wide.
7262 The value is measured in characters and includes any fringes or
7263 the scrollbar.
7264
7265 Emacs honors settings of this variable when enlarging or shrinking
7266 windows horizontally. A value less than 2 is invalid. */);
7267 window_min_width = 10;
7268
7269 DEFVAR_LISP ("scroll-preserve-screen-position",
7270 &Vscroll_preserve_screen_position,
7271 doc: /* *Controls if scroll commands move point to keep its screen position unchanged.
7272 A value of nil means point does not keep its screen position except
7273 at the scroll margin or window boundary respectively.
7274 A value of t means point keeps its screen position if the scroll
7275 command moved it vertically out of the window, e.g. when scrolling
7276 by full screens.
7277 Any other value means point always keeps its screen position. */);
7278 Vscroll_preserve_screen_position = Qnil;
7279
7280 DEFVAR_LISP ("window-point-insertion-type", &Vwindow_point_insertion_type,
7281 doc: /* Type of marker to use for `window-point'. */);
7282 Vwindow_point_insertion_type = Qnil;
7283
7284 DEFVAR_LISP ("window-configuration-change-hook",
7285 &Vwindow_configuration_change_hook,
7286 doc: /* Functions to call when window configuration changes.
7287 The buffer-local part is run once per window, with the relevant window
7288 selected; while the global part is run only once for the modified frame,
7289 with the relevant frame selected. */);
7290 Vwindow_configuration_change_hook = Qnil;
7291
7292 DEFVAR_LISP ("recenter-redisplay", &Vrecenter_redisplay,
7293 doc: /* If non-nil, then the `recenter' command with a nil argument
7294 the entire frame to be redrawn; the special value `tty' causes the
7295 frame to be redrawn only if it is a tty frame. */);
7296 Vrecenter_redisplay = Qtty;
7297
7298
7299 defsubr (&Sselected_window);
7300 defsubr (&Sminibuffer_window);
7301 defsubr (&Swindow_minibuffer_p);
7302 defsubr (&Swindowp);
7303 defsubr (&Swindow_live_p);
7304 defsubr (&Spos_visible_in_window_p);
7305 defsubr (&Swindow_line_height);
7306 defsubr (&Swindow_buffer);
7307 defsubr (&Swindow_height);
7308 defsubr (&Swindow_width);
7309 defsubr (&Swindow_full_width_p);
7310 defsubr (&Swindow_hscroll);
7311 defsubr (&Sset_window_hscroll);
7312 defsubr (&Swindow_redisplay_end_trigger);
7313 defsubr (&Sset_window_redisplay_end_trigger);
7314 defsubr (&Swindow_edges);
7315 defsubr (&Swindow_pixel_edges);
7316 defsubr (&Swindow_inside_edges);
7317 defsubr (&Swindow_inside_pixel_edges);
7318 defsubr (&Scoordinates_in_window_p);
7319 defsubr (&Swindow_at);
7320 defsubr (&Swindow_point);
7321 defsubr (&Swindow_start);
7322 defsubr (&Swindow_end);
7323 defsubr (&Sset_window_point);
7324 defsubr (&Sset_window_start);
7325 defsubr (&Swindow_dedicated_p);
7326 defsubr (&Sset_window_dedicated_p);
7327 defsubr (&Swindow_display_table);
7328 defsubr (&Sset_window_display_table);
7329 defsubr (&Snext_window);
7330 defsubr (&Sprevious_window);
7331 defsubr (&Sother_window);
7332 defsubr (&Sget_lru_window);
7333 defsubr (&Sget_largest_window);
7334 defsubr (&Sget_buffer_window);
7335 defsubr (&Sdelete_other_windows);
7336 defsubr (&Sdelete_windows_on);
7337 defsubr (&Sreplace_buffer_in_windows);
7338 defsubr (&Sdelete_window);
7339 defsubr (&Sset_window_buffer);
7340 defsubr (&Sselect_window);
7341 defsubr (&Sforce_window_update);
7342 defsubr (&Ssplit_window);
7343 defsubr (&Senlarge_window);
7344 defsubr (&Sshrink_window);
7345 defsubr (&Sadjust_window_trailing_edge);
7346 defsubr (&Sscroll_up);
7347 defsubr (&Sscroll_down);
7348 defsubr (&Sscroll_left);
7349 defsubr (&Sscroll_right);
7350 defsubr (&Sother_window_for_scrolling);
7351 defsubr (&Sscroll_other_window);
7352 defsubr (&Sminibuffer_selected_window);
7353 defsubr (&Srecenter);
7354 defsubr (&Swindow_text_height);
7355 defsubr (&Smove_to_window_line);
7356 defsubr (&Swindow_configuration_p);
7357 defsubr (&Swindow_configuration_frame);
7358 defsubr (&Sset_window_configuration);
7359 defsubr (&Scurrent_window_configuration);
7360 defsubr (&Ssave_window_excursion);
7361 defsubr (&Swindow_tree);
7362 defsubr (&Sset_window_margins);
7363 defsubr (&Swindow_margins);
7364 defsubr (&Sset_window_fringes);
7365 defsubr (&Swindow_fringes);
7366 defsubr (&Sset_window_scroll_bars);
7367 defsubr (&Swindow_scroll_bars);
7368 defsubr (&Swindow_vscroll);
7369 defsubr (&Sset_window_vscroll);
7370 defsubr (&Scompare_window_configurations);
7371 defsubr (&Swindow_list);
7372 defsubr (&Swindow_parameters);
7373 defsubr (&Swindow_parameter);
7374 defsubr (&Sset_window_parameter);
7375
7376 }
7377
7378 void
7379 keys_of_window ()
7380 {
7381 initial_define_key (control_x_map, '1', "delete-other-windows");
7382 initial_define_key (control_x_map, '2', "split-window");
7383 initial_define_key (control_x_map, '0', "delete-window");
7384 initial_define_key (control_x_map, 'o', "other-window");
7385 initial_define_key (control_x_map, '^', "enlarge-window");
7386 initial_define_key (control_x_map, '<', "scroll-left");
7387 initial_define_key (control_x_map, '>', "scroll-right");
7388
7389 initial_define_key (global_map, Ctl ('V'), "scroll-up");
7390 initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
7391 initial_define_key (meta_map, 'v', "scroll-down");
7392
7393 initial_define_key (global_map, Ctl('L'), "recenter");
7394 initial_define_key (meta_map, 'r', "move-to-window-line");
7395 }
7396
7397 /* arch-tag: 90a9c576-0590-48f1-a5f1-6c96a0452d9f
7398 (do not change this comment) */