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