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