(tmm-completion-prompt): Doc fix.
[bpt/emacs.git] / src / window.c
CommitLineData
7ab12479
JB
1/* Window creation, deletion and examination for GNU Emacs.
2 Does not include redisplay.
49b996e7 3 Copyright (C) 1985,86,87,93,94,95,96,97,1998,2000, 2001, 2002
6529ed87 4 Free Software Foundation, Inc.
7ab12479
JB
5
6This file is part of GNU Emacs.
7
8GNU Emacs is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
1113d9db 10the Free Software Foundation; either version 2, or (at your option)
7ab12479
JB
11any later version.
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
20the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21Boston, MA 02111-1307, USA. */
7ab12479 22
18160b98 23#include <config.h>
7ab12479
JB
24#include "lisp.h"
25#include "buffer.h"
3e4731a3 26#include "keyboard.h"
e35f6ff7 27#include "keymap.h"
44fa5b1e 28#include "frame.h"
7ab12479
JB
29#include "window.h"
30#include "commands.h"
31#include "indent.h"
32#include "termchar.h"
33#include "disptab.h"
dfcf069d 34#include "dispextern.h"
5500c422
GM
35#include "blockinput.h"
36#include "intervals.h"
37
6d55d620 38#ifdef HAVE_X_WINDOWS
dfcf069d 39#include "xterm.h"
5500c422 40#endif /* HAVE_X_WINDOWS */
8f23f280
AI
41#ifdef WINDOWSNT
42#include "w32term.h"
43#endif
1e3c8885
EZ
44#ifdef MSDOS
45#include "msdos.h"
46#endif
1a578e9b
AC
47#ifdef macintosh
48#include "macterm.h"
49#endif
5500c422 50
7442878f
GM
51/* Values returned from coordinates_in_window. */
52
53enum window_part
54{
55 ON_NOTHING,
56 ON_TEXT,
57 ON_MODE_LINE,
58 ON_VERTICAL_BORDER,
59 ON_HEADER_LINE,
60 ON_LEFT_FRINGE,
49b996e7
GM
61 ON_RIGHT_FRINGE,
62 ON_LEFT_MARGIN,
63 ON_RIGHT_MARGIN
7442878f
GM
64};
65
5500c422 66
3f8ab7bd 67Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
90647b07 68Lisp_Object Qwindow_size_fixed;
49b996e7 69extern Lisp_Object Qleft_margin, Qright_margin;
233a4a2c 70extern Lisp_Object Qheight, Qwidth;
7ab12479 71
521b203e 72static int displayed_window_lines P_ ((struct window *));
5e14b1fc 73static struct window *decode_window P_ ((Lisp_Object));
b7354ddf 74static Lisp_Object select_window_1 P_ ((Lisp_Object, int));
5500c422
GM
75static int count_windows P_ ((struct window *));
76static int get_leaf_windows P_ ((struct window *, struct window **, int));
77static void window_scroll P_ ((Lisp_Object, int, int, int));
78static void window_scroll_pixel_based P_ ((Lisp_Object, int, int, int));
79static void window_scroll_line_based P_ ((Lisp_Object, int, int, int));
233a4a2c 80static int window_min_size_1 P_ ((struct window *, int));
f984d4fc 81static int window_min_size P_ ((struct window *, int, int, int *));
233a4a2c 82static void size_window P_ ((Lisp_Object, int, int, int));
f95464e4 83static int freeze_window_start P_ ((struct window *, void *));
f984d4fc 84static int window_fixed_size_p P_ ((struct window *, int, int));
f95284d2 85static void enlarge_window P_ ((Lisp_Object, int, int, int));
67492200 86static Lisp_Object window_list P_ ((void));
f95464e4 87static int add_window_to_list P_ ((struct window *, void *));
118ea242
GM
88static int candidate_window_p P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
89 Lisp_Object));
67492200
GM
90static Lisp_Object next_window P_ ((Lisp_Object, Lisp_Object,
91 Lisp_Object, int));
92static void decode_next_window_args P_ ((Lisp_Object *, Lisp_Object *,
93 Lisp_Object *));
f95464e4
GM
94static int foreach_window_1 P_ ((struct window *,
95 int (* fn) (struct window *, void *),
96 void *));
cd2904bd 97static Lisp_Object window_list_1 P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
b7354ddf 98
b0b7ed0e
GM
99/* The value of `window-size-fixed'. */
100
101int window_size_fixed;
102
7ab12479
JB
103/* This is the window in which the terminal's cursor should
104 be left when nothing is being done with it. This must
105 always be a leaf window, and its buffer is selected by
106 the top level editing loop at the end of each command.
107
108 This value is always the same as
44fa5b1e 109 FRAME_SELECTED_WINDOW (selected_frame). */
7ab12479
JB
110
111Lisp_Object selected_window;
112
67492200
GM
113/* A list of all windows for use by next_window and Fwindow_list.
114 Functions creating or deleting windows should invalidate this cache
115 by setting it to nil. */
116
117Lisp_Object Vwindow_list;
118
5500c422
GM
119/* The mini-buffer window of the selected frame.
120 Note that you cannot test for mini-bufferness of an arbitrary window
121 by comparing against this; but you can test for mini-bufferness of
7ab12479 122 the selected window. */
5500c422 123
7ab12479
JB
124Lisp_Object minibuf_window;
125
3f49fddc
KS
126/* Non-nil means it is the window whose mode line should be
127 shown as the selected window when the minibuffer is selected. */
128
3dbab091 129Lisp_Object minibuf_selected_window;
3f49fddc 130
7ab12479 131/* Non-nil means it is the window for C-M-v to scroll
5500c422
GM
132 when the mini-buffer is selected. */
133
7ab12479
JB
134Lisp_Object Vminibuf_scroll_window;
135
136/* Non-nil means this is the buffer whose window C-M-v should scroll. */
5500c422 137
7ab12479
JB
138Lisp_Object Vother_window_scroll_buffer;
139
7ab12479 140/* Non-nil means it's function to call to display temp buffers. */
5500c422 141
7ab12479
JB
142Lisp_Object Vtemp_buffer_show_function;
143
cc91894c
KS
144/* Non-zero means to use mode-line-inactive face in all windows but the
145 selected-window and the minibuffer-scroll-window when the
146 minibuffer is active. */
147int mode_line_in_non_selected_windows;
26124d5e 148
7ab12479 149/* If a window gets smaller than either of these, it is removed. */
5500c422 150
31ade731
SM
151EMACS_INT window_min_height;
152EMACS_INT window_min_width;
7ab12479
JB
153
154/* Nonzero implies Fdisplay_buffer should create windows. */
5500c422 155
7ab12479
JB
156int pop_up_windows;
157
44fa5b1e 158/* Nonzero implies make new frames for Fdisplay_buffer. */
5500c422 159
44fa5b1e 160int pop_up_frames;
7ab12479 161
9c3da604
GM
162/* Nonzero means reuse existing frames for displaying buffers. */
163
164int display_buffer_reuse_frames;
165
7ab12479 166/* Non-nil means use this function instead of default */
5500c422 167
44fa5b1e 168Lisp_Object Vpop_up_frame_function;
7ab12479
JB
169
170/* Function to call to handle Fdisplay_buffer. */
5500c422 171
7ab12479
JB
172Lisp_Object Vdisplay_buffer_function;
173
6529ed87
GM
174/* Non-nil means that Fdisplay_buffer should even the heights of windows. */
175
176Lisp_Object Veven_window_heights;
177
a90712c2 178/* List of buffer *names* for buffers that should have their own frames. */
5500c422 179
a90712c2
RS
180Lisp_Object Vspecial_display_buffer_names;
181
182/* List of regexps for buffer names that should have their own frames. */
5500c422 183
a90712c2
RS
184Lisp_Object Vspecial_display_regexps;
185
186/* Function to pop up a special frame. */
5500c422 187
a90712c2
RS
188Lisp_Object Vspecial_display_function;
189
855d8627 190/* List of buffer *names* for buffers to appear in selected window. */
5500c422 191
855d8627
RS
192Lisp_Object Vsame_window_buffer_names;
193
194/* List of regexps for buffer names to appear in selected window. */
5500c422 195
855d8627
RS
196Lisp_Object Vsame_window_regexps;
197
a58ec57d 198/* Hook run at end of temp_output_buffer_show. */
5500c422 199
a58ec57d
RS
200Lisp_Object Qtemp_buffer_show_hook;
201
37962e60 202/* Fdisplay_buffer always splits the largest window
7ab12479 203 if that window is more than this high. */
5500c422 204
31ade731 205EMACS_INT split_height_threshold;
7ab12479
JB
206
207/* Number of lines of continuity in scrolling by screenfuls. */
5500c422 208
31ade731 209EMACS_INT next_screen_context_lines;
7ab12479
JB
210
211/* Incremented for each window created. */
5500c422 212
7ab12479
JB
213static int sequence_number;
214
5b03d3c0 215/* Nonzero after init_window_once has finished. */
5500c422 216
5b03d3c0
RS
217static int window_initialized;
218
543f5fb1 219/* Hook to run when window config changes. */
5500c422 220
543f5fb1
RS
221Lisp_Object Qwindow_configuration_change_hook;
222Lisp_Object Vwindow_configuration_change_hook;
223
9317a85d
RS
224/* Nonzero means scroll commands try to put point
225 at the same screen height as previously. */
9317a85d 226
5500c422
GM
227Lisp_Object Vscroll_preserve_screen_position;
228
229#if 0 /* This isn't used anywhere. */
91a78190 230/* Nonzero means we can split a frame even if it is "unsplittable". */
eddd51c2 231static int inhibit_frame_unsplittable;
5500c422 232#endif /* 0 */
7d601aaa 233
31ade731 234extern EMACS_INT scroll_margin;
9317a85d 235
dba06815 236extern Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
7ab12479
JB
237\f
238DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
fdb82f93
PJ
239 doc: /* Returns t if OBJECT is a window. */)
240 (object)
413430c5 241 Lisp_Object object;
7ab12479 242{
413430c5 243 return WINDOWP (object) ? Qt : Qnil;
7ab12479
JB
244}
245
806b4d9b 246DEFUN ("window-live-p", Fwindow_live_p, Swindow_live_p, 1, 1, 0,
fdb82f93 247 doc: /* Returns t if OBJECT is a window which is currently visible. */)
413430c5
EN
248 (object)
249 Lisp_Object object;
605be8af 250{
9e571f49 251 return WINDOW_LIVE_P (object) ? Qt : Qnil;
605be8af
JB
252}
253
7ab12479
JB
254Lisp_Object
255make_window ()
256{
cffec418 257 Lisp_Object val;
7ab12479 258 register struct window *p;
cffec418 259
26605be9 260 p = allocate_window ();
d834a2e9
KH
261 XSETFASTINT (p->sequence_number, ++sequence_number);
262 XSETFASTINT (p->left, 0);
263 XSETFASTINT (p->top, 0);
264 XSETFASTINT (p->height, 0);
265 XSETFASTINT (p->width, 0);
266 XSETFASTINT (p->hscroll, 0);
ea68264b 267 XSETFASTINT (p->min_hscroll, 0);
f984d4fc 268 p->orig_top = p->orig_height = Qnil;
7ab12479
JB
269 p->start = Fmake_marker ();
270 p->pointm = Fmake_marker ();
d834a2e9 271 XSETFASTINT (p->use_time, 0);
44fa5b1e 272 p->frame = Qnil;
7ab12479
JB
273 p->display_table = Qnil;
274 p->dedicated = Qnil;
5500c422
GM
275 p->pseudo_window_p = 0;
276 bzero (&p->cursor, sizeof (p->cursor));
277 bzero (&p->last_cursor, sizeof (p->last_cursor));
278 bzero (&p->phys_cursor, sizeof (p->phys_cursor));
279 p->desired_matrix = p->current_matrix = 0;
280 p->phys_cursor_type = -1;
4b26579e 281 p->phys_cursor_width = -1;
5500c422
GM
282 p->must_be_updated_p = 0;
283 XSETFASTINT (p->window_end_vpos, 0);
284 XSETFASTINT (p->window_end_pos, 0);
285 p->window_end_valid = Qnil;
286 p->vscroll = 0;
cffec418 287 XSETWINDOW (val, p);
5500c422 288 XSETFASTINT (p->last_point, 0);
7bbb5782 289 p->frozen_window_start_p = 0;
67492200
GM
290
291 Vwindow_list = Qnil;
7ab12479
JB
292 return val;
293}
294
295DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0,
fdb82f93
PJ
296 doc: /* Return the window that the cursor now appears in and commands apply to. */)
297 ()
7ab12479
JB
298{
299 return selected_window;
300}
301
83762ba4 302DEFUN ("minibuffer-window", Fminibuffer_window, Sminibuffer_window, 0, 1, 0,
fdb82f93
PJ
303 doc: /* Return the window used now for minibuffers.
304If the optional argument FRAME is specified, return the minibuffer window
305used by that frame. */)
306 (frame)
83762ba4 307 Lisp_Object frame;
7ab12479 308{
83762ba4 309 if (NILP (frame))
1ae1a37d 310 frame = selected_frame;
b7826503 311 CHECK_LIVE_FRAME (frame);
83762ba4 312 return FRAME_MINIBUF_WINDOW (XFRAME (frame));
7ab12479
JB
313}
314
605be8af 315DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1, 0,
fdb82f93
PJ
316 doc: /* Returns non-nil if WINDOW is a minibuffer window. */)
317 (window)
7ab12479
JB
318 Lisp_Object window;
319{
320 struct window *w = decode_window (window);
53bb6b99 321 return MINI_WINDOW_P (w) ? Qt : Qnil;
81e4d465
MB
322}
323
324
7ab12479 325DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
fdb82f93
PJ
326 Spos_visible_in_window_p, 0, 3, 0,
327 doc: /* Return t if position POS is currently on the frame in WINDOW.
328Return nil if that position is scrolled vertically out of view.
329If a character is only partially visible, nil is returned, unless the
330optional argument PARTIALLY is non-nil.
331POS defaults to point in WINDOW; WINDOW defaults to the selected window. */)
332 (pos, window, partially)
5cdb3cf3 333 Lisp_Object pos, window, partially;
7ab12479
JB
334{
335 register struct window *w;
7ab12479
JB
336 register int posint;
337 register struct buffer *buf;
9a132b1f
GM
338 struct text_pos top;
339 Lisp_Object in_window;
53bb6b99 340 int fully_p;
7ab12479 341
f28b75a9
MB
342 w = decode_window (window);
343 buf = XBUFFER (w->buffer);
344 SET_TEXT_POS_FROM_MARKER (top, w->start);
345
346 if (!NILP (pos))
7ab12479 347 {
b7826503 348 CHECK_NUMBER_COERCE_MARKER (pos);
7ab12479
JB
349 posint = XINT (pos);
350 }
f28b75a9
MB
351 else if (w == XWINDOW (selected_window))
352 posint = PT;
353 else
354 posint = XMARKER (w->pointm)->charpos;
7ab12479 355
53bb6b99 356 /* If position is above window start, it's not visible. */
5500c422 357 if (posint < CHARPOS (top))
9a132b1f
GM
358 in_window = Qnil;
359 else if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf)
81e4d465
MB
360 && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (buf)
361 && posint < BUF_Z (buf) - XFASTINT (w->window_end_pos))
81e4d465 362 {
53bb6b99
GM
363 /* If frame is up-to-date, and POSINT is < window end pos, use
364 that info. This doesn't work for POSINT == end pos, because
365 the window end pos is actually the position _after_ the last
366 char in the window. */
5cdb3cf3 367 if (NILP (partially))
53bb6b99 368 {
5cdb3cf3 369 pos_visible_p (w, posint, &fully_p, NILP (partially));
53bb6b99
GM
370 in_window = fully_p ? Qt : Qnil;
371 }
81e4d465 372 else
53bb6b99 373 in_window = Qt;
81e4d465 374 }
9a132b1f
GM
375 else if (posint > BUF_ZV (buf))
376 in_window = Qnil;
377 else if (CHARPOS (top) < BUF_BEGV (buf) || CHARPOS (top) > BUF_ZV (buf))
378 /* If window start is out of range, do something reasonable. */
379 in_window = Qnil;
7ab12479
JB
380 else
381 {
5cdb3cf3
MB
382 if (pos_visible_p (w, posint, &fully_p, NILP (partially)))
383 in_window = !NILP (partially) || fully_p ? Qt : Qnil;
81e4d465
MB
384 else
385 in_window = Qnil;
7ab12479 386 }
9a132b1f
GM
387
388 return in_window;
7ab12479 389}
53bb6b99 390
7ab12479
JB
391\f
392static struct window *
393decode_window (window)
394 register Lisp_Object window;
395{
265a9e55 396 if (NILP (window))
7ab12479
JB
397 return XWINDOW (selected_window);
398
b7826503 399 CHECK_LIVE_WINDOW (window);
7ab12479
JB
400 return XWINDOW (window);
401}
402
403DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
fdb82f93
PJ
404 doc: /* Return the buffer that WINDOW is displaying. */)
405 (window)
7ab12479
JB
406 Lisp_Object window;
407{
408 return decode_window (window)->buffer;
409}
410
411DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0,
fdb82f93
PJ
412 doc: /* Return the number of lines in WINDOW (including its mode line). */)
413 (window)
7ab12479
JB
414 Lisp_Object window;
415{
416 return decode_window (window)->height;
417}
418
419DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
fdb82f93
PJ
420 doc: /* Return the number of display columns in WINDOW.
421This is the width that is usable columns available for text in WINDOW.
422If you want to find out how many columns WINDOW takes up,
423use (let ((edges (window-edges))) (- (nth 2 edges) (nth 0 edges))). */)
424 (window)
7ab12479
JB
425 Lisp_Object window;
426{
ee61d94e 427 return make_number (window_internal_width (decode_window (window)));
7ab12479
JB
428}
429
430DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
fdb82f93
PJ
431 doc: /* Return the number of columns by which WINDOW is scrolled from left margin. */)
432 (window)
7ab12479
JB
433 Lisp_Object window;
434{
435 return decode_window (window)->hscroll;
436}
437
438DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
fdb82f93
PJ
439 doc: /* Set number of columns WINDOW is scrolled from left margin to NCOL.
440NCOL should be zero or positive. */)
441 (window, ncol)
ea68264b 442 Lisp_Object window, ncol;
7ab12479 443{
ea68264b
GM
444 struct window *w = decode_window (window);
445 int hscroll;
7ab12479 446
b7826503 447 CHECK_NUMBER (ncol);
ea68264b
GM
448 hscroll = max (0, XINT (ncol));
449
450 /* Prevent redisplay shortcuts when changing the hscroll. */
451 if (XINT (w->hscroll) != hscroll)
b1599b4c 452 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
ea68264b 453
c67fa410 454 w->hscroll = make_number (hscroll);
7ab12479
JB
455 return ncol;
456}
457
190eb263
RS
458DEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger,
459 Swindow_redisplay_end_trigger, 0, 1, 0,
fdb82f93
PJ
460 doc: /* Return WINDOW's redisplay end trigger value.
461See `set-window-redisplay-end-trigger' for more information. */)
462 (window)
190eb263
RS
463 Lisp_Object window;
464{
465 return decode_window (window)->redisplay_end_trigger;
466}
467
468DEFUN ("set-window-redisplay-end-trigger", Fset_window_redisplay_end_trigger,
469 Sset_window_redisplay_end_trigger, 2, 2, 0,
fdb82f93
PJ
470 doc: /* Set WINDOW's redisplay end trigger value to VALUE.
471VALUE should be a buffer position (typically a marker) or nil.
472If it is a buffer position, then if redisplay in WINDOW reaches a position
473beyond VALUE, the functions in `redisplay-end-trigger-functions' are called
474with two arguments: WINDOW, and the end trigger value.
475Afterwards the end-trigger value is reset to nil. */)
476 (window, value)
190eb263
RS
477 register Lisp_Object window, value;
478{
479 register struct window *w;
480
481 w = decode_window (window);
482 w->redisplay_end_trigger = value;
483 return value;
484}
485
7ab12479 486DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0,
fdb82f93
PJ
487 doc: /* Return a list of the edge coordinates of WINDOW.
488\(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.
489RIGHT is one more than the rightmost column used by WINDOW,
490and BOTTOM is one more than the bottommost row used by WINDOW
491 and its mode-line. */)
492 (window)
7ab12479
JB
493 Lisp_Object window;
494{
495 register struct window *w = decode_window (window);
496
497 return Fcons (w->left, Fcons (w->top,
111e5992 498 Fcons (make_number (WINDOW_RIGHT_EDGE (w)),
7ab12479
JB
499 Fcons (make_number (XFASTINT (w->top)
500 + XFASTINT (w->height)),
501 Qnil))));
502}
503
fbad6f9a 504/* Test if the character at column *X, row *Y is within window W.
d5783c40
JB
505 If it is not, return 0;
506 if it is in the window's text area,
507 set *x and *y to its location relative to the upper left corner
508 of the window, and
509 return 1;
510 if it is on the window's modeline, return 2;
511 if it is on the border between the window and its right sibling,
5500c422
GM
512 return 3.
513 if it is on the window's top line, return 4;
81d189fd 514 if it is in left or right fringe of the window,
49b996e7
GM
515 return 5 or 6, and convert *X and *Y to window-relative coordinates;
516 if it is in the marginal area to the left/right of the window,
517 return 7 or 8, and convert *X and *Y to window-relative coordinates.
5500c422
GM
518
519 X and Y are frame relative pixel coordinates. */
520
7442878f 521static enum window_part
d5783c40
JB
522coordinates_in_window (w, x, y)
523 register struct window *w;
524 register int *x, *y;
525{
1cb794ba
GM
526 /* Let's make this a global enum later, instead of using numbers
527 everywhere. */
b0228ace
GM
528 struct frame *f = XFRAME (WINDOW_FRAME (w));
529 int left_x, right_x, top_y, bottom_y;
7442878f 530 enum window_part part;
15c565ac 531 int ux = CANON_X_UNIT (f);
b0228ace
GM
532 int x0 = XFASTINT (w->left) * ux;
533 int x1 = x0 + XFASTINT (w->width) * ux;
dad75588
GM
534 /* The width of the area where the vertical line can be dragged.
535 (Between mode lines for instance. */
536 int grabbable_width = ux;
ac431108 537 int lmargin_width = 0, rmargin_width = 0;
b0228ace
GM
538
539 if (*x < x0 || *x >= x1)
540 return ON_NOTHING;
541
466539bc
EZ
542 /* In what's below, we subtract 1 when computing right_x because we
543 want the rightmost pixel, which is given by left_pixel+width-1. */
5500c422
GM
544 if (w->pseudo_window_p)
545 {
546 left_x = 0;
b0228ace 547 right_x = XFASTINT (w->width) * CANON_X_UNIT (f) - 1;
5500c422
GM
548 top_y = WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
549 bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
550 }
551 else
552 {
2add4349 553 left_x = (WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w)
50df5e5a 554 - FRAME_INTERNAL_BORDER_WIDTH_SAFE (f));
466539bc 555 right_x = WINDOW_DISPLAY_RIGHT_EDGE_PIXEL_X (w) - 1;
2add4349 556 top_y = (WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w)
50df5e5a 557 - FRAME_INTERNAL_BORDER_WIDTH_SAFE (f));
5500c422
GM
558 bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
559 }
37962e60 560
1cb794ba
GM
561 /* On the mode line or header line? If it's near the start of
562 the mode or header line of window that's has a horizontal
563 sibling, say it's on the vertical line. That's to be able
564 to resize windows horizontally in case we're using toolkit
565 scroll bars. */
b0228ace 566
1cb794ba 567 if (WINDOW_WANTS_MODELINE_P (w)
b0228ace
GM
568 && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w)
569 && *y < bottom_y)
1cb794ba 570 {
b0228ace
GM
571 /* We're somewhere on the mode line. We consider the place
572 between mode lines of horizontally adjacent mode lines
573 as the vertical border. If scroll bars on the left,
574 return the right window. */
575 part = ON_MODE_LINE;
576
577 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
578 {
dad75588 579 if (abs (*x - x0) < grabbable_width)
b0228ace
GM
580 part = ON_VERTICAL_BORDER;
581 }
dad75588 582 else if (!WINDOW_RIGHTMOST_P (w) && abs (*x - x1) < grabbable_width)
b0228ace 583 part = ON_VERTICAL_BORDER;
1cb794ba 584 }
b0228ace
GM
585 else if (WINDOW_WANTS_HEADER_LINE_P (w)
586 && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w)
587 && *y >= top_y)
588 {
589 part = ON_HEADER_LINE;
590
591 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
592 {
dad75588 593 if (abs (*x - x0) < grabbable_width)
b0228ace
GM
594 part = ON_VERTICAL_BORDER;
595 }
dad75588 596 else if (!WINDOW_RIGHTMOST_P (w) && abs (*x - x1) < grabbable_width)
b0228ace
GM
597 part = ON_VERTICAL_BORDER;
598 }
599 /* Outside anything interesting? */
600 else if (*y < top_y
601 || *y >= bottom_y
602 || *x < (left_x
c13418ac 603 - FRAME_LEFT_FRINGE_WIDTH (f)
b0228ace 604 - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * ux)
7442878f 605 || *x > (right_x
c13418ac 606 + FRAME_RIGHT_FRINGE_WIDTH (f)
7442878f 607 + FRAME_RIGHT_SCROLL_BAR_WIDTH (f) * ux))
1cb794ba 608 {
b0228ace 609 part = ON_NOTHING;
1cb794ba 610 }
b0228ace 611 else if (FRAME_WINDOW_P (f))
fbad6f9a 612 {
447e9da0
GM
613 if (!w->pseudo_window_p
614 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f)
615 && !WINDOW_RIGHTMOST_P (w)
c13418ac 616 && (abs (*x - right_x - FRAME_RIGHT_FRINGE_WIDTH (f)) < grabbable_width))
b0228ace
GM
617 {
618 part = ON_VERTICAL_BORDER;
619 }
620 else if (*x < left_x || *x > right_x)
447e9da0 621 {
81d189fd 622 /* Other lines than the mode line don't include fringes and
447e9da0 623 scroll bars on the left. */
fbad6f9a 624
447e9da0
GM
625 /* Convert X and Y to window-relative pixel coordinates. */
626 *x -= left_x;
627 *y -= top_y;
b0228ace
GM
628 part = *x < left_x ? ON_LEFT_FRINGE : ON_RIGHT_FRINGE;
629 }
630 else
631 {
ac431108
EZ
632 lmargin_width = window_box_width (w, LEFT_MARGIN_AREA);
633 rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA);
634 /* You can never be on a margin area if its width is zero. */
635 if (lmargin_width
636 && *x <= window_box_right (w, LEFT_MARGIN_AREA))
49b996e7 637 part = ON_LEFT_MARGIN;
ac431108
EZ
638 else if (rmargin_width
639 && *x >= window_box_left (w, RIGHT_MARGIN_AREA))
49b996e7
GM
640 part = ON_RIGHT_MARGIN;
641 else
642 {
643 part = ON_TEXT;
644 *x -= left_x;
645 *y -= top_y;
646 }
447e9da0 647 }
fbad6f9a 648 }
447e9da0
GM
649 else
650 {
651 /* Need to say "*x > right_x" rather than >=, since on character
652 terminals, the vertical line's x coordinate is right_x. */
653 if (*x < left_x || *x > right_x)
654 {
81d189fd 655 /* Other lines than the mode line don't include fringes and
447e9da0
GM
656 scroll bars on the left. */
657
658 /* Convert X and Y to window-relative pixel coordinates. */
659 *x -= left_x;
660 *y -= top_y;
b0228ace 661 part = *x < left_x ? ON_LEFT_FRINGE : ON_RIGHT_FRINGE;
447e9da0 662 }
447e9da0 663 /* Here, too, "*x > right_x" is because of character terminals. */
b0228ace
GM
664 else if (!w->pseudo_window_p
665 && !WINDOW_RIGHTMOST_P (w)
666 && *x > right_x - ux)
667 {
668 /* On the border on the right side of the window? Assume that
669 this area begins at RIGHT_X minus a canonical char width. */
670 part = ON_VERTICAL_BORDER;
671 }
672 else
673 {
ac431108
EZ
674 lmargin_width = window_box_width (w, LEFT_MARGIN_AREA);
675 rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA);
676 /* You can never be on a margin area if its width is zero.
677 This is especially important for character terminals. */
678 if (lmargin_width
679 && *x <= window_box_right (w, LEFT_MARGIN_AREA))
49b996e7 680 part = ON_LEFT_MARGIN;
ac431108
EZ
681 else if (rmargin_width
682 && *x >= window_box_left (w, RIGHT_MARGIN_AREA))
49b996e7
GM
683 part = ON_RIGHT_MARGIN;
684 else
685 {
686 part = ON_TEXT;
687 /* Convert X and Y to window-relative pixel coordinates. */
688 *x -= left_x;
689 *y -= top_y;
690 }
b0228ace 691 }
447e9da0 692 }
b0228ace
GM
693
694 return part;
d5783c40
JB
695}
696
b0228ace 697
d5783c40 698DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
fdb82f93
PJ
699 Scoordinates_in_window_p, 2, 2, 0,
700 doc: /* Return non-nil if COORDINATES are in WINDOW.
701COORDINATES is a cons of the form (X . Y), X and Y being distances
702measured in characters from the upper-left corner of the frame.
703\(0 . 0) denotes the character in the upper left corner of the
704frame.
705If COORDINATES are in the text portion of WINDOW,
706 the coordinates relative to the window are returned.
707If they are in the mode line of WINDOW, `mode-line' is returned.
708If they are in the top mode line of WINDOW, `header-line' is returned.
81d189fd
KS
709If they are in the left fringe of WINDOW, `left-fringe' is returned.
710If they are in the right fringe of WINDOW, `right-fringe' is returned.
fdb82f93 711If they are on the border between WINDOW and its right sibling,
49b996e7
GM
712 `vertical-line' is returned.
713If they are in the windows's left or right marginal areas, `left-margin'\n\
714 or `right-margin' is returned. */)
fdb82f93 715 (coordinates, window)
d5783c40
JB
716 register Lisp_Object coordinates, window;
717{
5500c422
GM
718 struct window *w;
719 struct frame *f;
d5783c40 720 int x, y;
5500c422 721 Lisp_Object lx, ly;
d5783c40 722
b7826503 723 CHECK_LIVE_WINDOW (window);
5500c422
GM
724 w = XWINDOW (window);
725 f = XFRAME (w->frame);
b7826503 726 CHECK_CONS (coordinates);
5500c422
GM
727 lx = Fcar (coordinates);
728 ly = Fcdr (coordinates);
b7826503
PJ
729 CHECK_NUMBER_OR_FLOAT (lx);
730 CHECK_NUMBER_OR_FLOAT (ly);
5500c422
GM
731 x = PIXEL_X_FROM_CANON_X (f, lx);
732 y = PIXEL_Y_FROM_CANON_Y (f, ly);
733
734 switch (coordinates_in_window (w, &x, &y))
d5783c40 735 {
7442878f 736 case ON_NOTHING:
d5783c40
JB
737 return Qnil;
738
7442878f
GM
739 case ON_TEXT:
740 /* X and Y are now window relative pixel coordinates. Convert
741 them to canonical char units before returning them. */
5500c422
GM
742 return Fcons (CANON_X_FROM_PIXEL_X (f, x),
743 CANON_Y_FROM_PIXEL_Y (f, y));
d5783c40 744
7442878f 745 case ON_MODE_LINE:
d5783c40 746 return Qmode_line;
37962e60 747
7442878f 748 case ON_VERTICAL_BORDER:
e5d77022 749 return Qvertical_line;
d5783c40 750
7442878f 751 case ON_HEADER_LINE:
045dee35 752 return Qheader_line;
5500c422 753
7442878f
GM
754 case ON_LEFT_FRINGE:
755 return Qleft_fringe;
fbad6f9a 756
7442878f
GM
757 case ON_RIGHT_FRINGE:
758 return Qright_fringe;
fbad6f9a 759
49b996e7
GM
760 case ON_LEFT_MARGIN:
761 return Qleft_margin;
762
763 case ON_RIGHT_MARGIN:
764 return Qright_margin;
765
d5783c40
JB
766 default:
767 abort ();
768 }
769}
770
67492200
GM
771
772/* Callback for foreach_window, used in window_from_coordinates.
f95464e4
GM
773 Check if window W contains coordinates specified by USER_DATA which
774 is actually a pointer to a struct check_window_data CW.
775
776 Check if window W contains coordinates *CW->x and *CW->y. If it
777 does, return W in *CW->window, as Lisp_Object, and return in
5372262f 778 *CW->part the part of the window under coordinates *X,*Y. Return
f95464e4
GM
779 zero from this function to stop iterating over windows. */
780
781struct check_window_data
782{
783 Lisp_Object *window;
784 int *x, *y, *part;
785};
67492200
GM
786
787static int
f95464e4 788check_window_containing (w, user_data)
67492200 789 struct window *w;
f95464e4 790 void *user_data;
67492200 791{
f95464e4 792 struct check_window_data *cw = (struct check_window_data *) user_data;
7442878f
GM
793 enum window_part found;
794 int continue_p = 1;
67492200 795
f95464e4 796 found = coordinates_in_window (w, cw->x, cw->y);
7442878f 797 if (found != ON_NOTHING)
67492200 798 {
f95464e4
GM
799 *cw->part = found - 1;
800 XSETWINDOW (*cw->window, w);
7442878f 801 continue_p = 0;
67492200
GM
802 }
803
7442878f 804 return continue_p;
67492200
GM
805}
806
807
5500c422
GM
808/* Find the window containing frame-relative pixel position X/Y and
809 return it as a Lisp_Object. If X, Y is on the window's modeline,
810 set *PART to 1; if it is on the separating line between the window
811 and its right sibling, set it to 2; otherwise set it to 0. If
812 there is no window under X, Y return nil and leave *PART
67492200
GM
813 unmodified. TOOL_BAR_P non-zero means detect tool-bar windows.
814
815 This function was previously implemented with a loop cycling over
816 windows with Fnext_window, and starting with the frame's selected
817 window. It turned out that this doesn't work with an
818 implementation of next_window using Vwindow_list, because
819 FRAME_SELECTED_WINDOW (F) is not always contained in the window
820 tree of F when this function is called asynchronously from
821 note_mouse_highlight. The original loop didn't terminate in this
822 case. */
5500c422 823
7ab12479 824Lisp_Object
67492200
GM
825window_from_coordinates (f, x, y, part, tool_bar_p)
826 struct frame *f;
7ab12479 827 int x, y;
d5783c40 828 int *part;
9ea173e8 829 int tool_bar_p;
7ab12479 830{
67492200 831 Lisp_Object window;
f95464e4 832 struct check_window_data cw;
5500c422 833
67492200 834 window = Qnil;
f95464e4
GM
835 cw.window = &window, cw.x = &x, cw.y = &y; cw.part = part;
836 foreach_window (f, check_window_containing, &cw);
67492200
GM
837
838 /* If not found above, see if it's in the tool bar window, if a tool
839 bar exists. */
840 if (NILP (window)
841 && tool_bar_p
842 && WINDOWP (f->tool_bar_window)
843 && XINT (XWINDOW (f->tool_bar_window)->height) > 0
7442878f
GM
844 && (coordinates_in_window (XWINDOW (f->tool_bar_window), &x, &y)
845 != ON_NOTHING))
5500c422
GM
846 {
847 *part = 0;
67492200 848 window = f->tool_bar_window;
5500c422 849 }
37962e60 850
67492200 851 return window;
7ab12479
JB
852}
853
ab17c3f2 854DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
fdb82f93
PJ
855 doc: /* Return window containing coordinates X and Y on FRAME.
856If omitted, FRAME defaults to the currently selected frame.
857The top left corner of the frame is considered to be row 0,
858column 0. */)
859 (x, y, frame)
860 Lisp_Object x, y, frame;
7ab12479
JB
861{
862 int part;
5500c422 863 struct frame *f;
7ab12479 864
44fa5b1e 865 if (NILP (frame))
1ae1a37d 866 frame = selected_frame;
b7826503 867 CHECK_LIVE_FRAME (frame);
5500c422 868 f = XFRAME (frame);
7ab12479 869
5500c422 870 /* Check that arguments are integers or floats. */
b7826503
PJ
871 CHECK_NUMBER_OR_FLOAT (x);
872 CHECK_NUMBER_OR_FLOAT (y);
5500c422
GM
873
874 return window_from_coordinates (f,
875 PIXEL_X_FROM_CANON_X (f, x),
876 PIXEL_Y_FROM_CANON_Y (f, y),
877 &part, 0);
7ab12479
JB
878}
879
880DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
fdb82f93
PJ
881 doc: /* Return current value of point in WINDOW.
882For a nonselected window, this is the value point would have
883if that window were selected.
884
885Note that, when WINDOW is the selected window and its buffer
886is also currently selected, the value returned is the same as (point).
887It would be more strictly correct to return the `top-level' value
888of point, outside of any save-excursion forms.
889But that is hard to define. */)
890 (window)
7ab12479
JB
891 Lisp_Object window;
892{
893 register struct window *w = decode_window (window);
894
895 if (w == XWINDOW (selected_window)
896 && current_buffer == XBUFFER (w->buffer))
897 return Fpoint ();
898 return Fmarker_position (w->pointm);
899}
900
901DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
fdb82f93
PJ
902 doc: /* Return position at which display currently starts in WINDOW.
903This is updated by redisplay or by calling `set-window-start'. */)
904 (window)
7ab12479
JB
905 Lisp_Object window;
906{
907 return Fmarker_position (decode_window (window)->start);
908}
909
8646118f
RS
910/* This is text temporarily removed from the doc string below.
911
fdb82f93
PJ
912This function returns nil if the position is not currently known.
913That happens when redisplay is preempted and doesn't finish.
914If in that case you want to compute where the end of the window would
915have been if redisplay had finished, do this:
916 (save-excursion
917 (goto-char (window-start window))
918 (vertical-motion (1- (window-height window)) window)
8646118f
RS
919 (point))") */
920
478292ed 921DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
fdb82f93
PJ
922 doc: /* Return position at which display currently ends in WINDOW.
923This is updated by redisplay, when it runs to completion.
924Simply changing the buffer text or setting `window-start'
925does not update this value.
926If UPDATE is non-nil, compute the up-to-date position
927if it isn't already recorded. */)
928 (window, update)
478292ed 929 Lisp_Object window, update;
7ab12479
JB
930{
931 Lisp_Object value;
932 struct window *w = decode_window (window);
5a41ab94
RS
933 Lisp_Object buf;
934
935 buf = w->buffer;
b7826503 936 CHECK_BUFFER (buf);
5a41ab94 937
8646118f 938#if 0 /* This change broke some things. We should make it later. */
7250968e
RS
939 /* If we don't know the end position, return nil.
940 The user can compute it with vertical-motion if he wants to.
941 It would be nicer to do it automatically,
942 but that's so slow that it would probably bother people. */
943 if (NILP (w->window_end_valid))
944 return Qnil;
8646118f 945#endif
7250968e 946
478292ed
RS
947 if (! NILP (update)
948 && ! (! NILP (w->window_end_valid)
949 && XFASTINT (w->last_modified) >= MODIFF))
950 {
cbc099e5
GM
951 struct text_pos startp;
952 struct it it;
99593a9d 953 struct buffer *old_buffer = NULL, *b = XBUFFER (buf);
2d6d9df0
GM
954
955 /* In case W->start is out of the range, use something
956 reasonable. This situation occured when loading a file with
957 `-l' containing a call to `rmail' with subsequent other
958 commands. At the end, W->start happened to be BEG, while
cbc099e5 959 rmail had already narrowed the buffer. */
2d6d9df0 960 if (XMARKER (w->start)->charpos < BEGV)
cbc099e5 961 SET_TEXT_POS (startp, BEGV, BEGV_BYTE);
2d6d9df0 962 else if (XMARKER (w->start)->charpos > ZV)
cbc099e5 963 SET_TEXT_POS (startp, ZV, ZV_BYTE);
2d6d9df0 964 else
cbc099e5
GM
965 SET_TEXT_POS_FROM_MARKER (startp, w->start);
966
967 /* Cannot use Fvertical_motion because that function doesn't
968 cope with variable-height lines. */
99593a9d
GM
969 if (b != current_buffer)
970 {
971 old_buffer = current_buffer;
972 set_buffer_internal (b);
973 }
974
cbc099e5
GM
975 start_display (&it, w, startp);
976 move_it_vertically (&it, window_box_height (w));
c3c45f65
GM
977 if (it.current_y < it.last_visible_y)
978 move_it_past_eol (&it);
cbc099e5 979 value = make_number (IT_CHARPOS (it));
99593a9d
GM
980
981 if (old_buffer)
982 set_buffer_internal (old_buffer);
478292ed
RS
983 }
984 else
cbc099e5 985 XSETINT (value, BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
7ab12479
JB
986
987 return value;
988}
989
990DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
fdb82f93
PJ
991 doc: /* Make point value in WINDOW be at position POS in WINDOW's buffer. */)
992 (window, pos)
7ab12479
JB
993 Lisp_Object window, pos;
994{
995 register struct window *w = decode_window (window);
996
b7826503 997 CHECK_NUMBER_COERCE_MARKER (pos);
e90c4fe6
RS
998 if (w == XWINDOW (selected_window)
999 && XBUFFER (w->buffer) == current_buffer)
7ab12479
JB
1000 Fgoto_char (pos);
1001 else
1002 set_marker_restricted (w->pointm, pos, w->buffer);
799417bd 1003
0685cb3c
GM
1004 /* We have to make sure that redisplay updates the window to show
1005 the new value of point. */
1006 if (!EQ (window, selected_window))
799417bd 1007 ++windows_or_buffers_changed;
ce7fae7d 1008
7ab12479
JB
1009 return pos;
1010}
1011
1012DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
fdb82f93
PJ
1013 doc: /* Make display in WINDOW start at position POS in WINDOW's buffer.
1014Optional third arg NOFORCE non-nil inhibits next redisplay
1015from overriding motion of point in order to display at this exact start. */)
1016 (window, pos, noforce)
7ab12479
JB
1017 Lisp_Object window, pos, noforce;
1018{
1019 register struct window *w = decode_window (window);
1020
b7826503 1021 CHECK_NUMBER_COERCE_MARKER (pos);
7ab12479
JB
1022 set_marker_restricted (w->start, pos, w->buffer);
1023 /* this is not right, but much easier than doing what is right. */
1024 w->start_at_line_beg = Qnil;
265a9e55 1025 if (NILP (noforce))
7ab12479
JB
1026 w->force_start = Qt;
1027 w->update_mode_line = Qt;
d834a2e9 1028 XSETFASTINT (w->last_modified, 0);
3cd21523 1029 XSETFASTINT (w->last_overlay_modified, 0);
62c07cc7
JB
1030 if (!EQ (window, selected_window))
1031 windows_or_buffers_changed++;
ce7fae7d 1032
7ab12479
JB
1033 return pos;
1034}
1035
1036DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
1037 1, 1, 0,
fdb82f93
PJ
1038 doc: /* Return WINDOW's dedicated object, usually t or nil.
1039See also `set-window-dedicated-p'. */)
1040 (window)
7ab12479
JB
1041 Lisp_Object window;
1042{
1043 return decode_window (window)->dedicated;
1044}
1045
d207b766
RS
1046DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p,
1047 Sset_window_dedicated_p, 2, 2, 0,
fdb82f93
PJ
1048 doc: /* Control whether WINDOW is dedicated to the buffer it displays.
1049If it is dedicated, Emacs will not automatically change
1050which buffer appears in it.
1051The second argument is the new value for the dedication flag;
1052non-nil means yes. */)
1053 (window, arg)
1054 Lisp_Object window, arg;
7ab12479
JB
1055{
1056 register struct window *w = decode_window (window);
1057
265a9e55 1058 if (NILP (arg))
7ab12479
JB
1059 w->dedicated = Qnil;
1060 else
d207b766 1061 w->dedicated = Qt;
7ab12479
JB
1062
1063 return w->dedicated;
1064}
1065
1066DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
1067 0, 1, 0,
fdb82f93
PJ
1068 doc: /* Return the display-table that WINDOW is using. */)
1069 (window)
7ab12479
JB
1070 Lisp_Object window;
1071{
1072 return decode_window (window)->display_table;
1073}
1074
5500c422
GM
1075/* Get the display table for use on window W. This is either W's
1076 display table or W's buffer's display table. Ignore the specified
1077 tables if they are not valid; if no valid table is specified,
1078 return 0. */
7ab12479 1079
319315f1 1080struct Lisp_Char_Table *
7ab12479
JB
1081window_display_table (w)
1082 struct window *w;
1083{
c756cdbe
GM
1084 struct Lisp_Char_Table *dp = NULL;
1085
1086 if (DISP_TABLE_P (w->display_table))
1087 dp = XCHAR_TABLE (w->display_table);
1088 else if (BUFFERP (w->buffer))
1089 {
1090 struct buffer *b = XBUFFER (w->buffer);
1091
1092 if (DISP_TABLE_P (b->display_table))
1093 dp = XCHAR_TABLE (b->display_table);
1094 else if (DISP_TABLE_P (Vstandard_display_table))
1095 dp = XCHAR_TABLE (Vstandard_display_table);
1096 }
171d003c 1097
c756cdbe 1098 return dp;
7ab12479
JB
1099}
1100
3a2712f9 1101DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_display_table, 2, 2, 0,
fdb82f93
PJ
1102 doc: /* Set WINDOW's display-table to TABLE. */)
1103 (window, table)
7ab12479
JB
1104 register Lisp_Object window, table;
1105{
1106 register struct window *w;
7ab12479
JB
1107
1108 w = decode_window (window);
1109 w->display_table = table;
1110 return table;
1111}
1112\f
1113/* Record info on buffer window w is displaying
1114 when it is about to cease to display that buffer. */
dfcf069d 1115static void
7ab12479
JB
1116unshow_buffer (w)
1117 register struct window *w;
1118{
12cae7c0 1119 Lisp_Object buf;
b73ea88e 1120 struct buffer *b;
7ab12479 1121
12cae7c0 1122 buf = w->buffer;
b73ea88e
RS
1123 b = XBUFFER (buf);
1124 if (b != XMARKER (w->pointm)->buffer)
7ab12479
JB
1125 abort ();
1126
573f41ab 1127#if 0
7ab12479
JB
1128 if (w == XWINDOW (selected_window)
1129 || ! EQ (buf, XWINDOW (selected_window)->buffer))
1130 /* Do this except when the selected window's buffer
1131 is being removed from some other window. */
573f41ab
RS
1132#endif
1133 /* last_window_start records the start position that this buffer
1134 had in the last window to be disconnected from it.
1135 Now that this statement is unconditional,
1136 it is possible for the buffer to be displayed in the
1137 selected window, while last_window_start reflects another
1138 window which was recently showing the same buffer.
1139 Some people might say that might be a good thing. Let's see. */
b73ea88e 1140 b->last_window_start = marker_position (w->start);
7ab12479
JB
1141
1142 /* Point in the selected window's buffer
1143 is actually stored in that buffer, and the window's pointm isn't used.
1144 So don't clobber point in that buffer. */
719eaeb1
GM
1145 if (! EQ (buf, XWINDOW (selected_window)->buffer)
1146 /* This line helps to fix Horsley's testbug.el bug. */
8801a864
KR
1147 && !(WINDOWP (b->last_selected_window)
1148 && w != XWINDOW (b->last_selected_window)
719eaeb1 1149 && EQ (buf, XWINDOW (b->last_selected_window)->buffer)))
b73ea88e
RS
1150 temp_set_point_both (b,
1151 clip_to_bounds (BUF_BEGV (b),
1152 XMARKER (w->pointm)->charpos,
1153 BUF_ZV (b)),
1154 clip_to_bounds (BUF_BEGV_BYTE (b),
1155 marker_byte_position (w->pointm),
1156 BUF_ZV_BYTE (b)));
719eaeb1 1157
8801a864
KR
1158 if (WINDOWP (b->last_selected_window)
1159 && w == XWINDOW (b->last_selected_window))
719eaeb1 1160 b->last_selected_window = Qnil;
7ab12479
JB
1161}
1162
1163/* Put replacement into the window structure in place of old. */
dfcf069d 1164static void
7ab12479
JB
1165replace_window (old, replacement)
1166 Lisp_Object old, replacement;
1167{
1168 register Lisp_Object tem;
1169 register struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
1170
44fa5b1e
JB
1171 /* If OLD is its frame's root_window, then replacement is the new
1172 root_window for that frame. */
7ab12479 1173
7f4161e0 1174 if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
44fa5b1e 1175 FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
7ab12479
JB
1176
1177 p->left = o->left;
1178 p->top = o->top;
1179 p->width = o->width;
1180 p->height = o->height;
5500c422
GM
1181 p->desired_matrix = p->current_matrix = 0;
1182 p->vscroll = 0;
1183 bzero (&p->cursor, sizeof (p->cursor));
1184 bzero (&p->last_cursor, sizeof (p->last_cursor));
1185 bzero (&p->phys_cursor, sizeof (p->phys_cursor));
1186 p->phys_cursor_type = -1;
4b26579e 1187 p->phys_cursor_width = -1;
5500c422
GM
1188 p->must_be_updated_p = 0;
1189 p->pseudo_window_p = 0;
1190 XSETFASTINT (p->window_end_vpos, 0);
1191 XSETFASTINT (p->window_end_pos, 0);
1192 p->window_end_valid = Qnil;
7bbb5782 1193 p->frozen_window_start_p = 0;
f984d4fc 1194 p->orig_top = p->orig_height = Qnil;
7ab12479
JB
1195
1196 p->next = tem = o->next;
265a9e55 1197 if (!NILP (tem))
7ab12479
JB
1198 XWINDOW (tem)->prev = replacement;
1199
1200 p->prev = tem = o->prev;
265a9e55 1201 if (!NILP (tem))
7ab12479
JB
1202 XWINDOW (tem)->next = replacement;
1203
1204 p->parent = tem = o->parent;
265a9e55 1205 if (!NILP (tem))
7ab12479
JB
1206 {
1207 if (EQ (XWINDOW (tem)->vchild, old))
1208 XWINDOW (tem)->vchild = replacement;
1209 if (EQ (XWINDOW (tem)->hchild, old))
1210 XWINDOW (tem)->hchild = replacement;
1211 }
1212
1213/*** Here, if replacement is a vertical combination
1214and so is its new parent, we should make replacement's
1215children be children of that parent instead. ***/
1216}
1217
1218DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
fdb82f93
PJ
1219 doc: /* Remove WINDOW from the display. Default is selected window. */)
1220 (window)
7ab12479 1221 register Lisp_Object window;
543f5fb1
RS
1222{
1223 delete_window (window);
1224
1225 if (! NILP (Vwindow_configuration_change_hook)
1226 && ! NILP (Vrun_hooks))
1227 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
1228
1229 return Qnil;
1230}
1231
5e14b1fc 1232void
543f5fb1
RS
1233delete_window (window)
1234 register Lisp_Object window;
7ab12479
JB
1235{
1236 register Lisp_Object tem, parent, sib;
1237 register struct window *p;
1238 register struct window *par;
951f9df5 1239 struct frame *f;
7ab12479 1240
605be8af
JB
1241 /* Because this function is called by other C code on non-leaf
1242 windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
1243 so we can't decode_window here. */
265a9e55 1244 if (NILP (window))
7ab12479
JB
1245 window = selected_window;
1246 else
b7826503 1247 CHECK_WINDOW (window);
7ab12479 1248 p = XWINDOW (window);
605be8af
JB
1249
1250 /* It's okay to delete an already-deleted window. */
1251 if (NILP (p->buffer)
1252 && NILP (p->hchild)
1253 && NILP (p->vchild))
296b535c 1254 return;
605be8af 1255
7ab12479 1256 parent = p->parent;
265a9e55 1257 if (NILP (parent))
7ab12479
JB
1258 error ("Attempt to delete minibuffer or sole ordinary window");
1259 par = XWINDOW (parent);
1260
1261 windows_or_buffers_changed++;
67492200 1262 Vwindow_list = Qnil;
951f9df5
GM
1263 f = XFRAME (WINDOW_FRAME (p));
1264 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
7ab12479 1265
605be8af
JB
1266 /* Are we trying to delete any frame's selected window? */
1267 {
192c3131 1268 Lisp_Object swindow, pwindow;
605be8af 1269
0def0403
RS
1270 /* See if the frame's selected window is either WINDOW
1271 or any subwindow of it, by finding all that window's parents
1272 and comparing each one with WINDOW. */
192c3131 1273 swindow = FRAME_SELECTED_WINDOW (f);
0def0403 1274
192c3131 1275 while (1)
0def0403 1276 {
192c3131
RS
1277 pwindow = swindow;
1278 while (!NILP (pwindow))
1279 {
1280 if (EQ (window, pwindow))
1281 break;
1282 pwindow = XWINDOW (pwindow)->parent;
1283 }
1284
1285 /* If the window being deleted is not a parent of SWINDOW,
1286 then SWINDOW is ok as the new selected window. */
1287 if (!EQ (window, pwindow))
0def0403 1288 break;
192c3131
RS
1289 /* Otherwise, try another window for SWINDOW. */
1290 swindow = Fnext_window (swindow, Qlambda, Qnil);;
1291
1292 /* If we get back to the frame's selected window,
1293 it means there was no acceptable alternative,
1294 so we cannot delete. */
1295 if (EQ (swindow, FRAME_SELECTED_WINDOW (f)))
1296 error ("Cannot delete window");
0def0403
RS
1297 }
1298
192c3131
RS
1299 /* If we need to change SWINDOW, do it. */
1300 if (! EQ (swindow, FRAME_SELECTED_WINDOW (f)))
605be8af 1301 {
605be8af
JB
1302 /* If we're about to delete the selected window on the
1303 selected frame, then we should use Fselect_window to select
1304 the new window. On the other hand, if we're about to
1305 delete the selected window on any other frame, we shouldn't do
1306 anything but set the frame's selected_window slot. */
192c3131
RS
1307 if (EQ (FRAME_SELECTED_WINDOW (f), selected_window))
1308 Fselect_window (swindow);
605be8af 1309 else
192c3131 1310 FRAME_SELECTED_WINDOW (f) = swindow;
605be8af
JB
1311 }
1312 }
7ab12479
JB
1313
1314 tem = p->buffer;
1315 /* tem is null for dummy parent windows
1316 (which have inferiors but not any contents themselves) */
265a9e55 1317 if (!NILP (tem))
7ab12479
JB
1318 {
1319 unshow_buffer (p);
1320 unchain_marker (p->pointm);
1321 unchain_marker (p->start);
7ab12479
JB
1322 }
1323
05e71564
GM
1324 /* Free window glyph matrices. It is sure that they are allocated
1325 again when ADJUST_GLYPHS is called. Block input so that expose
1326 events and other events that access glyph matrices are not
1327 processed while we are changing them. */
1328 BLOCK_INPUT;
951f9df5 1329 free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (f)));
5500c422 1330
7ab12479 1331 tem = p->next;
265a9e55 1332 if (!NILP (tem))
7ab12479
JB
1333 XWINDOW (tem)->prev = p->prev;
1334
1335 tem = p->prev;
265a9e55 1336 if (!NILP (tem))
7ab12479
JB
1337 XWINDOW (tem)->next = p->next;
1338
1339 if (EQ (window, par->hchild))
1340 par->hchild = p->next;
1341 if (EQ (window, par->vchild))
1342 par->vchild = p->next;
1343
1344 /* Find one of our siblings to give our space to. */
1345 sib = p->prev;
265a9e55 1346 if (NILP (sib))
7ab12479
JB
1347 {
1348 /* If p gives its space to its next sibling, that sibling needs
1349 to have its top/left side pulled back to where p's is.
1350 set_window_{height,width} will re-position the sibling's
1351 children. */
1352 sib = p->next;
7f4161e0
JB
1353 XWINDOW (sib)->top = p->top;
1354 XWINDOW (sib)->left = p->left;
7ab12479
JB
1355 }
1356
1357 /* Stretch that sibling. */
265a9e55 1358 if (!NILP (par->vchild))
7ab12479
JB
1359 set_window_height (sib,
1360 XFASTINT (XWINDOW (sib)->height) + XFASTINT (p->height),
1361 1);
265a9e55 1362 if (!NILP (par->hchild))
7ab12479
JB
1363 set_window_width (sib,
1364 XFASTINT (XWINDOW (sib)->width) + XFASTINT (p->width),
1365 1);
1366
1367 /* If parent now has only one child,
1368 put the child into the parent's place. */
7ab12479 1369 tem = par->hchild;
265a9e55 1370 if (NILP (tem))
7ab12479 1371 tem = par->vchild;
265a9e55 1372 if (NILP (XWINDOW (tem)->next))
7ab12479 1373 replace_window (parent, tem);
605be8af
JB
1374
1375 /* Since we may be deleting combination windows, we must make sure that
1376 not only p but all its children have been marked as deleted. */
1377 if (! NILP (p->hchild))
1378 delete_all_subwindows (XWINDOW (p->hchild));
1379 else if (! NILP (p->vchild))
1380 delete_all_subwindows (XWINDOW (p->vchild));
1381
1382 /* Mark this window as deleted. */
1383 p->buffer = p->hchild = p->vchild = Qnil;
5500c422
GM
1384
1385 /* Adjust glyph matrices. */
951f9df5 1386 adjust_glyphs (f);
05e71564 1387 UNBLOCK_INPUT;
7ab12479 1388}
67492200
GM
1389
1390
7ab12479 1391\f
67492200
GM
1392/***********************************************************************
1393 Window List
1394 ***********************************************************************/
1395
f95464e4
GM
1396/* Add window W to *USER_DATA. USER_DATA is actually a Lisp_Object
1397 pointer. This is a callback function for foreach_window, used in
1398 function window_list. */
67492200
GM
1399
1400static int
f95464e4 1401add_window_to_list (w, user_data)
67492200 1402 struct window *w;
f95464e4 1403 void *user_data;
67492200 1404{
f95464e4 1405 Lisp_Object *list = (Lisp_Object *) user_data;
67492200
GM
1406 Lisp_Object window;
1407 XSETWINDOW (window, w);
212116d6 1408 *list = Fcons (window, *list);
67492200
GM
1409 return 1;
1410}
1411
1412
1413/* Return a list of all windows, for use by next_window. If
1414 Vwindow_list is a list, return that list. Otherwise, build a new
1415 list, cache it in Vwindow_list, and return that. */
1416
1417static Lisp_Object
1418window_list ()
1419{
1420 if (!CONSP (Vwindow_list))
1421 {
1422 Lisp_Object tail;
212116d6 1423
67492200
GM
1424 Vwindow_list = Qnil;
1425 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
212116d6
GM
1426 {
1427 Lisp_Object args[2];
1428
1429 /* We are visiting windows in canonical order, and add
1430 new windows at the front of args[1], which means we
1431 have to reverse this list at the end. */
1432 args[1] = Qnil;
1433 foreach_window (XFRAME (XCAR (tail)), add_window_to_list, &args[1]);
1434 args[0] = Vwindow_list;
1435 args[1] = Fnreverse (args[1]);
1436 Vwindow_list = Fnconc (2, args);
1437 }
67492200
GM
1438 }
1439
1440 return Vwindow_list;
1441}
1442
1443
118ea242
GM
1444/* Value is non-zero if WINDOW satisfies the constraints given by
1445 OWINDOW, MINIBUF and ALL_FRAMES.
67492200 1446
118ea242
GM
1447 MINIBUF t means WINDOW may be minibuffer windows.
1448 `lambda' means WINDOW may not be a minibuffer window.
1449 a window means a specific minibuffer window
67492200 1450
118ea242
GM
1451 ALL_FRAMES t means search all frames,
1452 nil means search just current frame,
1453 `visible' means search just visible frames,
1454 0 means search visible and iconified frames,
1455 a window means search the frame that window belongs to,
1456 a frame means consider windows on that frame, only. */
67492200
GM
1457
1458static int
118ea242
GM
1459candidate_window_p (window, owindow, minibuf, all_frames)
1460 Lisp_Object window, owindow, minibuf, all_frames;
67492200
GM
1461{
1462 struct window *w = XWINDOW (window);
1463 struct frame *f = XFRAME (w->frame);
1464 int candidate_p = 1;
1465
1466 if (!BUFFERP (w->buffer))
1467 candidate_p = 0;
1468 else if (MINI_WINDOW_P (w)
1469 && (EQ (minibuf, Qlambda)
1470 || (WINDOWP (minibuf) && !EQ (minibuf, window))))
1471 {
1472 /* If MINIBUF is `lambda' don't consider any mini-windows.
1473 If it is a window, consider only that one. */
1474 candidate_p = 0;
1475 }
118ea242
GM
1476 else if (EQ (all_frames, Qt))
1477 candidate_p = 1;
67492200 1478 else if (NILP (all_frames))
118ea242
GM
1479 {
1480 xassert (WINDOWP (owindow));
1481 candidate_p = EQ (w->frame, XWINDOW (owindow)->frame);
1482 }
67492200
GM
1483 else if (EQ (all_frames, Qvisible))
1484 {
1485 FRAME_SAMPLE_VISIBILITY (f);
1486 candidate_p = FRAME_VISIBLE_P (f);
1487 }
1488 else if (INTEGERP (all_frames) && XINT (all_frames) == 0)
1489 {
1490 FRAME_SAMPLE_VISIBILITY (f);
1491 candidate_p = FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f);
1492 }
67492200
GM
1493 else if (WINDOWP (all_frames))
1494 candidate_p = (EQ (FRAME_MINIBUF_WINDOW (f), all_frames)
1495 || EQ (XWINDOW (all_frames)->frame, w->frame)
1496 || EQ (XWINDOW (all_frames)->frame, FRAME_FOCUS_FRAME (f)));
118ea242
GM
1497 else if (FRAMEP (all_frames))
1498 candidate_p = EQ (all_frames, w->frame);
67492200
GM
1499
1500 return candidate_p;
1501}
1502
1503
1504/* Decode arguments as allowed by Fnext_window, Fprevious_window, and
1505 Fwindow_list. See there for the meaning of WINDOW, MINIBUF, and
1506 ALL_FRAMES. */
1507
1508static void
1509decode_next_window_args (window, minibuf, all_frames)
1510 Lisp_Object *window, *minibuf, *all_frames;
1511{
1512 if (NILP (*window))
1513 *window = selected_window;
1514 else
b7826503 1515 CHECK_LIVE_WINDOW (*window);
67492200
GM
1516
1517 /* MINIBUF nil may or may not include minibuffers. Decide if it
1518 does. */
1519 if (NILP (*minibuf))
1520 *minibuf = minibuf_level ? minibuf_window : Qlambda;
1521 else if (!EQ (*minibuf, Qt))
1522 *minibuf = Qlambda;
1523
1524 /* Now *MINIBUF can be t => count all minibuffer windows, `lambda'
1525 => count none of them, or a specific minibuffer window (the
1526 active one) to count. */
1527
1528 /* ALL_FRAMES nil doesn't specify which frames to include. */
1529 if (NILP (*all_frames))
1530 *all_frames = (!EQ (*minibuf, Qlambda)
1531 ? FRAME_MINIBUF_WINDOW (XFRAME (XWINDOW (*window)->frame))
1532 : Qnil);
1533 else if (EQ (*all_frames, Qvisible))
1534 ;
1535 else if (XFASTINT (*all_frames) == 0)
1536 ;
1537 else if (FRAMEP (*all_frames))
1538 ;
1539 else if (!EQ (*all_frames, Qt))
1540 *all_frames = Qnil;
1541
1542 /* Now *ALL_FRAMES is t meaning search all frames, nil meaning
1543 search just current frame, `visible' meaning search just visible
1544 frames, 0 meaning search visible and iconified frames, or a
1545 window, meaning search the frame that window belongs to, or a
1546 frame, meaning consider windows on that frame, only. */
1547}
1548
1549
1550/* Return the next or previous window of WINDOW in canonical ordering
1551 of windows. NEXT_P non-zero means return the next window. See the
1552 documentation string of next-window for the meaning of MINIBUF and
1553 ALL_FRAMES. */
1554
1555static Lisp_Object
1556next_window (window, minibuf, all_frames, next_p)
1557 Lisp_Object window, minibuf, all_frames;
1558 int next_p;
1559{
1560 decode_next_window_args (&window, &minibuf, &all_frames);
1561
1562 /* If ALL_FRAMES is a frame, and WINDOW isn't on that frame, just
1563 return the first window on the frame. */
1564 if (FRAMEP (all_frames)
1565 && !EQ (all_frames, XWINDOW (window)->frame))
1566 return Fframe_first_window (all_frames);
1567
212116d6 1568 if (next_p)
67492200
GM
1569 {
1570 Lisp_Object list;
1571
1572 /* Find WINDOW in the list of all windows. */
1573 list = Fmemq (window, window_list ());
1574
1575 /* Scan forward from WINDOW to the end of the window list. */
1576 if (CONSP (list))
1577 for (list = XCDR (list); CONSP (list); list = XCDR (list))
118ea242 1578 if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
67492200
GM
1579 break;
1580
1581 /* Scan from the start of the window list up to WINDOW. */
1582 if (!CONSP (list))
1583 for (list = Vwindow_list;
1584 CONSP (list) && !EQ (XCAR (list), window);
1585 list = XCDR (list))
118ea242 1586 if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
67492200
GM
1587 break;
1588
1589 if (CONSP (list))
1590 window = XCAR (list);
1591 }
1592 else
1593 {
1594 Lisp_Object candidate, list;
1595
1596 /* Scan through the list of windows for candidates. If there are
1597 candidate windows in front of WINDOW, the last one of these
1598 is the one we want. If there are candidates following WINDOW
1599 in the list, again the last one of these is the one we want. */
1600 candidate = Qnil;
1601 for (list = window_list (); CONSP (list); list = XCDR (list))
1602 {
1603 if (EQ (XCAR (list), window))
1604 {
1605 if (WINDOWP (candidate))
1606 break;
1607 }
118ea242
GM
1608 else if (candidate_window_p (XCAR (list), window, minibuf,
1609 all_frames))
67492200
GM
1610 candidate = XCAR (list);
1611 }
1612
1613 if (WINDOWP (candidate))
1614 window = candidate;
1615 }
1616
1617 return window;
1618}
7ab12479 1619
7ab12479 1620
26f6279d 1621DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
fdb82f93
PJ
1622 doc: /* Return next window after WINDOW in canonical ordering of windows.
1623If omitted, WINDOW defaults to the selected window.
1624
1625Optional second arg MINIBUF t means count the minibuffer window even
1626if not active. MINIBUF nil or omitted means count the minibuffer iff
1627it is active. MINIBUF neither t nor nil means not to count the
1628minibuffer even if it is active.
1629
1630Several frames may share a single minibuffer; if the minibuffer
1631counts, all windows on all frames that share that minibuffer count
1632too. Therefore, `next-window' can be used to iterate through the
1633set of windows even when the minibuffer is on another frame. If the
1634minibuffer does not count, only windows from WINDOW's frame count.
1635
1636Optional third arg ALL-FRAMES t means include windows on all frames.
1637ALL-FRAMES nil or omitted means cycle within the frames as specified
1638above. ALL-FRAMES = `visible' means include windows on all visible frames.
1639ALL-FRAMES = 0 means include windows on all visible and iconified frames.
1640If ALL-FRAMES is a frame, restrict search to windows on that frame.
1641Anything else means restrict to WINDOW's frame.
1642
1643If you use consistent values for MINIBUF and ALL-FRAMES, you can use
1644`next-window' to iterate through the entire cycle of acceptable
1645windows, eventually ending up back at the window you started with.
1646`previous-window' traverses the same cycle, in the reverse order. */)
1647 (window, minibuf, all_frames)
67492200 1648 Lisp_Object window, minibuf, all_frames;
7ab12479 1649{
67492200 1650 return next_window (window, minibuf, all_frames, 1);
7ab12479
JB
1651}
1652
67492200 1653
26f6279d 1654DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
fdb82f93
PJ
1655 doc: /* Return the window preceding WINDOW in canonical ordering of windows.
1656If omitted, WINDOW defaults to the selected window.
1657
1658Optional second arg MINIBUF t means count the minibuffer window even
1659if not active. MINIBUF nil or omitted means count the minibuffer iff
1660it is active. MINIBUF neither t nor nil means not to count the
1661minibuffer even if it is active.
1662
1663Several frames may share a single minibuffer; if the minibuffer
1664counts, all windows on all frames that share that minibuffer count
1665too. Therefore, `previous-window' can be used to iterate through
1666the set of windows even when the minibuffer is on another frame. If
1667the minibuffer does not count, only windows from WINDOW's frame count
1668
1669Optional third arg ALL-FRAMES t means include windows on all frames.
1670ALL-FRAMES nil or omitted means cycle within the frames as specified
1671above. ALL-FRAMES = `visible' means include windows on all visible frames.
1672ALL-FRAMES = 0 means include windows on all visible and iconified frames.
1673If ALL-FRAMES is a frame, restrict search to windows on that frame.
1674Anything else means restrict to WINDOW's frame.
1675
1676If you use consistent values for MINIBUF and ALL-FRAMES, you can use
1677`previous-window' to iterate through the entire cycle of acceptable
1678windows, eventually ending up back at the window you started with.
1679`next-window' traverses the same cycle, in the reverse order. */)
1680 (window, minibuf, all_frames)
67492200 1681 Lisp_Object window, minibuf, all_frames;
7ab12479 1682{
67492200 1683 return next_window (window, minibuf, all_frames, 0);
7ab12479
JB
1684}
1685
67492200 1686
62c07cc7 1687DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
fdb82f93
PJ
1688 doc: /* Select the ARG'th different window on this frame.
1689All windows on current frame are arranged in a cyclic order.
1690This command selects the window ARG steps away in that order.
1691A negative ARG moves in the opposite order. If the optional second
1692argument ALL_FRAMES is non-nil, cycle through all frames. */)
1693 (arg, all_frames)
67492200 1694 Lisp_Object arg, all_frames;
7ab12479 1695{
67492200
GM
1696 Lisp_Object window;
1697 int i;
7ab12479 1698
b7826503 1699 CHECK_NUMBER (arg);
67492200
GM
1700 window = selected_window;
1701
1702 for (i = XINT (arg); i > 0; --i)
1703 window = Fnext_window (window, Qnil, all_frames);
1704 for (; i < 0; ++i)
1705 window = Fprevious_window (window, Qnil, all_frames);
50e88778 1706
67492200 1707 Fselect_window (window);
7ab12479
JB
1708 return Qnil;
1709}
67492200
GM
1710
1711
1712DEFUN ("window-list", Fwindow_list, Swindow_list, 0, 3, 0,
fdb82f93
PJ
1713 doc: /* Return a list of windows on FRAME, starting with WINDOW.
1714FRAME nil or omitted means use the selected frame.
1715WINDOW nil or omitted means use the selected window.
1716MINIBUF t means include the minibuffer window, even if it isn't active.
1717MINIBUF nil or omitted means include the minibuffer window only
1718if it's active.
1719MINIBUF neither nil nor t means never include the minibuffer window. */)
1720 (frame, minibuf, window)
cd2904bd
GM
1721 Lisp_Object frame, minibuf, window;
1722{
cd2904bd
GM
1723 if (NILP (window))
1724 window = selected_window;
1725 if (NILP (frame))
1726 frame = selected_frame;
1727
1728 if (!EQ (frame, XWINDOW (window)->frame))
1729 error ("Window is on a different frame");
1730
1731 return window_list_1 (window, minibuf, frame);
1732}
1733
1734
1735/* Return a list of windows in canonical ordering. Arguments are like
1736 for `next-window'. */
1737
1738static Lisp_Object
1739window_list_1 (window, minibuf, all_frames)
069f5950 1740 Lisp_Object window, minibuf, all_frames;
67492200
GM
1741{
1742 Lisp_Object tail, list;
1743
1744 decode_next_window_args (&window, &minibuf, &all_frames);
1745 list = Qnil;
1746
1747 for (tail = window_list (); CONSP (tail); tail = XCDR (tail))
118ea242 1748 if (candidate_window_p (XCAR (tail), window, minibuf, all_frames))
67492200
GM
1749 list = Fcons (XCAR (tail), list);
1750
118ea242 1751 return Fnreverse (list);
67492200
GM
1752}
1753
1754
7ab12479
JB
1755\f
1756/* Look at all windows, performing an operation specified by TYPE
1757 with argument OBJ.
75d8f668 1758 If FRAMES is Qt, look at all frames;
75d8f668 1759 Qnil, look at just the selected frame;
89bca612 1760 Qvisible, look at visible frames;
75d8f668 1761 a frame, just look at windows on that frame.
85fe3b5e 1762 If MINI is non-zero, perform the operation on minibuffer windows too. */
7ab12479
JB
1763
1764enum window_loop
1765{
1766 WINDOW_LOOP_UNUSED,
1767 GET_BUFFER_WINDOW, /* Arg is buffer */
1768 GET_LRU_WINDOW, /* Arg is t for full-width windows only */
1769 DELETE_OTHER_WINDOWS, /* Arg is window not to delete */
1770 DELETE_BUFFER_WINDOWS, /* Arg is buffer */
1771 GET_LARGEST_WINDOW,
3f8ab7bd
RS
1772 UNSHOW_BUFFER, /* Arg is buffer */
1773 CHECK_ALL_WINDOWS
7ab12479
JB
1774};
1775
1776static Lisp_Object
44fa5b1e 1777window_loop (type, obj, mini, frames)
7ab12479 1778 enum window_loop type;
118ea242 1779 Lisp_Object obj, frames;
7ab12479
JB
1780 int mini;
1781{
118ea242
GM
1782 Lisp_Object window, windows, best_window, frame_arg;
1783 struct frame *f;
ffdc852d 1784 struct gcpro gcpro1;
118ea242 1785
44fa5b1e
JB
1786 /* If we're only looping through windows on a particular frame,
1787 frame points to that frame. If we're looping through windows
1788 on all frames, frame is 0. */
1789 if (FRAMEP (frames))
118ea242 1790 f = XFRAME (frames);
44fa5b1e 1791 else if (NILP (frames))
118ea242 1792 f = SELECTED_FRAME ();
7ab12479 1793 else
118ea242
GM
1794 f = NULL;
1795
1796 if (f)
89bca612 1797 frame_arg = Qlambda;
f812f9c6
RS
1798 else if (XFASTINT (frames) == 0)
1799 frame_arg = frames;
89bca612
RS
1800 else if (EQ (frames, Qvisible))
1801 frame_arg = frames;
118ea242
GM
1802 else
1803 frame_arg = Qt;
7ab12479 1804
89bca612
RS
1805 /* frame_arg is Qlambda to stick to one frame,
1806 Qvisible to consider all visible frames,
1807 or Qt otherwise. */
1808
7ab12479 1809 /* Pick a window to start with. */
017b2bad 1810 if (WINDOWP (obj))
118ea242
GM
1811 window = obj;
1812 else if (f)
1813 window = FRAME_SELECTED_WINDOW (f);
7ab12479 1814 else
118ea242 1815 window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
4b206065 1816
cd2904bd 1817 windows = window_list_1 (window, mini ? Qt : Qnil, frame_arg);
118ea242 1818 GCPRO1 (windows);
7ab12479 1819 best_window = Qnil;
118ea242
GM
1820
1821 for (; CONSP (windows); windows = CDR (windows))
7ab12479 1822 {
118ea242
GM
1823 struct window *w;
1824
1825 window = XCAR (windows);
1826 w = XWINDOW (window);
1827
1828 /* Note that we do not pay attention here to whether the frame
1829 is visible, since Fwindow_list skips non-visible frames if
1830 that is desired, under the control of frame_arg. */
1831 if (!MINI_WINDOW_P (w)
65a04b96
RS
1832 /* For UNSHOW_BUFFER, we must always consider all windows. */
1833 || type == UNSHOW_BUFFER
7ab12479
JB
1834 || (mini && minibuf_level > 0))
1835 switch (type)
1836 {
1837 case GET_BUFFER_WINDOW:
118ea242 1838 if (EQ (w->buffer, obj)
5c204627
RS
1839 /* Don't find any minibuffer window
1840 except the one that is currently in use. */
118ea242
GM
1841 && (MINI_WINDOW_P (w)
1842 ? EQ (window, minibuf_window)
1843 : 1))
1844 {
5ddc1b75
GM
1845 if (NILP (best_window))
1846 best_window = window;
1847 else if (EQ (window, selected_window))
1848 /* For compatibility with 20.x, prefer to return
1849 selected-window. */
1850 best_window = window;
118ea242 1851 }
7ab12479
JB
1852 break;
1853
1854 case GET_LRU_WINDOW:
1855 /* t as arg means consider only full-width windows */
118ea242 1856 if (!NILP (obj) && !WINDOW_FULL_WIDTH_P (w))
7ab12479 1857 break;
7ab12479 1858 /* Ignore dedicated windows and minibuffers. */
118ea242 1859 if (MINI_WINDOW_P (w) || !NILP (w->dedicated))
7ab12479 1860 break;
265a9e55 1861 if (NILP (best_window)
7ab12479 1862 || (XFASTINT (XWINDOW (best_window)->use_time)
118ea242
GM
1863 > XFASTINT (w->use_time)))
1864 best_window = window;
7ab12479
JB
1865 break;
1866
1867 case DELETE_OTHER_WINDOWS:
118ea242
GM
1868 if (!EQ (window, obj))
1869 Fdelete_window (window);
7ab12479
JB
1870 break;
1871
1872 case DELETE_BUFFER_WINDOWS:
118ea242 1873 if (EQ (w->buffer, obj))
7ab12479 1874 {
118ea242 1875 struct frame *f = XFRAME (WINDOW_FRAME (w));
3548e138
RS
1876
1877 /* If this window is dedicated, and in a frame of its own,
1878 kill the frame. */
118ea242
GM
1879 if (EQ (window, FRAME_ROOT_WINDOW (f))
1880 && !NILP (w->dedicated)
3548e138 1881 && other_visible_frames (f))
7ab12479 1882 {
3548e138
RS
1883 /* Skip the other windows on this frame.
1884 There might be one, the minibuffer! */
118ea242
GM
1885 while (CONSP (XCDR (windows))
1886 && EQ (XWINDOW (XCAR (windows))->frame,
1887 XWINDOW (XCAR (XCDR (windows)))->frame))
1888 windows = XCDR (windows);
1889
3548e138 1890 /* Now we can safely delete the frame. */
118ea242
GM
1891 Fdelete_frame (w->frame, Qnil);
1892 }
1893 else if (NILP (w->parent))
1894 {
1895 /* If we're deleting the buffer displayed in the
1896 only window on the frame, find a new buffer to
1897 display there. */
1898 Lisp_Object buffer;
1899 buffer = Fother_buffer (obj, Qnil, w->frame);
118ea242
GM
1900 Fset_window_buffer (window, buffer);
1901 if (EQ (window, selected_window))
1902 Fset_buffer (w->buffer);
7ab12479
JB
1903 }
1904 else
118ea242 1905 Fdelete_window (window);
7ab12479
JB
1906 }
1907 break;
1908
1909 case GET_LARGEST_WINDOW:
7ab12479 1910 {
118ea242 1911 /* Ignore dedicated windows and minibuffers. */
c930dfab 1912 if (MINI_WINDOW_P (w) || !NILP (w->dedicated))
118ea242
GM
1913 break;
1914
c930dfab 1915 if (NILP (best_window))
118ea242 1916 best_window = window;
c930dfab
GM
1917 else
1918 {
1919 struct window *b = XWINDOW (best_window);
1920 if (XFASTINT (w->height) * XFASTINT (w->width)
1921 > XFASTINT (b->height) * XFASTINT (b->width))
1922 best_window = window;
1923 }
7ab12479
JB
1924 }
1925 break;
1926
1927 case UNSHOW_BUFFER:
118ea242 1928 if (EQ (w->buffer, obj))
7ab12479 1929 {
118ea242
GM
1930 Lisp_Object buffer;
1931 struct frame *f = XFRAME (w->frame);
1932
7ab12479 1933 /* Find another buffer to show in this window. */
118ea242 1934 buffer = Fother_buffer (obj, Qnil, w->frame);
118ea242 1935
38ab08d1
RS
1936 /* If this window is dedicated, and in a frame of its own,
1937 kill the frame. */
118ea242
GM
1938 if (EQ (window, FRAME_ROOT_WINDOW (f))
1939 && !NILP (w->dedicated)
38ab08d1 1940 && other_visible_frames (f))
45945a7b
RS
1941 {
1942 /* Skip the other windows on this frame.
1943 There might be one, the minibuffer! */
118ea242
GM
1944 while (CONSP (XCDR (windows))
1945 && EQ (XWINDOW (XCAR (windows))->frame,
1946 XWINDOW (XCAR (XCDR (windows)))->frame))
1947 windows = XCDR (windows);
1948
45945a7b 1949 /* Now we can safely delete the frame. */
118ea242 1950 Fdelete_frame (w->frame, Qnil);
45945a7b 1951 }
38ab08d1 1952 else
38ab08d1
RS
1953 {
1954 /* Otherwise show a different buffer in the window. */
118ea242
GM
1955 w->dedicated = Qnil;
1956 Fset_window_buffer (window, buffer);
1957 if (EQ (window, selected_window))
1958 Fset_buffer (w->buffer);
38ab08d1 1959 }
7ab12479
JB
1960 }
1961 break;
3f8ab7bd
RS
1962
1963 /* Check for a window that has a killed buffer. */
1964 case CHECK_ALL_WINDOWS:
118ea242
GM
1965 if (! NILP (w->buffer)
1966 && NILP (XBUFFER (w->buffer)->name))
3f8ab7bd 1967 abort ();
118ea242 1968 break;
6bbd7a29
GM
1969
1970 case WINDOW_LOOP_UNUSED:
1971 break;
7ab12479 1972 }
7ab12479 1973 }
7ab12479 1974
118ea242 1975 UNGCPRO;
7ab12479 1976 return best_window;
37962e60 1977}
605be8af 1978
3f8ab7bd
RS
1979/* Used for debugging. Abort if any window has a dead buffer. */
1980
233a4a2c 1981void
3f8ab7bd
RS
1982check_all_windows ()
1983{
1984 window_loop (CHECK_ALL_WINDOWS, Qnil, 1, Qt);
1985}
1986
7ab12479 1987DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
fdb82f93
PJ
1988 doc: /* Return the window least recently selected or used for display.
1989If optional argument FRAME is `visible', search all visible frames.
1990If FRAME is 0, search all visible and iconified frames.
1991If FRAME is t, search all frames.
1992If FRAME is nil, search only the selected frame.
1993If FRAME is a frame, search only that frame. */)
1994 (frame)
1995 Lisp_Object frame;
7ab12479
JB
1996{
1997 register Lisp_Object w;
1998 /* First try for a window that is full-width */
89bca612 1999 w = window_loop (GET_LRU_WINDOW, Qt, 0, frame);
265a9e55 2000 if (!NILP (w) && !EQ (w, selected_window))
7ab12479
JB
2001 return w;
2002 /* If none of them, try the rest */
89bca612 2003 return window_loop (GET_LRU_WINDOW, Qnil, 0, frame);
7ab12479
JB
2004}
2005
2006DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 1, 0,
fdb82f93
PJ
2007 doc: /* Return the largest window in area.
2008If optional argument FRAME is `visible', search all visible frames.
2009If FRAME is 0, search all visible and iconified frames.
2010If FRAME is t, search all frames.
2011If FRAME is nil, search only the selected frame.
2012If FRAME is a frame, search only that frame. */)
2013 (frame)
2014 Lisp_Object frame;
7ab12479
JB
2015{
2016 return window_loop (GET_LARGEST_WINDOW, Qnil, 0,
44fa5b1e 2017 frame);
7ab12479
JB
2018}
2019
2020DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 1, 2, 0,
fdb82f93
PJ
2021 doc: /* Return a window currently displaying BUFFER, or nil if none.
2022If optional argument FRAME is `visible', search all visible frames.
2023If optional argument FRAME is 0, search all visible and iconified frames.
2024If FRAME is t, search all frames.
2025If FRAME is nil, search only the selected frame.
2026If FRAME is a frame, search only that frame. */)
2027 (buffer, frame)
2028 Lisp_Object buffer, frame;
7ab12479
JB
2029{
2030 buffer = Fget_buffer (buffer);
017b2bad 2031 if (BUFFERP (buffer))
44fa5b1e 2032 return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame);
7ab12479
JB
2033 else
2034 return Qnil;
2035}
2036
2037DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
fdb82f93
PJ
2038 0, 1, "",
2039 doc: /* Make WINDOW (or the selected window) fill its frame.
2040Only the frame WINDOW is on is affected.
2041This function tries to reduce display jumps
2042by keeping the text previously visible in WINDOW
2043in the same place on the frame. Doing this depends on
2044the value of (window-start WINDOW), so if calling this function
2045in a program gives strange scrolling, make sure the window-start
2046value is reasonable when this function is called. */)
2047 (window)
7ab12479
JB
2048 Lisp_Object window;
2049{
2050 struct window *w;
00d3d838 2051 int startpos;
85fe3b5e 2052 int top, new_top;
7ab12479 2053
265a9e55 2054 if (NILP (window))
7ab12479
JB
2055 window = selected_window;
2056 else
b7826503 2057 CHECK_LIVE_WINDOW (window);
7ab12479 2058 w = XWINDOW (window);
a2b38b3c 2059
00d3d838 2060 startpos = marker_position (w->start);
5500c422 2061 top = XFASTINT (w->top) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
7ab12479 2062
a2b38b3c
RS
2063 if (MINI_WINDOW_P (w) && top > 0)
2064 error ("Can't expand minibuffer to full frame");
2065
70728a80 2066 window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_FRAME (w));
7ab12479 2067
00d3d838
KH
2068 /* Try to minimize scrolling, by setting the window start to the point
2069 will cause the text at the old window start to be at the same place
2070 on the frame. But don't try to do this if the window start is
2071 outside the visible portion (as might happen when the display is
2072 not current, due to typeahead). */
85fe3b5e
GM
2073 new_top = XFASTINT (w->top) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
2074 if (new_top != top
2075 && startpos >= BUF_BEGV (XBUFFER (w->buffer))
00d3d838
KH
2076 && startpos <= BUF_ZV (XBUFFER (w->buffer)))
2077 {
2078 struct position pos;
2079 struct buffer *obuf = current_buffer;
2080
2081 Fset_buffer (w->buffer);
2082 /* This computation used to temporarily move point, but that can
2083 have unwanted side effects due to text properties. */
0383eb57 2084 pos = *vmotion (startpos, -top, w);
4d047f50 2085
b73ea88e 2086 set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
85fe3b5e 2087 w->window_end_valid = Qnil;
b73ea88e
RS
2088 w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
2089 || FETCH_BYTE (pos.bytepos - 1) == '\n') ? Qt
00d3d838 2090 : Qnil);
80622eec
RS
2091 /* We need to do this, so that the window-scroll-functions
2092 get called. */
4d047f50 2093 w->optional_new_start = Qt;
00d3d838
KH
2094
2095 set_buffer_internal (obuf);
2096 }
5500c422 2097
7ab12479
JB
2098 return Qnil;
2099}
2100
2101DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
fdb82f93
PJ
2102 1, 2, "bDelete windows on (buffer): ",
2103 doc: /* Delete all windows showing BUFFER.
2104Optional second argument FRAME controls which frames are affected.
2105If optional argument FRAME is `visible', search all visible frames.
2106If FRAME is 0, search all visible and iconified frames.
2107If FRAME is nil, search all frames.
2108If FRAME is t, search only the selected frame.
2109If FRAME is a frame, search only that frame. */)
2110 (buffer, frame)
26f6279d 2111 Lisp_Object buffer, frame;
7ab12479 2112{
26f6279d
JB
2113 /* FRAME uses t and nil to mean the opposite of what window_loop
2114 expects. */
c520265e
RS
2115 if (NILP (frame))
2116 frame = Qt;
2117 else if (EQ (frame, Qt))
2118 frame = Qnil;
26f6279d 2119
265a9e55 2120 if (!NILP (buffer))
7ab12479
JB
2121 {
2122 buffer = Fget_buffer (buffer);
b7826503 2123 CHECK_BUFFER (buffer);
26f6279d 2124 window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
7ab12479 2125 }
5500c422 2126
7ab12479
JB
2127 return Qnil;
2128}
2129
2130DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
fdb82f93
PJ
2131 Sreplace_buffer_in_windows,
2132 1, 1, "bReplace buffer in windows: ",
2133 doc: /* Replace BUFFER with some other buffer in all windows showing it. */)
2134 (buffer)
7ab12479
JB
2135 Lisp_Object buffer;
2136{
265a9e55 2137 if (!NILP (buffer))
7ab12479
JB
2138 {
2139 buffer = Fget_buffer (buffer);
b7826503 2140 CHECK_BUFFER (buffer);
7ab12479
JB
2141 window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
2142 }
2143 return Qnil;
2144}
ff58478b
RS
2145
2146/* Replace BUFFER with some other buffer in all windows
2147 of all frames, even those on other keyboards. */
2148
2149void
2150replace_buffer_in_all_windows (buffer)
2151 Lisp_Object buffer;
2152{
27abb84f 2153#ifdef MULTI_KBOARD
ff58478b
RS
2154 Lisp_Object tail, frame;
2155
ff58478b
RS
2156 /* A single call to window_loop won't do the job
2157 because it only considers frames on the current keyboard.
2158 So loop manually over frames, and handle each one. */
2159 FOR_EACH_FRAME (tail, frame)
db7f721d 2160 window_loop (UNSHOW_BUFFER, buffer, 1, frame);
ff58478b 2161#else
db7f721d 2162 window_loop (UNSHOW_BUFFER, buffer, 1, Qt);
ff58478b
RS
2163#endif
2164}
7ab12479
JB
2165\f
2166/* Set the height of WINDOW and all its inferiors. */
a481b3ea
JB
2167
2168/* The smallest acceptable dimensions for a window. Anything smaller
2169 might crash Emacs. */
5500c422 2170
a481b3ea 2171#define MIN_SAFE_WINDOW_WIDTH (2)
dc1ab1ee 2172#define MIN_SAFE_WINDOW_HEIGHT (1)
a481b3ea
JB
2173
2174/* Make sure that window_min_height and window_min_width are
2175 not too small; if they are, set them to safe minima. */
2176
2177static void
2178check_min_window_sizes ()
2179{
2180 /* Smaller values might permit a crash. */
2181 if (window_min_width < MIN_SAFE_WINDOW_WIDTH)
2182 window_min_width = MIN_SAFE_WINDOW_WIDTH;
2183 if (window_min_height < MIN_SAFE_WINDOW_HEIGHT)
2184 window_min_height = MIN_SAFE_WINDOW_HEIGHT;
2185}
2186
2187/* If *ROWS or *COLS are too small a size for FRAME, set them to the
2188 minimum allowable size. */
5500c422 2189
605be8af 2190void
a481b3ea 2191check_frame_size (frame, rows, cols)
605be8af
JB
2192 FRAME_PTR frame;
2193 int *rows, *cols;
a481b3ea 2194{
628df3bf 2195 /* For height, we have to see:
54b8bcb5
RS
2196 how many windows the frame has at minimum (one or two),
2197 and whether it has a menu bar or other special stuff at the top. */
2198 int min_height
2199 = ((FRAME_MINIBUF_ONLY_P (frame) || ! FRAME_HAS_MINIBUF_P (frame))
2200 ? MIN_SAFE_WINDOW_HEIGHT
2201 : 2 * MIN_SAFE_WINDOW_HEIGHT);
5500c422
GM
2202
2203 if (FRAME_TOP_MARGIN (frame) > 0)
2204 min_height += FRAME_TOP_MARGIN (frame);
a481b3ea
JB
2205
2206 if (*rows < min_height)
2207 *rows = min_height;
2208 if (*cols < MIN_SAFE_WINDOW_WIDTH)
2209 *cols = MIN_SAFE_WINDOW_WIDTH;
2210}
2211
c1636aa6 2212
233a4a2c
GM
2213/* Value is non-zero if window W is fixed-size. WIDTH_P non-zero means
2214 check if W's width can be changed, otherwise check W's height.
2215 CHECK_SIBLINGS_P non-zero means check resizablity of WINDOW's
2216 siblings, too. If none of the siblings is resizable, WINDOW isn't
2217 either. */
c1636aa6 2218
233a4a2c
GM
2219static int
2220window_fixed_size_p (w, width_p, check_siblings_p)
2221 struct window *w;
2222 int width_p, check_siblings_p;
2223{
2224 int fixed_p;
2225 struct window *c;
2226
2227 if (!NILP (w->hchild))
2228 {
2229 c = XWINDOW (w->hchild);
2230
2231 if (width_p)
2232 {
2233 /* A horiz. combination is fixed-width if all of if its
2234 children are. */
2235 while (c && window_fixed_size_p (c, width_p, 0))
2236 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2237 fixed_p = c == NULL;
2238 }
2239 else
2240 {
2241 /* A horiz. combination is fixed-height if one of if its
2242 children is. */
2243 while (c && !window_fixed_size_p (c, width_p, 0))
2244 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2245 fixed_p = c != NULL;
2246 }
2247 }
2248 else if (!NILP (w->vchild))
2249 {
2250 c = XWINDOW (w->vchild);
2251
2252 if (width_p)
2253 {
2254 /* A vert. combination is fixed-width if one of if its
2255 children is. */
2256 while (c && !window_fixed_size_p (c, width_p, 0))
2257 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2258 fixed_p = c != NULL;
2259 }
2260 else
2261 {
2262 /* A vert. combination is fixed-height if all of if its
2263 children are. */
2264 while (c && window_fixed_size_p (c, width_p, 0))
2265 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2266 fixed_p = c == NULL;
2267 }
2268 }
2269 else if (BUFFERP (w->buffer))
2270 {
a34dfd12
GM
2271 if (w->height_fixed_p && !width_p)
2272 fixed_p = 1;
2273 else
233a4a2c 2274 {
a34dfd12
GM
2275 struct buffer *old = current_buffer;
2276 Lisp_Object val;
2277
2278 current_buffer = XBUFFER (w->buffer);
2279 val = find_symbol_value (Qwindow_size_fixed);
2280 current_buffer = old;
2281
2282 fixed_p = 0;
2283 if (!EQ (val, Qunbound))
2284 {
2285 fixed_p = !NILP (val);
2286
2287 if (fixed_p
2288 && ((EQ (val, Qheight) && width_p)
2289 || (EQ (val, Qwidth) && !width_p)))
2290 fixed_p = 0;
2291 }
233a4a2c
GM
2292 }
2293
2294 /* Can't tell if this one is resizable without looking at
2295 siblings. If all siblings are fixed-size this one is too. */
2296 if (!fixed_p && check_siblings_p && WINDOWP (w->parent))
2297 {
2298 Lisp_Object child;
2299
2300 for (child = w->prev; !NILP (child); child = XWINDOW (child)->prev)
2301 if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
2302 break;
2303
2304 if (NILP (child))
2305 for (child = w->next; !NILP (child); child = XWINDOW (child)->next)
2306 if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
2307 break;
2308
2309 if (NILP (child))
2310 fixed_p = 1;
2311 }
2312 }
2313 else
2314 fixed_p = 1;
2315
2316 return fixed_p;
2317}
2318
2319
2320/* Return the minimum size of window W, not taking fixed-width windows
2321 into account. WIDTH_P non-zero means return the minimum width,
2322 otherwise return the minimum height. If W is a combination window,
2323 compute the minimum size from the minimum sizes of W's children. */
2324
2325static int
2326window_min_size_1 (w, width_p)
c1636aa6
GM
2327 struct window *w;
2328 int width_p;
2329{
233a4a2c 2330 struct window *c;
c1636aa6
GM
2331 int size;
2332
233a4a2c
GM
2333 if (!NILP (w->hchild))
2334 {
2335 c = XWINDOW (w->hchild);
2336 size = 0;
2337
2338 if (width_p)
2339 {
2340 /* The min width of a horizontal combination is
2341 the sum of the min widths of its children. */
2342 while (c)
2343 {
2344 size += window_min_size_1 (c, width_p);
2345 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2346 }
2347 }
2348 else
2349 {
2350 /* The min height a horizontal combination equals
2351 the maximum of all min height of its children. */
2352 while (c)
2353 {
2354 int min_size = window_min_size_1 (c, width_p);
2355 size = max (min_size, size);
2356 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2357 }
2358 }
2359 }
2360 else if (!NILP (w->vchild))
2361 {
2362 c = XWINDOW (w->vchild);
2363 size = 0;
2364
2365 if (width_p)
2366 {
2367 /* The min width of a vertical combination is
2368 the maximum of the min widths of its children. */
2369 while (c)
2370 {
2371 int min_size = window_min_size_1 (c, width_p);
2372 size = max (min_size, size);
2373 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2374 }
2375 }
2376 else
2377 {
2378 /* The min height of a vertical combination equals
2379 the sum of the min height of its children. */
2380 while (c)
2381 {
2382 size += window_min_size_1 (c, width_p);
2383 c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
2384 }
2385 }
2386 }
c1636aa6
GM
2387 else
2388 {
233a4a2c
GM
2389 if (width_p)
2390 size = window_min_width;
c1636aa6 2391 else
233a4a2c
GM
2392 {
2393 if (MINI_WINDOW_P (w)
2394 || (!WINDOW_WANTS_MODELINE_P (w)
045dee35 2395 && !WINDOW_WANTS_HEADER_LINE_P (w)))
233a4a2c
GM
2396 size = 1;
2397 else
2398 size = window_min_height;
2399 }
c1636aa6
GM
2400 }
2401
2402 return size;
2403}
2404
2405
233a4a2c
GM
2406/* Return the minimum size of window W, taking fixed-size windows into
2407 account. WIDTH_P non-zero means return the minimum width,
f984d4fc
GM
2408 otherwise return the minimum height. IGNORE_FIXED_P non-zero means
2409 ignore if W is fixed-size. Set *FIXED to 1 if W is fixed-size
2410 unless FIXED is null. */
7ab12479 2411
233a4a2c 2412static int
f984d4fc 2413window_min_size (w, width_p, ignore_fixed_p, fixed)
233a4a2c 2414 struct window *w;
f984d4fc 2415 int width_p, ignore_fixed_p, *fixed;
233a4a2c
GM
2416{
2417 int size, fixed_p;
2418
f984d4fc
GM
2419 if (ignore_fixed_p)
2420 fixed_p = 0;
2421 else
2422 fixed_p = window_fixed_size_p (w, width_p, 1);
2423
233a4a2c
GM
2424 if (fixed)
2425 *fixed = fixed_p;
2426
2427 if (fixed_p)
2428 size = width_p ? XFASTINT (w->width) : XFASTINT (w->height);
2429 else
2430 size = window_min_size_1 (w, width_p);
f984d4fc 2431
233a4a2c
GM
2432 return size;
2433}
2434
2435
2436/* Set WINDOW's height or width to SIZE. WIDTH_P non-zero means set
2437 WINDOW's width. Resize WINDOW's children, if any, so that they
2438 keep their proportionate size relative to WINDOW. Propagate
2439 WINDOW's top or left edge position to children. Delete windows
192c3131
RS
2440 that become too small unless NODELETE_P is non-zero.
2441
2442 If NODELETE_P is 2, that means we do delete windows that are
2443 too small, even if they were too small before! */
233a4a2c
GM
2444
2445static void
2446size_window (window, size, width_p, nodelete_p)
7ab12479 2447 Lisp_Object window;
233a4a2c 2448 int size, width_p, nodelete_p;
7ab12479 2449{
233a4a2c
GM
2450 struct window *w = XWINDOW (window);
2451 struct window *c;
2452 Lisp_Object child, *forward, *sideward;
2453 int old_size, min_size;
7ab12479 2454
192c3131
RS
2455 if (nodelete_p == 2)
2456 nodelete_p = 0;
2457
a481b3ea 2458 check_min_window_sizes ();
7ae2f10f 2459 size = max (0, size);
233a4a2c 2460
b5f05b50
GM
2461 /* If the window has been "too small" at one point,
2462 don't delete it for being "too small" in the future.
2463 Preserve it as long as that is at all possible. */
233a4a2c
GM
2464 if (width_p)
2465 {
8b6d9dc9 2466 old_size = XINT (w->width);
233a4a2c
GM
2467 min_size = window_min_width;
2468 }
2469 else
2470 {
8b6d9dc9 2471 old_size = XINT (w->height);
233a4a2c
GM
2472 min_size = window_min_height;
2473 }
192c3131
RS
2474
2475 if (old_size < min_size && nodelete_p != 2)
b5f05b50
GM
2476 w->too_small_ok = Qt;
2477
233a4a2c 2478 /* Maybe delete WINDOW if it's too small. */
192c3131 2479 if (nodelete_p != 1 && !NILP (w->parent))
7ab12479 2480 {
b5f05b50 2481 if (!MINI_WINDOW_P (w) && !NILP (w->too_small_ok))
233a4a2c 2482 min_size = width_p ? MIN_SAFE_WINDOW_WIDTH : MIN_SAFE_WINDOW_HEIGHT;
b5f05b50 2483 else
233a4a2c 2484 min_size = width_p ? window_min_width : window_min_height;
b5f05b50 2485
233a4a2c 2486 if (size < min_size)
c1636aa6
GM
2487 {
2488 delete_window (window);
2489 return;
2490 }
7ab12479
JB
2491 }
2492
233a4a2c 2493 /* Set redisplay hints. */
7ae2f10f
GM
2494 w->last_modified = make_number (0);
2495 w->last_overlay_modified = make_number (0);
7ab12479 2496 windows_or_buffers_changed++;
7ae2f10f 2497 FRAME_WINDOW_SIZES_CHANGED (XFRAME (w->frame)) = 1;
29aeee73 2498
233a4a2c
GM
2499 if (width_p)
2500 {
2501 sideward = &w->vchild;
2502 forward = &w->hchild;
7ae2f10f 2503 w->width = make_number (size);
233a4a2c
GM
2504 }
2505 else
2506 {
2507 sideward = &w->hchild;
2508 forward = &w->vchild;
7ae2f10f 2509 w->height = make_number (size);
0130fe1a 2510 w->orig_height = Qnil;
233a4a2c
GM
2511 }
2512
2513 if (!NILP (*sideward))
7ab12479 2514 {
233a4a2c 2515 for (child = *sideward; !NILP (child); child = c->next)
7ab12479 2516 {
233a4a2c
GM
2517 c = XWINDOW (child);
2518 if (width_p)
2519 c->left = w->left;
2520 else
2521 c->top = w->top;
2522 size_window (child, size, width_p, nodelete_p);
7ab12479
JB
2523 }
2524 }
233a4a2c 2525 else if (!NILP (*forward))
7ab12479 2526 {
233a4a2c
GM
2527 int fixed_size, each, extra, n;
2528 int resize_fixed_p, nfixed;
8b6d9dc9 2529 int last_pos, first_pos, nchildren, total;
233a4a2c
GM
2530
2531 /* Determine the fixed-size portion of the this window, and the
2532 number of child windows. */
8b6d9dc9 2533 fixed_size = nchildren = nfixed = total = 0;
233a4a2c 2534 for (child = *forward; !NILP (child); child = c->next, ++nchildren)
7ab12479 2535 {
8b6d9dc9
GM
2536 int child_size;
2537
7ab12479 2538 c = XWINDOW (child);
8b6d9dc9
GM
2539 child_size = width_p ? XINT (c->width) : XINT (c->height);
2540 total += child_size;
2541
233a4a2c
GM
2542 if (window_fixed_size_p (c, width_p, 0))
2543 {
8b6d9dc9 2544 fixed_size += child_size;
233a4a2c
GM
2545 ++nfixed;
2546 }
2547 }
7ab12479 2548
233a4a2c
GM
2549 /* If the new size is smaller than fixed_size, or if there
2550 aren't any resizable windows, allow resizing fixed-size
2551 windows. */
2552 resize_fixed_p = nfixed == nchildren || size < fixed_size;
2553
2554 /* Compute how many lines/columns to add to each child. The
2555 value of extra takes care of rounding errors. */
2556 n = resize_fixed_p ? nchildren : nchildren - nfixed;
8b6d9dc9
GM
2557 each = (size - total) / n;
2558 extra = (size - total) - n * each;
233a4a2c
GM
2559
2560 /* Compute new children heights and edge positions. */
8b6d9dc9 2561 first_pos = width_p ? XINT (w->left) : XINT (w->top);
233a4a2c
GM
2562 last_pos = first_pos;
2563 for (child = *forward; !NILP (child); child = c->next)
2564 {
2565 int new_size, old_size;
2566
2567 c = XWINDOW (child);
2568 old_size = width_p ? XFASTINT (c->width) : XFASTINT (c->height);
2569 new_size = old_size;
7ab12479 2570
233a4a2c
GM
2571 /* The top or left edge position of this child equals the
2572 bottom or right edge of its predecessor. */
2573 if (width_p)
2574 c->left = make_number (last_pos);
2575 else
2576 c->top = make_number (last_pos);
7ab12479 2577
233a4a2c
GM
2578 /* If this child can be resized, do it. */
2579 if (resize_fixed_p || !window_fixed_size_p (c, width_p, 0))
2580 {
2581 new_size = old_size + each + extra;
2582 extra = 0;
2583 }
2584
2585 /* Set new height. Note that size_window also propagates
2586 edge positions to children, so it's not a no-op if we
2587 didn't change the child's size. */
2588 size_window (child, new_size, width_p, 1);
2589
2590 /* Remember the bottom/right edge position of this child; it
2591 will be used to set the top/left edge of the next child. */
2592 last_pos += new_size;
7ab12479 2593 }
233a4a2c
GM
2594
2595 /* We should have covered the parent exactly with child windows. */
2596 xassert (size == last_pos - first_pos);
2597
7ab12479 2598 /* Now delete any children that became too small. */
233a4a2c
GM
2599 if (!nodelete_p)
2600 for (child = *forward; !NILP (child); child = c->next)
7ab12479 2601 {
233a4a2c
GM
2602 int child_size;
2603 c = XWINDOW (child);
8b6d9dc9 2604 child_size = width_p ? XINT (c->width) : XINT (c->height);
192c3131 2605 size_window (child, child_size, width_p, 2);
7ab12479
JB
2606 }
2607 }
2608}
2609
233a4a2c
GM
2610/* Set WINDOW's height to HEIGHT, and recursively change the height of
2611 WINDOW's children. NODELETE non-zero means don't delete windows
2612 that become too small in the process. (The caller should check
2613 later and do so if appropriate.) */
7ab12479 2614
5e14b1fc 2615void
233a4a2c 2616set_window_height (window, height, nodelete)
7ab12479 2617 Lisp_Object window;
233a4a2c 2618 int height;
7ab12479
JB
2619 int nodelete;
2620{
233a4a2c
GM
2621 size_window (window, height, 0, nodelete);
2622}
7ab12479 2623
7ab12479 2624
233a4a2c
GM
2625/* Set WINDOW's width to WIDTH, and recursively change the width of
2626 WINDOW's children. NODELETE non-zero means don't delete windows
2627 that become too small in the process. (The caller should check
2628 later and do so if appropriate.) */
7ab12479 2629
233a4a2c
GM
2630void
2631set_window_width (window, width, nodelete)
2632 Lisp_Object window;
2633 int width;
2634 int nodelete;
2635{
2636 size_window (window, width, 1, nodelete);
7ab12479 2637}
233a4a2c 2638
7ab12479 2639\f
1d8d96fa 2640int window_select_count;
7ab12479 2641
5b03d3c0
RS
2642Lisp_Object
2643Fset_window_buffer_unwind (obuf)
2644 Lisp_Object obuf;
2645{
2646 Fset_buffer (obuf);
2647 return Qnil;
2648}
2649
7ab12479 2650
5500c422
GM
2651/* Make WINDOW display BUFFER as its contents. RUN_HOOKS_P non-zero
2652 means it's allowed to run hooks. See make_frame for a case where
2653 it's not allowed. */
7ab12479 2654
5500c422
GM
2655void
2656set_window_buffer (window, buffer, run_hooks_p)
2657 Lisp_Object window, buffer;
2658 int run_hooks_p;
2659{
2660 struct window *w = XWINDOW (window);
2661 struct buffer *b = XBUFFER (buffer);
2662 int count = specpdl_ptr - specpdl;
7ab12479
JB
2663
2664 w->buffer = buffer;
86e48436
RS
2665
2666 if (EQ (window, selected_window))
5500c422 2667 b->last_selected_window = window;
beb4e312
RS
2668
2669 /* Update time stamps of buffer display. */
5500c422
GM
2670 if (INTEGERP (b->display_count))
2671 XSETINT (b->display_count, XINT (b->display_count) + 1);
2672 b->display_time = Fcurrent_time ();
86e48436 2673
d834a2e9 2674 XSETFASTINT (w->window_end_pos, 0);
5500c422
GM
2675 XSETFASTINT (w->window_end_vpos, 0);
2676 bzero (&w->last_cursor, sizeof w->last_cursor);
5a41ab94 2677 w->window_end_valid = Qnil;
1c686c99 2678 w->hscroll = w->min_hscroll = make_number (0);
224227d1 2679 w->vscroll = 0;
5500c422 2680 set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
7ab12479 2681 set_marker_restricted (w->start,
5500c422 2682 make_number (b->last_window_start),
7ab12479
JB
2683 buffer);
2684 w->start_at_line_beg = Qnil;
e36ab06b 2685 w->force_start = Qnil;
d834a2e9 2686 XSETFASTINT (w->last_modified, 0);
3cd21523 2687 XSETFASTINT (w->last_overlay_modified, 0);
7ab12479 2688 windows_or_buffers_changed++;
5b03d3c0
RS
2689
2690 /* We must select BUFFER for running the window-scroll-functions.
2691 If WINDOW is selected, switch permanently.
2692 Otherwise, switch but go back to the ambient buffer afterward. */
7ab12479
JB
2693 if (EQ (window, selected_window))
2694 Fset_buffer (buffer);
5b03d3c0
RS
2695 /* We can't check ! NILP (Vwindow_scroll_functions) here
2696 because that might itself be a local variable. */
2697 else if (window_initialized)
2698 {
2699 record_unwind_protect (Fset_window_buffer_unwind, Fcurrent_buffer ());
2700 Fset_buffer (buffer);
2701 }
2702
5500c422 2703 /* Set left and right marginal area width from buffer. */
cfa22082 2704 Fset_window_margins (window, b->left_margin_width, b->right_margin_width);
7ab12479 2705
5500c422
GM
2706 if (run_hooks_p)
2707 {
2708 if (! NILP (Vwindow_scroll_functions))
2709 run_hook_with_args_2 (Qwindow_scroll_functions, window,
2710 Fmarker_position (w->start));
2711
2712 if (! NILP (Vwindow_configuration_change_hook)
2713 && ! NILP (Vrun_hooks))
2714 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
2715 }
543f5fb1 2716
5b03d3c0 2717 unbind_to (count, Qnil);
5500c422 2718}
5b03d3c0 2719
5500c422
GM
2720
2721DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 2, 0,
fdb82f93
PJ
2722 doc: /* Make WINDOW display BUFFER as its contents.
2723BUFFER can be a buffer or buffer name. */)
2724 (window, buffer)
5500c422
GM
2725 register Lisp_Object window, buffer;
2726{
2727 register Lisp_Object tem;
2728 register struct window *w = decode_window (window);
5500c422 2729
bed0c171 2730 XSETWINDOW (window, w);
5500c422 2731 buffer = Fget_buffer (buffer);
b7826503 2732 CHECK_BUFFER (buffer);
5500c422
GM
2733
2734 if (NILP (XBUFFER (buffer)->name))
2735 error ("Attempt to display deleted buffer");
2736
2737 tem = w->buffer;
2738 if (NILP (tem))
2739 error ("Window is deleted");
2740 else if (! EQ (tem, Qt)) /* w->buffer is t when the window
2741 is first being set up. */
2742 {
2743 if (!NILP (w->dedicated) && !EQ (tem, buffer))
2744 error ("Window is dedicated to `%s'",
2745 XSTRING (XBUFFER (tem)->name)->data);
2746
2747 unshow_buffer (w);
2748 }
2749
2750 set_window_buffer (window, buffer, 1);
7ab12479
JB
2751 return Qnil;
2752}
2753
2754DEFUN ("select-window", Fselect_window, Sselect_window, 1, 1, 0,
fdb82f93
PJ
2755 doc: /* Select WINDOW. Most editing will apply to WINDOW's buffer.
2756If WINDOW is not already selected, also make WINDOW's buffer current.
2757Note that the main editor command loop
2758selects the buffer of the selected window before each command. */)
2759 (window)
7ab12479 2760 register Lisp_Object window;
b7354ddf
RS
2761{
2762 return select_window_1 (window, 1);
2763}
2764\f
719eaeb1
GM
2765/* Note that selected_window can be nil
2766 when this is called from Fset_window_configuration. */
2767
b7354ddf
RS
2768static Lisp_Object
2769select_window_1 (window, recordflag)
2770 register Lisp_Object window;
2771 int recordflag;
7ab12479
JB
2772{
2773 register struct window *w;
719eaeb1 2774 register struct window *ow;
1ae1a37d 2775 struct frame *sf;
7ab12479 2776
b7826503 2777 CHECK_LIVE_WINDOW (window);
7ab12479
JB
2778
2779 w = XWINDOW (window);
50e88778 2780 w->frozen_window_start_p = 0;
7ab12479 2781
d834a2e9 2782 XSETFASTINT (w->use_time, ++window_select_count);
7ab12479
JB
2783 if (EQ (window, selected_window))
2784 return window;
2785
719eaeb1
GM
2786 if (!NILP (selected_window))
2787 {
2788 ow = XWINDOW (selected_window);
2789 if (! NILP (ow->buffer))
2790 set_marker_both (ow->pointm, ow->buffer,
2791 BUF_PT (XBUFFER (ow->buffer)),
2792 BUF_PT_BYTE (XBUFFER (ow->buffer)));
2793 }
7ab12479
JB
2794
2795 selected_window = window;
1ae1a37d
GM
2796 sf = SELECTED_FRAME ();
2797 if (XFRAME (WINDOW_FRAME (w)) != sf)
7ab12479 2798 {
44fa5b1e 2799 XFRAME (WINDOW_FRAME (w))->selected_window = window;
147a6615
RS
2800 /* Use this rather than Fhandle_switch_frame
2801 so that FRAME_FOCUS_FRAME is moved appropriately as we
2802 move around in the state where a minibuffer in a separate
2803 frame is active. */
2804 Fselect_frame (WINDOW_FRAME (w), Qnil);
7ab12479
JB
2805 }
2806 else
1ae1a37d 2807 sf->selected_window = window;
7ab12479 2808
b7354ddf
RS
2809 if (recordflag)
2810 record_buffer (w->buffer);
7ab12479
JB
2811 Fset_buffer (w->buffer);
2812
86e48436
RS
2813 XBUFFER (w->buffer)->last_selected_window = window;
2814
7ab12479
JB
2815 /* Go to the point recorded in the window.
2816 This is important when the buffer is in more
2817 than one window. It also matters when
2818 redisplay_window has altered point after scrolling,
2819 because it makes the change only in the window. */
2820 {
2821 register int new_point = marker_position (w->pointm);
2822 if (new_point < BEGV)
2823 SET_PT (BEGV);
a9c95e08 2824 else if (new_point > ZV)
7ab12479
JB
2825 SET_PT (ZV);
2826 else
2827 SET_PT (new_point);
2828 }
2829
2830 windows_or_buffers_changed++;
2831 return window;
2832}
b7354ddf 2833\f
441a127e
RS
2834/* Deiconify the frame containing the window WINDOW,
2835 unless it is the selected frame;
2836 then return WINDOW.
2837
2838 The reason for the exception for the selected frame
2839 is that it seems better not to change the selected frames visibility
2840 merely because of displaying a different buffer in it.
2841 The deiconification is useful when a buffer gets shown in
2842 another frame that you were not using lately. */
d07f802a
RS
2843
2844static Lisp_Object
2845display_buffer_1 (window)
2846 Lisp_Object window;
2847{
1ae1a37d
GM
2848 Lisp_Object frame = XWINDOW (window)->frame;
2849 FRAME_PTR f = XFRAME (frame);
2850
d07f802a 2851 FRAME_SAMPLE_VISIBILITY (f);
1ae1a37d
GM
2852
2853 if (!EQ (frame, selected_frame))
60117126
RS
2854 {
2855 if (FRAME_ICONIFIED_P (f))
1ae1a37d 2856 Fmake_frame_visible (frame);
37962e60 2857 else if (FRAME_VISIBLE_P (f))
1ae1a37d 2858 Fraise_frame (frame);
60117126 2859 }
1ae1a37d 2860
d07f802a
RS
2861 return window;
2862}
2863
4628f7a4 2864DEFUN ("special-display-p", Fspecial_display_p, Sspecial_display_p, 1, 1, 0,
fdb82f93
PJ
2865 doc: /* Returns non-nil if a buffer named BUFFER-NAME would be created specially.
2866The value is actually t if the frame should be called with default frame
2867parameters, and a list of frame parameters if they were specified.
2868See `special-display-buffer-names', and `special-display-regexps'. */)
2869 (buffer_name)
4628f7a4
EN
2870 Lisp_Object buffer_name;
2871{
2872 Lisp_Object tem;
2873
b7826503 2874 CHECK_STRING (buffer_name);
4628f7a4
EN
2875
2876 tem = Fmember (buffer_name, Vspecial_display_buffer_names);
2877 if (!NILP (tem))
2878 return Qt;
2879
2880 tem = Fassoc (buffer_name, Vspecial_display_buffer_names);
2881 if (!NILP (tem))
2882 return XCDR (tem);
2883
2884 for (tem = Vspecial_display_regexps; CONSP (tem); tem = XCDR (tem))
2885 {
2886 Lisp_Object car = XCAR (tem);
2887 if (STRINGP (car)
2888 && fast_string_match (car, buffer_name) >= 0)
2889 return Qt;
2890 else if (CONSP (car)
2891 && STRINGP (XCAR (car))
2892 && fast_string_match (XCAR (car), buffer_name) >= 0)
0057b00a 2893 return XCDR (car);
4628f7a4
EN
2894 }
2895 return Qnil;
2896}
2897
2898DEFUN ("same-window-p", Fsame_window_p, Ssame_window_p, 1, 1, 0,
fdb82f93
PJ
2899 doc: /* Returns non-nil if a new buffer named BUFFER-NAME would use the same window.
2900See `same-window-buffer-names' and `same-window-regexps'. */)
2901 (buffer_name)
4628f7a4
EN
2902 Lisp_Object buffer_name;
2903{
2904 Lisp_Object tem;
2905
b7826503 2906 CHECK_STRING (buffer_name);
4628f7a4
EN
2907
2908 tem = Fmember (buffer_name, Vsame_window_buffer_names);
2909 if (!NILP (tem))
2910 return Qt;
2911
2912 tem = Fassoc (buffer_name, Vsame_window_buffer_names);
2913 if (!NILP (tem))
2914 return Qt;
2915
2916 for (tem = Vsame_window_regexps; CONSP (tem); tem = XCDR (tem))
2917 {
2918 Lisp_Object car = XCAR (tem);
2919 if (STRINGP (car)
2920 && fast_string_match (car, buffer_name) >= 0)
2921 return Qt;
2922 else if (CONSP (car)
2923 && STRINGP (XCAR (car))
2924 && fast_string_match (XCAR (car), buffer_name) >= 0)
2925 return Qt;
2926 }
2927 return Qnil;
2928}
2929
fdb82f93 2930/* Use B so the default is (other-buffer). */
53f76081 2931DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 3,
fdb82f93
PJ
2932 "BDisplay buffer: \nP",
2933 doc: /* Make BUFFER appear in some window but don't select it.
2934BUFFER can be a buffer or a buffer name.
2935If BUFFER is shown already in some window, just use that one,
2936unless the window is the selected window and the optional second
2937argument NOT-THIS-WINDOW is non-nil (interactively, with prefix arg).
2938If `pop-up-frames' is non-nil, make a new frame if no window shows BUFFER.
2939Returns the window displaying BUFFER.
079d288f 2940If `display-buffer-reuse-frames' is non-nil, and another frame is currently
fdb82f93
PJ
2941displaying BUFFER, then simply raise that frame.
2942
2943The variables `special-display-buffer-names', `special-display-regexps',
2944`same-window-buffer-names', and `same-window-regexps' customize how certain
2945buffer names are handled.
2946
2947If optional argument FRAME is `visible', search all visible frames.
2948If FRAME is 0, search all visible and iconified frames.
2949If FRAME is t, search all frames.
2950If FRAME is a frame, search only that frame.
2951If FRAME is nil, search only the selected frame
2952 (actually the last nonminibuffer frame),
2953 unless `pop-up-frames' or `display-buffer-reuse-frames' is non-nil,
2954 which means search visible and iconified frames.
2955
2956If `even-window-heights' is non-nil, window heights will be evened out
2957if displaying the buffer causes two vertically adjacent windows to be
2958displayed. */)
2959 (buffer, not_this_window, frame)
53f76081 2960 register Lisp_Object buffer, not_this_window, frame;
7ab12479 2961{
aee631c2 2962 register Lisp_Object window, tem, swp;
1ae1a37d 2963 struct frame *f;
7ab12479 2964
aee631c2 2965 swp = Qnil;
7ab12479 2966 buffer = Fget_buffer (buffer);
b7826503 2967 CHECK_BUFFER (buffer);
7ab12479 2968
265a9e55 2969 if (!NILP (Vdisplay_buffer_function))
7ab12479
JB
2970 return call2 (Vdisplay_buffer_function, buffer, not_this_window);
2971
265a9e55 2972 if (NILP (not_this_window)
7ab12479 2973 && XBUFFER (XWINDOW (selected_window)->buffer) == XBUFFER (buffer))
d07f802a 2974 return display_buffer_1 (selected_window);
7ab12479 2975
855d8627
RS
2976 /* See if the user has specified this buffer should appear
2977 in the selected window. */
2978 if (NILP (not_this_window))
2979 {
aee631c2
RS
2980 swp = Fsame_window_p (XBUFFER (buffer)->name);
2981 if (!NILP (swp) && !no_switch_window (selected_window))
c63dc4a2
RS
2982 {
2983 Fswitch_to_buffer (buffer, Qnil);
d07f802a 2984 return display_buffer_1 (selected_window);
c63dc4a2 2985 }
855d8627
RS
2986 }
2987
079d288f 2988 /* If the user wants pop-up-frames or display-buffer-reuse-frames,
73dc5198
KH
2989 look for a window showing BUFFER on any visible or iconified frame.
2990 Otherwise search only the current frame. */
53f76081
RS
2991 if (! NILP (frame))
2992 tem = frame;
9c3da604
GM
2993 else if (pop_up_frames
2994 || display_buffer_reuse_frames
2995 || last_nonminibuf_frame == 0)
73dc5198
KH
2996 XSETFASTINT (tem, 0);
2997 else
73dc5198 2998 XSETFRAME (tem, last_nonminibuf_frame);
9c3da604 2999
73dc5198 3000 window = Fget_buffer_window (buffer, tem);
265a9e55
JB
3001 if (!NILP (window)
3002 && (NILP (not_this_window) || !EQ (window, selected_window)))
9c3da604 3003 return display_buffer_1 (window);
7ab12479 3004
a90712c2 3005 /* Certain buffer names get special handling. */
aee631c2 3006 if (!NILP (Vspecial_display_function) && NILP (swp))
a90712c2 3007 {
4628f7a4
EN
3008 tem = Fspecial_display_p (XBUFFER (buffer)->name);
3009 if (EQ (tem, Qt))
a90712c2 3010 return call1 (Vspecial_display_function, buffer);
4628f7a4
EN
3011 if (CONSP (tem))
3012 return call2 (Vspecial_display_function, buffer, tem);
a90712c2
RS
3013 }
3014
44fa5b1e
JB
3015 /* If there are no frames open that have more than a minibuffer,
3016 we need to create a new frame. */
3017 if (pop_up_frames || last_nonminibuf_frame == 0)
7ab12479 3018 {
a90712c2 3019 window = Fframe_selected_window (call0 (Vpop_up_frame_function));
7ab12479 3020 Fset_window_buffer (window, buffer);
d07f802a 3021 return display_buffer_1 (window);
7ab12479 3022 }
7ab12479 3023
1ae1a37d 3024 f = SELECTED_FRAME ();
43bad991 3025 if (pop_up_windows
1ae1a37d 3026 || FRAME_MINIBUF_ONLY_P (f)
cee67da9
RS
3027 /* If the current frame is a special display frame,
3028 don't try to reuse its windows. */
1ae1a37d 3029 || !NILP (XWINDOW (FRAME_ROOT_WINDOW (f))->dedicated))
7ab12479 3030 {
12cae7c0
KH
3031 Lisp_Object frames;
3032
37962e60 3033 frames = Qnil;
1ae1a37d 3034 if (FRAME_MINIBUF_ONLY_P (f))
74112613 3035 XSETFRAME (frames, last_nonminibuf_frame);
7ab12479
JB
3036 /* Don't try to create a window if would get an error */
3037 if (split_height_threshold < window_min_height << 1)
3038 split_height_threshold = window_min_height << 1;
3039
cee67da9
RS
3040 /* Note that both Fget_largest_window and Fget_lru_window
3041 ignore minibuffers and dedicated windows.
3042 This means they can return nil. */
7ab12479 3043
cee67da9
RS
3044 /* If the frame we would try to split cannot be split,
3045 try other frames. */
1ae1a37d 3046 if (FRAME_NO_SPLIT_P (NILP (frames) ? f : last_nonminibuf_frame))
cee67da9
RS
3047 {
3048 /* Try visible frames first. */
3049 window = Fget_largest_window (Qvisible);
3050 /* If that didn't work, try iconified frames. */
3051 if (NILP (window))
3052 window = Fget_largest_window (make_number (0));
3053 if (NILP (window))
3054 window = Fget_largest_window (Qt);
3055 }
3056 else
3057 window = Fget_largest_window (frames);
3058
92cca945
RS
3059 /* If we got a tall enough full-width window that can be split,
3060 split it. */
265a9e55 3061 if (!NILP (window)
92cca945 3062 && ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
7ab12479 3063 && window_height (window) >= split_height_threshold
111e5992 3064 && WINDOW_FULL_WIDTH_P (XWINDOW (window)))
7ab12479
JB
3065 window = Fsplit_window (window, Qnil, Qnil);
3066 else
3067 {
1942f68f
RS
3068 Lisp_Object upper, lower, other;
3069
44fa5b1e 3070 window = Fget_lru_window (frames);
92cca945
RS
3071 /* If the LRU window is selected, and big enough,
3072 and can be split, split it. */
cee67da9 3073 if (!NILP (window)
92cca945 3074 && ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
cee67da9
RS
3075 && (EQ (window, selected_window)
3076 || EQ (XWINDOW (window)->parent, Qnil))
7ab12479
JB
3077 && window_height (window) >= window_min_height << 1)
3078 window = Fsplit_window (window, Qnil, Qnil);
cee67da9 3079 /* If Fget_lru_window returned nil, try other approaches. */
48d9379d 3080
cee67da9 3081 /* Try visible frames first. */
48d9379d
RS
3082 if (NILP (window))
3083 window = Fget_buffer_window (buffer, Qvisible);
cee67da9
RS
3084 if (NILP (window))
3085 window = Fget_largest_window (Qvisible);
3086 /* If that didn't work, try iconified frames. */
48d9379d
RS
3087 if (NILP (window))
3088 window = Fget_buffer_window (buffer, make_number (0));
cee67da9
RS
3089 if (NILP (window))
3090 window = Fget_largest_window (make_number (0));
3091 /* Try invisible frames. */
48d9379d
RS
3092 if (NILP (window))
3093 window = Fget_buffer_window (buffer, Qt);
cee67da9
RS
3094 if (NILP (window))
3095 window = Fget_largest_window (Qt);
3096 /* As a last resort, make a new frame. */
3097 if (NILP (window))
3098 window = Fframe_selected_window (call0 (Vpop_up_frame_function));
1942f68f
RS
3099 /* If window appears above or below another,
3100 even out their heights. */
cac66e4f 3101 other = upper = lower = Qnil;
1942f68f
RS
3102 if (!NILP (XWINDOW (window)->prev))
3103 other = upper = XWINDOW (window)->prev, lower = window;
3104 if (!NILP (XWINDOW (window)->next))
3105 other = lower = XWINDOW (window)->next, upper = window;
3106 if (!NILP (other)
6529ed87 3107 && !NILP (Veven_window_heights)
1942f68f 3108 /* Check that OTHER and WINDOW are vertically arrayed. */
296b535c
KH
3109 && !EQ (XWINDOW (other)->top, XWINDOW (window)->top)
3110 && (XFASTINT (XWINDOW (other)->height)
3111 > XFASTINT (XWINDOW (window)->height)))
1942f68f 3112 {
296b535c
KH
3113 int total = (XFASTINT (XWINDOW (other)->height)
3114 + XFASTINT (XWINDOW (window)->height));
86c8e823
GM
3115 enlarge_window (upper,
3116 total / 2 - XFASTINT (XWINDOW (upper)->height),
f95284d2 3117 0, 0);
1942f68f 3118 }
7ab12479
JB
3119 }
3120 }
3121 else
3122 window = Fget_lru_window (Qnil);
3123
3124 Fset_window_buffer (window, buffer);
d07f802a 3125 return display_buffer_1 (window);
7ab12479
JB
3126}
3127
3128void
3129temp_output_buffer_show (buf)
3130 register Lisp_Object buf;
3131{
3132 register struct buffer *old = current_buffer;
3133 register Lisp_Object window;
3134 register struct window *w;
3135
bccd3dd1
RS
3136 XBUFFER (buf)->directory = current_buffer->directory;
3137
7ab12479 3138 Fset_buffer (buf);
c6367666 3139 BUF_SAVE_MODIFF (XBUFFER (buf)) = MODIFF;
7ab12479
JB
3140 BEGV = BEG;
3141 ZV = Z;
3142 SET_PT (BEG);
b1599b4c 3143 XBUFFER (buf)->prevent_redisplay_optimizations_p = 1;
7ab12479
JB
3144 set_buffer_internal (old);
3145
3146 if (!EQ (Vtemp_buffer_show_function, Qnil))
3147 call1 (Vtemp_buffer_show_function, buf);
3148 else
3149 {
53f76081 3150 window = Fdisplay_buffer (buf, Qnil, Qnil);
7ab12479 3151
1ae1a37d 3152 if (!EQ (XWINDOW (window)->frame, selected_frame))
44fa5b1e 3153 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
7ab12479
JB
3154 Vminibuf_scroll_window = window;
3155 w = XWINDOW (window);
d834a2e9 3156 XSETFASTINT (w->hscroll, 0);
ea68264b 3157 XSETFASTINT (w->min_hscroll, 0);
b73ea88e
RS
3158 set_marker_restricted_both (w->start, buf, 1, 1);
3159 set_marker_restricted_both (w->pointm, buf, 1, 1);
a58ec57d 3160
beb4e312
RS
3161 /* Run temp-buffer-show-hook, with the chosen window selected
3162 and it sbuffer current. */
f52cca03 3163 if (!NILP (Vrun_hooks))
2cccc823 3164 {
f52cca03
RS
3165 Lisp_Object tem;
3166 tem = Fboundp (Qtemp_buffer_show_hook);
2cccc823
RS
3167 if (!NILP (tem))
3168 {
f52cca03
RS
3169 tem = Fsymbol_value (Qtemp_buffer_show_hook);
3170 if (!NILP (tem))
3171 {
3172 int count = specpdl_ptr - specpdl;
b7354ddf
RS
3173 Lisp_Object prev_window;
3174 prev_window = selected_window;
2cccc823 3175
f52cca03 3176 /* Select the window that was chosen, for running the hook. */
65a04b96 3177 record_unwind_protect (Fselect_window, prev_window);
b7354ddf 3178 select_window_1 (window, 0);
beb4e312 3179 Fset_buffer (w->buffer);
f52cca03 3180 call1 (Vrun_hooks, Qtemp_buffer_show_hook);
b7354ddf 3181 select_window_1 (prev_window, 0);
f52cca03
RS
3182 unbind_to (count, Qnil);
3183 }
2cccc823
RS
3184 }
3185 }
3186 }
7ab12479
JB
3187}
3188\f
dfcf069d 3189static void
7ab12479
JB
3190make_dummy_parent (window)
3191 Lisp_Object window;
3192{
cffec418 3193 Lisp_Object new;
7ab12479 3194 register struct window *o, *p;
cffec418 3195 int i;
7ab12479 3196
cffec418 3197 o = XWINDOW (window);
26605be9 3198 p = allocate_window ();
cffec418 3199 for (i = 0; i < VECSIZE (struct window); ++i)
26605be9
GM
3200 ((struct Lisp_Vector *) p)->contents[i]
3201 = ((struct Lisp_Vector *)o)->contents[i];
cffec418 3202 XSETWINDOW (new, p);
7ab12479 3203
d834a2e9 3204 XSETFASTINT (p->sequence_number, ++sequence_number);
7ab12479
JB
3205
3206 /* Put new into window structure in place of window */
3207 replace_window (window, new);
3208
3209 o->next = Qnil;
3210 o->prev = Qnil;
3211 o->vchild = Qnil;
3212 o->hchild = Qnil;
3213 o->parent = new;
3214
3215 p->start = Qnil;
3216 p->pointm = Qnil;
3217 p->buffer = Qnil;
3218}
3219
3220DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
fdb82f93
PJ
3221 doc: /* Split WINDOW, putting SIZE lines in the first of the pair.
3222WINDOW defaults to selected one and SIZE to half its size.
3223If optional third arg HORFLAG is non-nil, split side by side
3224and put SIZE columns in the first of the pair. In that case,
3225SIZE includes that window's scroll bar, or the divider column to its right. */)
3226 (window, size, horflag)
77ae0fe3 3227 Lisp_Object window, size, horflag;
7ab12479
JB
3228{
3229 register Lisp_Object new;
3230 register struct window *o, *p;
c0807608 3231 FRAME_PTR fo;
77ae0fe3 3232 register int size_int;
7ab12479 3233
265a9e55 3234 if (NILP (window))
7ab12479
JB
3235 window = selected_window;
3236 else
b7826503 3237 CHECK_LIVE_WINDOW (window);
7ab12479
JB
3238
3239 o = XWINDOW (window);
c0807608 3240 fo = XFRAME (WINDOW_FRAME (o));
7ab12479 3241
77ae0fe3 3242 if (NILP (size))
7ab12479 3243 {
265a9e55 3244 if (!NILP (horflag))
c0807608 3245 /* Calculate the size of the left-hand window, by dividing
25b33244
KH
3246 the usable space in columns by two.
3247 We round up, since the left-hand window may include
3248 a dividing line, while the right-hand may not. */
3249 size_int = (XFASTINT (o->width) + 1) >> 1;
7ab12479 3250 else
77ae0fe3 3251 size_int = XFASTINT (o->height) >> 1;
7ab12479
JB
3252 }
3253 else
3254 {
b7826503 3255 CHECK_NUMBER (size);
77ae0fe3 3256 size_int = XINT (size);
7ab12479
JB
3257 }
3258
3259 if (MINI_WINDOW_P (o))
3260 error ("Attempt to split minibuffer window");
233a4a2c
GM
3261 else if (window_fixed_size_p (o, !NILP (horflag), 0))
3262 error ("Attempt to split fixed-size window");
7ab12479 3263
a481b3ea 3264 check_min_window_sizes ();
7ab12479 3265
265a9e55 3266 if (NILP (horflag))
7ab12479 3267 {
77ae0fe3
KH
3268 if (size_int < window_min_height)
3269 error ("Window height %d too small (after splitting)", size_int);
3270 if (size_int + window_min_height > XFASTINT (o->height))
37962e60 3271 error ("Window height %d too small (after splitting)",
77ae0fe3 3272 XFASTINT (o->height) - size_int);
265a9e55
JB
3273 if (NILP (o->parent)
3274 || NILP (XWINDOW (o->parent)->vchild))
7ab12479
JB
3275 {
3276 make_dummy_parent (window);
3277 new = o->parent;
3278 XWINDOW (new)->vchild = window;
3279 }
3280 }
3281 else
3282 {
77ae0fe3
KH
3283 if (size_int < window_min_width)
3284 error ("Window width %d too small (after splitting)", size_int);
a59fed7e
RS
3285
3286 if (size_int + window_min_width > XFASTINT (o->width))
37962e60 3287 error ("Window width %d too small (after splitting)",
a59fed7e 3288 XFASTINT (o->width) - size_int);
265a9e55
JB
3289 if (NILP (o->parent)
3290 || NILP (XWINDOW (o->parent)->hchild))
7ab12479
JB
3291 {
3292 make_dummy_parent (window);
3293 new = o->parent;
3294 XWINDOW (new)->hchild = window;
3295 }
3296 }
3297
3298 /* Now we know that window's parent is a vertical combination
3299 if we are dividing vertically, or a horizontal combination
3300 if we are making side-by-side windows */
3301
3302 windows_or_buffers_changed++;
c0807608 3303 FRAME_WINDOW_SIZES_CHANGED (fo) = 1;
7ab12479
JB
3304 new = make_window ();
3305 p = XWINDOW (new);
3306
44fa5b1e 3307 p->frame = o->frame;
7ab12479 3308 p->next = o->next;
265a9e55 3309 if (!NILP (p->next))
7ab12479
JB
3310 XWINDOW (p->next)->prev = new;
3311 p->prev = window;
3312 o->next = new;
3313 p->parent = o->parent;
3314 p->buffer = Qt;
5500c422
GM
3315 p->window_end_valid = Qnil;
3316 bzero (&p->last_cursor, sizeof p->last_cursor);
7ab12479 3317
44fa5b1e 3318 /* Apportion the available frame space among the two new windows */
7ab12479 3319
265a9e55 3320 if (!NILP (horflag))
7ab12479
JB
3321 {
3322 p->height = o->height;
3323 p->top = o->top;
a59fed7e 3324 XSETFASTINT (p->width, XFASTINT (o->width) - size_int);
77ae0fe3
KH
3325 XSETFASTINT (o->width, size_int);
3326 XSETFASTINT (p->left, XFASTINT (o->left) + size_int);
7ab12479
JB
3327 }
3328 else
3329 {
3330 p->left = o->left;
3331 p->width = o->width;
77ae0fe3
KH
3332 XSETFASTINT (p->height, XFASTINT (o->height) - size_int);
3333 XSETFASTINT (o->height, size_int);
3334 XSETFASTINT (p->top, XFASTINT (o->top) + size_int);
7ab12479
JB
3335 }
3336
5500c422
GM
3337 /* Adjust glyph matrices. */
3338 adjust_glyphs (fo);
543f5fb1 3339 Fset_window_buffer (new, o->buffer);
7ab12479
JB
3340 return new;
3341}
3342\f
f95284d2 3343DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 3, "p",
fdb82f93
PJ
3344 doc: /* Make current window ARG lines bigger.
3345From program, optional second arg non-nil means grow sideways ARG columns.
f95284d2
RS
3346Interactively, if an argument is not given, make the window one line bigger.
3347
3348Optional third arg PRESERVE-BEFORE, if non-nil, means do not change the size
3349of the siblings above or to the left of the selected window. Only
3350siblings to the right or below are changed. */)
3351 (arg, side, preserve_before)
3352 register Lisp_Object arg, side, preserve_before;
7ab12479 3353{
b7826503 3354 CHECK_NUMBER (arg);
f95284d2
RS
3355 enlarge_window (selected_window, XINT (arg), !NILP (side),
3356 !NILP (preserve_before));
543f5fb1
RS
3357
3358 if (! NILP (Vwindow_configuration_change_hook))
3359 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
3360
7ab12479
JB
3361 return Qnil;
3362}
3363
3364DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
fdb82f93
PJ
3365 doc: /* Make current window ARG lines smaller.
3366From program, optional second arg non-nil means shrink sideways arg columns.
3367Interactively, if an argument is not given, make the window one line smaller. */)
3368 (arg, side)
413430c5 3369 register Lisp_Object arg, side;
7ab12479 3370{
b7826503 3371 CHECK_NUMBER (arg);
f95284d2 3372 enlarge_window (selected_window, -XINT (arg), !NILP (side), 0);
543f5fb1
RS
3373
3374 if (! NILP (Vwindow_configuration_change_hook))
3375 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
3376
7ab12479
JB
3377 return Qnil;
3378}
3379
3380int
3381window_height (window)
3382 Lisp_Object window;
3383{
3384 register struct window *p = XWINDOW (window);
3385 return XFASTINT (p->height);
3386}
3387
3388int
3389window_width (window)
3390 Lisp_Object window;
3391{
3392 register struct window *p = XWINDOW (window);
3393 return XFASTINT (p->width);
3394}
3395
c1636aa6 3396
7ab12479 3397#define CURBEG(w) \
3578db3c 3398 *(widthflag ? &(XWINDOW (w)->left) : &(XWINDOW (w)->top))
7ab12479
JB
3399
3400#define CURSIZE(w) \
3578db3c 3401 *(widthflag ? &(XWINDOW (w)->width) : &(XWINDOW (w)->height))
7ab12479 3402
233a4a2c 3403
f95284d2 3404/* Enlarge WINDOW by DELTA. WIDTHFLAG non-zero means
233a4a2c 3405 increase its width. Siblings of the selected window are resized to
f95284d2
RS
3406 fulfill the size request. If they become too small in the process,
3407 they will be deleted.
3408
3409 If PRESERVE_BEFORE is nonzero, that means don't alter
3410 the siblings to the left or above WINDOW. */
7ab12479 3411
f984d4fc 3412static void
f95284d2 3413enlarge_window (window, delta, widthflag, preserve_before)
86c8e823 3414 Lisp_Object window;
f95284d2 3415 int delta, widthflag, preserve_before;
7ab12479 3416{
86c8e823 3417 Lisp_Object parent, next, prev;
233a4a2c 3418 struct window *p;
3578db3c
KR
3419 Lisp_Object *sizep;
3420 int maximum;
5e14b1fc
AS
3421 int (*sizefun) P_ ((Lisp_Object))
3422 = widthflag ? window_width : window_height;
233a4a2c 3423 void (*setsizefun) P_ ((Lisp_Object, int, int))
5e14b1fc 3424 = (widthflag ? set_window_width : set_window_height);
7ab12479 3425
233a4a2c
GM
3426 /* Check values of window_min_width and window_min_height for
3427 validity. */
a481b3ea 3428 check_min_window_sizes ();
7ab12479 3429
233a4a2c 3430 /* Give up if this window cannot be resized. */
233a4a2c
GM
3431 if (window_fixed_size_p (XWINDOW (window), widthflag, 1))
3432 error ("Window is not resizable");
3433
3434 /* Find the parent of the selected window. */
7ab12479
JB
3435 while (1)
3436 {
3437 p = XWINDOW (window);
3438 parent = p->parent;
233a4a2c 3439
265a9e55 3440 if (NILP (parent))
7ab12479
JB
3441 {
3442 if (widthflag)
3443 error ("No other window to side of this one");
3444 break;
3445 }
233a4a2c
GM
3446
3447 if (widthflag
3448 ? !NILP (XWINDOW (parent)->hchild)
265a9e55 3449 : !NILP (XWINDOW (parent)->vchild))
7ab12479 3450 break;
233a4a2c 3451
7ab12479
JB
3452 window = parent;
3453 }
3454
05c2896a 3455 sizep = &CURSIZE (window);
7ab12479 3456
7ab12479
JB
3457 {
3458 register int maxdelta;
7ab12479 3459
f95284d2
RS
3460 /* Compute the maximum size increment this window can have. */
3461
3462 if (preserve_before)
3463 {
3464 if (!NILP (parent))
3465 {
3466 maxdelta = (*sizefun) (parent) - XINT (*sizep);
3467 /* Subtract size of siblings before, since we can't take that. */
1ab964d7 3468 maxdelta -= XINT (CURBEG (window)) - XINT (CURBEG (parent));
f95284d2
RS
3469 }
3470 else
3471 maxdelta = (!NILP (p->next) ? ((*sizefun) (p->next)
3472 - window_min_size (XWINDOW (p->next),
3473 widthflag, 0, 0))
3474 : (delta = 0));
3475 }
3476 else
3477 maxdelta = (!NILP (parent) ? (*sizefun) (parent) - XINT (*sizep)
3478 /* This is a main window followed by a minibuffer. */
3479 : !NILP (p->next) ? ((*sizefun) (p->next)
3480 - window_min_size (XWINDOW (p->next),
3481 widthflag, 0, 0))
3482 /* This is a minibuffer following a main window. */
3483 : !NILP (p->prev) ? ((*sizefun) (p->prev)
3484 - window_min_size (XWINDOW (p->prev),
3485 widthflag, 0, 0))
3486 /* This is a frame with only one window, a minibuffer-only
3487 or a minibufferless frame. */
3488 : (delta = 0));
7ab12479
JB
3489
3490 if (delta > maxdelta)
3491 /* This case traps trying to make the minibuffer
44fa5b1e
JB
3492 the full frame, or make the only window aside from the
3493 minibuffer the full frame. */
7ab12479 3494 delta = maxdelta;
6b54027b 3495 }
d5783c40 3496
3578db3c 3497 if (XINT (*sizep) + delta < window_min_size (XWINDOW (window), widthflag, 0, 0))
6b54027b 3498 {
543f5fb1 3499 delete_window (window);
d5783c40 3500 return;
6b54027b
RS
3501 }
3502
3503 if (delta == 0)
3504 return;
7ab12479 3505
f95284d2 3506 /* Find the total we can get from other siblings without deleting them. */
db98a733
RS
3507 maximum = 0;
3508 for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
c1636aa6 3509 maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
f984d4fc 3510 widthflag, 0, 0);
f95284d2
RS
3511 if (! preserve_before)
3512 for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
3513 maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
3514 widthflag, 0, 0);
db98a733 3515
f95284d2 3516 /* If we can get it all from them without deleting them, do so. */
c6b530ed 3517 if (delta <= maximum)
7ab12479 3518 {
db98a733
RS
3519 Lisp_Object first_unaffected;
3520 Lisp_Object first_affected;
233a4a2c 3521 int fixed_p;
db98a733
RS
3522
3523 next = p->next;
3524 prev = p->prev;
3525 first_affected = window;
3526 /* Look at one sibling at a time,
3527 moving away from this window in both directions alternately,
3528 and take as much as we can get without deleting that sibling. */
f95284d2
RS
3529 while (delta != 0
3530 && (!NILP (next) || (!preserve_before && !NILP (prev))))
db98a733 3531 {
db98a733
RS
3532 if (! NILP (next))
3533 {
c1636aa6 3534 int this_one = ((*sizefun) (next)
233a4a2c 3535 - window_min_size (XWINDOW (next),
f984d4fc 3536 widthflag, 0, &fixed_p));
233a4a2c
GM
3537 if (!fixed_p)
3538 {
3539 if (this_one > delta)
3540 this_one = delta;
3541
3542 (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
3578db3c 3543 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
db98a733 3544
233a4a2c
GM
3545 delta -= this_one;
3546 }
3547
db98a733
RS
3548 next = XWINDOW (next)->next;
3549 }
233a4a2c 3550
db98a733
RS
3551 if (delta == 0)
3552 break;
233a4a2c 3553
f95284d2 3554 if (!preserve_before && ! NILP (prev))
db98a733 3555 {
c1636aa6 3556 int this_one = ((*sizefun) (prev)
233a4a2c 3557 - window_min_size (XWINDOW (prev),
f984d4fc 3558 widthflag, 0, &fixed_p));
233a4a2c
GM
3559 if (!fixed_p)
3560 {
3561 if (this_one > delta)
3562 this_one = delta;
3563
3564 first_affected = prev;
3565
3566 (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
3578db3c 3567 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
233a4a2c
GM
3568
3569 delta -= this_one;
3570 }
3571
db98a733
RS
3572 prev = XWINDOW (prev)->prev;
3573 }
3574 }
3575
233a4a2c
GM
3576 xassert (delta == 0);
3577
db98a733
RS
3578 /* Now recalculate the edge positions of all the windows affected,
3579 based on the new sizes. */
3580 first_unaffected = next;
3581 prev = first_affected;
3582 for (next = XWINDOW (prev)->next; ! EQ (next, first_unaffected);
3583 prev = next, next = XWINDOW (next)->next)
3584 {
3578db3c 3585 XSETINT (CURBEG (next), XINT (CURBEG (prev)) + (*sizefun) (prev));
db98a733
RS
3586 /* This does not change size of NEXT,
3587 but it propagates the new top edge to its children */
3588 (*setsizefun) (next, (*sizefun) (next), 0);
3589 }
7ab12479
JB
3590 }
3591 else
3592 {
3593 register int delta1;
3594 register int opht = (*sizefun) (parent);
3595
3578db3c 3596 if (opht <= XINT (*sizep) + delta)
daf516d3
RS
3597 {
3598 /* If trying to grow this window to or beyond size of the parent,
3599 just delete all the sibling windows. */
dc1ab1ee 3600 Lisp_Object start, tem, next;
daf516d3 3601
dc1ab1ee
RS
3602 start = XWINDOW (parent)->vchild;
3603 if (NILP (start))
3604 start = XWINDOW (parent)->hchild;
daf516d3 3605
dc1ab1ee
RS
3606 /* Delete any siblings that come after WINDOW. */
3607 tem = XWINDOW (window)->next;
daf516d3
RS
3608 while (! NILP (tem))
3609 {
3610 next = XWINDOW (tem)->next;
dc1ab1ee
RS
3611 delete_window (tem);
3612 tem = next;
3613 }
3614
3615 /* Delete any siblings that come after WINDOW.
3616 Note that if START is not WINDOW, then WINDOW still
3617 Fhas siblings, so WINDOW has not yet replaced its parent. */
3618 tem = start;
3619 while (! EQ (tem, window))
3620 {
3621 next = XWINDOW (tem)->next;
3622 delete_window (tem);
daf516d3
RS
3623 tem = next;
3624 }
3625 }
7ab12479 3626 else
233a4a2c
GM
3627 {
3628 /* Otherwise, make delta1 just right so that if we add
3629 delta1 lines to this window and to the parent, and then
3630 shrink the parent back to its original size, the new
3631 proportional size of this window will increase by delta.
3632
3633 The function size_window will compute the new height h'
3634 of the window from delta1 as:
3635
3636 e = delta1/n
3637 x = delta1 - delta1/n * n for the 1st resizable child
3638 h' = h + e + x
3639
3640 where n is the number of children that can be resized.
3641 We can ignore x by choosing a delta1 that is a multiple of
3642 n. We want the height of this window to come out as
3643
3644 h' = h + delta
3645
3646 So, delta1 must be
3647
3648 h + e = h + delta
3649 delta1/n = delta
3650 delta1 = n * delta.
3651
3652 The number of children n rquals the number of resizable
3653 children of this window + 1 because we know window itself
3654 is resizable (otherwise we would have signalled an error. */
3655
3656 struct window *w = XWINDOW (window);
3657 Lisp_Object s;
3658 int n = 1;
3659
3660 for (s = w->next; !NILP (s); s = XWINDOW (s)->next)
3661 if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
3662 ++n;
3663 for (s = w->prev; !NILP (s); s = XWINDOW (s)->prev)
3664 if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
3665 ++n;
3666
3667 delta1 = n * delta;
7ab12479 3668
daf516d3
RS
3669 /* Add delta1 lines or columns to this window, and to the parent,
3670 keeping things consistent while not affecting siblings. */
3671 XSETINT (CURSIZE (parent), opht + delta1);
3672 (*setsizefun) (window, XINT (*sizep) + delta1, 0);
3673
3674 /* Squeeze out delta1 lines or columns from our parent,
3675 shriking this window and siblings proportionately.
3676 This brings parent back to correct size.
3677 Delta1 was calculated so this makes this window the desired size,
3678 taking it all out of the siblings. */
3679 (*setsizefun) (parent, opht, 0);
3680
3681 }
7ab12479
JB
3682 }
3683
d834a2e9 3684 XSETFASTINT (p->last_modified, 0);
3cd21523 3685 XSETFASTINT (p->last_overlay_modified, 0);
5500c422
GM
3686
3687 /* Adjust glyph matrices. */
3688 adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
7ab12479 3689}
c1636aa6 3690
7ab12479
JB
3691#undef CURBEG
3692#undef CURSIZE
3693
5500c422 3694
f984d4fc
GM
3695\f
3696/***********************************************************************
3697 Resizing Mini-Windows
3698 ***********************************************************************/
3699
3700static void shrink_window_lowest_first P_ ((struct window *, int));
f984d4fc 3701
43b4a21f
GM
3702enum save_restore_action
3703{
3704 CHECK_ORIG_SIZES,
3705 SAVE_ORIG_SIZES,
3706 RESTORE_ORIG_SIZES
3707};
3708
3709static int save_restore_orig_size P_ ((struct window *,
3710 enum save_restore_action));
f984d4fc
GM
3711
3712/* Shrink windows rooted in window W to HEIGHT. Take the space needed
3713 from lowest windows first. */
3714
3715static void
3716shrink_window_lowest_first (w, height)
3717 struct window *w;
3718 int height;
3719{
3720 struct window *c;
3721 Lisp_Object child;
3722 int old_height;
3723
3724 xassert (!MINI_WINDOW_P (w));
3725
3726 /* Set redisplay hints. */
3727 XSETFASTINT (w->last_modified, 0);
3728 XSETFASTINT (w->last_overlay_modified, 0);
3729 windows_or_buffers_changed++;
3730 FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
3731
3732 old_height = XFASTINT (w->height);
3733 XSETFASTINT (w->height, height);
3734
3735 if (!NILP (w->hchild))
3736 {
3737 for (child = w->hchild; !NILP (child); child = c->next)
3738 {
3739 c = XWINDOW (child);
3740 c->top = w->top;
3741 shrink_window_lowest_first (c, height);
3742 }
3743 }
3744 else if (!NILP (w->vchild))
3745 {
3746 Lisp_Object last_child;
3747 int delta = old_height - height;
3748 int last_top;
6bbd7a29
GM
3749
3750 last_child = Qnil;
f984d4fc
GM
3751
3752 /* Find the last child. We are taking space from lowest windows
3753 first, so we iterate over children from the last child
3754 backwards. */
3755 for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
3756 last_child = child;
3757
3758 /* Assign new heights. We leave only MIN_SAFE_WINDOW_HEIGHT. */
3759 for (child = last_child; delta && !NILP (child); child = c->prev)
3760 {
3761 int this_one;
3762
3763 c = XWINDOW (child);
3764 this_one = XFASTINT (c->height) - MIN_SAFE_WINDOW_HEIGHT;
3765
3766 if (this_one > delta)
3767 this_one = delta;
3768
3769 shrink_window_lowest_first (c, XFASTINT (c->height) - this_one);
3770 delta -= this_one;
3771 }
3772
3773 /* Compute new positions. */
3578db3c 3774 last_top = XINT (w->top);
f984d4fc
GM
3775 for (child = w->vchild; !NILP (child); child = c->next)
3776 {
3777 c = XWINDOW (child);
3778 c->top = make_number (last_top);
3779 shrink_window_lowest_first (c, XFASTINT (c->height));
3780 last_top += XFASTINT (c->height);
3781 }
3782 }
3783}
3784
3785
43b4a21f
GM
3786/* Save, restore, or check positions and sizes in the window tree
3787 rooted at W. ACTION says what to do.
f984d4fc 3788
43b4a21f
GM
3789 If ACTION is CHECK_ORIG_SIZES, check if orig_top and orig_height
3790 members are valid for all windows in the window tree. Value is
3791 non-zero if they are valid.
3792
3793 If ACTION is SAVE_ORIG_SIZES, save members top and height in
3794 orig_top and orig_height for all windows in the tree.
3795
3796 If ACTION is RESTORE_ORIG_SIZES, restore top and height from
3797 values stored in orig_top and orig_height for all windows. */
3798
3799static int
3800save_restore_orig_size (w, action)
f984d4fc 3801 struct window *w;
43b4a21f 3802 enum save_restore_action action;
f984d4fc 3803{
43b4a21f
GM
3804 int success_p = 1;
3805
f984d4fc
GM
3806 while (w)
3807 {
3808 if (!NILP (w->hchild))
43b4a21f
GM
3809 {
3810 if (!save_restore_orig_size (XWINDOW (w->hchild), action))
3811 success_p = 0;
3812 }
f984d4fc 3813 else if (!NILP (w->vchild))
43b4a21f
GM
3814 {
3815 if (!save_restore_orig_size (XWINDOW (w->vchild), action))
3816 success_p = 0;
3817 }
f984d4fc 3818
43b4a21f 3819 switch (action)
f984d4fc 3820 {
43b4a21f
GM
3821 case CHECK_ORIG_SIZES:
3822 if (!INTEGERP (w->orig_top) || !INTEGERP (w->orig_height))
3823 return 0;
3824 break;
3825
3826 case SAVE_ORIG_SIZES:
f984d4fc
GM
3827 w->orig_top = w->top;
3828 w->orig_height = w->height;
43b4a21f
GM
3829 XSETFASTINT (w->last_modified, 0);
3830 XSETFASTINT (w->last_overlay_modified, 0);
3831 break;
3832
3833 case RESTORE_ORIG_SIZES:
f984d4fc
GM
3834 xassert (INTEGERP (w->orig_top) && INTEGERP (w->orig_height));
3835 w->top = w->orig_top;
3836 w->height = w->orig_height;
3837 w->orig_height = w->orig_top = Qnil;
43b4a21f
GM
3838 XSETFASTINT (w->last_modified, 0);
3839 XSETFASTINT (w->last_overlay_modified, 0);
3840 break;
3841
3842 default:
3843 abort ();
f984d4fc 3844 }
43b4a21f 3845
f984d4fc
GM
3846 w = NILP (w->next) ? NULL : XWINDOW (w->next);
3847 }
43b4a21f
GM
3848
3849 return success_p;
f984d4fc
GM
3850}
3851
3852
3853/* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we can
3854 without deleting other windows. */
3855
3856void
3857grow_mini_window (w, delta)
3858 struct window *w;
3859 int delta;
3860{
3861 struct frame *f = XFRAME (w->frame);
3862 struct window *root;
3863
3864 xassert (MINI_WINDOW_P (w));
3865 xassert (delta >= 0);
3866
3867 /* Check values of window_min_width and window_min_height for
3868 validity. */
3869 check_min_window_sizes ();
3870
3871 /* Compute how much we can enlarge the mini-window without deleting
3872 other windows. */
3873 root = XWINDOW (FRAME_ROOT_WINDOW (f));
3874 if (delta)
3875 {
3876 int min_height = window_min_size (root, 0, 0, 0);
3877 if (XFASTINT (root->height) - delta < min_height)
8b8bd9c6 3878 /* Note that the root window may already be smaller than
eafa3196
GM
3879 min_height. */
3880 delta = max (0, XFASTINT (root->height) - min_height);
f984d4fc
GM
3881 }
3882
3883 if (delta)
3884 {
3885 /* Save original window sizes and positions, if not already done. */
43b4a21f
GM
3886 if (!save_restore_orig_size (root, CHECK_ORIG_SIZES))
3887 save_restore_orig_size (root, SAVE_ORIG_SIZES);
f984d4fc
GM
3888
3889 /* Shrink other windows. */
3890 shrink_window_lowest_first (root, XFASTINT (root->height) - delta);
3891
3892 /* Grow the mini-window. */
3578db3c 3893 w->top = make_number (XFASTINT (root->top) + XFASTINT (root->height));
f984d4fc
GM
3894 w->height = make_number (XFASTINT (w->height) + delta);
3895 XSETFASTINT (w->last_modified, 0);
3896 XSETFASTINT (w->last_overlay_modified, 0);
3897
3898 adjust_glyphs (f);
3899 }
3900}
3901
3902
86c8e823
GM
3903/* Shrink mini-window W. If there is recorded info about window sizes
3904 before a call to grow_mini_window, restore recorded window sizes.
3905 Otherwise, if the mini-window is higher than 1 line, resize it to 1
3906 line. */
f984d4fc
GM
3907
3908void
3909shrink_mini_window (w)
3910 struct window *w;
3911{
3912 struct frame *f = XFRAME (w->frame);
3913 struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
3914
43b4a21f 3915 if (save_restore_orig_size (root, CHECK_ORIG_SIZES))
f984d4fc 3916 {
43b4a21f 3917 save_restore_orig_size (root, RESTORE_ORIG_SIZES);
f984d4fc
GM
3918 adjust_glyphs (f);
3919 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
3920 windows_or_buffers_changed = 1;
3921 }
86c8e823
GM
3922 else if (XFASTINT (w->height) > 1)
3923 {
0130fe1a
GM
3924 /* Distribute the additional lines of the mini-window
3925 among the other windows. */
86c8e823
GM
3926 Lisp_Object window;
3927 XSETWINDOW (window, w);
f95284d2 3928 enlarge_window (window, 1 - XFASTINT (w->height), 0, 0);
86c8e823 3929 }
f984d4fc
GM
3930}
3931
3932
3933\f
5500c422
GM
3934/* Mark window cursors off for all windows in the window tree rooted
3935 at W by setting their phys_cursor_on_p flag to zero. Called from
3936 xterm.c, e.g. when a frame is cleared and thereby all cursors on
3937 the frame are cleared. */
3938
3939void
3940mark_window_cursors_off (w)
3941 struct window *w;
3942{
3943 while (w)
3944 {
3945 if (!NILP (w->hchild))
3946 mark_window_cursors_off (XWINDOW (w->hchild));
3947 else if (!NILP (w->vchild))
3948 mark_window_cursors_off (XWINDOW (w->vchild));
3949 else
3950 w->phys_cursor_on_p = 0;
3951
3952 w = NILP (w->next) ? 0 : XWINDOW (w->next);
3953 }
3954}
3955
3956
e9c195b1 3957/* Return number of lines of text (not counting mode lines) in W. */
7ab12479
JB
3958
3959int
3960window_internal_height (w)
3961 struct window *w;
3962{
3963 int ht = XFASTINT (w->height);
3964
e9c195b1
GM
3965 if (!MINI_WINDOW_P (w))
3966 {
3967 if (!NILP (w->parent)
3968 || !NILP (w->vchild)
3969 || !NILP (w->hchild)
3970 || !NILP (w->next)
3971 || !NILP (w->prev)
3972 || WINDOW_WANTS_MODELINE_P (w))
3973 --ht;
7ab12479 3974
e9c195b1
GM
3975 if (WINDOW_WANTS_HEADER_LINE_P (w))
3976 --ht;
3977 }
7ab12479
JB
3978
3979 return ht;
3980}
3981
535e0b8e
JB
3982
3983/* Return the number of columns in W.
a3c87d4e 3984 Don't count columns occupied by scroll bars or the vertical bar
535e0b8e 3985 separating W from the sibling to its right. */
5500c422 3986
535e0b8e
JB
3987int
3988window_internal_width (w)
3989 struct window *w;
3990{
5500c422 3991 struct frame *f = XFRAME (WINDOW_FRAME (w));
535e0b8e
JB
3992 int width = XINT (w->width);
3993
a3c87d4e 3994 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5500c422
GM
3995 /* Scroll bars occupy a few columns. */
3996 width -= FRAME_SCROLL_BAR_COLS (f);
3997 else if (!WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
3998 /* The column of `|' characters separating side-by-side windows
3999 occupies one column only. */
4000 width -= 1;
4001
4002 /* On window-systems, areas to the left and right of the window
81d189fd 4003 are used as fringes. */
5500c422 4004 if (FRAME_WINDOW_P (f))
81d189fd 4005 width -= FRAME_FRINGE_COLS (f);
111e5992
RS
4006
4007 return width;
535e0b8e
JB
4008}
4009
5500c422
GM
4010\f
4011/************************************************************************
4012 Window Scrolling
4013 ***********************************************************************/
535e0b8e 4014
5500c422 4015/* Scroll contents of window WINDOW up. If WHOLE is non-zero, scroll
d4e7cf01 4016 N screen-fulls, which is defined as the height of the window minus
5500c422
GM
4017 next_screen_context_lines. If WHOLE is zero, scroll up N lines
4018 instead. Negative values of N mean scroll down. NOERROR non-zero
4019 means don't signal an error if we try to move over BEGV or ZV,
4020 respectively. */
7ab12479 4021
101d1605
RS
4022static void
4023window_scroll (window, n, whole, noerror)
7ab12479
JB
4024 Lisp_Object window;
4025 int n;
101d1605 4026 int whole;
f8026fd8 4027 int noerror;
5500c422
GM
4028{
4029 /* If we must, use the pixel-based version which is much slower than
4030 the line-based one but can handle varying line heights. */
4031 if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
4032 window_scroll_pixel_based (window, n, whole, noerror);
4033 else
4034 window_scroll_line_based (window, n, whole, noerror);
4035}
4036
4037
4038/* Implementation of window_scroll that works based on pixel line
4039 heights. See the comment of window_scroll for parameter
4040 descriptions. */
4041
4042static void
4043window_scroll_pixel_based (window, n, whole, noerror)
4044 Lisp_Object window;
4045 int n;
4046 int whole;
4047 int noerror;
4048{
4049 struct it it;
4050 struct window *w = XWINDOW (window);
4051 struct text_pos start;
4052 Lisp_Object tem;
4053 int this_scroll_margin;
4054 int preserve_y;
5cdb3cf3
MB
4055 /* True if we fiddled the window vscroll field without really scrolling. */
4056 int vscrolled = 0;
5500c422
GM
4057
4058 SET_TEXT_POS_FROM_MARKER (start, w->start);
4059
4060 /* If PT is not visible in WINDOW, move back one half of
288d4e06
GM
4061 the screen. Allow PT to be partially visible, otherwise
4062 something like (scroll-down 1) with PT in the line before
4063 the partially visible one would recenter. */
4064 tem = Fpos_visible_in_window_p (make_number (PT), window, Qt);
5500c422
GM
4065 if (NILP (tem))
4066 {
4067 /* Move backward half the height of the window. Performance note:
4068 vmotion used here is about 10% faster, but would give wrong
4069 results for variable height lines. */
4070 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
4071 it.current_y = it.last_visible_y;
202379cf 4072 move_it_vertically (&it, - window_box_height (w) / 2);
5500c422
GM
4073
4074 /* The function move_iterator_vertically may move over more than
4075 the specified y-distance. If it->w is small, e.g. a
4076 mini-buffer window, we may end up in front of the window's
4077 display area. This is the case when Start displaying at the
4078 start of the line containing PT in this case. */
4079 if (it.current_y <= 0)
4080 {
4081 init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
4082 move_it_vertically (&it, 0);
4083 it.current_y = 0;
4084 }
4085
4086 start = it.current.pos;
4087 }
4088
4089 /* If scroll_preserve_screen_position is non-zero, we try to set
4090 point in the same window line as it is now, so get that line. */
4091 if (!NILP (Vscroll_preserve_screen_position))
4092 {
4093 start_display (&it, w, start);
4094 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
4095 preserve_y = it.current_y;
4096 }
4097 else
4098 preserve_y = -1;
4099
4100 /* Move iterator it from start the specified distance forward or
4101 backward. The result is the new window start. */
4102 start_display (&it, w, start);
4103 if (whole)
4104 {
202379cf 4105 int screen_full = (window_box_height (w)
5500c422 4106 - next_screen_context_lines * CANON_Y_UNIT (it.f));
d4e7cf01 4107 int dy = n * screen_full;
d72340d4
GM
4108
4109 /* Note that move_it_vertically always moves the iterator to the
4110 start of a line. So, if the last line doesn't have a newline,
4111 we would end up at the start of the line ending at ZV. */
4112 if (dy <= 0)
4113 move_it_vertically_backward (&it, -dy);
4114 else if (dy > 0)
4115 move_it_to (&it, ZV, -1, it.current_y + dy, -1,
4116 MOVE_TO_POS | MOVE_TO_Y);
5500c422
GM
4117 }
4118 else
4119 move_it_by_lines (&it, n, 1);
4120
4121 /* End if we end up at ZV or BEGV. */
4122 if ((n > 0 && IT_CHARPOS (it) == ZV)
4123 || (n < 0 && IT_CHARPOS (it) == CHARPOS (start)))
4124 {
5cdb3cf3
MB
4125 if (IT_CHARPOS (it) == ZV)
4126 {
4127 if (it.current_y + it.max_ascent + it.max_descent
4128 > it.last_visible_y)
a74eca50
GM
4129 {
4130 /* The last line was only partially visible, make it fully
4131 visible. */
4132 w->vscroll = (it.last_visible_y
4133 - it.current_y + it.max_ascent + it.max_descent);
4134 adjust_glyphs (it.f);
4135 }
5cdb3cf3
MB
4136 else if (noerror)
4137 return;
4138 else
4139 Fsignal (Qend_of_buffer, Qnil);
4140 }
5500c422 4141 else
5cdb3cf3
MB
4142 {
4143 if (w->vscroll != 0)
4144 /* The first line was only partially visible, make it fully
4145 visible. */
4146 w->vscroll = 0;
4147 else if (noerror)
4148 return;
4149 else
4150 Fsignal (Qbeginning_of_buffer, Qnil);
4151 }
4152
4153 /* If control gets here, then we vscrolled. */
4154
4155 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
4156
4157 /* Don't try to change the window start below. */
4158 vscrolled = 1;
5500c422
GM
4159 }
4160
5cdb3cf3
MB
4161 if (! vscrolled)
4162 {
4163 /* Set the window start, and set up the window for redisplay. */
4164 set_marker_restricted (w->start, make_number (IT_CHARPOS (it)),
4165 w->buffer);
4166 w->start_at_line_beg = Fbolp ();
4167 w->update_mode_line = Qt;
4168 XSETFASTINT (w->last_modified, 0);
4169 XSETFASTINT (w->last_overlay_modified, 0);
4170 /* Set force_start so that redisplay_window will run the
4171 window-scroll-functions. */
4172 w->force_start = Qt;
4173 }
5500c422
GM
4174
4175 it.current_y = it.vpos = 0;
4176
4177 /* Preserve the screen position if we must. */
4178 if (preserve_y >= 0)
4179 {
4180 move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
4181 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
4182 }
4183 else
4184 {
4185 /* Move PT out of scroll margins. */
4186 this_scroll_margin = max (0, scroll_margin);
4187 this_scroll_margin = min (this_scroll_margin, XFASTINT (w->height) / 4);
4188 this_scroll_margin *= CANON_Y_UNIT (it.f);
4189
4190 if (n > 0)
4191 {
4192 /* We moved the window start towards ZV, so PT may be now
4193 in the scroll margin at the top. */
4194 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
4195 while (it.current_y < this_scroll_margin)
e9b2c961
RS
4196 {
4197 int prev = it.current_y;
4198 move_it_by_lines (&it, 1, 1);
4199 if (prev == it.current_y)
4200 break;
4201 }
5500c422
GM
4202 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
4203 }
4204 else if (n < 0)
4205 {
5cdb3cf3
MB
4206 int charpos, bytepos;
4207
5500c422
GM
4208 /* We moved the window start towards BEGV, so PT may be now
4209 in the scroll margin at the bottom. */
4210 move_it_to (&it, PT, -1,
4211 it.last_visible_y - this_scroll_margin - 1, -1,
4212 MOVE_TO_POS | MOVE_TO_Y);
5cdb3cf3
MB
4213
4214 /* Save our position, in case it's correct. */
4215 charpos = IT_CHARPOS (it);
4216 bytepos = IT_BYTEPOS (it);
5500c422 4217
5cdb3cf3
MB
4218 /* See if point is on a partially visible line at the end. */
4219 move_it_by_lines (&it, 1, 1);
4220 if (it.current_y > it.last_visible_y)
4221 /* The last line was only partially visible, so back up two
4222 lines to make sure we're on a fully visible line. */
4223 {
4224 move_it_by_lines (&it, -2, 0);
4225 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
4226 }
4227 else
4228 /* No, the position we saved is OK, so use it. */
4229 SET_PT_BOTH (charpos, bytepos);
5500c422
GM
4230 }
4231 }
4232}
4233
4234
4235/* Implementation of window_scroll that works based on screen lines.
4236 See the comment of window_scroll for parameter descriptions. */
4237
4238static void
4239window_scroll_line_based (window, n, whole, noerror)
4240 Lisp_Object window;
4241 int n;
4242 int whole;
4243 int noerror;
7ab12479
JB
4244{
4245 register struct window *w = XWINDOW (window);
5500c422 4246 register int opoint = PT, opoint_byte = PT_BYTE;
b73ea88e 4247 register int pos, pos_byte;
7ab12479
JB
4248 register int ht = window_internal_height (w);
4249 register Lisp_Object tem;
4250 int lose;
5500c422 4251 Lisp_Object bolp;
345d45b2 4252 int startpos;
101d1605
RS
4253 struct position posit;
4254 int original_vpos;
4255
d4e7cf01
GM
4256 /* If scrolling screen-fulls, compute the number of lines to
4257 scroll from the window's height. */
4258 if (whole)
4259 n *= max (1, ht - next_screen_context_lines);
4260
101d1605
RS
4261 startpos = marker_position (w->start);
4262
4263 posit = *compute_motion (startpos, 0, 0, 0,
4264 PT, ht, 0,
4265 window_internal_width (w), XINT (w->hscroll),
4266 0, w);
4267 original_vpos = posit.vpos;
0a1f771a 4268
d834a2e9 4269 XSETFASTINT (tem, PT);
6ffdb539 4270 tem = Fpos_visible_in_window_p (tem, window, Qnil);
7ab12479 4271
265a9e55 4272 if (NILP (tem))
7ab12479 4273 {
cd2be1dd 4274 Fvertical_motion (make_number (- (ht / 2)), window);
345d45b2 4275 startpos = PT;
7ab12479
JB
4276 }
4277
345d45b2 4278 SET_PT (startpos);
5ce7b543 4279 lose = n < 0 && PT == BEGV;
540b6aa0 4280 Fvertical_motion (make_number (n), window);
5ce7b543 4281 pos = PT;
b73ea88e 4282 pos_byte = PT_BYTE;
7ab12479 4283 bolp = Fbolp ();
b73ea88e 4284 SET_PT_BOTH (opoint, opoint_byte);
7ab12479
JB
4285
4286 if (lose)
f8026fd8
JB
4287 {
4288 if (noerror)
4289 return;
4290 else
4291 Fsignal (Qbeginning_of_buffer, Qnil);
4292 }
7ab12479
JB
4293
4294 if (pos < ZV)
7ab12479 4295 {
0c7da84e
RS
4296 int this_scroll_margin = scroll_margin;
4297
4298 /* Don't use a scroll margin that is negative or too large. */
4299 if (this_scroll_margin < 0)
4300 this_scroll_margin = 0;
4301
4302 if (XINT (w->height) < 4 * scroll_margin)
4303 this_scroll_margin = XINT (w->height) / 4;
4304
b73ea88e 4305 set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
7ab12479
JB
4306 w->start_at_line_beg = bolp;
4307 w->update_mode_line = Qt;
d834a2e9 4308 XSETFASTINT (w->last_modified, 0);
3cd21523 4309 XSETFASTINT (w->last_overlay_modified, 0);
345d45b2
RS
4310 /* Set force_start so that redisplay_window will run
4311 the window-scroll-functions. */
4312 w->force_start = Qt;
0c7da84e 4313
5500c422 4314 if (whole && !NILP (Vscroll_preserve_screen_position))
0c7da84e 4315 {
b73ea88e 4316 SET_PT_BOTH (pos, pos_byte);
101d1605 4317 Fvertical_motion (make_number (original_vpos), window);
0c7da84e 4318 }
101d1605
RS
4319 /* If we scrolled forward, put point enough lines down
4320 that it is outside the scroll margin. */
4321 else if (n > 0)
0c7da84e 4322 {
101d1605
RS
4323 int top_margin;
4324
4325 if (this_scroll_margin > 0)
4326 {
b73ea88e 4327 SET_PT_BOTH (pos, pos_byte);
101d1605
RS
4328 Fvertical_motion (make_number (this_scroll_margin), window);
4329 top_margin = PT;
4330 }
4331 else
4332 top_margin = pos;
4333
4334 if (top_margin <= opoint)
b73ea88e 4335 SET_PT_BOTH (opoint, opoint_byte);
5500c422 4336 else if (!NILP (Vscroll_preserve_screen_position))
101d1605 4337 {
b73ea88e 4338 SET_PT_BOTH (pos, pos_byte);
101d1605
RS
4339 Fvertical_motion (make_number (original_vpos), window);
4340 }
9317a85d 4341 else
335406fc 4342 SET_PT (top_margin);
0c7da84e 4343 }
101d1605 4344 else if (n < 0)
7ab12479 4345 {
101d1605
RS
4346 int bottom_margin;
4347
0c7da84e
RS
4348 /* If we scrolled backward, put point near the end of the window
4349 but not within the scroll margin. */
b73ea88e 4350 SET_PT_BOTH (pos, pos_byte);
0c7da84e 4351 tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
101d1605
RS
4352 if (XFASTINT (tem) == ht - this_scroll_margin)
4353 bottom_margin = PT;
4354 else
4355 bottom_margin = PT + 1;
4356
4357 if (bottom_margin > opoint)
b73ea88e 4358 SET_PT_BOTH (opoint, opoint_byte);
7ab12479 4359 else
101d1605 4360 {
5500c422 4361 if (!NILP (Vscroll_preserve_screen_position))
9317a85d 4362 {
b73ea88e 4363 SET_PT_BOTH (pos, pos_byte);
9317a85d
RS
4364 Fvertical_motion (make_number (original_vpos), window);
4365 }
4366 else
4367 Fvertical_motion (make_number (-1), window);
101d1605 4368 }
7ab12479
JB
4369 }
4370 }
4371 else
f8026fd8
JB
4372 {
4373 if (noerror)
4374 return;
4375 else
4376 Fsignal (Qend_of_buffer, Qnil);
4377 }
7ab12479 4378}
5500c422
GM
4379
4380
4381/* Scroll selected_window up or down. If N is nil, scroll a
4382 screen-full which is defined as the height of the window minus
4383 next_screen_context_lines. If N is the symbol `-', scroll.
4384 DIRECTION may be 1 meaning to scroll down, or -1 meaning to scroll
4385 up. This is the guts of Fscroll_up and Fscroll_down. */
7ab12479
JB
4386
4387static void
4388scroll_command (n, direction)
5500c422 4389 Lisp_Object n;
7ab12479
JB
4390 int direction;
4391{
d4e7cf01 4392 int count = BINDING_STACK_SIZE ();
7ab12479 4393
5500c422
GM
4394 xassert (abs (direction) == 1);
4395
4396 /* If selected window's buffer isn't current, make it current for
4397 the moment. But don't screw up if window_scroll gets an error. */
7ab12479 4398 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
95605e15
JB
4399 {
4400 record_unwind_protect (save_excursion_restore, save_excursion_save ());
4401 Fset_buffer (XWINDOW (selected_window)->buffer);
5500c422
GM
4402
4403 /* Make redisplay consider other windows than just selected_window. */
4404 ++windows_or_buffers_changed;
95605e15 4405 }
7ab12479 4406
265a9e55 4407 if (NILP (n))
d4e7cf01 4408 window_scroll (selected_window, direction, 1, 0);
7ab12479 4409 else if (EQ (n, Qminus))
d4e7cf01 4410 window_scroll (selected_window, -direction, 1, 0);
7ab12479
JB
4411 else
4412 {
4413 n = Fprefix_numeric_value (n);
101d1605 4414 window_scroll (selected_window, XINT (n) * direction, 0, 0);
7ab12479 4415 }
95605e15
JB
4416
4417 unbind_to (count, Qnil);
7ab12479
JB
4418}
4419
4420DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
fdb82f93
PJ
4421 doc: /* Scroll text of current window upward ARG lines; or near full screen if no ARG.
4422A near full screen is `next-screen-context-lines' less than a full screen.
4423Negative ARG means scroll downward.
4424If ARG is the atom `-', scroll downward by nearly full screen.
4425When calling from a program, supply as argument a number, nil, or `-'. */)
4426 (arg)
413430c5 4427 Lisp_Object arg;
7ab12479 4428{
413430c5 4429 scroll_command (arg, 1);
7ab12479
JB
4430 return Qnil;
4431}
4432
4433DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
fdb82f93
PJ
4434 doc: /* Scroll text of current window down ARG lines; or near full screen if no ARG.
4435A near full screen is `next-screen-context-lines' less than a full screen.
4436Negative ARG means scroll upward.
4437If ARG is the atom `-', scroll upward by nearly full screen.
4438When calling from a program, supply as argument a number, nil, or `-'. */)
4439 (arg)
413430c5 4440 Lisp_Object arg;
7ab12479 4441{
413430c5 4442 scroll_command (arg, -1);
7ab12479
JB
4443 return Qnil;
4444}
ccd0664b
RS
4445\f
4446DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0,
fdb82f93
PJ
4447 doc: /* Return the other window for \"other window scroll\" commands.
4448If in the minibuffer, `minibuffer-scroll-window' if non-nil
4449specifies the window.
4450If `other-window-scroll-buffer' is non-nil, a window
4451showing that buffer is used. */)
4452 ()
7ab12479 4453{
ccd0664b 4454 Lisp_Object window;
7ab12479
JB
4455
4456 if (MINI_WINDOW_P (XWINDOW (selected_window))
265a9e55 4457 && !NILP (Vminibuf_scroll_window))
7ab12479
JB
4458 window = Vminibuf_scroll_window;
4459 /* If buffer is specified, scroll that buffer. */
265a9e55 4460 else if (!NILP (Vother_window_scroll_buffer))
7ab12479
JB
4461 {
4462 window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
265a9e55 4463 if (NILP (window))
53f76081 4464 window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt, Qnil);
7ab12479
JB
4465 }
4466 else
dbc4e1c1
JB
4467 {
4468 /* Nothing specified; look for a neighboring window on the same
4469 frame. */
4470 window = Fnext_window (selected_window, Qnil, Qnil);
4471
4472 if (EQ (window, selected_window))
4473 /* That didn't get us anywhere; look for a window on another
4474 visible frame. */
4475 do
4476 window = Fnext_window (window, Qnil, Qt);
4477 while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
4478 && ! EQ (window, selected_window));
4479 }
4480
b7826503 4481 CHECK_LIVE_WINDOW (window);
7ab12479
JB
4482
4483 if (EQ (window, selected_window))
4484 error ("There is no other window");
4485
ccd0664b
RS
4486 return window;
4487}
4488
4489DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
fdb82f93
PJ
4490 doc: /* Scroll next window upward ARG lines; or near full screen if no ARG.
4491A near full screen is `next-screen-context-lines' less than a full screen.
4492The next window is the one below the current one; or the one at the top
4493if the current one is at the bottom. Negative ARG means scroll downward.
4494If ARG is the atom `-', scroll downward by nearly full screen.
4495When calling from a program, supply as argument a number, nil, or `-'.
4496
4497If in the minibuffer, `minibuffer-scroll-window' if non-nil
4498specifies the window to scroll.
4499If `other-window-scroll-buffer' is non-nil, scroll the window
4500showing that buffer, popping the buffer up if necessary. */)
4501 (arg)
d4e7cf01 4502 Lisp_Object arg;
ccd0664b 4503{
d4e7cf01
GM
4504 Lisp_Object window;
4505 struct window *w;
4506 int count = BINDING_STACK_SIZE ();
ccd0664b
RS
4507
4508 window = Fother_window_for_scrolling ();
7ab12479 4509 w = XWINDOW (window);
7ab12479
JB
4510
4511 /* Don't screw up if window_scroll gets an error. */
4512 record_unwind_protect (save_excursion_restore, save_excursion_save ());
5500c422 4513 ++windows_or_buffers_changed;
7ab12479
JB
4514
4515 Fset_buffer (w->buffer);
4516 SET_PT (marker_position (w->pointm));
4517
413430c5 4518 if (NILP (arg))
d4e7cf01 4519 window_scroll (window, 1, 1, 1);
413430c5 4520 else if (EQ (arg, Qminus))
d4e7cf01 4521 window_scroll (window, -1, 1, 1);
7ab12479
JB
4522 else
4523 {
413430c5
EN
4524 if (CONSP (arg))
4525 arg = Fcar (arg);
b7826503 4526 CHECK_NUMBER (arg);
101d1605 4527 window_scroll (window, XINT (arg), 0, 1);
7ab12479
JB
4528 }
4529
b73ea88e 4530 set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
f4e7b2c2 4531 unbind_to (count, Qnil);
7ab12479
JB
4532
4533 return Qnil;
4534}
4535\f
644b477c 4536DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 1, "P",
fdb82f93 4537 doc: /* Scroll selected window display ARG columns left.
2fe41216
EZ
4538Default for ARG is window width minus 2.
4539Value is the total amount of leftward horizontal scrolling in
4540effect after the change.
4541If `automatic-hscrolling' is non-nil, the argument ARG modifies
4542a lower bound for automatic scrolling, i.e. automatic scrolling
4543will not scroll a window to a column less than the value returned
4544by this function. */)
fdb82f93 4545 (arg)
7ab12479
JB
4546 register Lisp_Object arg;
4547{
c67fa410
GM
4548 Lisp_Object result;
4549 int hscroll;
4550 struct window *w = XWINDOW (selected_window);
4551
265a9e55 4552 if (NILP (arg))
c67fa410 4553 XSETFASTINT (arg, window_internal_width (w) - 2);
7ab12479
JB
4554 else
4555 arg = Fprefix_numeric_value (arg);
4556
c67fa410
GM
4557 hscroll = XINT (w->hscroll) + XINT (arg);
4558 result = Fset_window_hscroll (selected_window, make_number (hscroll));
4559
f5686fbd 4560 if (interactive_p (0))
c67fa410
GM
4561 w->min_hscroll = w->hscroll;
4562
4563 return result;
7ab12479
JB
4564}
4565
644b477c 4566DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 1, "P",
fdb82f93 4567 doc: /* Scroll selected window display ARG columns right.
2fe41216
EZ
4568Default for ARG is window width minus 2.
4569Value is the total amount of leftward horizontal scrolling in
4570effect after the change.
4571If `automatic-hscrolling' is non-nil, the argument ARG modifies
4572a lower bound for automatic scrolling, i.e. automatic scrolling
4573will not scroll a window to a column less than the value returned
4574by this function. */)
fdb82f93 4575 (arg)
7ab12479
JB
4576 register Lisp_Object arg;
4577{
c67fa410
GM
4578 Lisp_Object result;
4579 int hscroll;
4580 struct window *w = XWINDOW (selected_window);
4581
265a9e55 4582 if (NILP (arg))
c67fa410 4583 XSETFASTINT (arg, window_internal_width (w) - 2);
7ab12479
JB
4584 else
4585 arg = Fprefix_numeric_value (arg);
4586
c67fa410
GM
4587 hscroll = XINT (w->hscroll) - XINT (arg);
4588 result = Fset_window_hscroll (selected_window, make_number (hscroll));
4589
f5686fbd 4590 if (interactive_p (0))
c67fa410
GM
4591 w->min_hscroll = w->hscroll;
4592
4593 return result;
7ab12479
JB
4594}
4595
fa832261
KS
4596DEFUN ("minibuffer-selected-window", Fminibuffer_selected_window, Sminibuffer_selected_window, 0, 0, 0,
4597 doc: /* Return the window which was selected when entering the minibuffer.
4598Returns nil, if current window is not a minibuffer window. */)
4599 ()
4600{
4601 if (minibuf_level > 0
4602 && MINI_WINDOW_P (XWINDOW (selected_window))
4603 && !NILP (minibuf_selected_window)
4604 && WINDOW_LIVE_P (minibuf_selected_window))
4605 return minibuf_selected_window;
4606
4607 return Qnil;
4608}
4609
12c8b416
GM
4610/* Value is the number of lines actually displayed in window W,
4611 as opposed to its height. */
4612
4613static int
4614displayed_window_lines (w)
4615 struct window *w;
4616{
4617 struct it it;
4618 struct text_pos start;
4619 int height = window_box_height (w);
4620 struct buffer *old_buffer;
4621 int bottom_y;
4622
4623 if (XBUFFER (w->buffer) != current_buffer)
4624 {
4625 old_buffer = current_buffer;
4626 set_buffer_internal (XBUFFER (w->buffer));
4627 }
4628 else
4629 old_buffer = NULL;
4630
521b203e
GM
4631 /* In case W->start is out of the accessible range, do something
4632 reasonable. This happens in Info mode when Info-scroll-down
4633 calls (recenter -1) while W->start is 1. */
4634 if (XMARKER (w->start)->charpos < BEGV)
4635 SET_TEXT_POS (start, BEGV, BEGV_BYTE);
4636 else if (XMARKER (w->start)->charpos > ZV)
4637 SET_TEXT_POS (start, ZV, ZV_BYTE);
4638 else
4639 SET_TEXT_POS_FROM_MARKER (start, w->start);
4640
12c8b416
GM
4641 start_display (&it, w, start);
4642 move_it_vertically (&it, height);
c8bc6f65 4643 bottom_y = line_bottom_y (&it);
12c8b416
GM
4644
4645 /* Add in empty lines at the bottom of the window. */
4646 if (bottom_y < height)
4647 {
c8bc6f65
GM
4648 int uy = CANON_Y_UNIT (it.f);
4649 it.vpos += (height - bottom_y + uy - 1) / uy;
12c8b416
GM
4650 }
4651
c8bc6f65
GM
4652 if (old_buffer)
4653 set_buffer_internal (old_buffer);
4654
12c8b416
GM
4655 return it.vpos;
4656}
4657
4658
7ab12479 4659DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
fdb82f93
PJ
4660 doc: /* Center point in window and redisplay frame.
4661With prefix argument ARG, recenter putting point on screen line ARG
4662relative to the current window. If ARG is negative, it counts up from the
4663bottom of the window. (ARG should be less than the height of the window.)
4664
4665If ARG is omitted or nil, erase the entire frame and then
4666redraw with point in the center of the current window.
4667Just C-u as prefix means put point in the center of the window
4668and redisplay normally--don't erase and redraw the frame. */)
4669 (arg)
413430c5 4670 register Lisp_Object arg;
7ab12479 4671{
6df47b59 4672 struct window *w = XWINDOW (selected_window);
478292ed
RS
4673 struct buffer *buf = XBUFFER (w->buffer);
4674 struct buffer *obuf = current_buffer;
6df47b59
GM
4675 int center_p = 0;
4676 int charpos, bytepos;
7ab12479 4677
0fa5d25b
RS
4678 /* If redisplay is suppressed due to an error, try again. */
4679 obuf->display_error_modiff = 0;
4680
413430c5 4681 if (NILP (arg))
7ab12479 4682 {
f02d6d5c
KH
4683 int i;
4684
4685 /* Invalidate pixel data calculated for all compositions. */
4686 for (i = 0; i < n_compositions; i++)
4687 composition_table[i]->font = NULL;
7ab12479 4688
527b6458 4689 Fredraw_frame (w->frame);
44fa5b1e 4690 SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
6df47b59 4691 center_p = 1;
7ab12479 4692 }
413430c5 4693 else if (CONSP (arg)) /* Just C-u. */
6df47b59 4694 center_p = 1;
7ab12479
JB
4695 else
4696 {
413430c5 4697 arg = Fprefix_numeric_value (arg);
b7826503 4698 CHECK_NUMBER (arg);
7ab12479
JB
4699 }
4700
478292ed 4701 set_buffer_internal (buf);
7ab12479 4702
521b203e 4703 /* Handle centering on a graphical frame specially. Such frames can
6df47b59
GM
4704 have variable-height lines and centering point on the basis of
4705 line counts would lead to strange effects. */
521b203e 4706 if (FRAME_WINDOW_P (XFRAME (w->frame)))
6df47b59 4707 {
6df47b59
GM
4708 if (center_p)
4709 {
521b203e
GM
4710 struct it it;
4711 struct text_pos pt;
4712
4713 SET_TEXT_POS (pt, PT, PT_BYTE);
4714 start_display (&it, w, pt);
202379cf 4715 move_it_vertically (&it, - window_box_height (w) / 2);
521b203e
GM
4716 charpos = IT_CHARPOS (it);
4717 bytepos = IT_BYTEPOS (it);
6df47b59
GM
4718 }
4719 else if (XINT (arg) < 0)
4720 {
521b203e
GM
4721 struct it it;
4722 struct text_pos pt;
d466fa4d 4723 int y0, y1, h, nlines;
521b203e
GM
4724
4725 SET_TEXT_POS (pt, PT, PT_BYTE);
4726 start_display (&it, w, pt);
4727 y0 = it.current_y;
4728
d466fa4d 4729 /* The amount of pixels we have to move back is the window
521b203e
GM
4730 height minus what's displayed in the line containing PT,
4731 and the lines below. */
d466fa4d
GM
4732 nlines = - XINT (arg) - 1;
4733 move_it_by_lines (&it, nlines, 1);
4734
201c831a 4735 y1 = line_bottom_y (&it);
d466fa4d
GM
4736
4737 /* If we can't move down NLINES lines because we hit
4738 the end of the buffer, count in some empty lines. */
4739 if (it.vpos < nlines)
4740 y1 += (nlines - it.vpos) * CANON_Y_UNIT (it.f);
4741
201c831a
GM
4742 h = window_box_height (w) - (y1 - y0);
4743
521b203e 4744 start_display (&it, w, pt);
201c831a 4745 move_it_vertically (&it, - h);
521b203e
GM
4746 charpos = IT_CHARPOS (it);
4747 bytepos = IT_BYTEPOS (it);
6df47b59 4748 }
521b203e
GM
4749 else
4750 {
4751 struct position pos;
4752 pos = *vmotion (PT, - XINT (arg), w);
4753 charpos = pos.bufpos;
4754 bytepos = pos.bytepos;
4755 }
4756 }
4757 else
4758 {
4759 struct position pos;
4760 int ht = window_internal_height (w);
4761
4762 if (center_p)
4763 arg = make_number (ht / 2);
4764 else if (XINT (arg) < 0)
4765 arg = make_number (XINT (arg) + ht);
6df47b59
GM
4766
4767 pos = *vmotion (PT, - XINT (arg), w);
4768 charpos = pos.bufpos;
4769 bytepos = pos.bytepos;
4770 }
4771
4772 /* Set the new window start. */
4773 set_marker_both (w->start, w->buffer, charpos, bytepos);
2f3cad6c 4774 w->window_end_valid = Qnil;
7ab12479 4775 w->force_start = Qt;
6df47b59
GM
4776 if (bytepos == BEGV_BYTE || FETCH_BYTE (bytepos - 1) == '\n')
4777 w->start_at_line_beg = Qt;
4778 else
4779 w->start_at_line_beg = Qnil;
4780
478292ed 4781 set_buffer_internal (obuf);
7ab12479
JB
4782 return Qnil;
4783}
b7617575
GM
4784
4785
81fe0836 4786DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height,
fdb82f93
PJ
4787 0, 1, 0,
4788 doc: /* Return the height in lines of the text display area of WINDOW.
4789This doesn't include the mode-line (or header-line if any) or any
4790partial-height lines in the text display area. */)
4791 (window)
81fe0836
MB
4792 Lisp_Object window;
4793{
4794 struct window *w = decode_window (window);
4795 int pixel_height = window_box_height (w);
4796 int line_height = pixel_height / CANON_Y_UNIT (XFRAME (w->frame));
4797 return make_number (line_height);
4798}
4799
4800
7ab12479
JB
4801\f
4802DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
fdb82f93
PJ
4803 1, 1, "P",
4804 doc: /* Position point relative to window.
4805With no argument, position point at center of window.
4806An argument specifies vertical position within the window;
4807zero means top of window, negative means relative to bottom of window. */)
4808 (arg)
b7617575 4809 Lisp_Object arg;
7ab12479 4810{
b7617575
GM
4811 struct window *w = XWINDOW (selected_window);
4812 int lines, start;
540b6aa0 4813 Lisp_Object window;
7ab12479 4814
b7617575 4815 window = selected_window;
7ab12479
JB
4816 start = marker_position (w->start);
4817 if (start < BEGV || start > ZV)
4818 {
b7617575 4819 int height = window_internal_height (w);
cd2be1dd 4820 Fvertical_motion (make_number (- (height / 2)), window);
b73ea88e 4821 set_marker_both (w->start, w->buffer, PT, PT_BYTE);
7ab12479
JB
4822 w->start_at_line_beg = Fbolp ();
4823 w->force_start = Qt;
4824 }
4825 else
b73ea88e 4826 Fgoto_char (w->start);
7ab12479 4827
b7617575
GM
4828 lines = displayed_window_lines (w);
4829 if (NILP (arg))
4830 XSETFASTINT (arg, lines / 2);
4831 else
4832 {
4833 arg = Fprefix_numeric_value (arg);
4834 if (XINT (arg) < 0)
4835 XSETINT (arg, XINT (arg) + lines);
4836 }
4837
c8bc6f65 4838 /* Skip past a partially visible first line. */
163784df 4839 if (w->vscroll)
163784df
MB
4840 XSETINT (arg, XINT (arg) + 1);
4841
540b6aa0 4842 return Fvertical_motion (arg, window);
7ab12479 4843}
5500c422
GM
4844
4845
7ab12479 4846\f
5500c422
GM
4847/***********************************************************************
4848 Window Configuration
4849 ***********************************************************************/
4850
7ab12479
JB
4851struct save_window_data
4852 {
f5ccc0cc 4853 EMACS_INT size_from_Lisp_Vector_struct;
7ab12479 4854 struct Lisp_Vector *next_from_Lisp_Vector_struct;
8f6ea2e9 4855 Lisp_Object frame_width, frame_height, frame_menu_bar_lines;
9ea173e8 4856 Lisp_Object frame_tool_bar_lines;
bdc727bf 4857 Lisp_Object selected_frame;
7ab12479
JB
4858 Lisp_Object current_window;
4859 Lisp_Object current_buffer;
4860 Lisp_Object minibuf_scroll_window;
3f49fddc 4861 Lisp_Object minibuf_selected_window;
7ab12479 4862 Lisp_Object root_window;
bdc727bf 4863 Lisp_Object focus_frame;
756b6edc
RS
4864 /* Record the values of window-min-width and window-min-height
4865 so that window sizes remain consistent with them. */
4866 Lisp_Object min_width, min_height;
cbff28e8
RS
4867 /* A vector, each of whose elements is a struct saved_window
4868 for one window. */
7ab12479
JB
4869 Lisp_Object saved_windows;
4870 };
ff06df24 4871
cbff28e8 4872/* This is saved as a Lisp_Vector */
7ab12479 4873struct saved_window
ea68264b
GM
4874{
4875 /* these first two must agree with struct Lisp_Vector in lisp.h */
4876 EMACS_INT size_from_Lisp_Vector_struct;
4877 struct Lisp_Vector *next_from_Lisp_Vector_struct;
7ab12479 4878
ea68264b
GM
4879 Lisp_Object window;
4880 Lisp_Object buffer, start, pointm, mark;
4881 Lisp_Object left, top, width, height, hscroll, min_hscroll;
4882 Lisp_Object parent, prev;
4883 Lisp_Object start_at_line_beg;
4884 Lisp_Object display_table;
4885 Lisp_Object orig_top, orig_height;
4886};
4887
4888#define SAVED_WINDOW_VECTOR_SIZE 17 /* Arg to Fmake_vector */
7ab12479
JB
4889
4890#define SAVED_WINDOW_N(swv,n) \
4891 ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
4892
4893DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
fdb82f93
PJ
4894 doc: /* Return t if OBJECT is a window-configuration object. */)
4895 (object)
413430c5 4896 Lisp_Object object;
7ab12479 4897{
413430c5 4898 if (WINDOW_CONFIGURATIONP (object))
7ab12479
JB
4899 return Qt;
4900 return Qnil;
4901}
4902
3f8ab7bd 4903DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
fdb82f93
PJ
4904 doc: /* Return the frame that CONFIG, a window-configuration object, is about. */)
4905 (config)
3f8ab7bd
RS
4906 Lisp_Object config;
4907{
4908 register struct save_window_data *data;
4909 struct Lisp_Vector *saved_windows;
4910
4911 if (! WINDOW_CONFIGURATIONP (config))
4912 wrong_type_argument (Qwindow_configuration_p, config);
4913
4914 data = (struct save_window_data *) XVECTOR (config);
4915 saved_windows = XVECTOR (data->saved_windows);
4916 return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
4917}
4918
d5b2799e 4919DEFUN ("set-window-configuration", Fset_window_configuration,
fdb82f93
PJ
4920 Sset_window_configuration, 1, 1, 0,
4921 doc: /* Set the configuration of windows and buffers as specified by CONFIGURATION.
4922CONFIGURATION must be a value previously returned
4923by `current-window-configuration' (which see).
4924If CONFIGURATION was made from a frame that is now deleted,
4925only frame-independent values can be restored. In this case,
4926the return value is nil. Otherwise the value is t. */)
4927 (configuration)
2f83aebe 4928 Lisp_Object configuration;
7ab12479 4929{
7ab12479
JB
4930 register struct save_window_data *data;
4931 struct Lisp_Vector *saved_windows;
7ab12479 4932 Lisp_Object new_current_buffer;
fd482be5 4933 Lisp_Object frame;
44fa5b1e 4934 FRAME_PTR f;
d2b35234 4935 int old_point = -1;
7ab12479 4936
017b2bad 4937 while (!WINDOW_CONFIGURATIONP (configuration))
3f8ab7bd 4938 wrong_type_argument (Qwindow_configuration_p, configuration);
7ab12479 4939
2f83aebe 4940 data = (struct save_window_data *) XVECTOR (configuration);
7ab12479
JB
4941 saved_windows = XVECTOR (data->saved_windows);
4942
7ab12479 4943 new_current_buffer = data->current_buffer;
265a9e55 4944 if (NILP (XBUFFER (new_current_buffer)->name))
7ab12479 4945 new_current_buffer = Qnil;
d2b35234
RS
4946 else
4947 {
4948 if (XBUFFER (new_current_buffer) == current_buffer)
4949 old_point = PT;
4950 }
7ab12479 4951
fd482be5
JB
4952 frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
4953 f = XFRAME (frame);
aa35ba9e 4954
fd482be5
JB
4955 /* If f is a dead frame, don't bother rebuilding its window tree.
4956 However, there is other stuff we should still try to do below. */
4957 if (FRAME_LIVE_P (f))
7ab12479 4958 {
fd482be5
JB
4959 register struct window *w;
4960 register struct saved_window *p;
5500c422
GM
4961 struct window *root_window;
4962 struct window **leaf_windows;
4963 int n_leaf_windows;
c4280705 4964 int k, i, n;
fd482be5
JB
4965
4966 /* If the frame has been resized since this window configuration was
4967 made, we change the frame to the size specified in the
4968 configuration, restore the configuration, and then resize it
4969 back. We keep track of the prevailing height in these variables. */
4970 int previous_frame_height = FRAME_HEIGHT (f);
4971 int previous_frame_width = FRAME_WIDTH (f);
8f6ea2e9 4972 int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
9ea173e8 4973 int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
fd482be5 4974
d2b35234
RS
4975 /* The mouse highlighting code could get screwed up
4976 if it runs during this. */
4977 BLOCK_INPUT;
4978
fd482be5
JB
4979 if (XFASTINT (data->frame_height) != previous_frame_height
4980 || XFASTINT (data->frame_width) != previous_frame_width)
f8ad443a 4981 change_frame_size (f, XFASTINT (data->frame_height),
2b653806 4982 XFASTINT (data->frame_width), 0, 0, 0);
e3678b64 4983#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
8f6ea2e9
KH
4984 if (XFASTINT (data->frame_menu_bar_lines)
4985 != previous_frame_menu_bar_lines)
f8ad443a 4986 x_set_menu_bar_lines (f, data->frame_menu_bar_lines, make_number (0));
4314246f 4987#ifdef HAVE_WINDOW_SYSTEM
9ea173e8
GM
4988 if (XFASTINT (data->frame_tool_bar_lines)
4989 != previous_frame_tool_bar_lines)
4990 x_set_tool_bar_lines (f, data->frame_tool_bar_lines, make_number (0));
4314246f 4991#endif
217f2871 4992#endif
fd482be5 4993
719eaeb1
GM
4994 /* "Swap out" point from the selected window
4995 into its buffer. We do this now, before
4996 restoring the window contents, and prevent it from
4997 being done later on when we select a new window. */
596ae0cf
RS
4998 if (! NILP (XWINDOW (selected_window)->buffer))
4999 {
5000 w = XWINDOW (selected_window);
5001 set_marker_both (w->pointm,
5002 w->buffer,
5003 BUF_PT (XBUFFER (w->buffer)),
5004 BUF_PT_BYTE (XBUFFER (w->buffer)));
5005 }
5006
fd482be5 5007 windows_or_buffers_changed++;
29aeee73 5008 FRAME_WINDOW_SIZES_CHANGED (f) = 1;
fd482be5 5009
5500c422
GM
5010 /* Problem: Freeing all matrices and later allocating them again
5011 is a serious redisplay flickering problem. What we would
5012 really like to do is to free only those matrices not reused
5013 below. */
5014 root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
5015 leaf_windows
5016 = (struct window **) alloca (count_windows (root_window)
5017 * sizeof (struct window *));
5018 n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
5019
756b6edc
RS
5020 /* Temporarily avoid any problems with windows that are smaller
5021 than they are supposed to be. */
5022 window_min_height = 1;
5023 window_min_width = 1;
5024
fd482be5
JB
5025 /* Kludge Alert!
5026 Mark all windows now on frame as "deleted".
5027 Restoring the new configuration "undeletes" any that are in it.
37962e60 5028
fd482be5
JB
5029 Save their current buffers in their height fields, since we may
5030 need it later, if a buffer saved in the configuration is now
5031 dead. */
5032 delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
5033
5034 for (k = 0; k < saved_windows->size; k++)
5035 {
5036 p = SAVED_WINDOW_N (saved_windows, k);
5037 w = XWINDOW (p->window);
5038 w->next = Qnil;
7ab12479 5039
fd482be5
JB
5040 if (!NILP (p->parent))
5041 w->parent = SAVED_WINDOW_N (saved_windows,
5042 XFASTINT (p->parent))->window;
5043 else
5044 w->parent = Qnil;
7ab12479 5045
fd482be5 5046 if (!NILP (p->prev))
7ab12479 5047 {
fd482be5
JB
5048 w->prev = SAVED_WINDOW_N (saved_windows,
5049 XFASTINT (p->prev))->window;
5050 XWINDOW (w->prev)->next = p->window;
5051 }
5052 else
5053 {
5054 w->prev = Qnil;
5055 if (!NILP (w->parent))
5056 {
5057 if (EQ (p->width, XWINDOW (w->parent)->width))
5058 {
5059 XWINDOW (w->parent)->vchild = p->window;
5060 XWINDOW (w->parent)->hchild = Qnil;
5061 }
5062 else
5063 {
5064 XWINDOW (w->parent)->hchild = p->window;
5065 XWINDOW (w->parent)->vchild = Qnil;
5066 }
5067 }
5068 }
5069
5070 /* If we squirreled away the buffer in the window's height,
5071 restore it now. */
017b2bad 5072 if (BUFFERP (w->height))
fd482be5
JB
5073 w->buffer = w->height;
5074 w->left = p->left;
5075 w->top = p->top;
5076 w->width = p->width;
5077 w->height = p->height;
5078 w->hscroll = p->hscroll;
ea68264b 5079 w->min_hscroll = p->min_hscroll;
fd482be5 5080 w->display_table = p->display_table;
a1d58e5b
GM
5081 w->orig_top = p->orig_top;
5082 w->orig_height = p->orig_height;
d834a2e9 5083 XSETFASTINT (w->last_modified, 0);
3cd21523 5084 XSETFASTINT (w->last_overlay_modified, 0);
fd482be5
JB
5085
5086 /* Reinstall the saved buffer and pointers into it. */
5087 if (NILP (p->buffer))
5088 w->buffer = p->buffer;
5089 else
5090 {
5091 if (!NILP (XBUFFER (p->buffer)->name))
5092 /* If saved buffer is alive, install it. */
5093 {
5094 w->buffer = p->buffer;
5095 w->start_at_line_beg = p->start_at_line_beg;
b73ea88e
RS
5096 set_marker_restricted (w->start, p->start, w->buffer);
5097 set_marker_restricted (w->pointm, p->pointm, w->buffer);
fd482be5 5098 Fset_marker (XBUFFER (w->buffer)->mark,
b73ea88e 5099 p->mark, w->buffer);
fd482be5
JB
5100
5101 /* As documented in Fcurrent_window_configuration, don't
5102 save the location of point in the buffer which was current
5103 when the window configuration was recorded. */
6b54027b
RS
5104 if (!EQ (p->buffer, new_current_buffer)
5105 && XBUFFER (p->buffer) == current_buffer)
fd482be5
JB
5106 Fgoto_char (w->pointm);
5107 }
52a68e98
RS
5108 else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
5109 /* Else unless window has a live buffer, get one. */
7ab12479 5110 {
fd482be5
JB
5111 w->buffer = Fcdr (Fcar (Vbuffer_alist));
5112 /* This will set the markers to beginning of visible
5113 range. */
5114 set_marker_restricted (w->start, make_number (0), w->buffer);
5115 set_marker_restricted (w->pointm, make_number (0),w->buffer);
5116 w->start_at_line_beg = Qt;
7ab12479
JB
5117 }
5118 else
fd482be5 5119 /* Keeping window's old buffer; make sure the markers
52a68e98 5120 are real. */
7ab12479 5121 {
fd482be5
JB
5122 /* Set window markers at start of visible range. */
5123 if (XMARKER (w->start)->buffer == 0)
5124 set_marker_restricted (w->start, make_number (0),
5125 w->buffer);
5126 if (XMARKER (w->pointm)->buffer == 0)
b73ea88e
RS
5127 set_marker_restricted_both (w->pointm, w->buffer,
5128 BUF_PT (XBUFFER (w->buffer)),
5129 BUF_PT_BYTE (XBUFFER (w->buffer)));
fd482be5 5130 w->start_at_line_beg = Qt;
7ab12479
JB
5131 }
5132 }
5133 }
9ace597f 5134
fd482be5 5135 FRAME_ROOT_WINDOW (f) = data->root_window;
719eaeb1
GM
5136 /* Prevent "swapping out point" in the old selected window
5137 using the buffer that has been restored into it.
5138 That swapping out has already been done,
5139 near the beginning of this function. */
5140 selected_window = Qnil;
fd482be5 5141 Fselect_window (data->current_window);
396a830c
RS
5142 XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
5143 = selected_window;
7ab12479 5144
db269683 5145 if (NILP (data->focus_frame)
017b2bad 5146 || (FRAMEP (data->focus_frame)
db269683
JB
5147 && FRAME_LIVE_P (XFRAME (data->focus_frame))))
5148 Fredirect_frame_focus (frame, data->focus_frame);
7ab12479 5149
fd482be5
JB
5150#if 0 /* I don't understand why this is needed, and it causes problems
5151 when the frame's old selected window has been deleted. */
e4e59717 5152 if (f != selected_frame && FRAME_WINDOW_P (f))
9a7c6fc3 5153 do_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)),
d12f6f83 5154 0, 0);
fd482be5
JB
5155#endif
5156
5157 /* Set the screen height to the value it had before this function. */
5158 if (previous_frame_height != FRAME_HEIGHT (f)
5159 || previous_frame_width != FRAME_WIDTH (f))
5160 change_frame_size (f, previous_frame_height, previous_frame_width,
2b653806 5161 0, 0, 0);
e3678b64 5162#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
8f6ea2e9 5163 if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
f8ad443a
AS
5164 x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
5165 make_number (0));
4314246f 5166#ifdef HAVE_WINDOW_SYSTEM
9ea173e8
GM
5167 if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
5168 x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
5169 make_number (0));
4314246f 5170#endif
217f2871 5171#endif
d2b35234 5172
5500c422 5173 /* Now, free glyph matrices in windows that were not reused. */
c4280705
GM
5174 for (i = n = 0; i < n_leaf_windows; ++i)
5175 {
5176 if (NILP (leaf_windows[i]->buffer))
5177 {
5178 /* Assert it's not reused as a combination. */
5179 xassert (NILP (leaf_windows[i]->hchild)
5180 && NILP (leaf_windows[i]->vchild));
5181 free_window_matrices (leaf_windows[i]);
c4280705
GM
5182 }
5183 else if (EQ (leaf_windows[i]->buffer, new_current_buffer))
5184 ++n;
5185 }
5186
5187 /* If more than one window shows the new and old current buffer,
5188 don't try to preserve point in that buffer. */
5189 if (old_point > 0 && n > 1)
5190 old_point = -1;
5500c422
GM
5191
5192 adjust_glyphs (f);
5193
d2b35234 5194 UNBLOCK_INPUT;
756b6edc 5195
478292ed
RS
5196 /* Fselect_window will have made f the selected frame, so we
5197 reselect the proper frame here. Fhandle_switch_frame will change the
5198 selected window too, but that doesn't make the call to
5199 Fselect_window above totally superfluous; it still sets f's
5200 selected window. */
5201 if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
d12f6f83 5202 do_switch_frame (data->selected_frame, 0, 0);
478292ed
RS
5203
5204 if (! NILP (Vwindow_configuration_change_hook)
5205 && ! NILP (Vrun_hooks))
5206 call1 (Vrun_hooks, Qwindow_configuration_change_hook);
5207 }
bdc727bf
JB
5208
5209 if (!NILP (new_current_buffer))
d2b35234
RS
5210 {
5211 Fset_buffer (new_current_buffer);
5212
5213 /* If the buffer that is current now is the same
5214 that was current before setting the window configuration,
5215 don't alter its PT. */
5216 if (old_point >= 0)
5217 SET_PT (old_point);
5218 }
bdc727bf 5219
478292ed
RS
5220 /* Restore the minimum heights recorded in the configuration. */
5221 window_min_height = XINT (data->min_height);
5222 window_min_width = XINT (data->min_width);
543f5fb1 5223
478292ed 5224 Vminibuf_scroll_window = data->minibuf_scroll_window;
3dbab091 5225 minibuf_selected_window = data->minibuf_selected_window;
543f5fb1 5226
3f8ab7bd 5227 return (FRAME_LIVE_P (f) ? Qt : Qnil);
7ab12479
JB
5228}
5229
44fa5b1e 5230/* Mark all windows now on frame as deleted
7ab12479
JB
5231 by setting their buffers to nil. */
5232
fd482be5 5233void
7ab12479
JB
5234delete_all_subwindows (w)
5235 register struct window *w;
5236{
265a9e55 5237 if (!NILP (w->next))
7ab12479 5238 delete_all_subwindows (XWINDOW (w->next));
265a9e55 5239 if (!NILP (w->vchild))
7ab12479 5240 delete_all_subwindows (XWINDOW (w->vchild));
265a9e55 5241 if (!NILP (w->hchild))
7ab12479 5242 delete_all_subwindows (XWINDOW (w->hchild));
605be8af
JB
5243
5244 w->height = w->buffer; /* See Fset_window_configuration for excuse. */
5245
86e48436
RS
5246 if (!NILP (w->buffer))
5247 unshow_buffer (w);
5248
605be8af
JB
5249 /* We set all three of these fields to nil, to make sure that we can
5250 distinguish this dead window from any live window. Live leaf
5251 windows will have buffer set, and combination windows will have
5252 vchild or hchild set. */
5253 w->buffer = Qnil;
5254 w->vchild = Qnil;
5255 w->hchild = Qnil;
acf70840
GM
5256
5257 Vwindow_list = Qnil;
7ab12479
JB
5258}
5259\f
5260static int
5261count_windows (window)
5262 register struct window *window;
5263{
5264 register int count = 1;
265a9e55 5265 if (!NILP (window->next))
7ab12479 5266 count += count_windows (XWINDOW (window->next));
265a9e55 5267 if (!NILP (window->vchild))
7ab12479 5268 count += count_windows (XWINDOW (window->vchild));
265a9e55 5269 if (!NILP (window->hchild))
7ab12479
JB
5270 count += count_windows (XWINDOW (window->hchild));
5271 return count;
5272}
5273
5500c422
GM
5274
5275/* Fill vector FLAT with leaf windows under W, starting at index I.
5276 Value is last index + 1. */
5277
5278static int
5279get_leaf_windows (w, flat, i)
5280 struct window *w;
5281 struct window **flat;
5282 int i;
5283{
5284 while (w)
5285 {
5286 if (!NILP (w->hchild))
5287 i = get_leaf_windows (XWINDOW (w->hchild), flat, i);
5288 else if (!NILP (w->vchild))
5289 i = get_leaf_windows (XWINDOW (w->vchild), flat, i);
5290 else
5291 flat[i++] = w;
5292
5293 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5294 }
5295
5296 return i;
5297}
5298
5299
5300/* Return a pointer to the glyph W's physical cursor is on. Value is
5301 null if W's current matrix is invalid, so that no meaningfull glyph
5302 can be returned. */
5303
5304struct glyph *
5305get_phys_cursor_glyph (w)
5306 struct window *w;
5307{
5308 struct glyph_row *row;
5309 struct glyph *glyph;
5310
5311 if (w->phys_cursor.vpos >= 0
5312 && w->phys_cursor.vpos < w->current_matrix->nrows
5313 && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
5314 row->enabled_p)
5315 && row->used[TEXT_AREA] > w->phys_cursor.hpos)
5316 glyph = row->glyphs[TEXT_AREA] + w->phys_cursor.hpos;
5317 else
5318 glyph = NULL;
5319
5320 return glyph;
5321}
5322
5323
7ab12479
JB
5324static int
5325save_window_save (window, vector, i)
5326 Lisp_Object window;
5327 struct Lisp_Vector *vector;
5328 int i;
5329{
5330 register struct saved_window *p;
5331 register struct window *w;
5332 register Lisp_Object tem;
5333
265a9e55 5334 for (;!NILP (window); window = w->next)
7ab12479
JB
5335 {
5336 p = SAVED_WINDOW_N (vector, i);
5337 w = XWINDOW (window);
5338
d834a2e9 5339 XSETFASTINT (w->temslot, i++);
7ab12479
JB
5340 p->window = window;
5341 p->buffer = w->buffer;
5342 p->left = w->left;
5343 p->top = w->top;
5344 p->width = w->width;
5345 p->height = w->height;
5346 p->hscroll = w->hscroll;
ea68264b 5347 p->min_hscroll = w->min_hscroll;
7ab12479 5348 p->display_table = w->display_table;
a1d58e5b
GM
5349 p->orig_top = w->orig_top;
5350 p->orig_height = w->orig_height;
265a9e55 5351 if (!NILP (w->buffer))
7ab12479
JB
5352 {
5353 /* Save w's value of point in the window configuration.
5354 If w is the selected window, then get the value of point
5355 from the buffer; pointm is garbage in the selected window. */
5356 if (EQ (window, selected_window))
5357 {
5358 p->pointm = Fmake_marker ();
b73ea88e
RS
5359 set_marker_both (p->pointm, w->buffer,
5360 BUF_PT (XBUFFER (w->buffer)),
5361 BUF_PT_BYTE (XBUFFER (w->buffer)));
7ab12479
JB
5362 }
5363 else
eeb82665 5364 p->pointm = Fcopy_marker (w->pointm, Qnil);
7ab12479 5365
eeb82665 5366 p->start = Fcopy_marker (w->start, Qnil);
7ab12479
JB
5367 p->start_at_line_beg = w->start_at_line_beg;
5368
5369 tem = XBUFFER (w->buffer)->mark;
eeb82665 5370 p->mark = Fcopy_marker (tem, Qnil);
7ab12479
JB
5371 }
5372 else
5373 {
5374 p->pointm = Qnil;
5375 p->start = Qnil;
5376 p->mark = Qnil;
5377 p->start_at_line_beg = Qnil;
5378 }
5379
265a9e55 5380 if (NILP (w->parent))
7ab12479
JB
5381 p->parent = Qnil;
5382 else
5383 p->parent = XWINDOW (w->parent)->temslot;
5384
265a9e55 5385 if (NILP (w->prev))
7ab12479
JB
5386 p->prev = Qnil;
5387 else
5388 p->prev = XWINDOW (w->prev)->temslot;
5389
265a9e55 5390 if (!NILP (w->vchild))
7ab12479 5391 i = save_window_save (w->vchild, vector, i);
265a9e55 5392 if (!NILP (w->hchild))
7ab12479
JB
5393 i = save_window_save (w->hchild, vector, i);
5394 }
5395
5396 return i;
5397}
5398
a0d76c27 5399DEFUN ("current-window-configuration", Fcurrent_window_configuration,
fdb82f93
PJ
5400 Scurrent_window_configuration, 0, 1, 0,
5401 doc: /* Return an object representing the current window configuration of FRAME.
5402If FRAME is nil or omitted, use the selected frame.
5403This describes the number of windows, their sizes and current buffers,
5404and for each displayed buffer, where display starts, and the positions of
5405point and mark. An exception is made for point in the current buffer:
5406its value is -not- saved.
5407This also records the currently selected frame, and FRAME's focus
5408redirection (see `redirect-frame-focus'). */)
5409 (frame)
44fa5b1e 5410 Lisp_Object frame;
7ab12479
JB
5411{
5412 register Lisp_Object tem;
5413 register int n_windows;
5414 register struct save_window_data *data;
da2792e0 5415 register struct Lisp_Vector *vec;
7ab12479 5416 register int i;
44fa5b1e 5417 FRAME_PTR f;
43bad991 5418
44fa5b1e 5419 if (NILP (frame))
1ae1a37d 5420 frame = selected_frame;
b7826503 5421 CHECK_LIVE_FRAME (frame);
1ae1a37d 5422 f = XFRAME (frame);
7ab12479 5423
44fa5b1e 5424 n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
26605be9 5425 vec = allocate_other_vector (VECSIZE (struct save_window_data));
da2792e0
KH
5426 data = (struct save_window_data *)vec;
5427
d834a2e9
KH
5428 XSETFASTINT (data->frame_width, FRAME_WIDTH (f));
5429 XSETFASTINT (data->frame_height, FRAME_HEIGHT (f));
5430 XSETFASTINT (data->frame_menu_bar_lines, FRAME_MENU_BAR_LINES (f));
9ea173e8 5431 XSETFASTINT (data->frame_tool_bar_lines, FRAME_TOOL_BAR_LINES (f));
1ae1a37d 5432 data->selected_frame = selected_frame;
44fa5b1e 5433 data->current_window = FRAME_SELECTED_WINDOW (f);
74112613 5434 XSETBUFFER (data->current_buffer, current_buffer);
3f49fddc 5435 data->minibuf_scroll_window = minibuf_level > 0 ? Vminibuf_scroll_window : Qnil;
3dbab091 5436 data->minibuf_selected_window = minibuf_level > 0 ? minibuf_selected_window : Qnil;
44fa5b1e 5437 data->root_window = FRAME_ROOT_WINDOW (f);
bdc727bf 5438 data->focus_frame = FRAME_FOCUS_FRAME (f);
74112613
KH
5439 XSETINT (data->min_height, window_min_height);
5440 XSETINT (data->min_width, window_min_width);
7ab12479
JB
5441 tem = Fmake_vector (make_number (n_windows), Qnil);
5442 data->saved_windows = tem;
5443 for (i = 0; i < n_windows; i++)
5444 XVECTOR (tem)->contents[i]
5445 = Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil);
a1d58e5b 5446 save_window_save (FRAME_ROOT_WINDOW (f), XVECTOR (tem), 0);
74112613 5447 XSETWINDOW_CONFIGURATION (tem, data);
7ab12479
JB
5448 return (tem);
5449}
5450
5451DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
fdb82f93
PJ
5452 0, UNEVALLED, 0,
5453 doc: /* Execute body, preserving window sizes and contents.
5454Restore which buffer appears in which window, where display starts,
5455and the value of point and mark for each window.
5456Also restore the choice of selected window.
5457Also restore which buffer is current.
6924dda6
MB
5458Does not restore the value of point in current buffer.
5459usage: (save-window-excursion BODY ...) */)
fdb82f93 5460 (args)
7ab12479
JB
5461 Lisp_Object args;
5462{
5463 register Lisp_Object val;
5464 register int count = specpdl_ptr - specpdl;
5465
5466 record_unwind_protect (Fset_window_configuration,
43bad991 5467 Fcurrent_window_configuration (Qnil));
7ab12479
JB
5468 val = Fprogn (args);
5469 return unbind_to (count, val);
5470}
5500c422
GM
5471
5472\f
5473/***********************************************************************
5474 Marginal Areas
5475 ***********************************************************************/
5476
5477DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
a7bdfc08 5478 2, 3, 0,
fdb82f93
PJ
5479 doc: /* Set width of marginal areas of window WINDOW.
5480If window is nil, set margins of the currently selected window.
5481First parameter LEFT-WIDTH specifies the number of character
5482cells to reserve for the left marginal area. Second parameter
5483RIGHT-WIDTH does the same for the right marginal area.
5484A nil width parameter means no margin. */)
5485 (window, left, right)
5500c422
GM
5486 Lisp_Object window, left, right;
5487{
5488 struct window *w = decode_window (window);
5500c422
GM
5489
5490 if (!NILP (left))
b7826503 5491 CHECK_NUMBER_OR_FLOAT (left);
5500c422 5492 if (!NILP (right))
b7826503 5493 CHECK_NUMBER_OR_FLOAT (right);
5500c422
GM
5494
5495 /* Check widths < 0 and translate a zero width to nil.
5496 Margins that are too wide have to be checked elsewhere. */
5497 if ((INTEGERP (left) && XINT (left) < 0)
7539e11f 5498 || (FLOATP (left) && XFLOAT_DATA (left) <= 0))
5500c422
GM
5499 XSETFASTINT (left, 0);
5500 if (INTEGERP (left) && XFASTINT (left) == 0)
5501 left = Qnil;
5502
5503 if ((INTEGERP (right) && XINT (right) < 0)
7539e11f 5504 || (FLOATP (right) && XFLOAT_DATA (right) <= 0))
5500c422
GM
5505 XSETFASTINT (right, 0);
5506 if (INTEGERP (right) && XFASTINT (right) == 0)
5507 right = Qnil;
5508
5509 w->left_margin_width = left;
5510 w->right_margin_width = right;
5511
5512 ++windows_or_buffers_changed;
5513 adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
5514 return Qnil;
5515}
5516
5517
5518DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
5519 0, 1, 0,
fdb82f93
PJ
5520 doc: /* Get width of marginal areas of window WINDOW.
5521If WINDOW is omitted or nil, use the currently selected window.
5522Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).
5523If a marginal area does not exist, its width will be returned
5524as nil. */)
5525 (window)
5500c422
GM
5526 Lisp_Object window;
5527{
5528 struct window *w = decode_window (window);
5529 return Fcons (w->left_margin_width, w->right_margin_width);
5530}
5531
5532
7ab12479 5533\f
5500c422
GM
5534/***********************************************************************
5535 Smooth scrolling
5536 ***********************************************************************/
5537
5538DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 1, 0,
fdb82f93
PJ
5539 doc: /* Return the amount by which WINDOW is scrolled vertically.
5540Use the selected window if WINDOW is nil or omitted.
5541Value is a multiple of the canonical character height of WINDOW. */)
5542 (window)
5500c422
GM
5543 Lisp_Object window;
5544{
47004952 5545 Lisp_Object result;
5500c422
GM
5546 struct frame *f;
5547 struct window *w;
5548
5549 if (NILP (window))
5550 window = selected_window;
47004952 5551 else
b7826503 5552 CHECK_WINDOW (window);
5500c422
GM
5553 w = XWINDOW (window);
5554 f = XFRAME (w->frame);
5555
5556 if (FRAME_WINDOW_P (f))
47004952 5557 result = CANON_Y_FROM_PIXEL_Y (f, -w->vscroll);
5500c422 5558 else
47004952
GM
5559 result = make_number (0);
5560 return result;
5500c422
GM
5561}
5562
5563
5564DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
47004952 5565 2, 2, 0,
fdb82f93 5566 doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL.
b0f906c8
EZ
5567WINDOW nil means use the selected window. VSCROLL is a non-negative
5568multiple of the canonical character height of WINDOW. */)
fdb82f93 5569 (window, vscroll)
47004952 5570 Lisp_Object window, vscroll;
5500c422
GM
5571{
5572 struct window *w;
5573 struct frame *f;
5574
5500c422
GM
5575 if (NILP (window))
5576 window = selected_window;
47004952 5577 else
b7826503
PJ
5578 CHECK_WINDOW (window);
5579 CHECK_NUMBER_OR_FLOAT (vscroll);
47004952 5580
5500c422
GM
5581 w = XWINDOW (window);
5582 f = XFRAME (w->frame);
5583
5584 if (FRAME_WINDOW_P (f))
5585 {
5586 int old_dy = w->vscroll;
47004952
GM
5587
5588 w->vscroll = - CANON_Y_UNIT (f) * XFLOATINT (vscroll);
5589 w->vscroll = min (w->vscroll, 0);
5500c422
GM
5590
5591 /* Adjust glyph matrix of the frame if the virtual display
5592 area becomes larger than before. */
5593 if (w->vscroll < 0 && w->vscroll < old_dy)
5594 adjust_glyphs (f);
5595
5596 /* Prevent redisplay shortcuts. */
b1599b4c 5597 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
5500c422
GM
5598 }
5599
47004952 5600 return Fwindow_vscroll (window);
5500c422
GM
5601}
5602
7bbb5782
GM
5603\f
5604/* Call FN for all leaf windows on frame F. FN is called with the
5605 first argument being a pointer to the leaf window, and with
f95464e4 5606 additional argument USER_DATA. Stops when FN returns 0. */
7bbb5782
GM
5607
5608void
f95464e4 5609foreach_window (f, fn, user_data)
7bbb5782 5610 struct frame *f;
f95464e4
GM
5611 int (* fn) P_ ((struct window *, void *));
5612 void *user_data;
7bbb5782 5613{
f95464e4 5614 foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data);
7bbb5782
GM
5615}
5616
5617
5618/* Helper function for foreach_window. Call FN for all leaf windows
5619 reachable from W. FN is called with the first argument being a
f95464e4 5620 pointer to the leaf window, and with additional argument USER_DATA.
67492200 5621 Stop when FN returns 0. Value is 0 if stopped by FN. */
7bbb5782 5622
67492200 5623static int
f95464e4 5624foreach_window_1 (w, fn, user_data)
7bbb5782 5625 struct window *w;
f95464e4
GM
5626 int (* fn) P_ ((struct window *, void *));
5627 void *user_data;
7bbb5782 5628{
67492200
GM
5629 int cont;
5630
5631 for (cont = 1; w && cont;)
7bbb5782
GM
5632 {
5633 if (!NILP (w->hchild))
f95464e4 5634 cont = foreach_window_1 (XWINDOW (w->hchild), fn, user_data);
7bbb5782 5635 else if (!NILP (w->vchild))
f95464e4 5636 cont = foreach_window_1 (XWINDOW (w->vchild), fn, user_data);
0f532a9a
GM
5637 else
5638 cont = fn (w, user_data);
7bbb5782
GM
5639
5640 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5641 }
67492200
GM
5642
5643 return cont;
7bbb5782
GM
5644}
5645
5646
6d194a45 5647/* Freeze or unfreeze the window start of W unless it is a
f95464e4 5648 mini-window or the selected window. FREEZE_P non-null means freeze
7bbb5782
GM
5649 the window start. */
5650
67492200 5651static int
7bbb5782
GM
5652freeze_window_start (w, freeze_p)
5653 struct window *w;
f95464e4 5654 void *freeze_p;
7bbb5782
GM
5655{
5656 if (w == XWINDOW (selected_window)
5657 || MINI_WINDOW_P (w)
5658 || (MINI_WINDOW_P (XWINDOW (selected_window))
24d744ac 5659 && ! NILP (Vminibuf_scroll_window)
7bbb5782 5660 && w == XWINDOW (Vminibuf_scroll_window)))
f95464e4 5661 freeze_p = NULL;
7bbb5782 5662
f95464e4 5663 w->frozen_window_start_p = freeze_p != NULL;
67492200 5664 return 1;
7bbb5782
GM
5665}
5666
5667
5668/* Freeze or unfreeze the window starts of all leaf windows on frame
5669 F, except the selected window and a mini-window. FREEZE_P non-zero
5670 means freeze the window start. */
5671
5672void
5673freeze_window_starts (f, freeze_p)
5674 struct frame *f;
5675 int freeze_p;
5676{
cbccabec 5677 foreach_window (f, freeze_window_start, (void *) (freeze_p ? f : 0));
7bbb5782 5678}
5500c422
GM
5679
5680\f
5681/***********************************************************************
5682 Initialization
5683 ***********************************************************************/
5684
cbff28e8
RS
5685/* Return 1 if window configurations C1 and C2
5686 describe the same state of affairs. This is used by Fequal. */
5687
5688int
2f8274be 5689compare_window_configurations (c1, c2, ignore_positions)
cbff28e8 5690 Lisp_Object c1, c2;
2f8274be 5691 int ignore_positions;
cbff28e8
RS
5692{
5693 register struct save_window_data *d1, *d2;
5694 struct Lisp_Vector *sw1, *sw2;
5695 int i;
5696
4d3edcb4
GM
5697 if (!WINDOW_CONFIGURATIONP (c1))
5698 wrong_type_argument (Qwindow_configuration_p, c1);
5699 if (!WINDOW_CONFIGURATIONP (c2))
5700 wrong_type_argument (Qwindow_configuration_p, c2);
5701
cbff28e8
RS
5702 d1 = (struct save_window_data *) XVECTOR (c1);
5703 d2 = (struct save_window_data *) XVECTOR (c2);
5704 sw1 = XVECTOR (d1->saved_windows);
5705 sw2 = XVECTOR (d2->saved_windows);
5706
5707 if (! EQ (d1->frame_width, d2->frame_width))
5708 return 0;
5709 if (! EQ (d1->frame_height, d2->frame_height))
5710 return 0;
5711 if (! EQ (d1->frame_menu_bar_lines, d2->frame_menu_bar_lines))
5712 return 0;
5713 if (! EQ (d1->selected_frame, d2->selected_frame))
5714 return 0;
5715 /* Don't compare the current_window field directly.
5716 Instead see w1_is_current and w2_is_current, below. */
5717 if (! EQ (d1->current_buffer, d2->current_buffer))
5718 return 0;
2f8274be 5719 if (! ignore_positions)
3f49fddc
KS
5720 {
5721 if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
5722 return 0;
5723 if (! EQ (d1->minibuf_selected_window, d2->minibuf_selected_window))
5724 return 0;
5725 }
cbff28e8
RS
5726 /* Don't compare the root_window field.
5727 We don't require the two configurations
5728 to use the same window object,
5729 and the two root windows must be equivalent
5730 if everything else compares equal. */
5731 if (! EQ (d1->focus_frame, d2->focus_frame))
5732 return 0;
5733 if (! EQ (d1->min_width, d2->min_width))
5734 return 0;
5735 if (! EQ (d1->min_height, d2->min_height))
5736 return 0;
5737
5738 /* Verify that the two confis have the same number of windows. */
5739 if (sw1->size != sw2->size)
5740 return 0;
5741
5742 for (i = 0; i < sw1->size; i++)
5743 {
5744 struct saved_window *p1, *p2;
5745 int w1_is_current, w2_is_current;
5746
5747 p1 = SAVED_WINDOW_N (sw1, i);
5748 p2 = SAVED_WINDOW_N (sw2, i);
5749
5750 /* Verify that the current windows in the two
5751 configurations correspond to each other. */
5752 w1_is_current = EQ (d1->current_window, p1->window);
5753 w2_is_current = EQ (d2->current_window, p2->window);
5754
5755 if (w1_is_current != w2_is_current)
5756 return 0;
5757
5758 /* Verify that the corresponding windows do match. */
5759 if (! EQ (p1->buffer, p2->buffer))
5760 return 0;
5761 if (! EQ (p1->left, p2->left))
5762 return 0;
5763 if (! EQ (p1->top, p2->top))
5764 return 0;
5765 if (! EQ (p1->width, p2->width))
5766 return 0;
5767 if (! EQ (p1->height, p2->height))
5768 return 0;
cbff28e8
RS
5769 if (! EQ (p1->display_table, p2->display_table))
5770 return 0;
5771 if (! EQ (p1->parent, p2->parent))
5772 return 0;
5773 if (! EQ (p1->prev, p2->prev))
5774 return 0;
2f8274be
RS
5775 if (! ignore_positions)
5776 {
5777 if (! EQ (p1->hscroll, p2->hscroll))
5778 return 0;
ea68264b
GM
5779 if (!EQ (p1->min_hscroll, p2->min_hscroll))
5780 return 0;
2f8274be
RS
5781 if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
5782 return 0;
5783 if (NILP (Fequal (p1->start, p2->start)))
5784 return 0;
5785 if (NILP (Fequal (p1->pointm, p2->pointm)))
5786 return 0;
5787 if (NILP (Fequal (p1->mark, p2->mark)))
5788 return 0;
5789 }
cbff28e8
RS
5790 }
5791
5792 return 1;
5793}
2f8274be
RS
5794
5795DEFUN ("compare-window-configurations", Fcompare_window_configurations,
5796 Scompare_window_configurations, 2, 2, 0,
fdb82f93
PJ
5797 doc: /* Compare two window configurations as regards the structure of windows.
5798This function ignores details such as the values of point and mark
5799and scrolling positions. */)
5800 (x, y)
2f8274be
RS
5801 Lisp_Object x, y;
5802{
5803 if (compare_window_configurations (x, y, 1))
5804 return Qt;
5805 return Qnil;
5806}
cbff28e8 5807\f
dfcf069d 5808void
7ab12479
JB
5809init_window_once ()
5810{
1ae1a37d
GM
5811 struct frame *f = make_terminal_frame ();
5812 XSETFRAME (selected_frame, f);
5813 Vterminal_frame = selected_frame;
5814 minibuf_window = f->minibuffer_window;
5815 selected_window = f->selected_window;
5816 last_nonminibuf_frame = f;
5b03d3c0
RS
5817
5818 window_initialized = 1;
7ab12479
JB
5819}
5820
67492200
GM
5821void
5822init_window ()
5823{
5824 Vwindow_list = Qnil;
5825}
5826
dfcf069d 5827void
7ab12479
JB
5828syms_of_window ()
5829{
8a37516b
GM
5830 Qwindow_size_fixed = intern ("window-size-fixed");
5831 staticpro (&Qwindow_size_fixed);
233a4a2c 5832
543f5fb1
RS
5833 staticpro (&Qwindow_configuration_change_hook);
5834 Qwindow_configuration_change_hook
5835 = intern ("window-configuration-change-hook");
5836
7ab12479
JB
5837 Qwindowp = intern ("windowp");
5838 staticpro (&Qwindowp);
5839
3f8ab7bd
RS
5840 Qwindow_configuration_p = intern ("window-configuration-p");
5841 staticpro (&Qwindow_configuration_p);
5842
806b4d9b
JB
5843 Qwindow_live_p = intern ("window-live-p");
5844 staticpro (&Qwindow_live_p);
605be8af 5845
2cccc823 5846 Qtemp_buffer_show_hook = intern ("temp-buffer-show-hook");
a58ec57d
RS
5847 staticpro (&Qtemp_buffer_show_hook);
5848
67492200 5849 staticpro (&Vwindow_list);
8bfb170b
KS
5850
5851 minibuf_selected_window = Qnil;
3dbab091 5852 staticpro (&minibuf_selected_window);
67492200 5853
7ab12479 5854 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
fdb82f93
PJ
5855 doc: /* Non-nil means call as function to display a help buffer.
5856The function is called with one argument, the buffer to be displayed.
5857Used by `with-output-to-temp-buffer'.
5858If this function is used, then it must do the entire job of showing
5859the buffer; `temp-buffer-show-hook' is not run unless this function runs it. */);
7ab12479
JB
5860 Vtemp_buffer_show_function = Qnil;
5861
5862 DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
fdb82f93
PJ
5863 doc: /* If non-nil, function to call to handle `display-buffer'.
5864It will receive two args, the buffer and a flag which if non-nil means
5865 that the currently selected window is not acceptable.
5866Commands such as `switch-to-buffer-other-window' and `find-file-other-window'
5867work using this function. */);
7ab12479
JB
5868 Vdisplay_buffer_function = Qnil;
5869
6529ed87 5870 DEFVAR_LISP ("even-window-heights", &Veven_window_heights,
fdb82f93
PJ
5871 doc: /* *If non-nil, `display-buffer' should even the window heights.
5872If nil, `display-buffer' will leave the window configuration alone. */);
6529ed87
GM
5873 Veven_window_heights = Qt;
5874
7ab12479 5875 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
fdb82f93 5876 doc: /* Non-nil means it is the window that C-M-v in minibuffer should scroll. */);
7ab12479
JB
5877 Vminibuf_scroll_window = Qnil;
5878
cc91894c 5879 DEFVAR_BOOL ("mode-line-in-non-selected-windows", &mode_line_in_non_selected_windows,
26124d5e 5880 doc: /* Non-nil means to use `mode-line-inactive' face in non-selected windows.
cc91894c
KS
5881If the minibuffer is active, the `minibuffer-scroll-window' mode line
5882is displayed in the `mode-line' face. */);
5883 mode_line_in_non_selected_windows = 1;
26124d5e 5884
7ab12479 5885 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
fdb82f93 5886 doc: /* If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window. */);
7ab12479
JB
5887 Vother_window_scroll_buffer = Qnil;
5888
44fa5b1e 5889 DEFVAR_BOOL ("pop-up-frames", &pop_up_frames,
fdb82f93 5890 doc: /* *Non-nil means `display-buffer' should make a separate frame. */);
44fa5b1e 5891 pop_up_frames = 0;
7ab12479 5892
9c3da604 5893 DEFVAR_BOOL ("display-buffer-reuse-frames", &display_buffer_reuse_frames,
fdb82f93
PJ
5894 doc: /* *Non-nil means `display-buffer' should reuse frames.
5895If the buffer in question is already displayed in a frame, raise that frame. */);
9c3da604
GM
5896 display_buffer_reuse_frames = 0;
5897
44fa5b1e 5898 DEFVAR_LISP ("pop-up-frame-function", &Vpop_up_frame_function,
fdb82f93
PJ
5899 doc: /* Function to call to handle automatic new frame creation.
5900It is called with no arguments and should return a newly created frame.
5901
5902A typical value might be `(lambda () (new-frame pop-up-frame-alist))'
5903where `pop-up-frame-alist' would hold the default frame parameters. */);
44fa5b1e 5904 Vpop_up_frame_function = Qnil;
7ab12479 5905
a90712c2 5906 DEFVAR_LISP ("special-display-buffer-names", &Vspecial_display_buffer_names,
fdb82f93
PJ
5907 doc: /* *List of buffer names that should have their own special frames.
5908Displaying a buffer whose name is in this list makes a special frame for it
5909using `special-display-function'. See also `special-display-regexps'.
5910
5911An element of the list can be a list instead of just a string.
5912There are two ways to use a list as an element:
5913 (BUFFER FRAME-PARAMETERS...) (BUFFER FUNCTION OTHER-ARGS...)
5914In the first case, FRAME-PARAMETERS are used to create the frame.
5915In the latter case, FUNCTION is called with BUFFER as the first argument,
5916followed by OTHER-ARGS--it can display BUFFER in any way it likes.
5917All this is done by the function found in `special-display-function'.
5918
5919If this variable appears \"not to work\", because you add a name to it
5920but that buffer still appears in the selected window, look at the
5921values of `same-window-buffer-names' and `same-window-regexps'.
5922Those variables take precedence over this one. */);
a90712c2
RS
5923 Vspecial_display_buffer_names = Qnil;
5924
5925 DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
fdb82f93
PJ
5926 doc: /* *List of regexps saying which buffers should have their own special frames.
5927If a buffer name matches one of these regexps, it gets its own frame.
5928Displaying a buffer whose name is in this list makes a special frame for it
5929using `special-display-function'.
5930
5931An element of the list can be a list instead of just a string.
5932There are two ways to use a list as an element:
5933 (REGEXP FRAME-PARAMETERS...) (REGEXP FUNCTION OTHER-ARGS...)
5934In the first case, FRAME-PARAMETERS are used to create the frame.
5935In the latter case, FUNCTION is called with the buffer as first argument,
5936followed by OTHER-ARGS--it can display the buffer in any way it likes.
5937All this is done by the function found in `special-display-function'.
5938
5939If this variable appears \"not to work\", because you add a regexp to it
5940but the matching buffers still appear in the selected window, look at the
5941values of `same-window-buffer-names' and `same-window-regexps'.
5942Those variables take precedence over this one. */);
a90712c2
RS
5943 Vspecial_display_regexps = Qnil;
5944
5945 DEFVAR_LISP ("special-display-function", &Vspecial_display_function,
fdb82f93
PJ
5946 doc: /* Function to call to make a new frame for a special buffer.
5947It is called with two arguments, the buffer and optional buffer specific
5948data, and should return a window displaying that buffer.
5949The default value makes a separate frame for the buffer,
5950using `special-display-frame-alist' to specify the frame parameters.
5951
5952A buffer is special if its is listed in `special-display-buffer-names'
5953or matches a regexp in `special-display-regexps'. */);
a90712c2
RS
5954 Vspecial_display_function = Qnil;
5955
855d8627 5956 DEFVAR_LISP ("same-window-buffer-names", &Vsame_window_buffer_names,
fdb82f93
PJ
5957 doc: /* *List of buffer names that should appear in the selected window.
5958Displaying one of these buffers using `display-buffer' or `pop-to-buffer'
5959switches to it in the selected window, rather than making it appear
5960in some other window.
5961
5962An element of the list can be a cons cell instead of just a string.
5963Then the car must be a string, which specifies the buffer name.
5964This is for compatibility with `special-display-buffer-names';
5965the cdr of the cons cell is ignored.
5966
5967See also `same-window-regexps'. */);
855d8627
RS
5968 Vsame_window_buffer_names = Qnil;
5969
5970 DEFVAR_LISP ("same-window-regexps", &Vsame_window_regexps,
fdb82f93
PJ
5971 doc: /* *List of regexps saying which buffers should appear in the selected window.
5972If a buffer name matches one of these regexps, then displaying it
5973using `display-buffer' or `pop-to-buffer' switches to it
5974in the selected window, rather than making it appear in some other window.
5975
5976An element of the list can be a cons cell instead of just a string.
5977Then the car must be a string, which specifies the buffer name.
5978This is for compatibility with `special-display-buffer-names';
5979the cdr of the cons cell is ignored.
5980
5981See also `same-window-buffer-names'. */);
855d8627
RS
5982 Vsame_window_regexps = Qnil;
5983
7ab12479 5984 DEFVAR_BOOL ("pop-up-windows", &pop_up_windows,
fdb82f93 5985 doc: /* *Non-nil means display-buffer should make new windows. */);
7ab12479
JB
5986 pop_up_windows = 1;
5987
5988 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
fdb82f93 5989 doc: /* *Number of lines of continuity when scrolling by screenfuls. */);
7ab12479
JB
5990 next_screen_context_lines = 2;
5991
5992 DEFVAR_INT ("split-height-threshold", &split_height_threshold,
fdb82f93
PJ
5993 doc: /* *display-buffer would prefer to split the largest window if this large.
5994If there is only one window, it is split regardless of this value. */);
7ab12479
JB
5995 split_height_threshold = 500;
5996
5997 DEFVAR_INT ("window-min-height", &window_min_height,
fdb82f93 5998 doc: /* *Delete any window less than this tall (including its mode line). */);
7ab12479
JB
5999 window_min_height = 4;
6000
6001 DEFVAR_INT ("window-min-width", &window_min_width,
fdb82f93 6002 doc: /* *Delete any window less than this wide. */);
7ab12479
JB
6003 window_min_width = 10;
6004
5500c422
GM
6005 DEFVAR_LISP ("scroll-preserve-screen-position",
6006 &Vscroll_preserve_screen_position,
fdb82f93 6007 doc: /* *Non-nil means scroll commands move point to keep its screen line unchanged. */);
5500c422 6008 Vscroll_preserve_screen_position = Qnil;
9317a85d 6009
543f5fb1
RS
6010 DEFVAR_LISP ("window-configuration-change-hook",
6011 &Vwindow_configuration_change_hook,
fdb82f93
PJ
6012 doc: /* Functions to call when window configuration changes.
6013The selected frame is the one whose configuration has changed. */);
543f5fb1
RS
6014 Vwindow_configuration_change_hook = Qnil;
6015
b0b7ed0e 6016 DEFVAR_BOOL ("window-size-fixed", &window_size_fixed,
fdb82f93
PJ
6017 doc: /* Non-nil in a buffer means windows displaying the buffer are fixed-size.
6018Emacs won't change the size of any window displaying that buffer,
6019unless you explicitly change the size, or Emacs has no other choice.
6020This variable automatically becomes buffer-local when set. */);
b0b7ed0e
GM
6021 Fmake_variable_buffer_local (Qwindow_size_fixed);
6022 window_size_fixed = 0;
6023
7ab12479
JB
6024 defsubr (&Sselected_window);
6025 defsubr (&Sminibuffer_window);
6026 defsubr (&Swindow_minibuffer_p);
6027 defsubr (&Swindowp);
806b4d9b 6028 defsubr (&Swindow_live_p);
7ab12479
JB
6029 defsubr (&Spos_visible_in_window_p);
6030 defsubr (&Swindow_buffer);
6031 defsubr (&Swindow_height);
6032 defsubr (&Swindow_width);
6033 defsubr (&Swindow_hscroll);
6034 defsubr (&Sset_window_hscroll);
190eb263
RS
6035 defsubr (&Swindow_redisplay_end_trigger);
6036 defsubr (&Sset_window_redisplay_end_trigger);
7ab12479 6037 defsubr (&Swindow_edges);
d5783c40
JB
6038 defsubr (&Scoordinates_in_window_p);
6039 defsubr (&Swindow_at);
7ab12479
JB
6040 defsubr (&Swindow_point);
6041 defsubr (&Swindow_start);
6042 defsubr (&Swindow_end);
6043 defsubr (&Sset_window_point);
6044 defsubr (&Sset_window_start);
6045 defsubr (&Swindow_dedicated_p);
d207b766 6046 defsubr (&Sset_window_dedicated_p);
7ab12479
JB
6047 defsubr (&Swindow_display_table);
6048 defsubr (&Sset_window_display_table);
6049 defsubr (&Snext_window);
6050 defsubr (&Sprevious_window);
6051 defsubr (&Sother_window);
6052 defsubr (&Sget_lru_window);
6053 defsubr (&Sget_largest_window);
6054 defsubr (&Sget_buffer_window);
6055 defsubr (&Sdelete_other_windows);
6056 defsubr (&Sdelete_windows_on);
6057 defsubr (&Sreplace_buffer_in_windows);
6058 defsubr (&Sdelete_window);
6059 defsubr (&Sset_window_buffer);
6060 defsubr (&Sselect_window);
4628f7a4
EN
6061 defsubr (&Sspecial_display_p);
6062 defsubr (&Ssame_window_p);
7ab12479
JB
6063 defsubr (&Sdisplay_buffer);
6064 defsubr (&Ssplit_window);
6065 defsubr (&Senlarge_window);
6066 defsubr (&Sshrink_window);
6067 defsubr (&Sscroll_up);
6068 defsubr (&Sscroll_down);
6069 defsubr (&Sscroll_left);
6070 defsubr (&Sscroll_right);
ccd0664b 6071 defsubr (&Sother_window_for_scrolling);
7ab12479 6072 defsubr (&Sscroll_other_window);
fa832261 6073 defsubr (&Sminibuffer_selected_window);
7ab12479 6074 defsubr (&Srecenter);
81fe0836 6075 defsubr (&Swindow_text_height);
7ab12479
JB
6076 defsubr (&Smove_to_window_line);
6077 defsubr (&Swindow_configuration_p);
3f8ab7bd 6078 defsubr (&Swindow_configuration_frame);
7ab12479
JB
6079 defsubr (&Sset_window_configuration);
6080 defsubr (&Scurrent_window_configuration);
6081 defsubr (&Ssave_window_excursion);
5500c422
GM
6082 defsubr (&Sset_window_margins);
6083 defsubr (&Swindow_margins);
6084 defsubr (&Swindow_vscroll);
6085 defsubr (&Sset_window_vscroll);
2f8274be 6086 defsubr (&Scompare_window_configurations);
67492200 6087 defsubr (&Swindow_list);
7ab12479
JB
6088}
6089
dfcf069d 6090void
7ab12479
JB
6091keys_of_window ()
6092{
6093 initial_define_key (control_x_map, '1', "delete-other-windows");
6094 initial_define_key (control_x_map, '2', "split-window");
6095 initial_define_key (control_x_map, '0', "delete-window");
6096 initial_define_key (control_x_map, 'o', "other-window");
6097 initial_define_key (control_x_map, '^', "enlarge-window");
6098 initial_define_key (control_x_map, '<', "scroll-left");
6099 initial_define_key (control_x_map, '>', "scroll-right");
6100
6101 initial_define_key (global_map, Ctl ('V'), "scroll-up");
6102 initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
6103 initial_define_key (meta_map, 'v', "scroll-down");
6104
6105 initial_define_key (global_map, Ctl('L'), "recenter");
6106 initial_define_key (meta_map, 'r', "move-to-window-line");
6107}