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