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