XEmacs 21.2.19 "Shinjuku".
[chise/xemacs-chise.git.1] / src / window.c
1 /* Window creation, deletion and examination for XEmacs.
2    Copyright (C) 1985-1987, 1992-1995 Free Software Foundation, Inc.
3    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
4    Copyright (C) 1995, 1996 Ben Wing.
5    Copyright (C) 1996 Chuck Thompson.
6
7 This file is part of XEmacs.
8
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
12 later version.
13
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING.  If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 /* Synched up with: FSF 19.30. */
25 /* Beginning to diverge significantly. */
26
27 /* This file has been Mule-ized. */
28
29 #include <config.h>
30 #include "lisp.h"
31
32 #include "buffer.h"
33 #include "faces.h"
34 #include "frame.h"
35 #include "objects.h"
36 #include "glyphs.h"
37 #include "redisplay.h"
38 #include "window.h"
39 #include "elhash.h"
40 #include "commands.h"
41 #include "gutter.h"
42
43 Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configurationp;
44 Lisp_Object Qscroll_up, Qscroll_down, Qdisplay_buffer;
45
46 #ifdef MEMORY_USAGE_STATS
47 Lisp_Object Qface_cache, Qglyph_cache, Qline_start_cache, Qother_redisplay;
48 #ifdef HAVE_SCROLLBARS
49 Lisp_Object Qscrollbar_instances;
50 #endif
51 #endif
52
53 EXFUN (Fnext_window, 4);
54
55 static int window_pixel_width_to_char_width (struct window *w,
56                                              int pixel_width,
57                                              int include_margins_p);
58 static int window_char_width_to_pixel_width (struct window *w,
59                                              int char_width,
60                                              int include_margins_p);
61 static int window_pixel_height_to_char_height (struct window *w,
62                                                int pixel_height,
63                                                int include_gutters_p);
64 static int window_char_height_to_pixel_height (struct window *w,
65                                                int char_height,
66                                                int include_gutters_p);
67 static void change_window_height (struct window *w, int delta, int widthflag,
68                                   int inpixels);
69
70 /* Thickness of shadow border around 3d modelines. */
71 Lisp_Object Vmodeline_shadow_thickness;
72
73 /* Whether vertical dividers are draggable and displayed */
74 Lisp_Object Vvertical_divider_always_visible_p;
75
76 /* Whether a modeline should be displayed. */
77 Lisp_Object Vhas_modeline_p;
78
79 /* Thickness of shadow border around vertical dividers. */
80 Lisp_Object Vvertical_divider_shadow_thickness;
81
82 /* Divider surface width (not counting 3-d borders) */
83 Lisp_Object Vvertical_divider_line_width;
84
85 /* Spacing between outer egde of divider border and window edge */
86 Lisp_Object Vvertical_divider_spacing;
87
88 /* Scroll if point lands on the bottom line and that line is partially
89    clipped. */
90 int scroll_on_clipped_lines;
91
92 /* The minibuffer window of the selected frame.
93    Note that you cannot test for minibufferness of an arbitrary window
94    by comparing against this; but you can test for minibufferness of
95    the selected window.  */
96 Lisp_Object minibuf_window;
97
98 /* Non-nil means it is the window for C-M-v to scroll
99    when the minibuffer is selected.  */
100 Lisp_Object Vminibuffer_scroll_window;
101
102 /* Non-nil means this is the buffer whose window C-M-v should scroll.  */
103 Lisp_Object Vother_window_scroll_buffer;
104
105 /* Non-nil means it's the function to call to display temp buffers.  */
106 Lisp_Object Vtemp_buffer_show_function;
107
108 Lisp_Object Vtemp_buffer_show_hook;
109
110 /* If a window gets smaller than either of these, it is removed. */
111 int window_min_height;
112 int window_min_width;
113
114 /* Hook run at end of temp_output_buffer_show.  */
115 Lisp_Object Qtemp_buffer_show_hook;
116
117 /* Number of lines of continuity in scrolling by screenfuls.  */
118 int next_screen_context_lines;
119
120 /* List of freed window configurations with 1 - 10 windows. */
121 Lisp_Object Vwindow_configuration_free_list[10];
122
123 #define SET_LAST_MODIFIED(w, cache_too)         \
124 do {                                            \
125   (w)->last_modified[CURRENT_DISP] = Qzero;     \
126   (w)->last_modified[DESIRED_DISP] = Qzero;     \
127   (w)->last_modified[CMOTION_DISP] = Qzero;     \
128   if (cache_too)                                \
129     (w)->line_cache_last_updated = Qzero;       \
130 } while (0)
131
132 #define SET_LAST_FACECHANGE(w)                  \
133 do {                                            \
134   (w)->last_facechange[CURRENT_DISP] = Qzero;   \
135   (w)->last_facechange[DESIRED_DISP] = Qzero;   \
136   (w)->last_facechange[CMOTION_DISP] = Qzero;   \
137 } while (0)
138
139 \f
140 #define MARK_DISP_VARIABLE(field)               \
141   markobj (window->field[CURRENT_DISP]);        \
142   markobj (window->field[DESIRED_DISP]);        \
143   markobj (window->field[CMOTION_DISP]);
144
145 static Lisp_Object
146 mark_window (Lisp_Object obj, void (*markobj) (Lisp_Object))
147 {
148   struct window *window = XWINDOW (obj);
149   markobj (window->frame);
150   markobj (window->mini_p);
151   markobj (window->next);
152   markobj (window->prev);
153   markobj (window->hchild);
154   markobj (window->vchild);
155   markobj (window->parent);
156   markobj (window->buffer);
157   MARK_DISP_VARIABLE (start);
158   MARK_DISP_VARIABLE (pointm);
159   markobj (window->sb_point);   /* #### move to scrollbar.c? */
160   markobj (window->use_time);
161   MARK_DISP_VARIABLE (last_modified);
162   MARK_DISP_VARIABLE (last_point);
163   MARK_DISP_VARIABLE (last_start);
164   MARK_DISP_VARIABLE (last_facechange);
165   markobj (window->line_cache_last_updated);
166   markobj (window->redisplay_end_trigger);
167   markobj (window->subwindow_instance_cache);
168
169   mark_face_cachels (window->face_cachels, markobj);
170   mark_glyph_cachels (window->glyph_cachels, markobj);
171
172 #define WINDOW_SLOT(slot, compare) ((void) (markobj (window->slot)))
173 #include "winslots.h"
174
175   return Qnil;
176 }
177
178 static void
179 print_window (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
180 {
181   char buf[200];
182
183   if (print_readably)
184     error ("printing unreadable object #<window 0x%x>",
185            XWINDOW (obj)->header.uid);
186
187   write_c_string ("#<window", printcharfun);
188   if (!NILP (XWINDOW (obj)->buffer))
189     {
190       Lisp_Object name = XBUFFER (XWINDOW (obj)->buffer)->name;
191       write_c_string (" on ", printcharfun);
192       print_internal (name, printcharfun, 1);
193     }
194   sprintf (buf, " 0x%x>", XWINDOW (obj)->header.uid);
195   write_c_string (buf, printcharfun);
196 }
197
198 static void
199 finalize_window (void *header, int for_disksave)
200 {
201   struct window *w = (struct window *) header;
202
203   if (w->line_start_cache)
204     {
205       Dynarr_free (w->line_start_cache);
206       w->line_start_cache = 0;
207     }
208
209   if (w->face_cachels)
210     {
211       int i;
212
213       for (i = 0; i < Dynarr_length (w->face_cachels); i++)
214         {
215           struct face_cachel *cachel = Dynarr_atp (w->face_cachels, i);
216           if (cachel->merged_faces)
217             {
218               Dynarr_free (cachel->merged_faces);
219               cachel->merged_faces = 0;
220             }
221         }
222       Dynarr_free (w->face_cachels);
223       w->face_cachels = 0;
224     }
225
226   if (w->glyph_cachels)
227     {
228       Dynarr_free (w->glyph_cachels);
229       w->glyph_cachels = 0;
230     }
231 }
232
233 DEFINE_LRECORD_IMPLEMENTATION ("window", window,
234                                mark_window, print_window, finalize_window,
235                                0, 0, 0, struct window);
236
237
238 #define INIT_DISP_VARIABLE(field, initialization)       \
239   p->field[CURRENT_DISP] = initialization;              \
240   p->field[DESIRED_DISP] = initialization;              \
241   p->field[CMOTION_DISP] = initialization;
242
243 /* We have an implicit assertion that the first two elements (default
244    and modeline faces) are always present in the face_element_cache.
245    Normally redisplay ensures this.  However, it is possible for a
246    window to get created and functions which reference these values
247    called before redisplay works with the window for the first time.
248    All callers of allocate_window should therefore call
249    reset_face_cachels on the created window.  We can't do it
250    here because the window must have its frame pointer set or
251    reset_face_cachels will fail. */
252 Lisp_Object
253 allocate_window (void)
254 {
255   Lisp_Object val;
256   struct window *p = alloc_lcrecord_type (struct window, &lrecord_window);
257
258   zero_lcrecord (p);
259   XSETWINDOW (val, p);
260
261   p->dead = 0;
262   p->frame = Qnil;
263   p->mini_p = Qnil;
264   p->next = Qnil;
265   p->prev = Qnil;
266   p->hchild = Qnil;
267   p->vchild = Qnil;
268   p->parent = Qnil;
269   p->buffer = Qnil;
270   INIT_DISP_VARIABLE (start, Fmake_marker ());
271   INIT_DISP_VARIABLE (pointm, Fmake_marker ());
272   p->sb_point = Fmake_marker ();
273   p->use_time = Qzero;
274   INIT_DISP_VARIABLE (last_modified, Qzero);
275   INIT_DISP_VARIABLE (last_point, Fmake_marker ());
276   INIT_DISP_VARIABLE (last_start, Fmake_marker ());
277   INIT_DISP_VARIABLE (last_facechange, Qzero);
278   p->face_cachels     = Dynarr_new (face_cachel);
279   p->glyph_cachels    = Dynarr_new (glyph_cachel);
280   p->line_start_cache = Dynarr_new (line_start_cache);
281   p->subwindow_instance_cache = make_lisp_hash_table (10,
282                                                       HASH_TABLE_KEY_WEAK,
283                                                       HASH_TABLE_EQ);
284   p->line_cache_last_updated = Qzero;
285   INIT_DISP_VARIABLE (last_point_x, 0);
286   INIT_DISP_VARIABLE (last_point_y, 0);
287   INIT_DISP_VARIABLE (window_end_pos, 0);
288   p->redisplay_end_trigger = Qnil;
289
290 #define WINDOW_SLOT(slot, compare) p->slot = Qnil
291 #include "winslots.h"
292
293   p->windows_changed = 1;
294   p->shadow_thickness_changed = 1;
295
296   return val;
297 }
298 #undef INIT_DISP_VARIABLE
299 \f
300 /*
301  * The redisplay structures used to be stored with each window.  While
302  * they are logically something associated with frames they can't be
303  * stored there with a redisplay which handles variable height lines.
304  * Lines in horizontally split windows might not line up.  So they get
305  * stored with the windows.
306  *
307  * The problem with this is window configurations.  When restoring a
308  * window configuration it now becomes problematic to do an
309  * incremental redisplay.  The solution is to store the redisplay
310  * structures with the frame as they should be but laid out in the
311  * same manner as the window structure.  Thus is born the window
312  * mirror.
313  *
314  * It also becomes a convenient place to stick scrollbar instances
315  * since they extrapolate out to having the same problem described for
316  * the display structures.
317  */
318
319 /* Create a new window mirror structure and associated redisplay
320    structs. */
321 static struct window_mirror *
322 new_window_mirror (struct frame *f)
323 {
324   struct window_mirror *t = xnew_and_zero (struct window_mirror);
325
326   t->frame = f;
327
328   t->current_display_lines = Dynarr_new (display_line);
329   t->desired_display_lines = Dynarr_new (display_line);
330   t->buffer = NULL;
331
332 #ifdef HAVE_SCROLLBARS
333   t->scrollbar_vertical_instance = NULL;
334   t->scrollbar_horizontal_instance = NULL;
335 #endif
336
337   return t;
338 }
339
340 /* Synchronize the mirror structure with a given window structure.
341    This is normally called from update_frame_window_mirror with a
342    starting window of f->root_window. */
343 static struct window_mirror *
344 update_mirror_internal (Lisp_Object win, struct window_mirror *mir)
345 {
346   if (NILP (win))
347     {
348       if (mir)
349         {
350           free_window_mirror (mir);
351           mir = NULL;
352         }
353       return mir;
354     }
355   else
356     if (!mir)
357       mir = new_window_mirror (XFRAME (XWINDOW (win)->frame));
358
359   mir->next   = update_mirror_internal (XWINDOW (win)->next,   mir->next);
360   mir->hchild = update_mirror_internal (XWINDOW (win)->hchild, mir->hchild);
361   mir->vchild = update_mirror_internal (XWINDOW (win)->vchild, mir->vchild);
362
363   /*
364    * If the redisplay structs are not empty and the mirror has
365    * children, then this mirror structure was formerly being used for
366    * display but is no longer.  Reset its current display structs so
367    * that redisplay doesn't accidentally think they are accurate if it
368    * is later used for display purposes once again.  Also, mark the
369    * scrollbar instance as not active.
370    */
371   if (mir->vchild || mir->hchild)
372     {
373       /* The redisplay structures are big.  Leaving them around in
374          non-leaf windows can add up to a lot of wasted space.  So
375          don't do it. */
376       free_display_structs (mir);
377       mir->current_display_lines = Dynarr_new (display_line);
378       mir->desired_display_lines = Dynarr_new (display_line);
379
380 #ifdef HAVE_SCROLLBARS
381       update_window_scrollbars (XWINDOW (win), mir, 0, 0);
382 #endif
383       mir->buffer = NULL;
384     }
385
386   return mir;
387 }
388
389 /* Given a window mirror, determine which real window it contains the
390    redisplay structures for. */
391 static Lisp_Object
392 real_window_internal (Lisp_Object win, struct window_mirror *rmir,
393                       struct window_mirror *mir)
394 {
395   for (; !NILP (win) && rmir ; win = XWINDOW (win)->next, rmir = rmir->next)
396     {
397       if (mir == rmir)
398         return win;
399       if (!NILP (XWINDOW (win)->vchild))
400         {
401           Lisp_Object retval =
402             real_window_internal (XWINDOW (win)->vchild, rmir->vchild, mir);
403           if (!NILP (retval))
404             return retval;
405         }
406       if (!NILP (XWINDOW (win)->hchild))
407         {
408           Lisp_Object retval =
409             real_window_internal (XWINDOW (win)->hchild, rmir->hchild, mir);
410           if (!NILP (retval))
411             return retval;
412         }
413     }
414
415   return Qnil;
416 }
417
418 /* Given a real window, find the mirror structure which contains its
419    redisplay structures. */
420 static struct window_mirror *
421 find_window_mirror_internal (Lisp_Object win, struct window_mirror *rmir,
422                             struct window *w)
423 {
424   for (; !NILP (win); win = XWINDOW (win)->next, rmir = rmir->next)
425     {
426       if (w == XWINDOW (win))
427         return rmir;
428
429       if (!NILP (XWINDOW (win)->vchild))
430         {
431           struct window_mirror *retval =
432             find_window_mirror_internal (XWINDOW (win)->vchild,
433                                          rmir->vchild, w);
434           if (retval) return retval;
435         }
436
437       if (!NILP (XWINDOW (win)->hchild))
438         {
439           struct window_mirror *retval =
440             find_window_mirror_internal (XWINDOW (win)->hchild,
441                                          rmir->hchild, w);
442           if (retval) return retval;
443         }
444     }
445
446   return 0;
447 }
448
449 /* Update the mirror structure for the given frame. */
450 void
451 update_frame_window_mirror (struct frame *f)
452 {
453   f->root_mirror = update_mirror_internal (f->root_window, f->root_mirror);
454   f->mirror_dirty = 0;
455 }
456
457 /* Free a given mirror structure along with all of its children as
458    well as their associated display structures. */
459 void
460 free_window_mirror (struct window_mirror *mir)
461 {
462   while (mir)
463     {
464       struct window_mirror *prev = mir;
465       if (mir->hchild) free_window_mirror (mir->hchild);
466       if (mir->vchild) free_window_mirror (mir->vchild);
467 #ifdef HAVE_SCROLLBARS
468       release_window_mirror_scrollbars (mir);
469 #endif
470       free_display_structs (mir);
471       mir = mir->next;
472       xfree (prev);
473     }
474 }
475
476 /* Given a mirror structure, return the window it mirrors.  Calls
477    real_window_internal to do most of the work. */
478 Lisp_Object
479 real_window (struct window_mirror *mir, int no_abort)
480 {
481   Lisp_Object retval = real_window_internal (mir->frame->root_window,
482                                              mir->frame->root_mirror, mir);
483   if (NILP (retval) && !no_abort)
484     abort ();
485
486   return retval;
487 }
488
489 /* Given a real window, return its mirror structure.  Calls
490    find_window_mirror_internal to do all of the work. */
491 struct window_mirror *
492 find_window_mirror (struct window *w)
493 {
494   struct frame *f = XFRAME (w->frame);
495   if (f->mirror_dirty)
496     update_frame_window_mirror (f);
497   return find_window_mirror_internal (f->root_window, f->root_mirror, w);
498 }
499
500 /*****************************************************************************
501  find_window_by_pixel_pos
502
503  Given a pixel position relative to a frame, find the window at that
504  position.
505  ****************************************************************************/
506 struct window *
507 find_window_by_pixel_pos (int pix_x, int pix_y, Lisp_Object win)
508 {
509   if (NILP (win))
510     return 0;
511
512   for (; !NILP (win); win = XWINDOW (win)->next)
513     {
514       struct window *w;
515
516       if (!NILP (XWINDOW (win)->vchild))
517         {
518           w = find_window_by_pixel_pos (pix_x, pix_y, XWINDOW (win)->vchild);
519           if (w) return w;
520         }
521       if (!NILP (XWINDOW (win)->hchild))
522         {
523           w = find_window_by_pixel_pos (pix_x, pix_y, XWINDOW (win)->hchild);
524           if (w) return w;
525         }
526       w = XWINDOW (win);
527       if (pix_x >= WINDOW_LEFT (w)
528           && pix_x <= WINDOW_RIGHT (w)
529           && pix_y >= WINDOW_TOP (w)
530           && pix_y <= WINDOW_BOTTOM (w))
531         return w;
532     }
533   return NULL;
534 }
535
536 /* Return a pointer to the display structures for the given window. */
537 display_line_dynarr *
538 window_display_lines (struct window *w, int which)
539 {
540   struct window_mirror *t;
541
542   if (XFRAME (w->frame)->mirror_dirty)
543     update_frame_window_mirror (XFRAME (w->frame));
544   t = find_window_mirror (w);
545   if (!t)
546     abort ();
547
548   if (which == CURRENT_DISP)
549     return t->current_display_lines;
550   else if (which == DESIRED_DISP)
551     return t->desired_display_lines;
552   else if (which == CMOTION_DISP)
553     /* The CMOTION_DISP display lines are global. */
554     return cmotion_display_lines;
555   else
556     abort ();
557
558   return 0;     /* shut up compiler */
559 }
560
561 struct buffer *
562 window_display_buffer (struct window *w)
563 {
564   struct window_mirror *t;
565
566   if (XFRAME (w->frame)->mirror_dirty)
567     update_frame_window_mirror (XFRAME (w->frame));
568   t = find_window_mirror (w);
569   if (!t)
570     abort ();
571
572   return t->buffer;
573 }
574
575 void
576 set_window_display_buffer (struct window *w, struct buffer *b)
577 {
578   struct window_mirror *t;
579
580   if (XFRAME (w->frame)->mirror_dirty)
581     update_frame_window_mirror (XFRAME (w->frame));
582   t = find_window_mirror (w);
583   if (!t)
584     abort ();
585
586   t->buffer = b;
587 }
588
589 \f
590 /* Determining a window's position based solely on its pixel
591    positioning doesn't work.  Instead, we do it the intelligent way,
592    by checking its positioning in the window hierarchy. */
593 int
594 window_is_leftmost (struct window *w)
595 {
596   Lisp_Object parent, current_ancestor, window;
597
598   XSETWINDOW (window, w);
599
600   parent = XWINDOW (window)->parent;
601   current_ancestor = window;
602
603   while (!NILP (parent))
604     {
605       if (!NILP (XWINDOW (parent)->hchild) &&
606           !EQ (XWINDOW (parent)->hchild, current_ancestor))
607         return 0;
608
609       current_ancestor = parent;
610       parent = XWINDOW (parent)->parent;
611     }
612
613   return 1;
614 }
615
616 int
617 window_is_rightmost (struct window *w)
618 {
619   Lisp_Object parent, current_ancestor, window;
620
621   XSETWINDOW (window, w);
622
623   parent = XWINDOW (window)->parent;
624   current_ancestor = window;
625
626   while (!NILP (parent))
627     {
628       if (!NILP (XWINDOW (parent)->hchild)
629           && !NILP (XWINDOW (current_ancestor)->next))
630         return 0;
631
632       current_ancestor = parent;
633       parent = XWINDOW (parent)->parent;
634     }
635
636   return 1;
637 }
638
639 static int
640 window_full_width_p (struct window *w)
641 {
642   return window_is_leftmost (w) && window_is_rightmost (w);
643 }
644
645 int
646 window_is_highest (struct window *w)
647 {
648   Lisp_Object parent, current_ancestor, window;
649
650   XSETWINDOW (window, w);
651
652   parent = XWINDOW (window)->parent;
653   current_ancestor = window;
654
655   while (!NILP (parent))
656     {
657       if (!NILP (XWINDOW (parent)->vchild) &&
658           !EQ (XWINDOW (parent)->vchild, current_ancestor))
659         return 0;
660
661       current_ancestor = parent;
662       parent = XWINDOW (parent)->parent;
663     }
664
665   /* This is really to catch the minibuffer but we make it generic in
666      case we ever change things around to let the minibuffer be on top. */
667   if (NILP (XWINDOW (current_ancestor)->prev))
668     return 1;
669   else
670     return 0;
671 }
672
673 int
674 window_is_lowest (struct window *w)
675 {
676   Lisp_Object parent, current_ancestor, window;
677
678   XSETWINDOW (window, w);
679
680   parent = XWINDOW (window)->parent;
681   current_ancestor = window;
682
683   while (!NILP (parent))
684     {
685       if (!NILP (XWINDOW (parent)->vchild)
686           && !NILP (XWINDOW (current_ancestor)->next))
687         return 0;
688
689       current_ancestor = parent;
690       parent = XWINDOW (parent)->parent;
691     }
692
693   return 1;
694 }
695
696 #if 0 /* not currently used */
697
698 static int
699 window_full_height_p (struct window *w)
700 {
701   return window_is_highest (w) && window_is_lowest (w);
702 }
703
704 #endif
705
706 int
707 window_truncation_on (struct window *w)
708 {
709   /* Horizontally scrolled windows are truncated. */
710   if (w->hscroll)
711     return 1;
712
713   /* If truncate_partial_width_windows is true and the window is not
714      the full width of the frame it is truncated. */
715   if (truncate_partial_width_windows
716       && !(window_is_leftmost (w) && window_is_rightmost (w)))
717     return 1;
718
719   /* If the window's buffer's value of truncate_lines is non-nil, then
720      the window is truncated. */
721   if (!NILP (XBUFFER (w->buffer)->truncate_lines))
722     return 1;
723
724   return 0;
725 }
726
727 static int
728 have_undivided_common_edge (struct window *w_right, void *closure)
729 {
730   struct window *w_left = (struct window *) closure;
731   return (WINDOW_RIGHT (w_left) == WINDOW_LEFT (w_right)
732           && WINDOW_TOP (w_left) < WINDOW_BOTTOM (w_right)
733           && WINDOW_TOP (w_right) < WINDOW_BOTTOM (w_left)
734 #ifdef HAVE_SCROLLBARS
735           && (NILP (w_right->scrollbar_on_left_p)
736               || NILP (w_right->vertical_scrollbar_visible_p)
737               || ZEROP (w_right->scrollbar_width))
738 #endif
739           );
740 }
741
742 static int
743 window_needs_vertical_divider_1 (struct window *w)
744 {
745   /* Never if we're on the right */
746   if (window_is_rightmost (w))
747     return 0;
748
749   /* Always if draggable */
750   if (!NILP (w->vertical_divider_always_visible_p))
751     return 1;
752
753 #ifdef HAVE_SCROLLBARS
754   /* Our right scrollbar is enough to separate us at the right */
755   if (NILP (w->scrollbar_on_left_p)
756       && !NILP (w->vertical_scrollbar_visible_p)
757       && !ZEROP (w->scrollbar_width))
758     return 0;
759 #endif
760
761   /* Ok. to determine whether we need a divider on the left, we must
762      check that our right neighbor windows have scrollbars on their
763      left sides. We must check all such windows which have common
764      left edge with our window's right edge. */
765   return map_windows (XFRAME (WINDOW_FRAME (w)),
766                       have_undivided_common_edge, (void*)w);
767 }
768
769 int
770 window_needs_vertical_divider (struct window *w)
771 {
772   if (!w->need_vertical_divider_valid_p)
773     {
774       w->need_vertical_divider_p =
775         window_needs_vertical_divider_1 (w);
776       w->need_vertical_divider_valid_p = 1;
777     }
778   return w->need_vertical_divider_p;
779 }
780
781 /* Called from invalidate_vertical_divider_cache_in_frame */
782 int
783 invalidate_vertical_divider_cache_in_window (struct window *w,
784                                              void *u_n_u_s_e_d)
785 {
786   w->need_vertical_divider_valid_p = 0;
787   return 0;
788 }
789
790 /* Calculate width of vertical divider, including its shadows
791    and spacing. The returned value is effectively the distance
792    between adjacent window edges. This function does not check
793    whether a window needs a vertical divider, so the returned
794    value is a "theoretical" one */
795 int
796 window_divider_width (struct window *w)
797 {
798   /* the shadow thickness can be negative. This means that the divider
799      will have a depressed look */
800
801   if (FRAME_WIN_P (XFRAME (WINDOW_FRAME (w))))
802     return
803       XINT (w->vertical_divider_line_width)
804       + 2 * XINT (w->vertical_divider_spacing)
805       + 2 * abs (XINT (w->vertical_divider_shadow_thickness));
806   else
807     return XINT (w->vertical_divider_line_width) == 0 ? 0 : 1;
808 }
809
810 int
811 window_scrollbar_width (struct window *w)
812 {
813 #ifdef HAVE_SCROLLBARS
814   if (!WINDOW_WIN_P (w)
815       || MINI_WINDOW_P (w)
816       || NILP (w->buffer)
817       || NILP (w->vertical_scrollbar_visible_p))
818     /* #### when does NILP (w->buffer) happen? */
819     return 0;
820
821   return XINT (w->scrollbar_width);
822 #else
823   return 0;
824 #endif /* HAVE_SCROLLBARS */
825 }
826
827 /* Horizontal scrollbars are only active on windows with truncation
828    turned on. */
829 int
830 window_scrollbar_height (struct window *w)
831 {
832 #ifdef HAVE_SCROLLBARS
833   if (!WINDOW_WIN_P (w)
834       || MINI_WINDOW_P (w)
835       || NILP (w->buffer)
836       || NILP (w->horizontal_scrollbar_visible_p)
837       || !window_truncation_on (w))
838     return 0;
839
840   return XINT (w->scrollbar_height);
841 #else
842   return 0;
843 #endif /* HAVE_SCROLLBARS */
844 }
845
846 int
847 window_modeline_height (struct window *w)
848 {
849   struct frame *f = XFRAME (w->frame);
850   int modeline_height;
851
852   if (MINI_WINDOW_P (w) || NILP (w->buffer))
853     {
854       modeline_height = 0;
855     }
856   else if (!WINDOW_HAS_MODELINE_P (w))
857     {
858       if (window_scrollbar_height (w))
859         modeline_height = 0;
860       else
861         {
862           modeline_height = FRAMEMETH (f, divider_height, ());
863
864           if (!EQ (Qzero, w->modeline_shadow_thickness) && FRAME_WIN_P (f))
865             modeline_height += (2 * MODELINE_SHADOW_THICKNESS (w));
866         }
867     }
868   else
869     {
870       if (noninteractive)
871         modeline_height = 0;
872       else
873         {
874           display_line_dynarr *dla;
875
876           /* We don't force a regeneration of the modeline here.
877              Instead it is now a precondition that any function calling
878              this should make sure that one of these structures is
879              up-to-date.  In practice this only affects two internal
880              redisplay functions, regenerate_window and
881              regenerate_window_point_center. */
882           /* We check DESIRED_DISP because if it is valid it is more
883              up-to-date than CURRENT_DISP.  For calls to this outside
884              of redisplay it doesn't matter which structure we check
885              since there is a redisplay condition that these
886              structures be identical outside of redisplay. */
887           dla = window_display_lines (w, DESIRED_DISP);
888           if (dla && Dynarr_length (dla) && Dynarr_atp (dla, 0)->modeline)
889             modeline_height = (Dynarr_atp (dla, 0)->ascent +
890                                Dynarr_atp (dla, 0)->descent);
891           else
892             {
893               dla = window_display_lines (w, CURRENT_DISP);
894               if (dla && Dynarr_length (dla) && Dynarr_atp (dla, 0)->modeline)
895                 modeline_height = (Dynarr_atp (dla, 0)->ascent +
896                                    Dynarr_atp (dla, 0)->descent);
897               else
898                 /* This should be an abort except I'm not yet 100%
899                    confident that it won't ever get hit (though I
900                    haven't been able to trigger it).  It is extremely
901                    unlikely to cause any noticeable problem and even if
902                    it does it will be a minor display glitch. */
903                 /* #### Bullshit alert.  It does get hit and it causes
904                    noticeable glitches.  real_current_modeline_height
905                    is a kludge to fix this for 19.14. */
906                 modeline_height = real_current_modeline_height (w);
907             }
908
909           if (!EQ (Qzero, w->modeline_shadow_thickness) && FRAME_WIN_P (f))
910             modeline_height += (2 * MODELINE_SHADOW_THICKNESS (w));
911         }
912     }
913
914   return modeline_height;
915 }
916
917 /*****************************************************************************
918  margin_width_internal
919
920  For a given window, return the width in pixels of the specified margin.
921  ****************************************************************************/
922 static int
923 margin_width_internal (struct window *w, int left_margin)
924 {
925   struct buffer *b;
926   int window_cwidth = window_char_width (w, 1);
927   int margin_cwidth;
928   int font_width;
929   Lisp_Object window;
930
931   /* We might be getting called on a non-leaf. */
932   if (NILP (w->buffer))
933     return 0;
934
935   /* The minibuffer never has margins. */
936   if (MINI_WINDOW_P (w))
937     return 0;
938
939   XSETWINDOW (window, w);
940   b = XBUFFER (w->buffer);
941   margin_cwidth = (left_margin ? XINT (w->left_margin_width) :
942                    XINT (w->right_margin_width));
943
944   default_face_height_and_width (window, 0, &font_width);
945
946   /* The left margin takes precedence over the right margin so we
947      subtract its width from the space available for the right
948      margin. */
949   if (!left_margin)
950     window_cwidth -= XINT (w->left_margin_width);
951
952   /* The margin cannot be wider than the window is.  We allow the
953      value to be bigger since it is possible for the user to enlarge
954      the window such that the left margin value would no longer be too
955      big, but we won't return a value that is larger. */
956   if (margin_cwidth > window_cwidth)
957     margin_cwidth = window_cwidth;
958
959   /* At the user level the margin is always specified in characters.
960      Internally however it is manipulated in terms of pixels. */
961   return margin_cwidth * font_width;
962 }
963
964 int
965 window_left_margin_width (struct window *w)
966 {
967   return margin_width_internal (w, 1);
968 }
969
970 int
971 window_right_margin_width (struct window *w)
972 {
973   return margin_width_internal (w, 0);
974 }
975
976 /*****************************************************************************
977  Window Gutters
978
979  The gutters of a window are those areas in the boundary defined by
980  w->pixel_top, w->pixel_left, w->pixel_height and w->pixel_width which
981  do not contain text.  Items which may be in the gutters include
982  scrollbars, toolbars and modelines.  The margin areas are not
983  included.  This is an exception made because redisplay special cases
984  the handling of those areas in many places in such a way that
985  including them in the gutter area would make life difficult.
986
987  The size functions refer to height for the bottom and top gutters and
988  width for the left and right gutters.  The starting position
989  functions refer to the Y coord for bottom and top gutters and the X
990  coord for left and right gutters.  All starting positions are
991  relative to the frame, not the window.
992  ****************************************************************************/
993
994 int
995 window_top_gutter_height (struct window *w)
996 {
997   int gutter = WINDOW_REAL_TOP_GUTTER_BOUNDS (w);
998
999   if (!NILP (w->hchild) || !NILP (w->vchild))
1000     return 0;
1001
1002 #ifdef HAVE_SCROLLBARS
1003   if (!NILP (w->scrollbar_on_top_p))
1004     return window_scrollbar_height (w) + gutter;
1005   else
1006 #endif
1007     return gutter;
1008 }
1009
1010 int
1011 window_bottom_gutter_height (struct window *w)
1012 {
1013   int gutter = WINDOW_REAL_BOTTOM_GUTTER_BOUNDS (w);
1014
1015   if (!NILP (w->hchild) || !NILP (w->vchild))
1016     return 0;
1017
1018   gutter += window_modeline_height (w);
1019
1020 #ifdef HAVE_SCROLLBARS
1021   if (NILP (w->scrollbar_on_top_p))
1022     return window_scrollbar_height (w) + gutter;
1023   else
1024 #endif
1025     return gutter;
1026 }
1027
1028 int
1029 window_left_gutter_width (struct window *w, int modeline)
1030 {
1031   int gutter = WINDOW_REAL_LEFT_GUTTER_BOUNDS (w);
1032
1033   if (!NILP (w->hchild) || !NILP (w->vchild))
1034     return 0;
1035
1036 #ifdef HAVE_SCROLLBARS
1037   if (!modeline && !NILP (w->scrollbar_on_left_p))
1038     gutter += window_scrollbar_width (w);
1039 #endif
1040
1041   return gutter;
1042 }
1043
1044 int
1045 window_right_gutter_width (struct window *w, int modeline)
1046 {
1047   int gutter = WINDOW_REAL_RIGHT_GUTTER_BOUNDS (w);
1048
1049   if (!NILP (w->hchild) || !NILP (w->vchild))
1050     return 0;
1051
1052 #ifdef HAVE_SCROLLBARS
1053   if (!modeline && NILP (w->scrollbar_on_left_p))
1054     gutter += window_scrollbar_width (w);
1055 #endif
1056
1057   if (window_needs_vertical_divider (w))
1058     gutter += window_divider_width (w);
1059
1060   return gutter;
1061 }
1062
1063 \f
1064 DEFUN ("windowp", Fwindowp, 1, 1, 0, /*
1065 Return t if OBJ is a window.
1066 */
1067        (obj))
1068 {
1069   return WINDOWP (obj) ? Qt : Qnil;
1070 }
1071
1072 DEFUN ("window-live-p", Fwindow_live_p, 1, 1, 0, /*
1073 Return t if OBJ is a window which is currently visible.
1074 */
1075        (obj))
1076 {
1077   return WINDOWP (obj) && WINDOW_LIVE_P (XWINDOW (obj)) ? Qt : Qnil;
1078 }
1079
1080 DEFUN ("selected-window", Fselected_window, 0, 1, 0, /*
1081 Return the window that the cursor now appears in and commands apply to.
1082 If the optional argument CON-DEV-OR-FRAME is specified and is a frame, return
1083 the selected window used by that frame.  If CON-DEV-OR-FRAME is a device,
1084 then the selected frame on that device will be used.  If CON-DEV-OR-FRAME
1085 is a console, the selected frame on that console's selected device will
1086 be used.  Otherwise, the selected frame is used.
1087 */
1088        (con_dev_or_frame))
1089 {
1090   if (NILP (con_dev_or_frame) && NILP (Fselected_device (Qnil)))
1091     return Qnil; /* happens at startup */
1092
1093   {
1094     struct frame *f = decode_frame_or_selected (con_dev_or_frame);
1095     return FRAME_SELECTED_WINDOW (f);
1096   }
1097 }
1098
1099 DEFUN ("minibuffer-window", Fminibuffer_window, 0, 1, 0, /*
1100 Return the window used now for minibuffers.
1101 If the optional argument CON-DEV-OR-FRAME is specified and is a frame, return
1102 the minibuffer window used by that frame.  If CON-DEV-OR-FRAME is a device,
1103 then the selected frame on that device will be used.  If CON-DEV-OR-FRAME
1104 is a console, the selected frame on that console's selected device will
1105 be used.  Otherwise, the selected frame is used.
1106 */
1107        (con_dev_or_frame))
1108 {
1109   return FRAME_MINIBUF_WINDOW (decode_frame_or_selected (con_dev_or_frame));
1110 }
1111
1112 DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, 1, 1, 0, /*
1113 Return non-nil if WINDOW is a minibuffer window.
1114 */
1115        (window))
1116 {
1117   return MINI_WINDOW_P (decode_window (window)) ? Qt : Qnil;
1118 }
1119
1120 DEFUN ("window-first-hchild", Fwindow_first_hchild, 1, 1, 0, /*
1121 Return the first horizontal child of WINDOW, or nil.
1122 */
1123        (window))
1124 {
1125   return decode_window (window)->hchild;
1126 }
1127
1128 DEFUN ("window-first-vchild", Fwindow_first_vchild, 1, 1, 0, /*
1129 Return the first vertical child of WINDOW, or nil.
1130 */
1131        (window))
1132 {
1133   return decode_window (window)->vchild;
1134 }
1135
1136 DEFUN ("window-next-child", Fwindow_next_child, 1, 1, 0, /*
1137 Return the next window on the same level as WINDOW, or nil.
1138 */
1139        (window))
1140 {
1141   return decode_window (window)->next;
1142 }
1143
1144 DEFUN ("window-previous-child", Fwindow_previous_child, 1, 1, 0, /*
1145 Return the previous window on the same level as WINDOW, or nil.
1146 */
1147        (window))
1148 {
1149   return decode_window (window)->prev;
1150 }
1151
1152 DEFUN ("window-parent", Fwindow_parent, 1, 1, 0, /*
1153 Return the parent of WINDOW, or nil.
1154 */
1155        (window))
1156 {
1157   return decode_window (window)->parent;
1158 }
1159
1160 DEFUN ("window-lowest-p", Fwindow_lowest_p, 1, 1, 0, /*
1161 Return non-nil if WINDOW is along the bottom of its frame.
1162 */
1163        (window))
1164 {
1165   return window_is_lowest (decode_window (window)) ? Qt : Qnil;
1166 }
1167
1168 DEFUN ("window-highest-p", Fwindow_highest_p, 1, 1, 0, /*
1169 Return non-nil if WINDOW is along the top of its frame.
1170 */
1171        (window))
1172 {
1173   return window_is_highest (decode_window (window)) ? Qt : Qnil;
1174 }
1175
1176 DEFUN ("window-leftmost-p", Fwindow_leftmost_p, 1, 1, 0, /*
1177 Return non-nil if WINDOW is along the left edge of its frame.
1178 */
1179        (window))
1180 {
1181   return window_is_leftmost (decode_window (window)) ? Qt : Qnil;
1182 }
1183
1184 DEFUN ("window-rightmost-p", Fwindow_rightmost_p, 1, 1, 0, /*
1185 Return non-nil if WINDOW is along the right edge of its frame.
1186 */
1187        (window))
1188 {
1189   return window_is_rightmost (decode_window (window)) ? Qt : Qnil;
1190 }
1191
1192 DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p, 0, 2, 0, /*
1193 Return t if position POS is currently on the frame in WINDOW.
1194 Returns nil if that position is scrolled vertically out of view.
1195 POS defaults to point in WINDOW's buffer; WINDOW, to the selected window.
1196 */
1197        (pos, window))
1198 {
1199   struct window *w = decode_window (window);
1200   Bufpos top = marker_position (w->start[CURRENT_DISP]);
1201   Bufpos posint;
1202   struct buffer *buf = XBUFFER (w->buffer);
1203
1204   if (NILP (pos))
1205     posint = BUF_PT (buf);
1206   else
1207     {
1208       CHECK_INT_COERCE_MARKER (pos);
1209       posint = XINT (pos);
1210     }
1211
1212   if (posint < top || posint > BUF_ZV (buf))
1213     return Qnil;
1214
1215   /* w->start can be out of range.  If it is, do something reasonable.  */
1216   if (top < BUF_BEGV (buf) || top > BUF_ZV (buf))
1217     return Qnil;
1218
1219   return point_would_be_visible (w, top, posint) ? Qt : Qnil;
1220 }
1221
1222 \f
1223 struct window *
1224 decode_window (Lisp_Object window)
1225 {
1226   if (NILP (window))
1227     return XWINDOW (Fselected_window (Qnil));
1228
1229   CHECK_LIVE_WINDOW (window);
1230   return XWINDOW (window);
1231 }
1232
1233 DEFUN ("window-buffer", Fwindow_buffer, 0, 1, 0, /*
1234 Return the buffer that WINDOW is displaying.
1235 */
1236        (window))
1237 {
1238   return decode_window (window)->buffer;
1239 }
1240
1241 DEFUN ("window-frame", Fwindow_frame, 0, 1, 0, /*
1242 Return the frame that window WINDOW is on.
1243 */
1244        (window))
1245 {
1246   return decode_window (window)->frame;
1247 }
1248
1249 DEFUN ("window-height", Fwindow_height, 0, 1, 0, /*
1250 Return the number of default lines in WINDOW.
1251 This actually works by dividing the window's pixel height (including
1252 the modeline and horizontal scrollbar, if any) by the height of the
1253 default font; therefore, the number of displayed lines will probably
1254 be different.
1255 Use `window-height' to get consistent results in geometry calculations.
1256 Use `window-displayed-height' to get the actual number of lines
1257 currently displayed in a window.
1258 */
1259        (window))
1260 {
1261   return make_int (window_char_height (decode_window (window), 1));
1262 }
1263
1264 DEFUN ("window-displayed-height", Fwindow_displayed_height, 0, 1, 0, /*
1265 Return the number of lines currently displayed in WINDOW.
1266 This counts the actual number of lines displayed in WINDOW
1267 \(as opposed to `window-height').  The modeline and horizontal
1268 scrollbar do not count as lines.  If there is some blank space
1269 between the end of the buffer and the end of the window, this
1270 function pretends that there are lines of text in the default
1271 font there.
1272 */
1273      (window))
1274 {
1275   return make_int (window_displayed_height (decode_window (window)));
1276 }
1277
1278 DEFUN ("window-pixel-height", Fwindow_pixel_height, 0, 1, 0, /*
1279 Return the height of WINDOW in pixels.  Defaults to current window.
1280 This includes the window's modeline and horizontal scrollbar (if any).
1281 */
1282        (window))
1283 {
1284   return make_int (decode_window (window)->pixel_height);
1285 }
1286
1287 DEFUN ("window-text-area-pixel-height",
1288        Fwindow_text_area_pixel_height, 0, 1, 0, /*
1289 Return the height in pixels of the text-displaying portion of WINDOW.
1290 Unlike `window-pixel-height', the space occupied by the modeline and
1291 horizontal scrollbar, if any, is not counted.
1292 */
1293      (window))
1294 {
1295   struct window *w = decode_window (window);
1296
1297   return make_int (WINDOW_TEXT_HEIGHT (w));
1298 }
1299
1300 DEFUN ("window-displayed-text-pixel-height",
1301        Fwindow_displayed_text_pixel_height, 0, 2, 0, /*
1302 Return the height in pixels of the text displayed in WINDOW.
1303 Unlike `window-text-area-pixel-height', any blank space below the
1304 end of the buffer is not included.  If optional argument NOCLIPPED
1305 is non-nil, do not include space occupied by clipped lines.
1306 */
1307      (window, noclipped))
1308 {
1309   struct window *w;
1310   Bufpos start, eobuf;
1311   int defheight;
1312   int hlimit, height, prev_height = -1;
1313   int line;
1314   int elt, nelt, i;
1315   int needed;
1316   line_start_cache_dynarr *cache;
1317
1318   if (NILP (window))
1319     window = Fselected_window (Qnil);
1320
1321   CHECK_LIVE_WINDOW (window);
1322   w = XWINDOW (window);
1323
1324   start  = marker_position (w->start[CURRENT_DISP]);
1325   hlimit = WINDOW_TEXT_HEIGHT (w);
1326   eobuf  = BUF_ZV (XBUFFER (w->buffer));
1327
1328   default_face_height_and_width (window, &defheight, NULL);
1329
1330   /* guess lines needed in line start cache + a few extra */
1331   needed = (hlimit + defheight-1) / defheight + 3;
1332
1333   while (1) {
1334     elt = point_in_line_start_cache (w, start, needed);
1335     assert (elt >= 0); /* in the cache */
1336
1337     cache = w->line_start_cache;
1338     nelt  = Dynarr_length (cache);
1339
1340     height = 0;
1341     for (i = elt; i < nelt; i++) {
1342       line = Dynarr_atp (cache, i)->height;
1343
1344       if (height + line > hlimit)
1345         return make_int (!NILP (noclipped) ? height : hlimit);
1346
1347       height += line;
1348
1349       if (height == hlimit || Dynarr_atp (cache, i)->end >= eobuf)
1350         return make_int (height);
1351     }
1352
1353     /* get here => need more cache lines.  try again. */
1354     assert(height > prev_height); /* progress? */
1355     prev_height = height;
1356
1357     needed += ((hlimit - height)*(nelt - elt) + height-1)/height + 3;
1358   }
1359
1360   RETURN_NOT_REACHED(make_int (0))        /* shut up compiler */
1361 }
1362
1363 DEFUN ("window-width", Fwindow_width, 0, 1, 0, /*
1364 Return the number of display columns in WINDOW.
1365 This is the width that is usable columns available for text in WINDOW.
1366 */
1367        (window))
1368 {
1369   return make_int (window_char_width (decode_window (window), 0));
1370 }
1371
1372 DEFUN ("window-pixel-width", Fwindow_pixel_width, 0, 1, 0, /*
1373 Return the width of WINDOW in pixels.  Defaults to current window.
1374 */
1375        (window))
1376 {
1377   return make_int (decode_window (window)->pixel_width);
1378 }
1379
1380 DEFUN ("window-text-area-pixel-width",
1381        Fwindow_text_area_pixel_width, 0, 1, 0, /*
1382 Return the width in pixels of the text-displaying portion of WINDOW.
1383 Unlike `window-pixel-width', the space occupied by the vertical
1384 scrollbar or divider, if any, is not counted.
1385 */
1386      (window))
1387 {
1388   struct window *w = decode_window (window);
1389
1390   return make_int (WINDOW_TEXT_WIDTH (w));
1391 }
1392
1393 DEFUN ("window-hscroll", Fwindow_hscroll, 0, 1, 0, /*
1394 Return the number of columns by which WINDOW is scrolled from left margin.
1395 */
1396        (window))
1397 {
1398   return make_int (decode_window (window)->hscroll);
1399 }
1400
1401 #ifdef MODELINE_IS_SCROLLABLE
1402 DEFUN ("modeline-hscroll", Fmodeline_hscroll, 0, 1, 0, /*
1403 Return the number of columns by which WINDOW's modeline is scrolled from
1404 left margin. If the window has no modeline, return nil.
1405 */
1406        (window))
1407 {
1408   struct window *w = decode_window (window);
1409
1410   return (WINDOW_HAS_MODELINE_P (w)) ? make_int (w->modeline_hscroll) : Qnil;
1411 }
1412
1413 DEFUN ("set-modeline-hscroll", Fset_modeline_hscroll, 2, 2, 0, /*
1414 Set number of columns WINDOW's modeline is scrolled from left margin to NCOL.
1415 NCOL should be zero or positive. If NCOL is negative, it will be forced to 0.
1416 If the window has no modeline, do nothing and return nil.
1417 */
1418        (window, ncol))
1419 {
1420   struct window *w = decode_window (window);
1421
1422   if (WINDOW_HAS_MODELINE_P (w))
1423     {
1424       int ncols;
1425       CHECK_INT (ncol);
1426       ncols = XINT (ncol);
1427       if (ncols < 0) ncols = 0;
1428       if (w->modeline_hscroll != ncols)
1429         MARK_MODELINE_CHANGED;
1430       w->modeline_hscroll = ncols;
1431       return ncol;
1432     }
1433   return Qnil;
1434 }
1435 #endif /* MODELINE_IS_SCROLLABLE */
1436
1437 DEFUN ("set-window-hscroll", Fset_window_hscroll, 2, 2, 0, /*
1438 Set number of columns WINDOW is scrolled from left margin to NCOL.
1439 NCOL should be zero or positive.
1440 */
1441        (window, ncol))
1442 {
1443   struct window *w;
1444   int ncols;
1445
1446   CHECK_INT (ncol);
1447   ncols = XINT (ncol);
1448   if (ncols < 0) ncols = 0;
1449   w = decode_window (window);
1450   if (w->hscroll != ncols)
1451     MARK_CLIP_CHANGED;  /* FSF marks differently but we aren't FSF. */
1452   w->hscroll = ncols;
1453   return ncol;
1454 }
1455
1456 #if 0 /* bogus FSF crock */
1457
1458 xxDEFUN ("window-redisplay-end-trigger",
1459          Fwindow_redisplay_end_trigger, 0, 1, 0, /*
1460 Return WINDOW's redisplay end trigger value.
1461 See `set-window-redisplay-end-trigger' for more information.
1462 */
1463          (window))
1464 {
1465   return decode_window (window)->redisplay_end_trigger;
1466 }
1467
1468 xxDEFUN ("set-window-redisplay-end-trigger",
1469          Fset_window_redisplay_end_trigger, 2, 2, 0, /*
1470 Set WINDOW's redisplay end trigger value to VALUE.
1471 VALUE should be a buffer position (typically a marker) or nil.
1472 If it is a buffer position, then if redisplay in WINDOW reaches a position
1473 beyond VALUE, the functions in `redisplay-end-trigger-functions' are called
1474 with two arguments: WINDOW, and the end trigger value.
1475 Afterwards the end-trigger value is reset to nil.
1476 */
1477          (window, value))
1478 {
1479   return (decode_window (window)->redisplay_end_trigger = value);
1480 }
1481
1482 #endif /* 0 */
1483
1484 DEFUN ("window-pixel-edges", Fwindow_pixel_edges, 0, 1, 0, /*
1485 Return a list of the pixel edge coordinates of WINDOW.
1486 \(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.
1487 The frame toolbars and menubars are considered to be outside of this area.
1488 */
1489        (window))
1490 {
1491   struct window *w = decode_window (window);
1492   struct frame *f = XFRAME (w->frame);
1493
1494   int left = w->pixel_left - FRAME_LEFT_BORDER_END (f);
1495   int top  = w->pixel_top  - FRAME_TOP_BORDER_END  (f);
1496
1497   return list4 (make_int (left),
1498                 make_int (top),
1499                 make_int (left + w->pixel_width),
1500                 make_int (top + w->pixel_height));
1501 }
1502
1503 DEFUN ("window-text-area-pixel-edges",
1504        Fwindow_text_area_pixel_edges, 0, 1, 0, /*
1505 Return a list of the pixel edge coordinates of the text area of WINDOW.
1506 Returns the list \(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at the
1507 top left corner of the window.
1508 */
1509        (window))
1510 {
1511   struct window *w = decode_window (window);
1512
1513   int left   = window_left_gutter_width (w, /* modeline = */ 0);
1514   int top    = window_top_gutter_height (w);
1515   int right  = WINDOW_WIDTH (w) - window_right_gutter_width (w, 0);
1516   int bottom = WINDOW_HEIGHT (w) - window_bottom_gutter_height (w);
1517
1518   return list4 (make_int (left),
1519                 make_int (top),
1520                 make_int (right),
1521                 make_int (bottom));
1522 }
1523
1524 DEFUN ("window-point", Fwindow_point, 0, 1, 0, /*
1525 Return current value of point in WINDOW.
1526 For a nonselected window, this is the value point would have
1527 if that window were selected.
1528
1529 Note that, when WINDOW is the selected window and its buffer
1530 is also currently selected, the value returned is the same as (point).
1531 It would be more strictly correct to return the `top-level' value
1532 of point, outside of any save-excursion forms.
1533 But that is hard to define.
1534 */
1535        (window))
1536 {
1537   struct window *w = decode_window (window);
1538
1539   /* The special check for current buffer is necessary for this
1540      function to work as defined when called within an excursion. */
1541   if (w == XWINDOW (Fselected_window (XFRAME (w->frame)->device))
1542       && current_buffer == XBUFFER (w->buffer))
1543     return Fpoint (Qnil);
1544   return Fmarker_position (w->pointm[CURRENT_DISP]);
1545 }
1546
1547 DEFUN ("window-start", Fwindow_start, 0, 1, 0, /*
1548 Return position at which display currently starts in WINDOW.
1549 This is updated by redisplay or by calling `set-window-start'.
1550 */
1551        (window))
1552 {
1553   return Fmarker_position (decode_window (window)->start[CURRENT_DISP]);
1554 }
1555
1556 DEFUN ("window-end", Fwindow_end, 0, 2, 0, /*
1557 Return position at which display currently ends in WINDOW.
1558 This is updated by redisplay, when it runs to completion.
1559 Simply changing the buffer text or setting `window-start'
1560 does not update this value.
1561 If GUARANTEE is non-nil, then the return value is guaranteed to be
1562 the value of window-end at the end of the next full redisplay assuming
1563 nothing else changes in the meantime.  This function is potentially much
1564 slower with this flag set.
1565 */
1566        (window, guarantee))
1567 {
1568   struct window *w = decode_window (window);
1569
1570   if (NILP (guarantee))
1571     {
1572       Lisp_Object buf;
1573       buf = w->buffer;
1574       CHECK_BUFFER (buf);
1575       return make_int (BUF_Z (XBUFFER (buf)) - w->window_end_pos[CURRENT_DISP]);
1576     }
1577   else
1578     {
1579       Bufpos startp = marker_position (w->start[CURRENT_DISP]);
1580       return make_int (end_of_last_line (w, startp));
1581     }
1582 }
1583
1584 DEFUN ("set-window-point", Fset_window_point, 2, 2, 0, /*
1585 Make point value in WINDOW be at position POS in WINDOW's buffer.
1586 */
1587        (window, pos))
1588 {
1589   struct window *w = decode_window (window);
1590
1591   CHECK_INT_COERCE_MARKER (pos);
1592   if (w == XWINDOW (Fselected_window (Qnil)))
1593     Fgoto_char (pos, Qnil);
1594   else
1595     set_marker_restricted (w->pointm[CURRENT_DISP], pos, w->buffer);
1596
1597   MARK_POINT_CHANGED;
1598   return pos;
1599 }
1600
1601 DEFUN ("set-window-start", Fset_window_start, 2, 3, 0, /*
1602 Make display in WINDOW start at position POS in WINDOW's buffer.
1603 Optional third arg NOFORCE non-nil inhibits next redisplay
1604 from overriding motion of point in order to display at this exact start.
1605 */
1606        (window, pos, noforce))
1607 {
1608   struct window *w = decode_window (window);
1609
1610   CHECK_INT_COERCE_MARKER (pos);
1611   set_marker_restricted (w->start[CURRENT_DISP], pos, w->buffer);
1612   /* this is not right, but much easier than doing what is right. */
1613   /* w->start_at_line_beg = 0; */
1614   /* WTF is the above supposed to mean?  GE */
1615   w->start_at_line_beg = beginning_of_line_p (XBUFFER (w->buffer),
1616                                               marker_position (w->start[CURRENT_DISP]));
1617   if (NILP (noforce))
1618     w->force_start = 1;
1619   w->redo_modeline = 1;
1620   SET_LAST_MODIFIED (w, 0);
1621   SET_LAST_FACECHANGE (w);
1622
1623   MARK_WINDOWS_CHANGED (w);
1624
1625   return pos;
1626 }
1627
1628 DEFUN ("window-dedicated-p", Fwindow_dedicated_p, 1, 1, 0, /*
1629 Return WINDOW's dedicated object, usually t or nil.
1630 See also `set-window-dedicated-p'.
1631 */
1632        (window))
1633 {
1634   return decode_window (window)->dedicated;
1635 }
1636
1637 DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p, 2, 2, 0, /*
1638 Control whether WINDOW is dedicated to the buffer it displays.
1639 If it is dedicated, Emacs will not automatically change
1640 which buffer appears in it.
1641 The second argument is the new value for the dedication flag;
1642 non-nil means yes.
1643 */
1644        (window, arg))
1645 {
1646   struct window *w = decode_window (window);
1647
1648   w->dedicated = NILP (arg) ? Qnil : Qt;
1649
1650   return w->dedicated;
1651 }
1652
1653 /* FSFmacs has window-display-table here.  We have display table as a
1654    specifier. */
1655
1656 \f
1657 /* Record info on buffer window w is displaying
1658    when it is about to cease to display that buffer.  */
1659 static void
1660 unshow_buffer (struct window *w)
1661 {
1662   Lisp_Object buf = w->buffer;
1663
1664   if (XBUFFER (buf) != XMARKER (w->pointm[CURRENT_DISP])->buffer)
1665     abort ();
1666
1667   /* FSF disables this check, so I'll do it too.  I hope it won't
1668      break things.  --ben */
1669 #if 0
1670   if (w == XWINDOW (Fselected_window (Qnil))
1671       || ! EQ (buf, XWINDOW (Fselected_window (Qnil))->buffer))
1672     /* Do this except when the selected window's buffer
1673        is being removed from some other window.  */
1674 #endif
1675     /* last_window_start records the start position that this buffer
1676        had in the last window to be disconnected from it.
1677        Now that this statement is unconditional,
1678        it is possible for the buffer to be displayed in the
1679        selected window, while last_window_start reflects another
1680        window which was recently showing the same buffer.
1681        Some people might say that might be a good thing.  Let's see.  */
1682     XBUFFER (buf)->last_window_start =
1683       marker_position (w->start[CURRENT_DISP]);
1684
1685   /* Point in the selected window's buffer
1686      is actually stored in that buffer, and the window's pointm isn't used.
1687      So don't clobber point in that buffer.  */
1688   if (! EQ (buf, XWINDOW (Fselected_window (Qnil))->buffer))
1689     {
1690       struct buffer *b= XBUFFER (buf);
1691       BUF_SET_PT (b, bufpos_clip_to_bounds (BUF_BEGV (b),
1692                                      marker_position (w->pointm[CURRENT_DISP]),
1693                                      BUF_ZV (b)));
1694     }
1695 }
1696
1697 /* Put REPLACEMENT into the window structure in place of OLD. */
1698 static void
1699 replace_window (Lisp_Object old, Lisp_Object replacement)
1700 {
1701   Lisp_Object tem;
1702   struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
1703
1704   /* If OLD is its frame's root_window, then replacement is the new
1705      root_window for that frame.  */
1706
1707   if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
1708     FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
1709
1710   WINDOW_LEFT (p) = WINDOW_LEFT (o);
1711   WINDOW_TOP (p) = WINDOW_TOP (o);
1712   WINDOW_WIDTH (p) = WINDOW_WIDTH (o);
1713   WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o);
1714
1715   p->next = tem = o->next;
1716   if (!NILP (tem))
1717     XWINDOW (tem)->prev = replacement;
1718
1719   p->prev = tem = o->prev;
1720   if (!NILP (tem))
1721     XWINDOW (tem)->next = replacement;
1722
1723   p->parent = tem = o->parent;
1724   if (!NILP (tem))
1725     {
1726       if (EQ (XWINDOW (tem)->vchild, old))
1727         XWINDOW (tem)->vchild = replacement;
1728       if (EQ (XWINDOW (tem)->hchild, old))
1729         XWINDOW (tem)->hchild = replacement;
1730     }
1731
1732   /* #### Here, if replacement is a vertical combination
1733      and so is its new parent, we should make replacement's
1734      children be children of that parent instead. */
1735 }
1736
1737 /* we're deleting W; set the structure of W to indicate this. */
1738
1739 static void
1740 mark_window_as_deleted (struct window *w)
1741 {
1742   /* In the loop
1743      (while t (split-window) (delete-window))
1744      we end up with a tree of deleted windows which are all connected
1745      through the `next' slot.  This might not seem so bad, as they're
1746      deleted, and will presumably be GCed - but if even *one* of those
1747      windows is still being pointed to, by the user, or by a window
1748      configuration, then *all* of those windows stick around.
1749
1750      Since the window-configuration code doesn't need any of the
1751      pointers to other windows (they are all recreated from the
1752      window-config data), we set them all to nil so that we
1753      are able to collect more actual garbage.
1754    */
1755   w->next = Qnil;
1756   w->prev = Qnil;
1757   w->hchild = Qnil;
1758   w->vchild = Qnil;
1759   w->parent = Qnil;
1760
1761   w->dead = 1;
1762
1763   /* Free the extra data structures attached to windows immediately so
1764      they don't sit around consuming excess space.  They will be
1765      reinitialized by the window-configuration code as necessary. */
1766   finalize_window ((void *) w, 0);
1767 }
1768
1769 DEFUN ("delete-window", Fdelete_window, 0, 2, "", /*
1770 Remove WINDOW from the display.  Default is selected window.
1771 If window is the only one on the frame, the frame is destroyed.
1772 Normally, you cannot delete the last non-minibuffer-only frame (you must
1773 use `save-buffers-kill-emacs' or `kill-emacs').  However, if optional
1774 second argument FORCE is non-nil, you can delete the last frame. (This
1775 will automatically call `save-buffers-kill-emacs'.)
1776 */
1777        (window, force))
1778 {
1779   /* This function can GC if this is the only window in the frame */
1780   struct window *w;
1781   Lisp_Object parent;
1782   struct window *par;
1783   Lisp_Object frame;
1784   struct frame *f;
1785   struct device *d;
1786
1787   /* Note: this function is called by other C code on non-leaf
1788      windows. */
1789
1790   /* Do the equivalent of decode_window() but don't error out on
1791      deleted window; it's OK to delete an already-deleted window. */
1792   if (NILP (window))
1793     window = Fselected_window (Qnil);
1794   else
1795     CHECK_WINDOW (window);
1796   w = XWINDOW (window);
1797
1798   /* It's okay to delete an already-deleted window.  */
1799   if (! WINDOW_LIVE_P (w))
1800     return Qnil;
1801
1802   frame = WINDOW_FRAME (w);
1803   f = XFRAME (frame);
1804   d = XDEVICE (FRAME_DEVICE (f));
1805
1806   if (TOP_LEVEL_WINDOW_P (w))
1807     {
1808       if (NILP (memq_no_quit (frame, DEVICE_FRAME_LIST (d))))
1809         /* this frame isn't fully initialized yet; don't blow up. */
1810         return Qnil;
1811
1812       if (MINI_WINDOW_P (XWINDOW (window)))
1813         error ("Attempt to delete the minibuffer window");
1814
1815       /* It has been suggested that it's a good thing for C-x 0 to have this
1816          behavior, but not such a good idea for #'delete-window to have it.
1817          Maybe C-x 0 should be bound to something else, or maybe frame
1818          deletion should only happen when this is called interactively.
1819        */
1820       delete_frame_internal (f, !NILP (force), 0, 0);
1821       return Qnil;
1822     }
1823
1824   /* At this point, we know the window has a parent. */
1825   parent = w->parent;
1826   par = XWINDOW (parent);
1827
1828   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
1829
1830   /* Are we trying to delete any frame's selected window?
1831      Note that we could be dealing with a non-leaf window
1832      where the selected window is one of our children.
1833      So, we check by scanning all the ancestors of the
1834      frame's selected window and comparing each one with
1835      WINDOW.  */
1836   {
1837     Lisp_Object pwindow;
1838
1839     pwindow = FRAME_SELECTED_WINDOW (f);
1840
1841     while (!NILP (pwindow))
1842       {
1843         if (EQ (window, pwindow))
1844           break;
1845         pwindow = XWINDOW (pwindow)->parent;
1846       }
1847
1848     if (EQ (window, pwindow))
1849       {
1850         /* OK, we found it. */
1851         Lisp_Object alternative;
1852         alternative = Fnext_window (window, Qlambda, Qnil, Qnil);
1853
1854         /* If we're about to delete the selected window on the
1855            selected frame, then we should use Fselect_window to select
1856            the new window.  On the other hand, if we're about to
1857            delete the selected window on any other frame, we shouldn't do
1858            anything but set the frame's selected_window slot.  */
1859         if (EQ (frame, Fselected_frame (Qnil)))
1860           Fselect_window (alternative, Qnil);
1861         else
1862           set_frame_selected_window (f, alternative);
1863       }
1864   }
1865
1866   /* w->buffer is nil in a non-leaf window; in this case,
1867      get rid of the markers we maintain that point into that buffer. */
1868   if (!NILP (w->buffer))
1869     {
1870       unshow_buffer (w);
1871       unchain_marker (w->pointm[CURRENT_DISP]);
1872       unchain_marker (w->pointm[DESIRED_DISP]);
1873       unchain_marker (w->pointm[CMOTION_DISP]);
1874       unchain_marker (w->start[CURRENT_DISP]);
1875       unchain_marker (w->start[DESIRED_DISP]);
1876       unchain_marker (w->start[CMOTION_DISP]);
1877       unchain_marker (w->sb_point);
1878       /* This breaks set-window-configuration if windows in the saved
1879          configuration get deleted and multiple frames are in use. */
1880       /* w->buffer = Qnil; */
1881     }
1882
1883   /* close up the hole in the sibling list */
1884   if (!NILP (w->next))
1885     XWINDOW (w->next)->prev = w->prev;
1886   if (!NILP (w->prev))
1887     XWINDOW (w->prev)->next = w->next;
1888   if (EQ (window, par->hchild))
1889     par->hchild = w->next;
1890   if (EQ (window, par->vchild))
1891     par->vchild = w->next;
1892
1893   /* Find one of our siblings to give our space to.  */
1894   {
1895     Lisp_Object sib = w->prev;
1896     if (NILP (sib))
1897       {
1898         /* If w gives its space to its next sibling, that sibling needs
1899            to have its top/left side pulled back to where w's is.
1900            set_window_{height,width} will re-position the sibling's
1901            children.  */
1902         sib = w->next;
1903         WINDOW_TOP (XWINDOW (sib)) = WINDOW_TOP (w);
1904         WINDOW_LEFT (XWINDOW (sib)) = WINDOW_LEFT (w);
1905       }
1906
1907     /* Stretch that sibling.  */
1908     if (!NILP (par->vchild))
1909       set_window_pixheight
1910         (sib, (WINDOW_HEIGHT (XWINDOW (sib)) + WINDOW_HEIGHT (w)), 1);
1911     if (!NILP (par->hchild))
1912       set_window_pixwidth
1913         (sib, (WINDOW_WIDTH (XWINDOW (sib)) + WINDOW_WIDTH (w)), 1);
1914   }
1915
1916   /* If parent now has only one child,
1917      put the child into the parent's place.  */
1918   {
1919     Lisp_Object parchild = par->hchild;
1920     if (NILP (parchild))
1921       parchild = par->vchild;
1922     if (NILP (XWINDOW (parchild)->next))
1923       {
1924         replace_window (parent, parchild);
1925         mark_window_as_deleted (XWINDOW (parent));
1926       }
1927   }
1928
1929   /* Since we may be deleting combination windows, we must make sure that
1930      not only W but all its children have been marked as deleted.  */
1931   if (!NILP (w->hchild))
1932     delete_all_subwindows (XWINDOW (w->hchild));
1933   else if (!NILP (w->vchild))
1934     delete_all_subwindows (XWINDOW (w->vchild));
1935
1936   mark_window_as_deleted (w);
1937
1938   f->mirror_dirty = 1;
1939   return Qnil;
1940 }
1941
1942 \f
1943 DEFUN ("next-window", Fnext_window, 0, 4, 0, /*
1944 Return next window after WINDOW in canonical ordering of windows.
1945 If omitted, WINDOW defaults to the selected window.
1946
1947 Optional second arg MINIBUF t means count the minibuffer window even
1948 if not active.  MINIBUF nil or omitted means count the minibuffer iff
1949 it is active.  MINIBUF neither t nor nil means not to count the
1950 minibuffer even if it is active.
1951
1952 Several frames may share a single minibuffer; if the minibuffer
1953 counts, all windows on all frames that share that minibuffer count
1954 too.  Therefore, `next-window' can be used to iterate through the
1955 set of windows even when the minibuffer is on another frame.  If the
1956 minibuffer does not count, only windows from WINDOW's frame count.
1957
1958 Optional third arg ALL-FRAMES t means include windows on all frames.
1959 ALL-FRAMES nil or omitted means cycle within the frames as specified
1960 above.  ALL-FRAMES = `visible' means include windows on all visible frames.
1961 ALL-FRAMES = 0 means include windows on all visible and iconified frames.
1962 If ALL-FRAMES is a frame, restrict search to windows on that frame.
1963 Anything else means restrict to WINDOW's frame.
1964
1965 Optional fourth argument CONSOLE controls which consoles or devices the
1966 returned window may be on.  If CONSOLE is a console, return windows only
1967 on that console.  If CONSOLE is a device, return windows only on that
1968 device.  If CONSOLE is a console type, return windows only on consoles
1969 of that type.  If CONSOLE is 'window-system, return any windows on any
1970 window-system consoles.  If CONSOLE is nil or omitted, return windows only
1971 on WINDOW's console.  Otherwise, all windows are considered.
1972
1973 If you use consistent values for MINIBUF, ALL-FRAMES, and CONSOLE, you
1974 can use `next-window' to iterate through the entire cycle of acceptable
1975 windows, eventually ending up back at the window you started with.
1976 `previous-window' traverses the same cycle, in the reverse order.
1977 */
1978      (window, minibuf, all_frames, console))
1979 {
1980   Lisp_Object tem;
1981   Lisp_Object start_window;
1982
1983   if (NILP (window))
1984     window = Fselected_window (Qnil);
1985   else
1986     CHECK_LIVE_WINDOW (window);
1987
1988   start_window = window;
1989
1990   /* minibuf == nil may or may not include minibuffers.
1991      Decide if it does.  */
1992   if (NILP (minibuf))
1993     minibuf = (minibuf_level ? minibuf_window : Qlambda);
1994   else if (! EQ (minibuf, Qt))
1995     minibuf = Qlambda;
1996   /* Now minibuf can be t => count all minibuffer windows,
1997      lambda => count none of them,
1998      or a specific minibuffer window (the active one) to count.  */
1999
2000   /* all_frames == nil doesn't specify which frames to include.  */
2001   if (NILP (all_frames))
2002     all_frames = (! EQ (minibuf, Qlambda)
2003                   ? (FRAME_MINIBUF_WINDOW
2004                      (XFRAME
2005                       (WINDOW_FRAME
2006                        (XWINDOW (window)))))
2007                   : Qnil);
2008   else if (EQ (all_frames, Qvisible))
2009     ;
2010   else if (ZEROP (all_frames))
2011     ;
2012   else if (FRAMEP (all_frames) && ! EQ (all_frames, Fwindow_frame (window)))
2013     /* If all_frames is a frame and window arg isn't on that frame, just
2014        return the first window on the frame.  */
2015     return frame_first_window (XFRAME (all_frames));
2016   else if (! EQ (all_frames, Qt))
2017     all_frames = Qnil;
2018   /* Now all_frames is t meaning search all frames,
2019      nil meaning search just current frame,
2020      visible meaning search just visible frames,
2021      0 meaning search visible and iconified frames,
2022      or a window, meaning search the frame that window belongs to.  */
2023
2024   /* Do this loop at least once, to get the next window, and perhaps
2025      again, if we hit the minibuffer and that is not acceptable.  */
2026   do
2027     {
2028       /* Find a window that actually has a next one.  This loop
2029          climbs up the tree.  */
2030       while (tem = XWINDOW (window)->next, NILP (tem))
2031         if (tem = XWINDOW (window)->parent, !NILP (tem))
2032           window = tem;
2033         else  /* window must be minibuffer window now */
2034           {
2035             /* We've reached the end of this frame.
2036                Which other frames are acceptable?  */
2037             tem = WINDOW_FRAME (XWINDOW (window));
2038
2039             if (! NILP (all_frames))
2040               {
2041                 Lisp_Object tem1;
2042
2043                 tem1 = tem;
2044                 tem = next_frame (tem, all_frames, console);
2045                 /* In the case where the minibuffer is active,
2046                    and we include its frame as well as the selected one,
2047                    next_frame may get stuck in that frame.
2048                    If that happens, go back to the selected frame
2049                    so we can complete the cycle.  */
2050                 if (EQ (tem, tem1))
2051                   XSETFRAME (tem, selected_frame ());
2052               }
2053
2054             tem = FRAME_ROOT_WINDOW (XFRAME (tem));
2055             break;
2056           }
2057
2058       window = tem;
2059
2060       /* If we're in a combination window, find its first child and
2061          recurse on that.  Otherwise, we've found the window we want.  */
2062       while (1)
2063         {
2064           if (!NILP (XWINDOW (window)->hchild))
2065             window = XWINDOW (window)->hchild;
2066           else if (!NILP (XWINDOW (window)->vchild))
2067             window = XWINDOW (window)->vchild;
2068           else break;
2069         }
2070     }
2071   /* "acceptable" is the correct spelling. */
2072   /* Which windows are acceptable?
2073      Exit the loop and accept this window if
2074      this isn't a minibuffer window,
2075      or we're accepting all minibuffer windows,
2076      or this is the active minibuffer and we are accepting that one, or
2077      we've come all the way around and we're back at the original window.  */
2078   while (MINI_WINDOW_P (XWINDOW (window))
2079          && ! EQ (minibuf, Qt)
2080          && ! EQ (minibuf, window)
2081          && ! EQ (window, start_window));
2082
2083   return window;
2084 }
2085
2086 DEFUN ("previous-window", Fprevious_window, 0, 4, 0, /*
2087 Return the window preceding WINDOW in canonical ordering of windows.
2088 If omitted, WINDOW defaults to the selected window.
2089
2090 Optional second arg MINIBUF t means count the minibuffer window even
2091 if not active.  MINIBUF nil or omitted means count the minibuffer iff
2092 it is active.  MINIBUF neither t nor nil means not to count the
2093 minibuffer even if it is active.
2094
2095 Several frames may share a single minibuffer; if the minibuffer
2096 counts, all windows on all frames that share that minibuffer count
2097 too.  Therefore, `previous-window' can be used to iterate through
2098 the set of windows even when the minibuffer is on another frame.  If
2099 the minibuffer does not count, only windows from WINDOW's frame count
2100
2101 If optional third arg ALL-FRAMES t means include windows on all frames.
2102 ALL-FRAMES nil or omitted means cycle within the frames as specified
2103 above.  ALL-FRAMES = `visible' means include windows on all visible frames.
2104 ALL-FRAMES = 0 means include windows on all visible and iconified frames.
2105 If ALL-FRAMES is a frame, restrict search to windows on that frame.
2106 Anything else means restrict to WINDOW's frame.
2107
2108 Optional fourth argument CONSOLE controls which consoles or devices the
2109 returned window may be on.  If CONSOLE is a console, return windows only
2110 on that console.  If CONSOLE is a device, return windows only on that
2111 device.  If CONSOLE is a console type, return windows only on consoles
2112 of that type.  If CONSOLE is 'window-system, return any windows on any
2113 window-system consoles.  If CONSOLE is nil or omitted, return windows only
2114 on WINDOW's console.  Otherwise, all windows are considered.
2115
2116 If you use consistent values for MINIBUF, ALL-FRAMES, and CONSOLE, you
2117 can use `previous-window' to iterate through the entire cycle of acceptable
2118 windows, eventually ending up back at the window you started with.
2119 `next-window' traverses the same cycle, in the reverse order.
2120 */
2121      (window, minibuf, all_frames, console))
2122 {
2123   Lisp_Object tem;
2124   Lisp_Object start_window;
2125
2126   if (NILP (window))
2127     window = Fselected_window (Qnil);
2128   else
2129     CHECK_LIVE_WINDOW (window);
2130
2131   start_window = window;
2132
2133   /* minibuf == nil may or may not include minibuffers.
2134      Decide if it does.  */
2135   if (NILP (minibuf))
2136     minibuf = (minibuf_level ? minibuf_window : Qlambda);
2137   else if (! EQ (minibuf, Qt))
2138     minibuf = Qlambda;
2139   /* Now minibuf can be t => count all minibuffer windows,
2140      lambda => count none of them,
2141      or a specific minibuffer window (the active one) to count.  */
2142
2143   /* all_frames == nil doesn't specify which frames to include.
2144      Decide which frames it includes.  */
2145   if (NILP (all_frames))
2146     all_frames = (! EQ (minibuf, Qlambda)
2147                   ? (FRAME_MINIBUF_WINDOW
2148                      (XFRAME
2149                       (WINDOW_FRAME
2150                        (XWINDOW (window)))))
2151                   : Qnil);
2152   else if (EQ (all_frames, Qvisible))
2153     ;
2154   else if (ZEROP (all_frames))
2155     ;
2156   else if (FRAMEP (all_frames) && ! EQ (all_frames, Fwindow_frame (window)))
2157     /* If all_frames is a frame and window arg isn't on that frame, just
2158        return the first window on the frame.  */
2159     return frame_first_window (XFRAME (all_frames));
2160   else if (! EQ (all_frames, Qt))
2161     all_frames = Qnil;
2162   /* Now all_frames is t meaning search all frames,
2163      nil meaning search just current frame,
2164      visible meaning search just visible frames,
2165      0 meaning search visible and iconified frames,
2166      or a window, meaning search the frame that window belongs to.  */
2167
2168   /* Do this loop at least once, to get the next window, and perhaps
2169      again, if we hit the minibuffer and that is not acceptable.  */
2170   do
2171     {
2172       /* Find a window that actually has a next one.  This loop
2173          climbs up the tree.  */
2174       while (tem = XWINDOW (window)->prev, NILP (tem))
2175         if (tem = XWINDOW (window)->parent, !NILP (tem))
2176           window = tem;
2177         else  /* window must be minibuffer window now */
2178           {
2179             /* We have found the top window on the frame.
2180                Which frames are acceptable?  */
2181             tem = WINDOW_FRAME (XWINDOW (window));
2182
2183             if (! NILP (all_frames))
2184               /* It's actually important that we use prev_frame here,
2185                  rather than next_frame.  All the windows acceptable
2186                  according to the given parameters should form a ring;
2187                  Fnext_window and Fprevious_window should go back and
2188                  forth around the ring.  If we use next_frame here,
2189                  then Fnext_window and Fprevious_window take different
2190                  paths through the set of acceptable windows.
2191                  window_loop assumes that these `ring' requirement are
2192                  met.  */
2193               {
2194                 Lisp_Object tem1;
2195
2196                 tem1 = tem;
2197                 tem = prev_frame (tem, all_frames, console);
2198                 /* In the case where the minibuffer is active,
2199                    and we include its frame as well as the selected one,
2200                    next_frame may get stuck in that frame.
2201                    If that happens, go back to the selected frame
2202                    so we can complete the cycle.  */
2203                 if (EQ (tem, tem1))
2204                   XSETFRAME (tem, selected_frame ());
2205               }
2206
2207             /* If this frame has a minibuffer, find that window first,
2208                because it is conceptually the last window in that frame.  */
2209             if (FRAME_HAS_MINIBUF_P (XFRAME (tem)))
2210               tem = FRAME_MINIBUF_WINDOW (XFRAME (tem));
2211             else
2212               tem = FRAME_ROOT_WINDOW (XFRAME (tem));
2213
2214             break;
2215           }
2216
2217       window = tem;
2218
2219       /* If we're in a combination window, find its first child and
2220          recurse on that.  Otherwise, we've found the window we want.  */
2221       while (1)
2222         {
2223           if (!NILP (XWINDOW (window)->hchild))
2224             window = XWINDOW (window)->hchild;
2225           else if (!NILP (XWINDOW (window)->vchild))
2226             window = XWINDOW (window)->vchild;
2227           else break;
2228           while (tem = XWINDOW (window)->next, !NILP (tem))
2229             window = tem;
2230         }
2231     }
2232   /* Which windows are acceptable?
2233      Exit the loop and accept this window if
2234      this isn't a minibuffer window,
2235      or we're accepting all minibuffer windows,
2236      or this is the active minibuffer and we are accepting that one, or
2237      we've come all the way around and we're back at the original window.  */
2238   while (MINI_WINDOW_P (XWINDOW (window))
2239          && ! EQ (minibuf, Qt)
2240          && ! EQ (minibuf, window)
2241          && ! EQ (window, start_window));
2242
2243   return window;
2244 }
2245
2246 DEFUN ("next-vertical-window", Fnext_vertical_window, 0, 1, 0, /*
2247 Return the next window which is vertically after WINDOW.
2248 */
2249        (window))
2250 {
2251   Lisp_Object root;
2252   struct window *w = decode_window (window);
2253   XSETWINDOW (window, w);
2254
2255   if (MINI_WINDOW_P (XWINDOW (window)))
2256     return Qnil;
2257
2258   root = FRAME_ROOT_WINDOW (XFRAME (WINDOW_FRAME (XWINDOW (window))));
2259
2260   if (EQ (window, root))
2261     {
2262       while (1)
2263         if (!NILP (XWINDOW (window)->hchild))
2264           window = XWINDOW (window)->hchild;
2265         else if (!NILP (XWINDOW (window)->vchild))
2266           window = XWINDOW (window)->vchild;
2267         else
2268           return window;
2269     }
2270
2271   do
2272     {
2273       if (!NILP (XWINDOW (window)->parent) &&
2274           !NILP (XWINDOW (XWINDOW (window)->parent)->vchild))
2275         {
2276           if (!NILP (XWINDOW (window)->next))
2277             return XWINDOW (window)->next;
2278           else
2279             window = XWINDOW (window)->parent;
2280         }
2281       else
2282         window = XWINDOW (window)->parent;
2283     }
2284   while (!EQ (window, root));
2285
2286   while (1)
2287     if (!NILP (XWINDOW (window)->hchild))
2288       window = XWINDOW (window)->hchild;
2289     else if (!NILP (XWINDOW (window)->vchild))
2290       window = XWINDOW (window)->vchild;
2291     else
2292       return window;
2293 }
2294
2295 DEFUN ("other-window", Fother_window, 1, 3, "p", /*
2296 Select the N'th different window on this frame.
2297 All windows on current frame are arranged in a cyclic order.
2298 This command selects the window N steps away in that order.
2299 A negative N moves in the opposite order.
2300
2301 If optional argument FRAME is `visible', search all visible frames.
2302 If FRAME is 0, search all visible and iconified frames.
2303 If FRAME is t, search all frames.
2304 If FRAME is nil, search only the selected frame.
2305 If FRAME is a frame, search only that frame.
2306
2307 Optional third argument CONSOLE controls which consoles or devices the
2308 returned window may be on.  If CONSOLE is a console, return windows only
2309 on that console.  If CONSOLE is a device, return windows only on that
2310 device.  If CONSOLE is a console type, return windows only on consoles
2311 of that type.  If CONSOLE is 'window-system, return any windows on any
2312 window-system consoles.  If CONSOLE is nil or omitted, return windows only
2313 on FRAME'S console, or on the selected console if FRAME is not a frame.
2314 Otherwise, all windows are considered.
2315 */
2316        (n, frame, console))
2317 {
2318   int i;
2319   Lisp_Object w;
2320
2321   CHECK_INT (n);
2322   w = Fselected_window (Qnil);
2323   i = XINT (n);
2324
2325   while (i > 0)
2326     {
2327       w = Fnext_window (w, Qnil, frame, console);
2328       i--;
2329     }
2330   while (i < 0)
2331     {
2332       w = Fprevious_window (w, Qnil, frame, console);
2333       i++;
2334     }
2335   Fselect_window (w, Qnil);
2336   return Qnil;
2337 }
2338
2339 \f
2340 /* Look at all windows, performing an operation specified by TYPE
2341    with argument OBJ.
2342
2343    If FRAMES is Qt, look at all frames, if Qnil, look at just the selected
2344    frame.  If FRAMES is a frame, just look at windows on that frame.
2345    If MINI is non-zero, perform the operation on minibuffer windows too.
2346 */
2347
2348 enum window_loop
2349 {
2350   WINDOW_LOOP_UNUSED,
2351   GET_BUFFER_WINDOW,            /* Arg is buffer */
2352   GET_LRU_WINDOW,               /* Arg is t for full-width windows only */
2353   DELETE_OTHER_WINDOWS,         /* Arg is window not to delete */
2354   DELETE_BUFFER_WINDOWS,        /* Arg is buffer */
2355   GET_LARGEST_WINDOW,
2356   UNSHOW_BUFFER,                /* Arg is buffer */
2357   GET_BUFFER_WINDOW_COUNT,      /* Arg is buffer */
2358   GET_BUFFER_MRU_WINDOW         /* Arg is buffer */
2359 };
2360
2361 static Lisp_Object
2362 window_loop (enum window_loop type,
2363              Lisp_Object obj,
2364              int mini,
2365              Lisp_Object frames,
2366              int dedicated_too,
2367              Lisp_Object console)
2368 {
2369   /* This function can GC if type == DELETE_BUFFER_WINDOWS or UNSHOW_BUFFER */
2370   Lisp_Object w;
2371   Lisp_Object best_window = Qnil;
2372   Lisp_Object next_window;
2373   Lisp_Object last_window;
2374   struct frame *frame;
2375   Lisp_Object frame_arg = Qt;
2376   int count = 0;                /* for GET_BUFFER_WINDOW_COUNT */
2377   /* #### I think the change of "precomputing" last_window and next_window
2378    * ####  catch the lossage this is meant(?) to punt on...
2379    */
2380   int lose_lose = 0;
2381   Lisp_Object devcons, concons;
2382
2383   /* FRAME_ARG is Qlambda to stick to one frame,
2384      Qvisible to consider all visible frames,
2385      or Qt otherwise.  */
2386
2387   /* If we're only looping through windows on a particular frame,
2388      FRAME points to that frame.  If we're looping through windows
2389      on all frames, FRAME is 0.  */
2390
2391   if (FRAMEP (frames))
2392     frame = XFRAME (frames);
2393   else if (NILP (frames))
2394     frame = selected_frame ();
2395   else
2396     frame = 0;
2397   if (frame)
2398     frame_arg = Qlambda;
2399   else if (ZEROP (frames))
2400     frame_arg = frames;
2401   else if (EQ (frames, Qvisible))
2402     frame_arg = frames;
2403
2404   DEVICE_LOOP_NO_BREAK (devcons, concons)
2405     {
2406       Lisp_Object device = XCAR (devcons);
2407       Lisp_Object the_frame;
2408
2409       if (frame)
2410         XSETFRAME (the_frame, frame);
2411       else
2412         the_frame = DEVICE_SELECTED_FRAME (XDEVICE (device));
2413
2414       if (NILP (the_frame))
2415         continue;
2416
2417       if (!device_matches_console_spec (the_frame, device, console))
2418         continue;
2419
2420       /* Pick a window to start with.  */
2421       if (WINDOWP (obj))
2422         w = obj;
2423       else
2424         w = FRAME_SELECTED_WINDOW (XFRAME (the_frame));
2425
2426       /* Figure out the last window we're going to mess with.  Since
2427          Fnext_window, given the same options, is guaranteed to go in a
2428          ring, we can just use Fprevious_window to find the last one.
2429
2430          We can't just wait until we hit the first window again,
2431          because it might be deleted.  */
2432
2433       last_window = Fprevious_window (w, mini ? Qt : Qnil, frame_arg, Qt);
2434
2435       best_window = Qnil;
2436       for (;;)
2437         {
2438           struct window *p = XWINDOW (w);
2439           struct frame *w_frame = XFRAME (WINDOW_FRAME (p));
2440
2441           /* Pick the next window now, since some operations will delete
2442              the current window.  */
2443           next_window = Fnext_window (w, mini ? Qt : Qnil, frame_arg, Qt);
2444
2445           /* #### Still needed ?? */
2446           /* Given the outstanding quality of the rest of this code,
2447              I feel no shame about putting this piece of shit in. */
2448           if (++lose_lose >= 500)
2449             return Qnil;
2450
2451           /* Note that we do not pay attention here to whether
2452              the frame is visible, since Fnext_window skips non-visible frames
2453              if that is desired, under the control of frame_arg.  */
2454           if (! MINI_WINDOW_P (p)
2455               || (mini && minibuf_level > 0))
2456             switch (type)
2457               {
2458               case GET_BUFFER_WINDOW:
2459                 {
2460                   if (XBUFFER (p->buffer) == XBUFFER (obj))
2461                     return w;
2462                   break;
2463                 }
2464
2465               case GET_BUFFER_WINDOW_COUNT:
2466                 {
2467                   if (XBUFFER (p->buffer) == XBUFFER (obj))
2468                     count++;
2469                   break;
2470                 }
2471
2472               case GET_LRU_WINDOW:
2473                 {
2474                   /* t as arg means consider only full-width windows */
2475                   if (!NILP (obj)
2476                       && !window_full_width_p (p))
2477                     break;
2478                   /* Ignore dedicated windows and minibuffers.  */
2479                   if (MINI_WINDOW_P (p)
2480                       || (dedicated_too ? 0 : !NILP (p->dedicated)))
2481                     break;
2482                   if (NILP (best_window)
2483                       || (XINT (XWINDOW (best_window)->use_time)
2484                           > XINT (p->use_time)))
2485                     best_window = w;
2486                   break;
2487                 }
2488
2489               case GET_BUFFER_MRU_WINDOW:
2490                 {
2491                   /* #### what about the first check in GET_LRU_WINDOW? */
2492                   /* Ignore dedicated windows and minibuffers. */
2493                   if (MINI_WINDOW_P (p)
2494                       || (dedicated_too ? 0 : !NILP (p->dedicated)))
2495                     break;
2496
2497                   if (XBUFFER (p->buffer) == XBUFFER (obj))
2498                     {
2499                       if (NILP (best_window)
2500                           || (XINT (XWINDOW (best_window)->use_time)
2501                               < XINT (p->use_time)))
2502                         best_window = w;
2503                     }
2504                   break;
2505                 }
2506
2507               case DELETE_OTHER_WINDOWS:
2508                 {
2509                   /* Don't delete the last window on a frame; this can
2510                      happen when the minibuffer is selected, and would
2511                      cause the frame to be deleted. */
2512                   if (p != XWINDOW (obj) && !TOP_LEVEL_WINDOW_P (XWINDOW (w)))
2513                     Fdelete_window (w, Qnil);
2514                   break;
2515                 }
2516
2517               case DELETE_BUFFER_WINDOWS:
2518                 {
2519                   if (EQ (p->buffer, obj))
2520                     {
2521                       struct frame *f = XFRAME (WINDOW_FRAME (p));
2522
2523                       /* If this window is dedicated, and in a frame
2524                          of its own, kill the frame.  */
2525                       if (EQ (w, FRAME_ROOT_WINDOW (f))
2526                           && !NILP (p->dedicated)
2527                           && other_visible_frames (f))
2528                         {
2529                           /* Skip the other windows on this frame.
2530                              There might be one, the minibuffer!  */
2531                           if (! EQ (w, last_window))
2532                             while (f == XFRAME (WINDOW_FRAME
2533                                                 (XWINDOW (next_window))))
2534                               {
2535                                 /* As we go, check for the end of the
2536                                    loop.  We mustn't start going
2537                                    around a second time.  */
2538                                 if (EQ (next_window, last_window))
2539                                   {
2540                                     last_window = w;
2541                                     break;
2542                                   }
2543                                 next_window = Fnext_window (next_window,
2544                                                             mini ? Qt : Qnil,
2545                                                             frame_arg, Qt);
2546                               }
2547                           /* Now we can safely delete the frame.  */
2548                           Fdelete_frame (WINDOW_FRAME (p), Qnil);
2549                         }
2550                       else
2551                         /* If we're deleting the buffer displayed in
2552                            the only window on the frame, find a new
2553                            buffer to display there.  */
2554                         if (NILP (p->parent))
2555                           {
2556                             Lisp_Object new_buffer;
2557                             new_buffer = Fother_buffer (obj, Qnil, Qnil);
2558                             if (NILP (new_buffer))
2559                               new_buffer = Fget_buffer_create (QSscratch);
2560                             Fset_window_buffer (w, new_buffer);
2561                             if (EQ (w, Fselected_window (Qnil)))
2562                               Fset_buffer (p->buffer);
2563                           }
2564                         else
2565                           Fdelete_window (w, Qnil);
2566                     }
2567                   break;
2568                 }
2569
2570               case GET_LARGEST_WINDOW:
2571                 {
2572                   /* Ignore dedicated windows and minibuffers.  */
2573                   if (MINI_WINDOW_P (p)
2574                       || (dedicated_too ? 0 : !NILP (p->dedicated)))
2575                     break;
2576                   {
2577                     /* write the check as follows to avoid tripping
2578                        error_check_window() --ben */
2579                     struct window *b = NILP (best_window) ? 0 :
2580                       XWINDOW (best_window);
2581                     if (NILP (best_window)
2582                         || ((WINDOW_HEIGHT (p) * WINDOW_WIDTH (p))
2583                             > (WINDOW_HEIGHT (b) * WINDOW_WIDTH (b))))
2584                       best_window = w;
2585                   }
2586                   break;
2587                 }
2588
2589               case UNSHOW_BUFFER:
2590                 {
2591                   if (EQ (p->buffer, obj))
2592                     {
2593                       /* Find another buffer to show in this window.  */
2594                       Lisp_Object another_buffer =
2595                         Fother_buffer (obj, Qnil, Qnil);
2596                       if (NILP (another_buffer))
2597                         another_buffer
2598                           = Fget_buffer_create (QSscratch);
2599                       /* If this window is dedicated, and in a frame
2600                          of its own, kill the frame.  */
2601                       if (EQ (w, FRAME_ROOT_WINDOW (w_frame))
2602                           && !NILP (p->dedicated)
2603                           && other_visible_frames (w_frame))
2604                         {
2605                           /* Skip the other windows on this frame.
2606                              There might be one, the minibuffer!  */
2607                           if (! EQ (w, last_window))
2608                             while (w_frame == XFRAME (WINDOW_FRAME
2609                                                       (XWINDOW (next_window))))
2610                               {
2611                                 /* As we go, check for the end of the
2612                                    loop.  We mustn't start going
2613                                    around a second time.  */
2614                                 if (EQ (next_window, last_window))
2615                                   {
2616                                     last_window = w;
2617                                     break;
2618                                   }
2619                                 next_window = Fnext_window (next_window,
2620                                                             mini ? Qt : Qnil,
2621                                                             frame_arg, Qt);
2622                               }
2623                           /* Now we can safely delete the frame.  */
2624                           delete_frame_internal (XFRAME (WINDOW_FRAME (p)),
2625                                                  0, 0, 0);
2626                         }
2627                       else
2628                         {
2629                           /* Otherwise show a different buffer in the
2630                              window.  */
2631                           p->dedicated = Qnil;
2632                           Fset_window_buffer (w, another_buffer);
2633                           if (EQ (w, Fselected_window (Qnil)))
2634                             Fset_buffer (p->buffer);
2635                         }
2636                     }
2637                   break;
2638                 }
2639
2640               default:
2641                 abort ();
2642               }
2643
2644           if (EQ (w, last_window))
2645             break;
2646
2647           w = next_window;
2648         }
2649     }
2650
2651   return type == GET_BUFFER_WINDOW_COUNT ? make_int (count) : best_window;
2652 }
2653
2654 #if 0 /* not currently used */
2655
2656 int
2657 buffer_window_count (struct buffer *b, struct frame *f)
2658 {
2659   Lisp_Object buffer, frame;
2660
2661   XSETFRAME (frame, f);
2662   XSETBUFFER (buffer, b);
2663
2664   return XINT (window_loop (GET_BUFFER_WINDOW_COUNT, buffer, 0, frame, 1,
2665                             Qnil));
2666 }
2667
2668 int
2669 buffer_window_mru (struct window *w)
2670 {
2671   Lisp_Object window =
2672     window_loop (GET_BUFFER_MRU_WINDOW, w->buffer, 0, w->frame, 1, Qnil);
2673
2674   if (NILP (window))
2675     return 0;
2676   else if (XWINDOW (window) == w)
2677     return 1;
2678   else
2679     return 0;
2680 }
2681
2682 #endif
2683
2684 \f
2685 DEFUN ("get-lru-window", Fget_lru_window, 0, 2, 0, /*
2686 Return the window least recently selected or used for display.
2687 If optional argument FRAME is `visible', search all visible frames.
2688 If FRAME is 0, search all visible and iconified frames.
2689 If FRAME is t, search all frames.
2690 If FRAME is nil, search only the selected frame.
2691 If FRAME is a frame, search only that frame.
2692
2693 Optional second argument CONSOLE controls which consoles or devices the
2694 returned window may be on.  If CONSOLE is a console, return windows only
2695 on that console.  If CONSOLE is a device, return windows only on that
2696 device.  If CONSOLE is a console type, return windows only on consoles
2697 of that type.  If CONSOLE is 'window-system, return any windows on any
2698 window-system consoles.  If CONSOLE is nil or omitted, return windows only
2699 on FRAME'S console, or on the selected console if FRAME is not a frame.
2700 Otherwise, all windows are considered.
2701 */
2702        (frame, console))
2703 {
2704   Lisp_Object w;
2705   /* First try for a non-dedicated window that is full-width */
2706   w = window_loop (GET_LRU_WINDOW, Qt, 0, frame, 0, console);
2707   if (!NILP (w) && !EQ (w, Fselected_window (Qnil)))
2708     return w;
2709
2710   /* Then try for any non-dedicated window */
2711   w = window_loop (GET_LRU_WINDOW, Qnil, 0, frame, 0, console);
2712   if (!NILP (w) && !EQ (w, Fselected_window (Qnil)))
2713     return w;
2714
2715 #if 0
2716   /* FSFmacs never returns a dedicated window here.  If we do,
2717      it makes `display-buffer' not work right.  #### All of this
2718      shit is so disgusting and awful that it needs to be rethought
2719      from scratch. */
2720   /* then try for a dedicated window that is full-width */
2721   w = window_loop (GET_LRU_WINDOW, Qt, 0, frame, 1, console);
2722   if (!NILP (w) && !EQ (w, Fselected_window (Qnil)))
2723     return w;
2724
2725   /* If none of them, then all windows, dedicated or not. */
2726   w = window_loop (GET_LRU_WINDOW, Qnil, 0, frame, 1, console);
2727
2728   /* At this point we damn well better have found something. */
2729   if (NILP (w)) abort ();
2730 #endif
2731
2732   return w;
2733 }
2734
2735 DEFUN ("get-largest-window", Fget_largest_window, 0, 2, 0, /*
2736 Return the window largest in area.
2737 If optional argument FRAME is `visible', search all visible frames.
2738 If FRAME is 0, search all visible and iconified frames.
2739 If FRAME is t, search all frames.
2740 If FRAME is nil, search only the selected frame.
2741 If FRAME is a frame, search only that frame.
2742
2743 Optional second argument CONSOLE controls which consoles or devices the
2744 returned window may be on.  If CONSOLE is a console, return windows only
2745 on that console.  If CONSOLE is a device, return windows only on that
2746 device.  If CONSOLE is a console type, return windows only on consoles
2747 of that type.  If CONSOLE is 'window-system, return any windows on any
2748 window-system consoles.  If CONSOLE is nil or omitted, return windows only
2749 on FRAME'S console, or on the selected console if FRAME is not a frame.
2750 Otherwise, all windows are considered.
2751 */
2752        (frame, console))
2753 {
2754   /* Don't search dedicated windows because FSFmacs doesn't.
2755      This stuff is all black magic so don't try to apply common
2756      sense to it. */
2757   return window_loop (GET_LARGEST_WINDOW, Qnil, 0, frame, 0, console);
2758 }
2759
2760 DEFUN ("get-buffer-window", Fget_buffer_window, 1, 3, 0, /*
2761 Return a window currently displaying BUFFER, or nil if none.
2762 If optional argument FRAME is `visible', search all visible frames.
2763 If optional argument FRAME is 0, search all visible and iconified frames.
2764 If FRAME is t, search all frames.
2765 If FRAME is nil, search only the selected frame.
2766 If FRAME is a frame, search only that frame.
2767
2768 Optional third argument CONSOLE controls which consoles or devices the
2769 returned window may be on.  If CONSOLE is a console, return windows only
2770 on that console.  If CONSOLE is a device, return windows only on that
2771 device.  If CONSOLE is a console type, return windows only on consoles
2772 of that type.  If CONSOLE is 'window-system, return any windows on any
2773 window-system consoles.  If CONSOLE is nil or omitted, return windows only
2774 on FRAME'S console, or on the selected console if FRAME is not a frame.
2775 Otherwise, all windows are considered.
2776 */
2777        (buffer, frame, console))
2778 {
2779   buffer = Fget_buffer (buffer);
2780   if (BUFFERP (buffer))
2781     /* Search dedicated windows too. (Doesn't matter here anyway.) */
2782     return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame, 1, console);
2783   else
2784     return Qnil;
2785 }
2786
2787 /* These functions used to be `buffer-left-margin-pixel-width', etc.
2788    but there is no sensible way to implement those functions, since
2789    you can't in general derive a window from a buffer. */
2790
2791 DEFUN ("window-left-margin-pixel-width", Fwindow_left_margin_pixel_width,
2792        0, 1, 0, /*
2793 Return the width in pixels of the left outside margin of window WINDOW.
2794 If WINDOW is nil, the selected window is assumed.
2795 */
2796        (window))
2797 {
2798   return make_int (window_left_margin_width (decode_window (window)));
2799 }
2800
2801 DEFUN ("window-right-margin-pixel-width", Fwindow_right_margin_pixel_width,
2802        0, 1, 0, /*
2803 Return the width in pixels of the right outside margin of window WINDOW.
2804 If WINDOW is nil, the selected window is assumed.
2805 */
2806        (window))
2807 {
2808   return make_int (window_right_margin_width (decode_window (window)));
2809 }
2810
2811 DEFUN ("delete-other-windows", Fdelete_other_windows, 0, 1, "", /*
2812 Make WINDOW (or the selected window) fill its frame.
2813 Only the frame WINDOW is on is affected.
2814 This function tries to reduce display jumps
2815 by keeping the text previously visible in WINDOW
2816 in the same place on the frame.  Doing this depends on
2817 the value of (window-start WINDOW), so if calling this function
2818 in a program gives strange scrolling, make sure the window-start
2819 value is reasonable when this function is called.
2820 */
2821        (window))
2822 {
2823   struct window *w = decode_window (window);
2824   struct buffer *b = XBUFFER (w->buffer);
2825   Bufpos start_pos;
2826   int old_top = WINDOW_TOP (w);
2827
2828   XSETWINDOW (window, w);
2829
2830   if (MINI_WINDOW_P (w) && old_top > 0)
2831     error ("Can't expand minibuffer to full frame");
2832
2833   /* Ignore dedicated windows. */
2834   window_loop (DELETE_OTHER_WINDOWS, window, 0, w->frame, 0, Qnil);
2835
2836   start_pos = marker_position (w->start[CURRENT_DISP]);
2837
2838   /* Try to minimize scrolling, by setting the window start to the
2839      point which will cause the text at the old window start to be at
2840      the same place on the frame.  But don't try to do this if the
2841      window start is outside the visible portion (as might happen when
2842      the display is not current, due to typeahead). */
2843   if (start_pos >= BUF_BEGV (b) && start_pos <= BUF_ZV (b)
2844       && !MINI_WINDOW_P (w))
2845     {
2846       Bufpos new_start = start_with_line_at_pixpos (w, start_pos, old_top);
2847
2848       if (new_start >= BUF_BEGV (b) && new_start <= BUF_ZV (b))
2849         {
2850           Fset_marker (w->start[CURRENT_DISP], make_int (new_start),
2851                        w->buffer);
2852           w->start_at_line_beg = beginning_of_line_p (b, new_start);
2853         }
2854       /* We need to do this, so that the window-scroll-functions
2855          get called.  */
2856       w->force_start = 1;
2857     }
2858
2859   return Qnil;
2860 }
2861
2862 DEFUN ("delete-windows-on", Fdelete_windows_on, 1, 3,
2863        "bDelete windows on (buffer): ", /*
2864 Delete all windows showing BUFFER.
2865 Optional second argument FRAME controls which frames are affected.
2866 If nil or omitted, delete all windows showing BUFFER in any frame.
2867 If t, delete only windows showing BUFFER in the selected frame.
2868 If `visible', delete all windows showing BUFFER in any visible frame.
2869 If a frame, delete only windows showing BUFFER in that frame.
2870
2871 Optional third argument CONSOLE controls which consoles or devices the
2872 returned window may be on.  If CONSOLE is a console, return windows only
2873 on that console.  If CONSOLE is a device, return windows only on that
2874 device.  If CONSOLE is a console type, return windows only on consoles
2875 of that type.  If CONSOLE is 'window-system, return any windows on any
2876 window-system consoles.  If CONSOLE is nil or omitted, return windows only
2877 on FRAME'S console, or on the selected console if FRAME is not a frame.
2878 Otherwise, all windows are considered.
2879 */
2880        (buffer, frame, console))
2881 {
2882   /* This function can GC */
2883   /* FRAME uses t and nil to mean the opposite of what window_loop
2884      expects. */
2885   if (!FRAMEP (frame))
2886     frame = NILP (frame) ? Qt : Qnil;
2887
2888   if (!NILP (buffer))
2889     {
2890       buffer = Fget_buffer (buffer);
2891       CHECK_BUFFER (buffer);
2892       /* Ignore dedicated windows. */
2893       window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame, 0, console);
2894     }
2895   return Qnil;
2896 }
2897
2898 DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows, 1, 1,
2899        "bReplace buffer in windows: ", /*
2900 Replace BUFFER with some other buffer in all windows showing it.
2901 */
2902        (buffer))
2903 {
2904   /* This function can GC */
2905   if (!NILP (buffer))
2906     {
2907       buffer = Fget_buffer (buffer);
2908       CHECK_BUFFER (buffer);
2909       /* Ignore dedicated windows. */
2910       window_loop (UNSHOW_BUFFER, buffer, 0, Qt, 0, Qnil);
2911     }
2912   return Qnil;
2913 }
2914 \f
2915 /* The smallest acceptable dimensions for a window.  Anything smaller
2916    might crash Emacs.  */
2917 #define MIN_SAFE_WINDOW_WIDTH  (2)
2918 #define MIN_SAFE_WINDOW_HEIGHT (2)
2919
2920 /* Make sure that window_min_height and window_min_width are
2921    not too small; if they are, set them to safe minima.  */
2922
2923 static void
2924 check_min_window_sizes (void)
2925 {
2926   /* Smaller values might permit a crash.  */
2927   if (window_min_width < MIN_SAFE_WINDOW_WIDTH)
2928     window_min_width = MIN_SAFE_WINDOW_WIDTH;
2929   if (window_min_height < MIN_SAFE_WINDOW_HEIGHT)
2930     window_min_height = MIN_SAFE_WINDOW_HEIGHT;
2931 }
2932
2933 /* If *ROWS or *COLS are too small a size for FRAME, set them to the
2934    minimum allowable size.  */
2935 void
2936 check_frame_size (struct frame *frame, int *rows, int *cols)
2937 {
2938   /* For height, we have to see whether the frame has a minibuffer, and
2939      whether it wants a modeline.  */
2940   int min_height =
2941     (FRAME_MINIBUF_ONLY_P (frame) ? MIN_SAFE_WINDOW_HEIGHT - 1
2942      : (! FRAME_HAS_MINIBUF_P (frame)) ? MIN_SAFE_WINDOW_HEIGHT
2943      : 2 * MIN_SAFE_WINDOW_HEIGHT - 1);
2944
2945   if (*rows < min_height)
2946     *rows = min_height;
2947   if (*cols  < MIN_SAFE_WINDOW_WIDTH)
2948     *cols = MIN_SAFE_WINDOW_WIDTH;
2949 }
2950
2951 /* Normally the window is deleted if it gets too small.
2952    nodelete nonzero means do not do this.
2953    (The caller should check later and do so if appropriate)  */
2954 static void
2955 set_window_pixsize (Lisp_Object window, int new_pixsize, int nodelete,
2956                     int set_height)
2957 {
2958   struct window *w = XWINDOW (window);
2959   struct frame *f = XFRAME (w->frame);
2960   struct window *c;
2961   int old_pixsize = (set_height ? WINDOW_HEIGHT (w) : WINDOW_WIDTH (w));
2962   Lisp_Object child, minor_kid, major_kid;
2963   int minsize;
2964   int line_size;
2965   int defheight, defwidth;
2966
2967   /* #### This is very likely incorrect and instead the char_to_pixel_
2968      functions should be called. */
2969   default_face_height_and_width (window, &defheight, &defwidth);
2970   line_size = (set_height ? defheight : defwidth);
2971
2972   check_min_window_sizes ();
2973
2974   minsize = (set_height ? window_min_height : window_min_width);
2975   minsize *= line_size;
2976
2977   if (!nodelete
2978       && !TOP_LEVEL_WINDOW_P (w)
2979       && new_pixsize < minsize)
2980     {
2981       Fdelete_window (window, Qnil);
2982       return;
2983     }
2984
2985   SET_LAST_MODIFIED (w, 0);
2986   SET_LAST_FACECHANGE (w);
2987   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);     /* multiple windows affected */
2988   if (set_height)
2989     {
2990       WINDOW_HEIGHT (w) = new_pixsize;
2991       major_kid = w->vchild;
2992       minor_kid = w->hchild;
2993     }
2994   else
2995     {
2996       WINDOW_WIDTH (w) = new_pixsize;
2997       major_kid = w->hchild;
2998       minor_kid = w->vchild;
2999     }
3000
3001   if (!NILP (minor_kid))
3002     {
3003       for (child = minor_kid; !NILP (child); child = XWINDOW (child)->next)
3004         {
3005           if (set_height)
3006             WINDOW_TOP (XWINDOW (child)) = WINDOW_TOP (w);
3007           else
3008             WINDOW_LEFT (XWINDOW (child)) = WINDOW_LEFT (w);
3009
3010           set_window_pixsize (child, new_pixsize, nodelete, set_height);
3011         }
3012     }
3013   else if (!NILP (major_kid))
3014     {
3015       int last_pos, last_old_pos, pos, old_pos, first;
3016       int pixel_adj_left = new_pixsize - old_pixsize;
3017       int div_val = old_pixsize << 1;
3018
3019       /*
3020        * Previously we bailed out here if there was no size change.
3021        * (pixel_adj_left == 0) But this broke toolbar updates.  If a
3022        * toolbar appears or disappears, windows may not change size,
3023        * but their top and left coordinates need to be updated.
3024        *
3025        * So we don't bail until after the loop below.
3026        */
3027
3028       last_pos = first = (set_height ? WINDOW_TOP (w) : WINDOW_LEFT (w));
3029       last_old_pos = 0;
3030
3031       for (child = major_kid; !NILP (child); child = c->next)
3032         {
3033           c = XWINDOW (child);
3034
3035           if (set_height)
3036             {
3037               old_pos = last_old_pos + WINDOW_HEIGHT (c);
3038               WINDOW_TOP (c) = last_pos;
3039             }
3040           else
3041             {
3042               old_pos = last_old_pos + WINDOW_WIDTH (c);
3043               WINDOW_LEFT (c) = last_pos;
3044             }
3045
3046           pos = (((old_pos * new_pixsize) << 1) + old_pixsize) / div_val;
3047           /* All but the last window should have a height which is
3048              a multiple of the default line height. */
3049           if (!NILP (c->next))
3050             pos = (pos / line_size) * line_size;
3051
3052           /* Avoid confusion: don't delete child if it becomes too small */
3053           set_window_pixsize (child, pos + first - last_pos, 1, set_height);
3054
3055           last_pos = pos + first;
3056           last_old_pos = old_pos;
3057         }
3058
3059       /* Sometimes we may get called with our old size.  In that case
3060          we don't need to do anything else. */
3061       if (!pixel_adj_left)
3062         return;
3063
3064       /* Now delete any children that became too small.  */
3065       if (!nodelete)
3066         for (child = major_kid; !NILP (child); child = XWINDOW (child)->next)
3067           {
3068             if (set_height)
3069               set_window_pixheight (child, WINDOW_HEIGHT (XWINDOW (child)), 0);
3070             else
3071               set_window_pixwidth (child, WINDOW_WIDTH (XWINDOW (child)), 0);
3072           }
3073     }
3074 }
3075
3076 /* Set the height of WINDOW and all its inferiors.  */
3077 void
3078 set_window_pixheight (Lisp_Object window, int new_pixheight, int nodelete)
3079 {
3080   set_window_pixsize (window, new_pixheight, nodelete, 1);
3081 }
3082
3083 /* Recursively set width of WINDOW and its inferiors. */
3084 void
3085 set_window_pixwidth (Lisp_Object window, int new_pixwidth, int nodelete)
3086 {
3087   set_window_pixsize (window, new_pixwidth, nodelete, 0);
3088 }
3089
3090 \f
3091 static int window_select_count;
3092
3093 DEFUN ("set-window-buffer", Fset_window_buffer, 2, 2, 0, /*
3094 Make WINDOW display BUFFER as its contents.
3095 BUFFER can be a buffer or buffer name.
3096 */
3097        (window, buffer))
3098 {
3099   Lisp_Object tem;
3100   struct window *w = decode_window (window);
3101
3102   buffer = Fget_buffer (buffer);
3103   CHECK_BUFFER (buffer);
3104
3105   if (!BUFFER_LIVE_P (XBUFFER (buffer)))
3106     error ("Attempt to display deleted buffer");
3107
3108   tem = w->buffer;
3109   if (NILP (tem))
3110     error ("Window is deleted");
3111
3112   /* While this seems like a logical thing to do, it causes problems
3113      because of saved window configurations.  It is possible for a
3114      buffer to get restored into a window in which it is already being
3115      displayed, but start and point are actually at completely
3116      different locations.  So we let this function complete fully and
3117      it will then make sure redisplay correctly updates things.
3118
3119      #### This is a kludge.  The correct approach is not to do this
3120      but to fix set-window-configuration. */
3121 #if 0
3122   else if (EQ (tem, buffer))
3123     return Qnil;
3124 #endif
3125   else if (! EQ (tem, Qt))      /* w->buffer is t when the window
3126                                    is first being set up.  */
3127     {
3128       if (!NILP (w->dedicated) && !EQ (tem, buffer))
3129         error ("Window is dedicated to buffer %s",
3130                XSTRING_DATA (XBUFFER (tem)->name));
3131
3132       unshow_buffer (w);
3133     }
3134
3135   w->buffer = buffer;
3136   w->window_end_pos[CURRENT_DISP] = 0;
3137   w->hscroll = 0;
3138   w->modeline_hscroll = 0;
3139   Fset_marker (w->pointm[CURRENT_DISP],
3140                make_int (BUF_PT (XBUFFER (buffer))),
3141                buffer);
3142   set_marker_restricted (w->start[CURRENT_DISP],
3143                          make_int (XBUFFER (buffer)->last_window_start),
3144                          buffer);
3145   Fset_marker (w->sb_point, w->start[CURRENT_DISP], buffer);
3146   /* set start_at_line_beg correctly. GE */
3147   w->start_at_line_beg = beginning_of_line_p (XBUFFER (buffer),
3148                                               marker_position (w->start[CURRENT_DISP]));
3149   w->force_start = 0;           /* Lucid fix */
3150   SET_LAST_MODIFIED (w, 1);
3151   SET_LAST_FACECHANGE (w);
3152   MARK_WINDOWS_CHANGED (w);
3153   recompute_all_cached_specifiers_in_window (w);
3154   if (EQ (window, Fselected_window (Qnil)))
3155     {
3156       Fset_buffer (buffer);
3157     }
3158   return Qnil;
3159 }
3160
3161 DEFUN ("select-window", Fselect_window, 1, 2, 0, /*
3162 Select WINDOW.  Most editing will apply to WINDOW's buffer.
3163 The main editor command loop selects the buffer of the selected window
3164 before each command.
3165
3166 With non-nil optional argument `norecord', do not modify the
3167 global or per-frame buffer ordering.
3168 */
3169        (window, norecord))
3170 {
3171   struct window *w;
3172   Lisp_Object old_selected_window = Fselected_window (Qnil);
3173
3174   CHECK_LIVE_WINDOW (window);
3175   w = XWINDOW (window);
3176
3177   /* we have already caught dead-window errors */
3178   if (!NILP (w->hchild) || !NILP (w->vchild))
3179     error ("Trying to select non-leaf window");
3180
3181   w->use_time = make_int (++window_select_count);
3182   if (EQ (window, old_selected_window))
3183     return window;
3184
3185   /* deselect the old window, if it exists (it might not exist if
3186      the selected device has no frames, which occurs at startup) */
3187   if (!NILP (old_selected_window))
3188     {
3189       struct window *ow = XWINDOW (old_selected_window);
3190
3191       Fset_marker (ow->pointm[CURRENT_DISP],
3192                    make_int (BUF_PT (XBUFFER (ow->buffer))),
3193                    ow->buffer);
3194
3195       MARK_WINDOWS_CHANGED (ow);
3196     }
3197
3198   /* now select the window's frame */
3199   set_frame_selected_window (XFRAME (WINDOW_FRAME (w)), window);
3200
3201   select_frame_1 (WINDOW_FRAME (w));
3202
3203   /* also select the window's buffer */
3204   if (NILP (norecord))
3205     Frecord_buffer (w->buffer);
3206   Fset_buffer (w->buffer);
3207
3208   /* Go to the point recorded in the window.
3209      This is important when the buffer is in more
3210      than one window.  It also matters when
3211      redisplay_window has altered point after scrolling,
3212      because it makes the change only in the window.  */
3213   {
3214     Bufpos new_point = marker_position (w->pointm[CURRENT_DISP]);
3215     if (new_point < BUF_BEGV (current_buffer))
3216       new_point = BUF_BEGV (current_buffer);
3217     else if (new_point > BUF_ZV (current_buffer))
3218       new_point = BUF_ZV (current_buffer);
3219
3220     BUF_SET_PT (current_buffer, new_point);
3221   }
3222
3223   MARK_WINDOWS_CHANGED (w);
3224
3225   return window;
3226 }
3227
3228 Lisp_Object
3229 display_buffer (Lisp_Object buffer, Lisp_Object not_this_window_p,
3230                 Lisp_Object override_frame)
3231 {
3232   return call3 (Qdisplay_buffer, buffer, not_this_window_p, override_frame);
3233 }
3234
3235 void
3236 temp_output_buffer_show (Lisp_Object buf, Lisp_Object same_frame)
3237 {
3238   /* This function can GC */
3239   Lisp_Object window;
3240   struct window *w;
3241   struct buffer *b = XBUFFER (buf);
3242
3243   BUF_SAVE_MODIFF (XBUFFER (buf)) = BUF_MODIFF (b);
3244   widen_buffer (b, 0);
3245   BUF_SET_PT (b, BUF_BEG (b));
3246
3247   if (!NILP (Vtemp_buffer_show_function))
3248     call1 (Vtemp_buffer_show_function, buf);
3249   else
3250     {
3251       window = display_buffer (buf, Qnil, same_frame);
3252
3253       if (!EQ (XWINDOW (window)->frame, Fselected_frame (Qnil)))
3254         Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
3255
3256       Vminibuffer_scroll_window = window;
3257       w = XWINDOW (window);
3258       w->hscroll = 0;
3259       w->modeline_hscroll = 0;
3260       set_marker_restricted (w->start[CURRENT_DISP], make_int (1), buf);
3261       set_marker_restricted (w->pointm[CURRENT_DISP], make_int (1), buf);
3262       set_marker_restricted (w->sb_point, make_int (1), buf);
3263
3264       /* Run temp-buffer-show-hook, with the chosen window selected.  */
3265       if (!preparing_for_armageddon)
3266         {
3267           Lisp_Object tem;
3268           tem = Fboundp (Qtemp_buffer_show_hook);
3269           if (!NILP (tem))
3270             {
3271               tem = Fsymbol_value (Qtemp_buffer_show_hook);
3272               if (!NILP (tem))
3273                 {
3274                   int count = specpdl_depth ();
3275
3276                   /* Select the window that was chosen, for running
3277                      the hook.  */
3278                   record_unwind_protect (save_window_excursion_unwind,
3279                                          Fcurrent_window_configuration (Qnil));
3280
3281                   Fselect_window (window, Qnil);
3282                   run_hook (Qtemp_buffer_show_hook);
3283                   unbind_to (count, Qnil);
3284                 }
3285             }
3286         }
3287     }
3288 }
3289 \f
3290 static void
3291 make_dummy_parent (Lisp_Object window)
3292 {
3293   Lisp_Object new;
3294   struct window *o = XWINDOW (window);
3295   struct window *p = alloc_lcrecord_type (struct window, &lrecord_window);
3296
3297   XSETWINDOW (new, p);
3298   copy_lcrecord (p, o);
3299
3300   /* Don't copy the pointers to the line start cache or the face
3301      instances. */
3302   p->line_start_cache = Dynarr_new (line_start_cache);
3303   p->face_cachels     = Dynarr_new (face_cachel);
3304   p->glyph_cachels    = Dynarr_new (glyph_cachel);
3305
3306   /* Put new into window structure in place of window */
3307   replace_window (window, new);
3308
3309   o->next = Qnil;
3310   o->prev = Qnil;
3311   o->vchild = Qnil;
3312   o->hchild = Qnil;
3313   o->parent = new;
3314
3315   p->start[CURRENT_DISP] = Qnil;
3316   p->start[DESIRED_DISP] = Qnil;
3317   p->start[CMOTION_DISP] = Qnil;
3318   p->pointm[CURRENT_DISP] = Qnil;
3319   p->pointm[DESIRED_DISP] = Qnil;
3320   p->pointm[CMOTION_DISP] = Qnil;
3321   p->sb_point = Qnil;
3322   p->buffer = Qnil;
3323 }
3324
3325 DEFUN ("split-window", Fsplit_window, 0, 3, "", /*
3326 Split WINDOW, putting SIZE lines in the first of the pair.
3327 WINDOW defaults to selected one and SIZE to half its size.
3328 If optional third arg HOR-FLAG is non-nil, split side by side
3329 and put SIZE columns in the first of the pair.
3330 */
3331        (window, chsize, horflag))
3332 {
3333   Lisp_Object new;
3334   struct window *o, *p;
3335   struct frame *f;
3336   int size;
3337   int psize;
3338
3339   if (NILP (window))
3340     window = Fselected_window (Qnil);
3341   else
3342     CHECK_LIVE_WINDOW (window);
3343
3344   o = XWINDOW (window);
3345   f = XFRAME (WINDOW_FRAME (o));
3346
3347   if (NILP (chsize))
3348     {
3349       if (!NILP (horflag))
3350         /* In the new scheme, we are symmetric with respect to separators
3351            so there is no need to do weird things here. */
3352         {
3353           psize = WINDOW_WIDTH (o) >> 1;
3354           size = window_pixel_width_to_char_width (o, psize, 0);
3355         }
3356       else
3357         {
3358           psize = WINDOW_HEIGHT (o) >> 1;
3359           size = window_pixel_height_to_char_height (o, psize, 1);
3360         }
3361     }
3362   else
3363     {
3364       CHECK_INT (chsize);
3365       size = XINT (chsize);
3366       if (!NILP (horflag))
3367         psize = window_char_width_to_pixel_width (o, size, 0);
3368       else
3369         psize = window_char_height_to_pixel_height (o, size, 1);
3370     }
3371
3372   if (MINI_WINDOW_P (o))
3373     error ("Attempt to split minibuffer window");
3374   else if (FRAME_NO_SPLIT_P (XFRAME (WINDOW_FRAME (o))))
3375     error ("Attempt to split unsplittable frame");
3376
3377   check_min_window_sizes ();
3378
3379   if (NILP (horflag))
3380     {
3381       if (size < window_min_height)
3382         error ("Window height %d too small (after splitting)", size);
3383       if (size + window_min_height > window_char_height (o, 1))
3384         error ("Window height %d too small (after splitting)",
3385                window_char_height (o, 1) - size);
3386       if (NILP (o->parent)
3387           || NILP (XWINDOW (o->parent)->vchild))
3388         {
3389           make_dummy_parent (window);
3390           reset_face_cachels (XWINDOW (window));
3391           new = o->parent;
3392           XWINDOW (new)->vchild = window;
3393           XFRAME (o->frame)->mirror_dirty = 1;
3394         }
3395     }
3396   else
3397     {
3398       if (size < window_min_width)
3399         error ("Window width %d too small (after splitting)", size);
3400       if (size + window_min_width > window_char_width (o, 0))
3401         error ("Window width %d too small (after splitting)",
3402                window_char_width (o, 0) - size);
3403       if (NILP (o->parent)
3404           || NILP (XWINDOW (o->parent)->hchild))
3405         {
3406           make_dummy_parent (window);
3407           reset_face_cachels (XWINDOW (window));
3408           new = o->parent;
3409           XWINDOW (new)->hchild = window;
3410           XFRAME (o->frame)->mirror_dirty = 1;
3411         }
3412     }
3413
3414   /* Now we know that window's parent is a vertical combination
3415      if we are dividing vertically, or a horizontal combination
3416      if we are making side-by-side windows */
3417
3418   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
3419   new = allocate_window ();
3420   p = XWINDOW (new);
3421
3422   p->frame = o->frame;
3423   p->next = o->next;
3424   if (!NILP (p->next))
3425     XWINDOW (p->next)->prev = new;
3426   p->prev = window;
3427   o->next = new;
3428   p->parent = o->parent;
3429   p->buffer = Qt;
3430
3431   reset_face_cachels (p);
3432   reset_glyph_cachels (p);
3433
3434
3435   /* Apportion the available frame space among the two new windows */
3436
3437   if (!NILP (horflag))
3438     {
3439       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o);
3440       WINDOW_TOP (p) = WINDOW_TOP (o);
3441       WINDOW_WIDTH (p) = WINDOW_WIDTH (o) - psize;
3442       WINDOW_WIDTH (o) = psize;
3443       WINDOW_LEFT (p) = WINDOW_LEFT (o) + psize;
3444     }
3445   else
3446     {
3447       WINDOW_LEFT (p) = WINDOW_LEFT (o);
3448       WINDOW_WIDTH (p) = WINDOW_WIDTH (o);
3449       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o) - psize;
3450       WINDOW_HEIGHT (o) = psize;
3451       WINDOW_TOP (p) = WINDOW_TOP (o) + psize;
3452     }
3453
3454   XFRAME (p->frame)->mirror_dirty = 1;
3455   /* do this last (after the window is completely initialized and
3456      the mirror-dirty flag is set) so that specifier recomputation
3457      caused as a result of this will work properly and not abort. */
3458   Fset_window_buffer (new, o->buffer);
3459   return new;
3460 }
3461 \f
3462
3463 DEFUN ("enlarge-window", Fenlarge_window, 1, 3, "_p", /*
3464 Make the selected window N lines bigger.
3465 From program, optional second arg SIDE non-nil means grow sideways N columns,
3466 and optional third arg WINDOW specifies the window to change instead of the
3467 selected window.
3468 */
3469        (n, side, window))
3470 {
3471   struct window *w = decode_window (window);
3472   CHECK_INT (n);
3473   change_window_height (w, XINT (n), !NILP (side), /* inpixels */ 0);
3474   return Qnil;
3475 }
3476
3477 DEFUN ("enlarge-window-pixels", Fenlarge_window_pixels, 1, 3, "_p", /*
3478 Make the selected window N pixels bigger.
3479 From program, optional second arg SIDE non-nil means grow sideways N pixels,
3480 and optional third arg WINDOW specifies the window to change instead of the
3481 selected window.
3482 */
3483        (n, side, window))
3484 {
3485   struct window *w = decode_window (window);
3486   CHECK_INT (n);
3487   change_window_height (w, XINT (n), !NILP (side), /* inpixels */ 1);
3488   return Qnil;
3489 }
3490
3491 DEFUN ("shrink-window", Fshrink_window, 1, 3, "_p", /*
3492 Make the selected window N lines smaller.
3493 From program, optional second arg SIDE non-nil means shrink sideways N columns,
3494 and optional third arg WINDOW specifies the window to change instead of the
3495 selected window.
3496 */
3497        (n, side, window))
3498 {
3499   CHECK_INT (n);
3500   change_window_height (decode_window (window), -XINT (n), !NILP (side),
3501                         /* inpixels */ 0);
3502   return Qnil;
3503 }
3504
3505 DEFUN ("shrink-window-pixels", Fshrink_window_pixels, 1, 3, "_p", /*
3506 Make the selected window N pixels smaller.
3507 From program, optional second arg SIDE non-nil means shrink sideways N pixels,
3508 and optional third arg WINDOW specifies the window to change instead of the
3509 selected window.
3510 */
3511        (n, side, window))
3512 {
3513   CHECK_INT (n);
3514   change_window_height (decode_window (window), -XINT (n), !NILP (side),
3515                         /* inpixels */ 1);
3516   return Qnil;
3517 }
3518
3519 static int
3520 window_pixel_height (Lisp_Object window)
3521 {
3522   return WINDOW_HEIGHT (XWINDOW (window));
3523 }
3524
3525 static int
3526 window_pixel_height_to_char_height (struct window *w, int pixel_height,
3527                                     int include_gutters_p)
3528 {
3529   int avail_height;
3530   int defheight, defwidth;
3531   int char_height;
3532   Lisp_Object window;
3533
3534   XSETWINDOW (window, w);
3535
3536   avail_height = (pixel_height -
3537                   (include_gutters_p ? 0 :
3538                    window_top_gutter_height (w) +
3539                    window_bottom_gutter_height (w)));
3540
3541   default_face_height_and_width (window, &defheight, &defwidth);
3542
3543   char_height = avail_height / defheight;
3544
3545   /* It's the calling function's responsibility to check these values
3546      and make sure they're not out of range.
3547
3548      #### We need to go through the calling functions and actually
3549      do this. */
3550   return max (0, char_height);
3551 }
3552
3553 static int
3554 window_char_height_to_pixel_height (struct window *w, int char_height,
3555                                     int include_gutters_p)
3556 {
3557   int avail_height;
3558   int defheight, defwidth;
3559   int pixel_height;
3560
3561   Lisp_Object window;
3562
3563   XSETWINDOW (window, w);
3564
3565   default_face_height_and_width (window, &defheight, &defwidth);
3566
3567   avail_height = char_height * defheight;
3568   pixel_height = (avail_height +
3569                   (include_gutters_p ? 0 :
3570                    window_top_gutter_height (w) +
3571                    window_bottom_gutter_height (w)));
3572
3573   /* It's the calling function's responsibility to check these values
3574      and make sure they're not out of range.
3575
3576      #### We need to go through the calling functions and actually
3577      do this. */
3578   return max (0, pixel_height);
3579 }
3580
3581 /* Return number of default lines of text can fit in the window W.
3582    If INCLUDE_GUTTERS_P is 1, include "gutter" space (modeline plus
3583    horizontal scrollbar) in the space that is used for the calculation.
3584    */
3585 int
3586 window_char_height (struct window *w, int include_gutters_p)
3587 {
3588   return window_pixel_height_to_char_height (w, WINDOW_HEIGHT (w),
3589                                              include_gutters_p);
3590 }
3591
3592 /*
3593  * Return number of lines currently displayed in window w.  If
3594  * end-of-buffer is displayed then the area below end-of-buffer is assume
3595  * to be blank lines of default height.
3596  * Does not include the modeline.
3597  */
3598 int
3599 window_displayed_height (struct window *w)
3600 {
3601   struct buffer *b = XBUFFER (w->buffer);
3602   display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
3603   int num_lines;
3604   Charcount end_pos = (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b)
3605                        ? -1
3606                        : w->window_end_pos[CURRENT_DISP]);
3607
3608   if (!Dynarr_length (dla))
3609     return window_char_height (w, 0);
3610
3611   num_lines = Dynarr_length (dla);
3612
3613   /* #### Document and assert somewhere that w->window_end_pos == -1
3614      indicates that end-of-buffer is being displayed. */
3615   if (end_pos == -1)
3616     {
3617       struct display_line *dl = Dynarr_atp (dla, 0);
3618       int ypos1 = dl->ypos + dl->descent;
3619       int ypos2 = WINDOW_TEXT_BOTTOM (w);
3620       Lisp_Object window;
3621       int defheight, defwidth;
3622
3623       XSETWINDOW (window, w);
3624
3625       if (dl->modeline)
3626         {
3627           num_lines--;
3628
3629           if (Dynarr_length (dla) == 1)
3630             ypos1 = WINDOW_TEXT_TOP (w);
3631           else
3632             {
3633               dl = Dynarr_atp (dla, Dynarr_length (dla) - 1);
3634               /* If this line is clipped then we know that there is no
3635                  blank room between eob and the modeline.  If we are
3636                  scrolling on clipped lines just know off the clipped
3637                  line and return .*/
3638               if (scroll_on_clipped_lines && dl->clip)
3639                 return num_lines - 1;
3640               ypos1 = dl->ypos + dl->descent - dl->clip;
3641             }
3642         }
3643
3644       default_face_height_and_width (window, &defheight, &defwidth);
3645       /* #### This probably needs to know about the clipping area once a
3646          final definition is decided on. */
3647       num_lines += ((ypos2 - ypos1) / defheight);
3648     }
3649   else
3650     {
3651       if (num_lines > 1 && Dynarr_atp (dla, 0)->modeline)
3652         num_lines--;
3653
3654       if (scroll_on_clipped_lines
3655           && Dynarr_atp (dla, Dynarr_length (dla) - 1)->clip)
3656         num_lines--;
3657     }
3658
3659   return num_lines;
3660 }
3661
3662 static int
3663 window_pixel_width (Lisp_Object window)
3664 {
3665   return WINDOW_WIDTH (XWINDOW (window));
3666 }
3667
3668 static int
3669 window_pixel_width_to_char_width (struct window *w, int pixel_width,
3670                                   int include_margins_p)
3671 {
3672   int avail_width;
3673   int char_width;
3674   int defheight, defwidth;
3675   Lisp_Object window;
3676
3677   XSETWINDOW (window, w);
3678
3679   avail_width = (pixel_width -
3680                  window_left_gutter_width (w, 0) -
3681                  window_right_gutter_width (w, 0) -
3682                  (include_margins_p ? 0 : window_left_margin_width (w)) -
3683                  (include_margins_p ? 0 : window_right_margin_width (w)));
3684
3685   default_face_height_and_width (window, &defheight, &defwidth);
3686
3687   char_width = (avail_width / defwidth);
3688
3689   /* It's the calling function's responsibility to check these values
3690      and make sure they're not out of range.
3691
3692      #### We need to go through the calling functions and actually
3693      do this. */
3694   return max (0, char_width);
3695 }
3696
3697 static int
3698 window_char_width_to_pixel_width (struct window *w, int char_width,
3699                                   int include_margins_p)
3700 {
3701   int avail_width;
3702   int pixel_width;
3703   int defheight, defwidth;
3704   Lisp_Object window;
3705
3706   XSETWINDOW (window, w);
3707
3708   default_face_height_and_width (window, &defheight, &defwidth);
3709
3710   avail_width = char_width * defwidth;
3711   pixel_width = (avail_width +
3712                  window_left_gutter_width (w, 0) +
3713                  window_right_gutter_width (w, 0) +
3714                  (include_margins_p ? 0 : window_left_margin_width (w)) +
3715                  (include_margins_p ? 0 : window_right_margin_width (w)));
3716
3717   /* It's the calling function's responsibility to check these values
3718      and make sure they're not out of range.
3719
3720      #### We need to go through the calling functions and actually
3721      do this. */
3722   return max (0, pixel_width);
3723 }
3724
3725 /* This returns the usable space which doesn't include space needed by
3726    scrollbars or divider lines. */
3727 int
3728 window_char_width (struct window *w, int include_margins_p)
3729 {
3730   return window_pixel_width_to_char_width (w, WINDOW_WIDTH (w),
3731                                            include_margins_p);
3732 }
3733
3734 #define MINSIZE(w)                                              \
3735   (widthflag                                                    \
3736    ? window_min_width * defwidth                                \
3737    : (defheight * (MINI_WINDOW_P (XWINDOW (w)) ? 1 : window_min_height)))
3738
3739 #define CURBEG(w) \
3740   *(widthflag ? (int *) &WINDOW_LEFT (w) : (int *) &WINDOW_TOP (w))
3741
3742 #define CURSIZE(w) \
3743   *(widthflag ? (int *) &WINDOW_WIDTH (w) : (int *) &WINDOW_HEIGHT (w))
3744
3745 #define CURCHARSIZE(w) \
3746   (widthflag ? window_char_width (w, 0) : window_char_height (w, 1))
3747
3748 #define MINCHARSIZE(window) \
3749   (widthflag ? window_min_width : MINI_WINDOW_P (XWINDOW (window)) \
3750    ? 1 : window_min_height)
3751
3752 /* Unlike set_window_pixheight, this function
3753    also changes the heights of the siblings so as to
3754    keep everything consistent. */
3755
3756 static void
3757 change_window_height (struct window *win, int delta, int widthflag,
3758                       int inpixels)
3759 {
3760   Lisp_Object parent;
3761   Lisp_Object window;
3762   struct window *w;
3763   struct frame *f;
3764   int *sizep;
3765   int (*sizefun) (Lisp_Object) = (widthflag
3766                                   ? window_pixel_width
3767                                   : window_pixel_height);
3768   void (*setsizefun) (Lisp_Object, int, int) = (widthflag
3769                                                 ? set_window_pixwidth
3770                                                 : set_window_pixheight);
3771   int dim;
3772   int defheight, defwidth;
3773
3774   if (delta == 0)
3775     return;
3776
3777   check_min_window_sizes ();
3778
3779   XSETWINDOW (window, win);
3780   f = XFRAME (win->frame);
3781   if (EQ (window, FRAME_ROOT_WINDOW (f)))
3782     error ("Won't change only window");
3783
3784   /* #### This is very likely incorrect and instead the char_to_pixel_
3785      functions should be called. */
3786   default_face_height_and_width (window, &defheight, &defwidth);
3787
3788   while (1)
3789     {
3790       w = XWINDOW (window);
3791       parent = w->parent;
3792       if (NILP (parent))
3793         {
3794           if (widthflag)
3795             error ("No other window to side of this one");
3796           break;
3797         }
3798       if (widthflag
3799           ? !NILP (XWINDOW (parent)->hchild)
3800           : !NILP (XWINDOW (parent)->vchild))
3801         break;
3802       window = parent;
3803     }
3804
3805   sizep = &CURSIZE (w);
3806   dim = CURCHARSIZE (w);
3807
3808   if ((inpixels  && (*sizep + delta) < MINSIZE (window)) ||
3809       (!inpixels && (dim + delta) < MINCHARSIZE (window)))
3810     {
3811       if (MINI_WINDOW_P (XWINDOW (window)))
3812         return;
3813       else if (!NILP (parent))
3814         {
3815           Fdelete_window (window, Qnil);
3816           return;
3817         }
3818     }
3819
3820   if (!inpixels)
3821     delta *= (widthflag ? defwidth : defheight);
3822
3823   {
3824     int maxdelta;
3825
3826     maxdelta = ((!NILP (parent))
3827                 ? (*sizefun) (parent) - *sizep
3828                 : ((!NILP (w->next))
3829                    ? (*sizefun) (w->next) - MINSIZE (w->next)
3830                    : ((!NILP (w->prev))
3831                       ? (*sizefun) (w->prev) - MINSIZE (w->prev)
3832                       /* This is a frame with only one window,
3833                          a minibuffer-only or a minibufferless frame.  */
3834                       : (delta = 0))));
3835
3836     if (delta > maxdelta)
3837       /* This case traps trying to make the minibuffer
3838          the full frame, or make the only window aside from the
3839          minibuffer the full frame.  */
3840       delta = maxdelta;
3841
3842     if (delta == 0)
3843       return;
3844
3845 #if 0 /* FSFmacs */
3846     /* #### Chuck: is this correct? */
3847     if (*sizep + delta < MINSIZE (window))
3848       {
3849         Fdelete_window (window);
3850         return;
3851       }
3852 #endif
3853   }
3854
3855   if (!NILP (w->next) &&
3856       (*sizefun) (w->next) - delta >= (int) MINSIZE (w->next))
3857     {
3858       CURBEG (XWINDOW (w->next)) += delta;
3859       (*setsizefun) (w->next, (*sizefun) (w->next) - delta, 0);
3860       (*setsizefun) (window, *sizep + delta, 0);
3861     }
3862   else if (!NILP (w->prev) &&
3863            (*sizefun) (w->prev) - delta >= (int) MINSIZE (w->prev))
3864     {
3865       (*setsizefun) (w->prev, (*sizefun) (w->prev) - delta, 0);
3866       CURBEG (w) -= delta;
3867       (*setsizefun) (window, *sizep + delta, 0);
3868     }
3869   else
3870     {
3871       int delta1;
3872       int opht = (*sizefun) (parent);
3873
3874       /* If trying to grow this window to or beyond size of the parent,
3875          make delta1 so big that, on shrinking back down,
3876          all the siblings end up with less than one line and are deleted.  */
3877       if (opht <= *sizep + delta)
3878         delta1 = opht * opht * 2;
3879       /* Otherwise, make delta1 just right so that if we add delta1
3880          lines to this window and to the parent, and then shrink
3881          the parent back to its original size, the new proportional
3882          size of this window will increase by delta.  */
3883       else
3884         delta1 = (delta * opht * 100) / ((opht - *sizep - delta) * 100);
3885
3886       /* Add delta1 lines or columns to this window, and to the parent,
3887          keeping things consistent while not affecting siblings.  */
3888       CURSIZE (XWINDOW (parent)) = opht + delta1;
3889       (*setsizefun) (window, *sizep + delta1, 0);
3890
3891       /* Squeeze out delta1 lines or columns from our parent,
3892          shrinking this window and siblings proportionately.
3893          This brings parent back to correct size.
3894          Delta1 was calculated so this makes this window the desired size,
3895          taking it all out of the siblings.  */
3896       (*setsizefun) (parent, opht, 0);
3897     }
3898
3899   SET_LAST_MODIFIED (w, 0);
3900   SET_LAST_FACECHANGE (w);
3901   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
3902   /* overkill maybe, but better to be correct */
3903   MARK_FRAME_GUTTERS_CHANGED (f);
3904 }
3905 #undef MINSIZE
3906 #undef CURBEG
3907 #undef CURSIZE
3908 #undef CURCHARSIZE
3909 #undef MINCHARSIZE
3910
3911 \f
3912
3913 /* Scroll contents of window WINDOW up N lines.  */
3914 void
3915 window_scroll (Lisp_Object window, Lisp_Object n, int direction,
3916                Error_behavior errb)
3917 {
3918   struct window *w = XWINDOW (window);
3919   struct buffer *b = XBUFFER (w->buffer);
3920   int selected = EQ (window, Fselected_window (Qnil));
3921   int value = 0;
3922   Lisp_Object point, tem;
3923
3924   if (selected)
3925     point = make_int (BUF_PT (b));
3926   else
3927     {
3928       Bufpos pos = marker_position (w->pointm[CURRENT_DISP]);
3929
3930       if (pos < BUF_BEGV (b))
3931         pos = BUF_BEGV (b);
3932       else if (pos > BUF_ZV (b))
3933         pos = BUF_ZV (b);
3934
3935       point = make_int (pos);
3936     }
3937
3938   /* Always set force_start so that redisplay_window will run
3939      the window-scroll-functions.  */
3940   w->force_start = 1;
3941
3942   /* #### When the fuck does this happen?  I'm so glad that history has
3943      completely documented the behavior of the scrolling functions under
3944      all circumstances. */
3945   tem = Fpos_visible_in_window_p (point, window);
3946   if (NILP (tem))
3947     {
3948       Fvertical_motion (make_int (-window_char_height (w, 0) / 2),
3949                         window, Qnil);
3950       Fset_marker (w->start[CURRENT_DISP], point, w->buffer);
3951       w->start_at_line_beg = beginning_of_line_p (b, XINT (point));
3952       MARK_WINDOWS_CHANGED (w);
3953     }
3954
3955   if (!NILP (n))
3956     {
3957       if (EQ (n, Qminus))
3958         direction *= -1;
3959       else
3960         {
3961           n = Fprefix_numeric_value (n);
3962           value = XINT (n) * direction;
3963
3964           if (!value)
3965             return;     /* someone just made a pointless call */
3966         }
3967     }
3968
3969   /* If the user didn't specify how far to scroll then we have to figure it
3970      out by ourselves. */
3971   if (NILP (n) || EQ (n, Qminus))
3972     {
3973       /* Going forwards is easy.  If that is what we are doing then just
3974          set value and the section which handles the user specifying a
3975          positive value will work. */
3976       if (direction == 1)
3977         {
3978           value = window_displayed_height (w) - next_screen_context_lines;
3979           value = (value < 1 ? 1 : value);
3980         }
3981
3982       /* Going backwards is hard.  We can't use the same loop used if the
3983          user specified a negative value because we care about
3984          next_screen_context_lines.  In a variable height world you don't
3985          know how many lines above you can actually be displayed and still
3986          have the context lines appear.  So we leave value set to 0 and add
3987          a separate section to deal with this. */
3988
3989     }
3990
3991   if (direction == 1 && !value)
3992     {
3993       return;
3994     }
3995   else if (value > 0)
3996     {
3997       int vtarget;
3998       Bufpos startp, old_start;
3999
4000       old_start = marker_position (w->start[CURRENT_DISP]);
4001       startp = vmotion (w, old_start, value, &vtarget);
4002
4003       if (vtarget < value &&
4004           (w->window_end_pos[CURRENT_DISP] == -1
4005            || (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b))))
4006         {
4007           maybe_signal_error (Qend_of_buffer, Qnil, Qwindow, errb);
4008           return;
4009         }
4010       else
4011         {
4012           set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4013                                  w->buffer);
4014           w->force_start = 1;
4015           w->start_at_line_beg = beginning_of_line_p (b, startp);
4016           MARK_WINDOWS_CHANGED (w);
4017
4018           if (!point_would_be_visible (w, startp, XINT (point)))
4019             {
4020               if (selected)
4021                 BUF_SET_PT (b, startp);
4022               else
4023                 set_marker_restricted (w->pointm[CURRENT_DISP],
4024                                        make_int (startp),
4025                                        w->buffer);
4026             }
4027         }
4028     }
4029   else if (value < 0)
4030     {
4031       int vtarget;
4032       Bufpos startp, old_start;
4033
4034       old_start = marker_position (w->start[CURRENT_DISP]);
4035       startp = vmotion (w, old_start, value, &vtarget);
4036
4037       if (vtarget > value
4038           && marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b))
4039         {
4040           maybe_signal_error (Qbeginning_of_buffer, Qnil, Qwindow, errb);
4041           return;
4042         }
4043       else
4044         {
4045           set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4046                                  w->buffer);
4047           w->force_start = 1;
4048           w->start_at_line_beg = beginning_of_line_p (b, startp);
4049           MARK_WINDOWS_CHANGED (w);
4050
4051           if (!point_would_be_visible (w, startp, XINT (point)))
4052             {
4053               Bufpos new_point;
4054
4055               if (MINI_WINDOW_P (w))
4056                 new_point = startp;
4057               else
4058                 new_point = start_of_last_line (w, startp);
4059
4060               if (selected)
4061                 BUF_SET_PT (b, new_point);
4062               else
4063                 set_marker_restricted (w->pointm[CURRENT_DISP],
4064                                        make_int (new_point),
4065                                        w->buffer);
4066             }
4067         }
4068     }
4069   else  /* value == 0 && direction == -1 */
4070     {
4071       if (marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b))
4072         {
4073           maybe_signal_error (Qbeginning_of_buffer, Qnil, Qwindow, errb);
4074           return;
4075         }
4076       else
4077         {
4078           int vtarget;
4079           int movement = next_screen_context_lines - 1;
4080           Bufpos old_startp = marker_position (w->start[CURRENT_DISP]);
4081           Bufpos bottom = vmotion (w, old_startp, movement, &vtarget);
4082           Bufpos startp =
4083             start_with_point_on_display_line (w, bottom,
4084                                               -1 - (movement - vtarget));
4085
4086           if (startp >= old_startp)
4087             startp = vmotion (w, old_startp, -1, NULL);
4088
4089           set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4090                                  w->buffer);
4091           w->force_start = 1;
4092           w->start_at_line_beg = beginning_of_line_p (b, startp);
4093           MARK_WINDOWS_CHANGED (w);
4094
4095           if (!point_would_be_visible (w, startp, XINT (point)))
4096             {
4097               Bufpos new_point = start_of_last_line (w, startp);
4098
4099               if (selected)
4100                 BUF_SET_PT (b, new_point);
4101               else
4102                 set_marker_restricted (w->pointm[CURRENT_DISP],
4103                                        make_int (new_point),
4104                                        w->buffer);
4105             }
4106         }
4107     }
4108
4109 }
4110 \f
4111 DEFUN ("scroll-up", Fscroll_up, 0, 1, "_P", /*
4112 Scroll text of current window upward N lines; or near full screen if no arg.
4113 A near full screen is `next-screen-context-lines' less than a full screen.
4114 Negative N means scroll downward.
4115 When calling from a program, supply an integer as argument or nil.
4116 On attempt to scroll past end of buffer, `end-of-buffer' is signaled.
4117 On attempt to scroll past beginning of buffer, `beginning-of-buffer' is
4118 signaled.
4119 */
4120        (n))
4121 {
4122   window_scroll (Fselected_window (Qnil), n, 1, ERROR_ME);
4123   return Qnil;
4124 }
4125
4126 DEFUN ("scroll-down", Fscroll_down, 0, 1, "_P", /*
4127 Scroll text of current window downward N lines; or near full screen if no arg.
4128 A near full screen is `next-screen-context-lines' less than a full screen.
4129 Negative N means scroll upward.
4130 When calling from a program, supply a number as argument or nil.
4131 On attempt to scroll past end of buffer, `end-of-buffer' is signaled.
4132 On attempt to scroll past beginning of buffer, `beginning-of-buffer' is
4133 signaled.
4134 */
4135        (n))
4136 {
4137   window_scroll (Fselected_window (Qnil), n, -1, ERROR_ME);
4138   return Qnil;
4139 }
4140 \f
4141 DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, 0, 0, 0, /*
4142 Return the other window for "other window scroll" commands.
4143 If in the minibuffer, `minibuffer-scroll-window' if non-nil
4144 specifies the window.
4145 If `other-window-scroll-buffer' is non-nil, a window
4146 showing that buffer is used.
4147 */
4148        ())
4149 {
4150   Lisp_Object window;
4151   Lisp_Object selected_window = Fselected_window (Qnil);
4152
4153   if (MINI_WINDOW_P (XWINDOW (selected_window))
4154       && !NILP (Vminibuffer_scroll_window))
4155     window = Vminibuffer_scroll_window;
4156   /* If buffer is specified, scroll that buffer.  */
4157   else if (!NILP (Vother_window_scroll_buffer))
4158     {
4159       window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil, Qnil);
4160       if (NILP (window))
4161         window = display_buffer (Vother_window_scroll_buffer, Qt, Qnil);
4162     }
4163   else
4164     {
4165       /* Nothing specified; look for a neighboring window on the same
4166          frame.  */
4167       window = Fnext_window (selected_window, Qnil, Qnil, Qnil);
4168
4169       if (EQ (window, selected_window))
4170         /* That didn't get us anywhere; look for a window on another
4171            visible frame.  */
4172         do
4173           window = Fnext_window (window, Qnil, Qt, Qnil);
4174         while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
4175                && ! EQ (window, selected_window));
4176     }
4177
4178   CHECK_LIVE_WINDOW (window);
4179
4180   if (EQ (window, selected_window))
4181     error ("There is no other window");
4182
4183   return window;
4184  }
4185
4186 DEFUN ("scroll-other-window", Fscroll_other_window, 0, 1, "_P", /*
4187 Scroll next window upward N lines; or near full frame if no arg.
4188 The next window is the one below the current one; or the one at the top
4189 if the current one is at the bottom.  Negative N means scroll downward.
4190 When calling from a program, supply a number as argument or nil.
4191
4192 If in the minibuffer, `minibuffer-scroll-window' if non-nil
4193 specifies the window to scroll.
4194 If `other-window-scroll-buffer' is non-nil, scroll the window
4195 showing that buffer, popping the buffer up if necessary.
4196 */
4197        (n))
4198 {
4199   window_scroll (Fother_window_for_scrolling (), n, 1, ERROR_ME);
4200   return Qnil;
4201 }
4202 \f
4203 DEFUN ("scroll-left", Fscroll_left, 0, 1, "_P", /*
4204 Scroll selected window display N columns left.
4205 Default for N is window width minus 2.
4206 */
4207        (n))
4208 {
4209   Lisp_Object window = Fselected_window (Qnil);
4210   struct window *w = XWINDOW (window);
4211   int count = (NILP (n) ?
4212                window_char_width (w, 0) - 2 :
4213                XINT (Fprefix_numeric_value (n)));
4214
4215   return Fset_window_hscroll (window, make_int (w->hscroll + count));
4216 }
4217
4218 DEFUN ("scroll-right", Fscroll_right, 0, 1, "_P", /*
4219 Scroll selected window display N columns right.
4220 Default for N is window width minus 2.
4221 */
4222        (n))
4223 {
4224   Lisp_Object window = Fselected_window (Qnil);
4225   struct window *w = XWINDOW (window);
4226   int count = (NILP (n) ?
4227                window_char_width (w, 0) - 2 :
4228                XINT (Fprefix_numeric_value (n)));
4229
4230   return Fset_window_hscroll (window, make_int (w->hscroll - count));
4231 }
4232 \f
4233 DEFUN ("center-to-window-line", Fcenter_to_window_line, 0, 2, "_P", /*
4234 Center point in WINDOW.  With N, put point on line N.
4235 The desired position of point is always relative to the window.
4236 If WINDOW is nil, the selected window is used.
4237 */
4238        (n, window))
4239 {
4240   struct window *w = decode_window (window);
4241   struct buffer *b = XBUFFER (w->buffer);
4242   Bufpos opoint = BUF_PT (b);
4243   Bufpos startp;
4244
4245   if (NILP (n))
4246     startp = start_with_line_at_pixpos (w, opoint, window_half_pixpos (w));
4247   else
4248     {
4249       n = Fprefix_numeric_value (n);
4250       CHECK_INT (n);
4251       startp = start_with_point_on_display_line (w, opoint, XINT (n));
4252     }
4253
4254   Fset_marker (w->start[CURRENT_DISP], make_int (startp), w->buffer);
4255
4256   w->start_at_line_beg = beginning_of_line_p (b, startp);
4257   w->force_start = 1;
4258   MARK_WINDOWS_CHANGED (w);
4259   return Qnil;
4260 }
4261
4262 DEFUN ("move-to-window-line", Fmove_to_window_line, 1, 2, "_P", /*
4263 Position point relative to WINDOW.
4264 With no argument, position text at center of window.
4265 An argument specifies window line; zero means top of window,
4266 negative means relative to bottom of window.
4267 If WINDOW is nil, the selected window is used.
4268 */
4269        (arg, window))
4270 {
4271   struct window *w;
4272   struct buffer *b;
4273   int height;
4274   Bufpos start, new_point;
4275   int selected;
4276
4277   /* Don't use decode_window() because we need the new value of
4278      WINDOW.  */
4279   if (NILP (window))
4280     window = Fselected_window (Qnil);
4281   else
4282     CHECK_LIVE_WINDOW (window);
4283   w = XWINDOW (window);
4284   b = XBUFFER (w->buffer);
4285
4286   height = window_displayed_height (w);
4287   selected = EQ (window, Fselected_window (w->frame));
4288
4289   if (NILP (arg))
4290     {
4291       int retval;
4292
4293       if (XINT (w->last_modified[CURRENT_DISP]) >= BUF_MODIFF (b)
4294           && XINT (w->last_facechange[CURRENT_DISP]) >= BUF_FACECHANGE (b))
4295         {
4296           new_point = point_at_center (w, CURRENT_DISP, 0, 0);
4297
4298           if (selected)
4299             BUF_SET_PT (b, new_point);
4300           else
4301             Fset_window_point (window, make_int (new_point));
4302
4303           retval = line_at_center (w, CURRENT_DISP, 0, 0);
4304         }
4305       else
4306         {
4307           start = marker_position (w->start[CURRENT_DISP]);
4308           if (start < BUF_BEGV (b))
4309             start = BUF_BEGV (b);
4310           else if (start > BUF_ZV (b))
4311             start = BUF_ZV (b);
4312
4313           if (selected)
4314             new_point = BUF_PT (b);
4315           else
4316             new_point = marker_position (w->pointm[CURRENT_DISP]);
4317
4318           new_point = point_at_center (w, CMOTION_DISP, start, BUF_PT (b));
4319
4320           if (selected)
4321             BUF_SET_PT (b, new_point);
4322           else
4323             Fset_window_point (window, make_int (new_point));
4324
4325           retval = line_at_center (w, CMOTION_DISP, start, BUF_PT (b));
4326         }
4327
4328       return make_int (retval);
4329     }
4330   else
4331     {
4332       /* #### Is this going to work right when at eob? */
4333       arg = Fprefix_numeric_value (arg);
4334       if (XINT (arg) < 0)
4335         XSETINT (arg, XINT (arg) + height);
4336     }
4337
4338   start = marker_position (w->start[CURRENT_DISP]);
4339   if (start < BUF_BEGV (b) || start > BUF_ZV (b))
4340     {
4341       if (selected)
4342         new_point = BUF_PT (b);
4343       else
4344         new_point = marker_position (w->pointm[CURRENT_DISP]);
4345
4346       new_point = vmotion (XWINDOW (window), new_point, -height / 2, 0);
4347
4348       if (selected)
4349         BUF_SET_PT (b, new_point);
4350       else
4351         Fset_window_point (window, make_int (new_point));
4352
4353       Fset_marker (w->start[CURRENT_DISP], make_int (new_point),
4354                    w->buffer);
4355       w->start_at_line_beg = beginning_of_line_p (b, new_point);
4356       w->force_start = 1;
4357     }
4358   else
4359     {
4360       if (selected)
4361         BUF_SET_PT (b, start);
4362       else
4363         Fset_window_point (window, make_int (start));
4364     }
4365
4366   if (selected)
4367     return Fvertical_motion (arg, window, Qnil);
4368   else
4369     {
4370       int vpos;
4371       new_point = vmotion (XWINDOW (window),
4372                            marker_position (w->pointm[CURRENT_DISP]),
4373                            XINT (arg), &vpos);
4374       Fset_window_point (window, make_int (new_point));
4375       return make_int (vpos);
4376     }
4377 }
4378
4379 \f
4380 static int
4381 map_windows_1 (Lisp_Object window,
4382                int (*mapfun) (struct window *w, void *closure),
4383                void *closure)
4384 {
4385   for (; !NILP (window); window = XWINDOW (window)->next)
4386     {
4387       int retval;
4388       struct window *w = XWINDOW (window);
4389
4390       if (!NILP (w->vchild))
4391         retval = map_windows_1 (w->vchild, mapfun, closure);
4392       else if (!NILP (w->hchild))
4393         retval = map_windows_1 (w->hchild, mapfun, closure);
4394       else
4395         retval = (mapfun) (w, closure);
4396
4397       if (retval)
4398         return retval;
4399     }
4400
4401   return 0;
4402 }
4403
4404 /* Map MAPFUN over the windows in F.  CLOSURE is passed to each
4405    invocation of MAPFUN.  If any invocation of MAPFUN returns
4406    non-zero, the mapping is halted.  Otherwise, map_windows() maps
4407    over all windows in F.
4408
4409    If MAPFUN creates or deletes windows, the behavior is undefined.  */
4410
4411 int
4412 map_windows (struct frame *f, int (*mapfun) (struct window *w, void *closure),
4413              void *closure)
4414 {
4415   if (f)
4416     return map_windows_1 (FRAME_ROOT_WINDOW (f), mapfun, closure);
4417   else
4418     {
4419       Lisp_Object frmcons, devcons, concons;
4420
4421       FRAME_LOOP_NO_BREAK(frmcons, devcons, concons)
4422         {
4423           int v = map_windows_1 (FRAME_ROOT_WINDOW (XFRAME (XCAR (frmcons))),
4424                                  mapfun, closure);
4425           if (v)
4426             return v;
4427         }
4428     }
4429
4430   return 0;
4431 }
4432
4433 \f
4434 static void
4435 modeline_shadow_thickness_changed (Lisp_Object specifier, struct window *w,
4436                                    Lisp_Object oldval)
4437 {
4438   w->shadow_thickness_changed = 1;
4439   MARK_WINDOWS_CHANGED (w);
4440 }
4441
4442 static void
4443 vertical_divider_changed_in_window (Lisp_Object specifier,
4444                                     struct window *w,
4445                                     Lisp_Object oldval)
4446 {
4447   MARK_WINDOWS_CHANGED (w);
4448   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (XFRAME (WINDOW_FRAME (w)));
4449 }
4450
4451 /* also used in scrollbar.c */
4452 void
4453 some_window_value_changed (Lisp_Object specifier, struct window *w,
4454                            Lisp_Object oldval)
4455 {
4456   MARK_WINDOWS_CHANGED (w);
4457 }
4458
4459 #ifdef MEMORY_USAGE_STATS
4460
4461 struct window_stats
4462 {
4463   int face;
4464   int glyph;
4465 #ifdef HAVE_SCROLLBARS
4466   int scrollbar;
4467 #endif
4468   int line_start;
4469   int other_redisplay;
4470   int other;
4471 };
4472
4473 static void
4474 compute_window_mirror_usage (struct window_mirror *mir,
4475                              struct window_stats *stats,
4476                              struct overhead_stats *ovstats)
4477 {
4478   if (!mir)
4479     return;
4480   stats->other += malloced_storage_size (mir, sizeof (struct window_mirror),
4481                                          ovstats);
4482 #ifdef HAVE_SCROLLBARS
4483   {
4484     struct device *d = XDEVICE (FRAME_DEVICE (mir->frame));
4485
4486     stats->scrollbar +=
4487       compute_scrollbar_instance_usage (d, mir->scrollbar_vertical_instance,
4488                                         ovstats);
4489     stats->scrollbar +=
4490       compute_scrollbar_instance_usage (d, mir->scrollbar_horizontal_instance,
4491                                         ovstats);
4492   }
4493 #endif /* HAVE_SCROLLBARS */
4494   stats->other_redisplay +=
4495     compute_display_line_dynarr_usage (mir->current_display_lines, ovstats);
4496   stats->other_redisplay +=
4497     compute_display_line_dynarr_usage (mir->desired_display_lines, ovstats);
4498 }
4499
4500 static void
4501 compute_window_usage (struct window *w, struct window_stats *stats,
4502                       struct overhead_stats *ovstats)
4503 {
4504   xzero (*stats);
4505   stats->other += malloced_storage_size (w, sizeof (struct window), ovstats);
4506   stats->face += compute_face_cachel_usage (w->face_cachels, ovstats);
4507   stats->glyph += compute_glyph_cachel_usage (w->glyph_cachels, ovstats);
4508   stats->line_start +=
4509     compute_line_start_cache_dynarr_usage (w->line_start_cache, ovstats);
4510   compute_window_mirror_usage (find_window_mirror (w), stats, ovstats);
4511 }
4512
4513 DEFUN ("window-memory-usage", Fwindow_memory_usage, 1, 1, 0, /*
4514 Return stats about the memory usage of window WINDOW.
4515 The values returned are in the form of an alist of usage types and byte
4516 counts.  The byte counts attempt to encompass all the memory used
4517 by the window (separate from the memory logically associated with a
4518 buffer or frame), including internal structures and any malloc()
4519 overhead associated with them.  In practice, the byte counts are
4520 underestimated because certain memory usage is very hard to determine
4521 \(e.g. the amount of memory used inside the Xt library or inside the
4522 X server) and because there is other stuff that might logically
4523 be associated with a window, buffer, or frame (e.g. window configurations,
4524 glyphs) but should not obviously be included in the usage counts.
4525
4526 Multiple slices of the total memory usage may be returned, separated
4527 by a nil.  Each slice represents a particular view of the memory, a
4528 particular way of partitioning it into groups.  Within a slice, there
4529 is no overlap between the groups of memory, and each slice collectively
4530 represents all the memory concerned.
4531 */
4532        (window))
4533 {
4534   struct window_stats stats;
4535   struct overhead_stats ovstats;
4536   Lisp_Object val = Qnil;
4537
4538   CHECK_WINDOW (window); /* dead windows should be allowed, no? */
4539   xzero (ovstats);
4540   compute_window_usage (XWINDOW (window), &stats, &ovstats);
4541
4542   val = acons (Qface_cache,          make_int (stats.face),              val);
4543   val = acons (Qglyph_cache,         make_int (stats.glyph),             val);
4544 #ifdef HAVE_SCROLLBARS
4545   val = acons (Qscrollbar_instances, make_int (stats.scrollbar),         val);
4546 #endif
4547   val = acons (Qline_start_cache,    make_int (stats.line_start),        val);
4548   val = acons (Qother_redisplay,     make_int (stats.other_redisplay),   val);
4549   val = acons (Qother,               make_int (stats.other),             val);
4550   val = Fcons (Qnil, val);
4551   val = acons (Qactually_requested,  make_int (ovstats.was_requested),   val);
4552   val = acons (Qmalloc_overhead,     make_int (ovstats.malloc_overhead), val);
4553   val = acons (Qdynarr_overhead,     make_int (ovstats.dynarr_overhead), val);
4554
4555   return Fnreverse (val);
4556 }
4557
4558 #endif /* MEMORY_USAGE_STATS */
4559
4560 \f
4561 /************************************************************************/
4562 /*                         Window configurations                        */
4563 /************************************************************************/
4564
4565 /* #### This window configuration stuff has had serious bugs lurking in it
4566    for years; it would be a -huge- win if this was reimplemented in lisp.
4567  */
4568
4569 /* If you add anything to this structure make sure saved_window_equal
4570    knows about it. */
4571 struct saved_window
4572 {
4573   Lisp_Object window;         /* window */
4574   Lisp_Object buffer;         /* buffer */
4575   Lisp_Object start;          /* copied marker */
4576   Lisp_Object pointm;         /* copied marker */
4577   Lisp_Object sb_point;       /* copied marker */
4578   Lisp_Object mark;           /* copied marker */
4579   int pixel_left;
4580   int pixel_top;
4581   int pixel_width;
4582   int pixel_height;
4583   int hscroll;
4584   int modeline_hscroll;
4585   int parent_index;           /* index into saved_windows */
4586   int prev_index;             /* index into saved_windows */
4587   char start_at_line_beg; /* boolean */
4588
4589 #define WINDOW_SLOT_DECLARATION
4590 #define WINDOW_SLOT(slot, compare) Lisp_Object slot
4591 #include "winslots.h"
4592 };
4593
4594 /* If you add anything to this structure make sure window_config_equal
4595    knows about it. */
4596 struct window_config
4597 {
4598   struct lcrecord_header header;
4599   /*  int frame_width; No longer needed, JV
4600       int frame_height; */
4601 #if 0 /* FSFmacs */
4602   Lisp_Object selected_frame;
4603 #endif
4604   Lisp_Object current_window;
4605   Lisp_Object current_buffer;
4606   Lisp_Object minibuffer_scroll_window;
4607   Lisp_Object root_window;
4608   int minibuf_height; /* 0 = no minibuffer, <0, size in lines, >0 in pixels */
4609   /* Record the values of window-min-width and window-min-height
4610      so that window sizes remain consistent with them.  */
4611   int min_width, min_height;
4612   int saved_windows_count;
4613   /* Zero-sized arrays aren't ANSI C */
4614   struct saved_window saved_windows[1];
4615 };
4616
4617 #define SAVED_WINDOW_N(conf, n) (&((conf)->saved_windows[(n)]))
4618 #define XWINDOW_CONFIGURATION(x) XRECORD (x, window_configuration, struct window_config)
4619 #define XSETWINDOW_CONFIGURATION(x, p) XSETRECORD (x, p, window_configuration)
4620 #define WINDOW_CONFIGURATIONP(x) RECORDP (x, window_configuration)
4621 #define GC_WINDOW_CONFIGURATIONP(x) GC_RECORDP (x, window_configuration)
4622 #define CHECK_WINDOW_CONFIGURATION(x) CHECK_RECORD (x, window_configuration)
4623
4624 static Lisp_Object
4625 mark_window_config (Lisp_Object obj, void (*markobj) (Lisp_Object))
4626 {
4627   struct window_config *config = XWINDOW_CONFIGURATION (obj);
4628   int i;
4629   markobj (config->current_window);
4630   markobj (config->current_buffer);
4631   markobj (config->minibuffer_scroll_window);
4632   markobj (config->root_window);
4633
4634   for (i = 0; i < config->saved_windows_count; i++)
4635     {
4636       struct saved_window *s = SAVED_WINDOW_N (config, i);
4637       markobj (s->window);
4638       markobj (s->buffer);
4639       markobj (s->start);
4640       markobj (s->pointm);
4641       markobj (s->sb_point);
4642       markobj (s->mark);
4643 #if 0
4644       /* #### This looked like this. I do not see why specifier cached
4645          values should not be marked, as such specifiers as toolbars
4646          might have GC-able instances. Freed configs are not marked,
4647          aren't they?  -- kkm */
4648       markobj (s->dedicated);
4649 #else
4650 #define WINDOW_SLOT(slot, compare) ((void) (markobj (s->slot)))
4651 #include "winslots.h"
4652 #endif
4653     }
4654   return Qnil;
4655 }
4656
4657 static size_t
4658 sizeof_window_config_for_n_windows (int n)
4659 {
4660   return (sizeof (struct window_config) +
4661           /* n - 1 because zero-sized arrays aren't ANSI C */
4662           (n - 1) *sizeof (struct saved_window));
4663 }
4664
4665 static size_t
4666 sizeof_window_config (CONST void *h)
4667 {
4668   CONST struct window_config *c = (CONST struct window_config *) h;
4669   return sizeof_window_config_for_n_windows (c->saved_windows_count);
4670 }
4671
4672 static void
4673 print_window_config (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
4674 {
4675   struct window_config *config = XWINDOW_CONFIGURATION (obj);
4676   char buf[200];
4677   if (print_readably)
4678     error ("printing unreadable object #<window-configuration 0x%x>",
4679            config->header.uid);
4680   write_c_string ("#<window-configuration ", printcharfun);
4681   sprintf (buf, "0x%x>", config->header.uid);
4682   write_c_string (buf, printcharfun);
4683 }
4684
4685 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION ("window-configuration",
4686                                         window_configuration,
4687                                         mark_window_config,
4688                                         print_window_config,
4689                                         0, 0, 0, 0, sizeof_window_config,
4690                                         struct window_config);
4691
4692
4693 /* Returns a boolean indicating whether the two saved windows are
4694    identical. */
4695 static int
4696 saved_window_equal (struct saved_window *win1, struct saved_window *win2)
4697 {
4698 #define WINDOW_SLOT(slot, compare)              \
4699   if (!compare (win1->slot, win2->slot))        \
4700     return 0;
4701 #include "winslots.h"
4702
4703   return
4704     EQ (win1->window, win2->window) &&
4705     EQ (win1->buffer, win2->buffer) &&
4706     internal_equal (win1->start,    win2->start, 0) &&
4707     internal_equal (win1->pointm,   win2->pointm, 0) &&
4708     internal_equal (win1->sb_point, win2->sb_point, 0) &&
4709     internal_equal (win1->mark,     win2->mark, 0) &&
4710     win1->pixel_left   == win2->pixel_left &&
4711     win1->pixel_top    == win2->pixel_top &&
4712     win1->pixel_width  == win2->pixel_width &&
4713     win1->pixel_height == win2->pixel_height &&
4714     win1->hscroll      == win2->hscroll &&
4715     win1->modeline_hscroll == win2->modeline_hscroll &&
4716     win1->parent_index == win2->parent_index &&
4717     win1->prev_index   == win2->prev_index &&
4718     win1->start_at_line_beg == win2->start_at_line_beg;
4719 }
4720
4721 /* Returns a boolean indicating whether the two given configurations
4722    are identical. */
4723 static int
4724 window_config_equal (Lisp_Object conf1, Lisp_Object conf2)
4725 {
4726   struct window_config *fig1, *fig2;
4727   int i;
4728
4729   /* First check if they are truly the same. */
4730   if (EQ (conf1, conf2))
4731     return 1;
4732
4733   fig1 = XWINDOW_CONFIGURATION (conf1);
4734   fig2 = XWINDOW_CONFIGURATION (conf2);
4735
4736   if (!((fig1->saved_windows_count == fig2->saved_windows_count) &&
4737         EQ (fig1->current_window,           fig2->current_window) &&
4738         EQ (fig1->current_buffer,           fig2->current_buffer) &&
4739         EQ (fig1->root_window,              fig2->root_window) &&
4740         EQ (fig1->minibuffer_scroll_window, fig2->minibuffer_scroll_window)))
4741         /* &&
4742         fig1->frame_width  == fig2->frame_width &&
4743         fig1->frame_height == fig2->frame_height)) */
4744     return 0;
4745
4746   for (i = 0; i < fig1->saved_windows_count; i++)
4747     {
4748       if (!saved_window_equal (SAVED_WINDOW_N (fig1, i),
4749                                SAVED_WINDOW_N (fig2, i)))
4750         return 0;
4751     }
4752
4753   return 1;
4754 }
4755
4756 DEFUN ("window-configuration-p", Fwindow_configuration_p, 1, 1, 0, /*
4757 Return t if OBJECT is a window-configuration object.
4758 */
4759        (obj))
4760 {
4761   return WINDOW_CONFIGURATIONP (obj) ? Qt : Qnil;
4762 }
4763
4764 static int
4765 mark_windows_in_use_closure (struct window *w, void *closure)
4766 {
4767   int mark = *(int *)closure;
4768   w->config_mark = mark;
4769   return 0;
4770 }
4771
4772 static void
4773 mark_windows_in_use (struct frame *f, int mark)
4774 {
4775   map_windows (f, mark_windows_in_use_closure, &mark);
4776 }
4777
4778 /* Lisp_Object return value so it can be used in record_unwind_protect() */
4779 static Lisp_Object
4780 free_window_configuration (Lisp_Object window_config)
4781 {
4782   int i;
4783   struct window_config *config = XWINDOW_CONFIGURATION (window_config);
4784
4785   /* Free all the markers.  It's not completely necessary that
4786      we do this (window configs sitting in a free list aren't
4787      marked normally so the markers wouldn't be marked anyway)
4788      but it's more efficient. */
4789   for (i = 0; i < config->saved_windows_count; i++)
4790     {
4791       struct saved_window *p = SAVED_WINDOW_N (config, i);
4792
4793       if (!NILP (p->pointm))
4794         {
4795           free_marker (XMARKER (p->pointm));
4796           p->pointm = Qnil;
4797         }
4798       if (!NILP (p->start))
4799         {
4800           free_marker (XMARKER (p->start));
4801           p->start = Qnil;
4802         }
4803       if (!NILP (p->sb_point))
4804         {
4805           free_marker (XMARKER (p->sb_point));
4806           p->sb_point = Qnil;
4807         }
4808       if (!NILP (p->mark))
4809         {
4810           free_marker (XMARKER (p->mark));
4811           p->mark = Qnil;
4812         }
4813     }
4814
4815   if (config->saved_windows_count <= countof (Vwindow_configuration_free_list))
4816     free_managed_lcrecord (Vwindow_configuration_free_list
4817                            [config->saved_windows_count - 1],
4818                            window_config);
4819
4820   return Qnil;
4821 }
4822
4823 DEFUN ("set-window-configuration", Fset_window_configuration, 1, 1, 0, /*
4824 Set the configuration of windows and buffers as specified by CONFIGURATION.
4825 CONFIGURATION must be a value previously returned
4826 by `current-window-configuration' (which see).
4827 */
4828        (configuration))
4829 {
4830   struct window *w;
4831   struct window_config *config;
4832   struct saved_window *p;
4833   Lisp_Object new_current_buffer;
4834   int k;
4835   Lisp_Object frame;
4836   struct frame *f;
4837   struct gcpro gcpro1;
4838   Lisp_Object old_window_config;
4839   /*  int previous_frame_height;
4840       int previous_frame_width;*/
4841   int previous_pixel_top;
4842   int previous_pixel_height;
4843   int previous_pixel_left;
4844   int previous_pixel_width;
4845   int previous_minibuf_height, previous_minibuf_top,previous_minibuf_width;
4846   int real_font_height;
4847   int converted_minibuf_height,target_minibuf_height; 
4848   int specpdl_count = specpdl_depth ();
4849
4850   GCPRO1 (configuration);
4851
4852   CHECK_WINDOW_CONFIGURATION (configuration);
4853   config = XWINDOW_CONFIGURATION (configuration);
4854
4855   frame = XWINDOW (SAVED_WINDOW_N (config, 0)->window)->frame;
4856   f = XFRAME (frame);
4857
4858   /* Do not signal an error here if the frame was deleted.  There are
4859      reasonable cases where we could get here with a deleted frame and
4860      just want to do close to nothing instead. */
4861
4862   if (FRAME_LIVE_P (f))
4863     {
4864       /* restore the frame characteristics */
4865
4866       new_current_buffer = config->current_buffer;
4867       if (!BUFFER_LIVE_P (XBUFFER (new_current_buffer)))
4868         new_current_buffer = Qnil;
4869
4870       /*
4871        * Assumed precondition:  w->config_mark = 0 for all w
4872        * This procedure should ensure this is true by the time it exits
4873        * to ensure the precondition for future calls.
4874        *
4875        * We use w->config_mark to know whether we're modifying a
4876        * window that is currently visible on the frame (#### we
4877        * should just be able to check whether the window is dead
4878        * or not, but this way is safer?).  As we process each
4879        * window, we set its config_mark to 0.  At the end, we
4880        * go through all the windows that used to be on the frame,
4881        * set each one's config_mark to 0 (to maintain the
4882        * assumed precondition) and delete each one that's no
4883        * longer in use.
4884        *
4885        * #### Using a window-configuration to keep track of
4886        * the current windows is wasteful.  All we need is the
4887        * list of windows, so we could just use a dynarr.
4888        */
4889       old_window_config = Fcurrent_window_configuration (frame);
4890
4891       /* If the new configuration is already equal to the old, then stop
4892          right here.  This saves the work below and it also saves
4893          triggering a full redisplay of this window.  This is a huge win
4894          when using the mouse since the mode motion code uses
4895          save-window-excursion extensively but will rarely cause the
4896          configuration to actually change. */
4897       if (window_config_equal (configuration, old_window_config))
4898         {
4899           free_window_configuration (old_window_config);
4900           UNGCPRO;
4901           return Qnil;
4902         }
4903
4904       /* We can't quit or even check for quit because that may cause
4905          investigation of the frame state, which may crash if the frame is
4906          in an inconsistent state. */
4907       begin_dont_check_for_quit ();
4908       record_unwind_protect (free_window_configuration, old_window_config);
4909
4910       mark_windows_in_use (f, 1);
4911
4912 #if 0
4913       /* JV: This is bogus,
4914          First of all, the units are inconsistent. The frame sizes are measured
4915          in characters but the window sizes are stored in pixels. So if a 
4916          font size change happened between saving and restoring, the
4917          frame "sizes" maybe equal but the windows still should be
4918          resized. This is tickled alot by the new "character size
4919          stays constant" policy in 21.0. It leads to very wierd
4920          glitches (and possibly craches when asserts are tickled).
4921
4922          Just changing the units doens't help because changing the
4923          toolbar configuration can also change the pixel positions.
4924          Luckily there is a much simpler way of doing this, see below.
4925        */
4926       previous_frame_width = FRAME_WIDTH (f);
4927       previous_frame_height = FRAME_HEIGHT (f);
4928       /* If the frame has been resized since this window configuration was
4929          made, we change the frame to the size specified in the
4930          configuration, restore the configuration, and then resize it
4931          back.  We keep track of the prevailing height in these variables.  */
4932       if (config->frame_height != FRAME_HEIGHT (f)
4933           || config->frame_width != FRAME_WIDTH (f))
4934         change_frame_size (f, config->frame_height, config->frame_width, 0);
4935 #endif
4936       
4937       previous_pixel_top = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_top;
4938       previous_pixel_height = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_height;
4939       previous_pixel_left = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_left;
4940       previous_pixel_width = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_width;
4941
4942       /* remember some properties of the minibuffer */
4943
4944       default_face_height_and_width (frame, &real_font_height, 0);
4945       assert(real_font_height > 0);
4946   
4947       if (FRAME_HAS_MINIBUF_P (f) && ! FRAME_MINIBUF_ONLY_P (f))
4948         {
4949           previous_minibuf_height
4950             = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_height;
4951           previous_minibuf_top
4952             = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_top;
4953           previous_minibuf_width
4954             = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_width;
4955         }
4956       else
4957         {
4958           previous_minibuf_height = 0;
4959           previous_minibuf_width = 0;
4960         }
4961       converted_minibuf_height =
4962         (previous_minibuf_height % real_font_height) == 0 ?
4963         - (previous_minibuf_height / real_font_height ) :    /* lines */
4964             previous_minibuf_height;   /* pixels */
4965            
4966       /* Temporarily avoid any problems with windows that are smaller
4967          than they are supposed to be.  */
4968       window_min_height = 1;
4969       window_min_width = 1;
4970
4971       /* OK, now restore all the windows in the window config.
4972          This may involve "undeleting" windows, since the
4973          windows in the window config may be deleted.
4974          */
4975       for (k = 0; k < config->saved_windows_count; k++)
4976         {
4977           p = SAVED_WINDOW_N (config, k);
4978           w = XWINDOW (p->window);
4979           w->next = Qnil;
4980
4981           /* The window might be dead.  In this case, its redisplay
4982              structures were freed, so we need to reallocate them. */
4983           if (!w->face_cachels)
4984             {
4985               w->face_cachels = Dynarr_new (face_cachel);
4986               reset_face_cachels (w);
4987             }
4988           if (!w->glyph_cachels)
4989             w->glyph_cachels = Dynarr_new (glyph_cachel);
4990           if (!w->line_start_cache)
4991             w->line_start_cache = Dynarr_new (line_start_cache);
4992           w->dead = 0;
4993
4994           if (p->parent_index >= 0)
4995             w->parent = SAVED_WINDOW_N (config, p->parent_index)->window;
4996           else
4997             w->parent = Qnil;
4998
4999           if (p->prev_index >= 0)
5000             {
5001               w->prev = SAVED_WINDOW_N (config, p->prev_index)->window;
5002
5003               /* This is true for a minibuffer-only frame. */
5004               if (!NILP (w->mini_p) && EQ (w->prev, p->window))
5005                 w->next = Qnil;
5006               else
5007                 XWINDOW (w->prev)->next = p->window;
5008             }
5009           else
5010             {
5011               w->prev = Qnil;
5012               if (!NILP (w->parent))
5013                 {
5014                   if (WINDOW_WIDTH (p) == WINDOW_WIDTH (XWINDOW (w->parent)))
5015                     {
5016                       XWINDOW (w->parent)->vchild = p->window;
5017                       XWINDOW (w->parent)->hchild = Qnil;
5018                     }
5019                   else
5020                     {
5021                       XWINDOW (w->parent)->hchild = p->window;
5022                       XWINDOW (w->parent)->vchild = Qnil;
5023                     }
5024                 }
5025             }
5026           if (!w->config_mark)
5027             {
5028               /* #### This should be equivalent to the window previously
5029                  having been dead.  If we're brave, we'll put in an
5030                  assertion to this effect. */
5031               MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
5032             }
5033           else /* if (!EQ (w->buffer, p->buffer)) */
5034             {
5035               /* With the new redisplay we let it know that a change has
5036                  been made and it will take care of the rest.  If we don't
5037                  tell it something has possibly changed it could lead to
5038                  incorrect display. */
5039               MARK_WINDOWS_CHANGED (w);
5040             }
5041
5042           WINDOW_LEFT (w) = WINDOW_LEFT (p);
5043           WINDOW_TOP (w) = WINDOW_TOP (p);
5044           WINDOW_WIDTH (w) = WINDOW_WIDTH (p);
5045           WINDOW_HEIGHT (w) = WINDOW_HEIGHT (p);
5046           w->hscroll = p->hscroll;
5047           w->modeline_hscroll = p->modeline_hscroll;
5048           w->line_cache_last_updated = Qzero;
5049           SET_LAST_MODIFIED (w, 1);
5050           SET_LAST_FACECHANGE (w);
5051           w->config_mark = 0;
5052
5053 #define WINDOW_SLOT(slot, compare) w->slot = p->slot;
5054 #include "winslots.h"
5055
5056           /* Reinstall the saved buffer and pointers into it.  */
5057           if (NILP (p->buffer))
5058             w->buffer = p->buffer;
5059           else
5060             {
5061               if (BUFFER_LIVE_P (XBUFFER (p->buffer)))
5062                 /* If saved buffer is alive, install it.  */
5063                 {
5064                   w->buffer = p->buffer;
5065                   w->start_at_line_beg = p->start_at_line_beg;
5066                   set_marker_restricted (w->start[CURRENT_DISP],
5067                                          Fmarker_position (p->start),
5068                                          w->buffer);
5069                   set_marker_restricted (w->pointm[CURRENT_DISP],
5070                                          Fmarker_position (p->pointm),
5071                                          w->buffer);
5072                   set_marker_restricted (w->sb_point,
5073                                          Fmarker_position (p->sb_point),
5074                                          w->buffer);
5075                   Fset_marker (XBUFFER (w->buffer)->mark,
5076                                Fmarker_position (p->mark), w->buffer);
5077
5078                   /* As documented in Fcurrent_window_configuration, don't
5079                      save the location of point in the buffer which was current
5080                      when the window configuration was recorded.  */
5081                   if (!EQ (p->buffer, new_current_buffer) &&
5082                       XBUFFER (p->buffer) == current_buffer)
5083                     Fgoto_char (w->pointm[CURRENT_DISP], Qnil);
5084                 }
5085               else if (NILP (w->buffer) ||
5086                        !BUFFER_LIVE_P (XBUFFER (w->buffer)))
5087                 /* Else if window's old buffer is dead too, get a live one.  */
5088                 {
5089                   /* #### The following line makes me nervous... */
5090                   /* w->buffer = Fcdr (Fcar (XFRAME (w->frame)->buffer_alist));*/
5091                   w->buffer = Fget_buffer_create (QSscratch);
5092                   /* w->buffer = Fother_buffer (Qnil, w->frame, Qnil); */
5093                   /* This will set the markers to beginning of visible
5094                      range.  */
5095                   set_marker_restricted (w->start[CURRENT_DISP], Qzero, w->buffer);
5096                   set_marker_restricted (w->pointm[CURRENT_DISP], Qzero,
5097                                          w->buffer);
5098                   set_marker_restricted (w->sb_point, Qzero, w->buffer);
5099                   w->start_at_line_beg = 1;
5100                 }
5101               else
5102                 /* Keeping window's old buffer; make sure the markers
5103                    are real.  */
5104                 {
5105                   /* Set window markers at start of visible range.  */
5106                   if (XMARKER (w->start[CURRENT_DISP])->buffer == 0)
5107                     set_marker_restricted (w->start[CURRENT_DISP], Qzero,
5108                                            w->buffer);
5109                   if (XMARKER (w->sb_point)->buffer == 0)
5110                     set_marker_restricted (w->sb_point, Qzero, w->buffer);
5111                   if (XMARKER (w->pointm[CURRENT_DISP])->buffer == 0)
5112                     set_marker_restricted (w->pointm[CURRENT_DISP],
5113                                            make_int
5114                                            (BUF_PT (XBUFFER (w->buffer))),
5115                                            w->buffer);
5116                   w->start_at_line_beg = 1;
5117                 }
5118             }
5119         }
5120
5121       FRAME_ROOT_WINDOW (f) = config->root_window;
5122       /* Note that FSFmacs unilaterally calls Fselect_window() here, and
5123          then calls do_switch_frame() below to select the frame that was
5124          recorded in the window config as being selected.
5125
5126          Instead, we don't ever change the selected frame, and either
5127          call Fselect_window() below if the window config's frame is
5128          currently selected, or just set the selected window of the
5129          window config's frame. */
5130
5131 #if 0
5132       /* Set the frame height to the value it had before this function.  */
5133       if (previous_frame_height != FRAME_HEIGHT (f)
5134           || previous_frame_width != FRAME_WIDTH (f))
5135         change_frame_size (f, previous_frame_height, previous_frame_width, 0);
5136 #endif
5137       /* We just reset the size and position of the minibuffer, to its old
5138          value, which needn't be valid. So we do some magic to see which value
5139          to actually take. Then we set it.
5140
5141          The magic:
5142          We take the old value if is in the same units but differs from the
5143          current value.
5144
5145          #### Now we get more cases correct then ever before, but
5146          are we treating all? For instance what if the frames minibuf window
5147          is no longer the same one? 
5148       */
5149       target_minibuf_height = previous_minibuf_height;
5150       if (converted_minibuf_height &&
5151           (converted_minibuf_height * config->minibuf_height) > 0 &&
5152           (converted_minibuf_height !=  config->minibuf_height))
5153         {
5154           target_minibuf_height = config->minibuf_height < 0 ?
5155             - (config->minibuf_height * real_font_height) :
5156             config->minibuf_height;
5157           target_minibuf_height =
5158             max(target_minibuf_height,real_font_height);
5159         }
5160       if (previous_minibuf_height)
5161         {
5162           XWINDOW (FRAME_MINIBUF_WINDOW (f))->pixel_top
5163             = previous_minibuf_top -
5164                   (target_minibuf_height - previous_minibuf_height);
5165           set_window_pixheight (FRAME_MINIBUF_WINDOW (f),
5166                                 target_minibuf_height, 0);
5167           set_window_pixwidth  (FRAME_MINIBUF_WINDOW (f),
5168                             previous_minibuf_width, 0);
5169         }
5170         
5171       /* This is a better way to deal with frame resizing, etc.
5172          What we _actually_ want is for the old (just restored)
5173          root window to fit
5174          into the place of the new one. So we just do that. Simple! */
5175       XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_top = previous_pixel_top;
5176       /* Note that this function also updates the subwindow
5177          "pixel_top"s */
5178       set_window_pixheight (FRAME_ROOT_WINDOW (f),
5179           previous_pixel_height -
5180                   (target_minibuf_height - previous_minibuf_height), 0);
5181       XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_left = previous_pixel_left;
5182       /* Note that this function also updates the subwindow
5183          "pixel_left"s */
5184       set_window_pixwidth (FRAME_ROOT_WINDOW (f), previous_pixel_width, 0);
5185       
5186       /* If restoring in the current frame make the window current,
5187          otherwise just update the frame selected_window slot to be
5188          the restored current_window. */
5189       if (f == selected_frame ())
5190         {
5191           /* When using `pop-window-configuration', often the minibuffer
5192              ends up as the selected window even though it's not active ...
5193              I really don't know the cause of this, but it should never
5194              happen.  This kludge should fix it.
5195
5196              #### Find out why this is really going wrong. */
5197           if (!minibuf_level &&
5198               MINI_WINDOW_P (XWINDOW (config->current_window)))
5199             Fselect_window (Fnext_window (config->current_window,
5200                                           Qnil, Qnil, Qnil),
5201                             Qnil);
5202           else
5203             Fselect_window (config->current_window, Qnil);
5204           if (!NILP (new_current_buffer))
5205             Fset_buffer (new_current_buffer);
5206           else
5207             Fset_buffer (XWINDOW (Fselected_window (Qnil))->buffer);
5208         }
5209       else
5210         set_frame_selected_window (f, config->current_window);
5211     }
5212   else
5213     old_window_config = Qnil; /* Warning suppression */
5214
5215   /* Restore the minimum heights recorded in the configuration.  */
5216   window_min_height = config->min_height;
5217   window_min_width = config->min_width;
5218
5219 #if 0 /* FSFmacs */
5220   /* see above comment */
5221   /* Fselect_window will have made f the selected frame, so we
5222      reselect the proper frame here.  Fhandle_switch_frame will change the
5223      selected window too, but that doesn't make the call to
5224      Fselect_window above totally superfluous; it still sets f's
5225      selected window.  */
5226   if (FRAME_LIVE_P (XFRAME (config->selected_frame)))
5227     do_switch_frame (config->selected_frame, Qnil, 0);
5228 #endif
5229
5230   Vminibuffer_scroll_window = config->minibuffer_scroll_window;
5231
5232   if (FRAME_LIVE_P (f))
5233     {
5234       /* Do this before calling recompute_all_cached_specifiers_in_window()
5235          so that things like redisplay_redraw_cursor() won't abort due
5236          to no window mirror present. */
5237       f->mirror_dirty = 1;
5238
5239       config = XWINDOW_CONFIGURATION (old_window_config);
5240       for (k = 0; k < config->saved_windows_count; k++)
5241         {
5242           p = SAVED_WINDOW_N (config, k);
5243           w = XWINDOW (p->window);
5244           /* Remember, we set w->config_mark on all currently visible
5245              windows, and reset it on all newly visible windows.
5246              Any windows still marked need to be deleted. */
5247           if (w->config_mark)
5248             {
5249               mark_window_as_deleted (w);
5250               w->config_mark = 0;
5251             }
5252           else
5253             {
5254               /* We just potentially changed the window's buffer and
5255                  potentially turned a dead window into a live one,
5256                  so we need to recompute the cached specifier values. */
5257               recompute_all_cached_specifiers_in_window (w);
5258             }
5259         }
5260     }
5261
5262   /* Now restore things, when everything else if OK. */
5263
5264   unbind_to (specpdl_count, Qnil);
5265
5266   UNGCPRO;
5267
5268   return Qnil;
5269 }
5270
5271 /* Mark all subwindows of a window as deleted.  The argument
5272    W is actually the subwindow tree of the window in question. */
5273
5274 void
5275 delete_all_subwindows (struct window *w)
5276 {
5277   if (!NILP (w->next))   delete_all_subwindows (XWINDOW (w->next));
5278   if (!NILP (w->vchild)) delete_all_subwindows (XWINDOW (w->vchild));
5279   if (!NILP (w->hchild)) delete_all_subwindows (XWINDOW (w->hchild));
5280
5281   mark_window_as_deleted (w);
5282 }
5283
5284 \f
5285 static int
5286 count_windows (struct window *window)
5287 {
5288   return 1 +
5289     (!NILP (window->next)   ? count_windows (XWINDOW (window->next))   : 0) +
5290     (!NILP (window->vchild) ? count_windows (XWINDOW (window->vchild)) : 0) +
5291     (!NILP (window->hchild) ? count_windows (XWINDOW (window->hchild)) : 0);
5292 }
5293
5294 static int
5295 saved_window_index (Lisp_Object window, struct window_config *config, int lim)
5296 {
5297   int j;
5298   for (j = 0; j < lim; j++)
5299     {
5300       if (EQ (SAVED_WINDOW_N (config, j)->window, window))
5301         return j;
5302     }
5303   abort ();
5304   return 0;     /* suppress compiler warning */
5305 }
5306
5307 static int
5308 save_window_save (Lisp_Object window, struct window_config *config, int i)
5309 {
5310   struct window *w;
5311
5312   for (; !NILP (window); window = w->next)
5313     {
5314       struct saved_window *p = SAVED_WINDOW_N (config, i);
5315
5316       w = XWINDOW (window);
5317       i++;
5318       p->window = window;
5319       p->buffer = w->buffer;
5320       WINDOW_LEFT (p) = WINDOW_LEFT (w);
5321       WINDOW_TOP (p) = WINDOW_TOP (w);
5322       WINDOW_WIDTH (p) = WINDOW_WIDTH (w);
5323       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (w);
5324       p->hscroll = w->hscroll;
5325       p->modeline_hscroll = w->modeline_hscroll;
5326
5327 #define WINDOW_SLOT(slot, compare) p->slot = w->slot;
5328 #include "winslots.h"
5329
5330       if (!NILP (w->buffer))
5331         {
5332           /* Save w's value of point in the window configuration.
5333              If w is the selected window, then get the value of point
5334              from the buffer; pointm is garbage in the selected window.  */
5335           if (EQ (window, Fselected_window (Qnil)))
5336             {
5337               p->pointm = noseeum_make_marker ();
5338               Fset_marker (p->pointm,
5339                            make_int (BUF_PT (XBUFFER (w->buffer))),
5340                            w->buffer);
5341             }
5342           else
5343             p->pointm = noseeum_copy_marker (w->pointm[CURRENT_DISP], Qnil);
5344
5345           p->start = noseeum_copy_marker (w->start[CURRENT_DISP], Qnil);
5346           p->sb_point = noseeum_copy_marker (w->sb_point, Qnil);
5347           p->start_at_line_beg = w->start_at_line_beg;
5348
5349           p->mark = noseeum_copy_marker (XBUFFER (w->buffer)->mark, Qnil);
5350         }
5351       else
5352         {
5353           p->pointm = Qnil;
5354           p->start = Qnil;
5355           p->sb_point = Qnil;
5356           p->mark = Qnil;
5357           p->start_at_line_beg = 0;
5358         }
5359
5360       if (NILP (w->parent))
5361         p->parent_index = -1;
5362       else
5363         p->parent_index = saved_window_index (w->parent, config, i);
5364       if (NILP (w->prev))
5365         p->prev_index = -1;
5366       else
5367         p->prev_index = saved_window_index (w->prev, config, i);
5368       if (!NILP (w->vchild))
5369         i = save_window_save (w->vchild, config, i);
5370       if (!NILP (w->hchild))
5371         i = save_window_save (w->hchild, config, i);
5372     }
5373
5374   return i;
5375 }
5376
5377 #if 0 /* FSFmacs */
5378 /* Added to doc string:
5379
5380 This also records the currently selected frame, and FRAME's focus
5381 redirection (see `redirect-frame-focus').
5382
5383 */
5384 #endif
5385
5386 DEFUN ("current-window-configuration", Fcurrent_window_configuration, 0, 1, 0, /*
5387 Return an object representing the current window configuration of FRAME.
5388 If FRAME is nil or omitted, use the selected frame.
5389 This describes the number of windows, their sizes and current buffers,
5390 and for each displayed buffer, where display starts, and the positions of
5391 point and mark.  An exception is made for point in the current buffer:
5392 its value is -not- saved.
5393 */
5394        (frame))
5395 {
5396   Lisp_Object result;
5397   struct frame *f = decode_frame (frame);
5398   struct window_config *config;
5399   int n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
5400   int minibuf_height;
5401   int real_font_height;
5402
5403   if (n_windows <= countof (Vwindow_configuration_free_list))
5404     config = XWINDOW_CONFIGURATION (allocate_managed_lcrecord
5405                                     (Vwindow_configuration_free_list
5406                                      [n_windows - 1]));
5407   else
5408     /* More than ten windows; just allocate directly */
5409     config = (struct window_config *)
5410       alloc_lcrecord (sizeof_window_config_for_n_windows (n_windows),
5411                       &lrecord_window_configuration);
5412   XSETWINDOW_CONFIGURATION (result, config);
5413   /*
5414   config->frame_width = FRAME_WIDTH (f);
5415   config->frame_height = FRAME_HEIGHT (f); */
5416   config->current_window = FRAME_SELECTED_WINDOW (f);
5417   XSETBUFFER (config->current_buffer, current_buffer);
5418   config->minibuffer_scroll_window = Vminibuffer_scroll_window;
5419   config->root_window = FRAME_ROOT_WINDOW (f);
5420   config->min_height = window_min_height;
5421   config->min_width = window_min_width;
5422   config->saved_windows_count = n_windows;
5423   save_window_save (FRAME_ROOT_WINDOW (f), config, 0);
5424
5425   /* save the minibuffer height using the heuristics from
5426      change_frame_size_1 */
5427   
5428   XSETFRAME (frame, f); /* frame could have been nil ! */
5429   default_face_height_and_width (frame, &real_font_height, 0);
5430   assert(real_font_height > 0);
5431   
5432   if (FRAME_HAS_MINIBUF_P (f) && ! FRAME_MINIBUF_ONLY_P (f))
5433     minibuf_height = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_height;
5434   else
5435     minibuf_height = 0;
5436   config->minibuf_height = (minibuf_height % real_font_height) == 0 ?
5437     - (minibuf_height / real_font_height ) :    /* lines */
5438     minibuf_height;   /* pixels */
5439
5440   return result;
5441 }
5442
5443 Lisp_Object
5444 save_window_excursion_unwind (Lisp_Object window_config)
5445 {
5446   Lisp_Object val = Fset_window_configuration (window_config);
5447   free_window_configuration (window_config);
5448   return val;
5449 }
5450
5451 DEFUN ("save-window-excursion", Fsave_window_excursion, 0, UNEVALLED, 0, /*
5452 Execute body, preserving window sizes and contents.
5453 Restores which buffer appears in which window, where display starts,
5454 as well as the current buffer.
5455 Does not restore the value of point in current buffer.
5456 */
5457        (args))
5458 {
5459   /* This function can GC */
5460   Lisp_Object val;
5461   int speccount = specpdl_depth ();
5462
5463   record_unwind_protect (save_window_excursion_unwind,
5464                          Fcurrent_window_configuration (Qnil));
5465   val = Fprogn (args);
5466   return unbind_to (speccount, val);
5467 }
5468
5469 \f
5470 #ifdef DEBUG_XEMACS
5471 /* This is short and simple in elisp, but... it was written to debug
5472    problems purely on the C side.  That is where we need to call it so
5473    here it is. */
5474 static void
5475 debug_print_window (Lisp_Object window, int level)
5476 {
5477   int i;
5478   Lisp_Object child = Fwindow_first_vchild (window);
5479
5480   if (NILP (child))
5481     child = Fwindow_first_hchild (window);
5482
5483   for (i = level; i > 0; i--)
5484     putc ('\t', stderr);
5485
5486   fputs ("#<window", stderr);
5487   {
5488     Lisp_Object buffer = XWINDOW (window)->buffer;
5489     if (!NILP (buffer) && BUFFERP (buffer))
5490       fprintf (stderr, " on %s", XSTRING_DATA (XBUFFER (buffer)->name));
5491   }
5492   fprintf (stderr, " 0x%x>", XWINDOW (window)->header.uid);
5493
5494   while (!NILP (child))
5495     {
5496       debug_print_window (child, level + 1);
5497       child = Fwindow_next_child (child);
5498     }
5499 }
5500
5501 void debug_print_windows (struct frame *f);
5502 void
5503 debug_print_windows (struct frame *f)
5504 {
5505   debug_print_window (f->root_window, 0);
5506   putc ('\n', stderr);
5507 }
5508 #endif /* DEBUG_XEMACS */
5509
5510 \f
5511 /************************************************************************/
5512 /*                            initialization                            */
5513 /************************************************************************/
5514
5515 void
5516 syms_of_window (void)
5517 {
5518   defsymbol (&Qwindowp, "windowp");
5519   defsymbol (&Qwindow_live_p, "window-live-p");
5520   defsymbol (&Qwindow_configurationp, "window-configuration-p");
5521   defsymbol (&Qscroll_up, "scroll-up");
5522   defsymbol (&Qscroll_down, "scroll-down");
5523   defsymbol (&Qtemp_buffer_show_hook, "temp-buffer-show-hook");
5524   defsymbol (&Qdisplay_buffer, "display-buffer");
5525
5526 #ifdef MEMORY_USAGE_STATS
5527   defsymbol (&Qface_cache, "face-cache");
5528   defsymbol (&Qglyph_cache, "glyph-cache");
5529   defsymbol (&Qline_start_cache, "line-start-cache");
5530 #ifdef HAVE_SCROLLBARS
5531   defsymbol (&Qscrollbar_instances, "scrollbar-instances");
5532 #endif
5533   defsymbol (&Qother_redisplay, "other-redisplay");
5534   /* Qother in general.c */
5535 #endif
5536
5537   DEFSUBR (Fselected_window);
5538   DEFSUBR (Fminibuffer_window);
5539   DEFSUBR (Fwindow_minibuffer_p);
5540   DEFSUBR (Fwindowp);
5541   DEFSUBR (Fwindow_live_p);
5542   DEFSUBR (Fwindow_first_hchild);
5543   DEFSUBR (Fwindow_first_vchild);
5544   DEFSUBR (Fwindow_next_child);
5545   DEFSUBR (Fwindow_previous_child);
5546   DEFSUBR (Fwindow_parent);
5547   DEFSUBR (Fwindow_lowest_p);
5548   DEFSUBR (Fwindow_highest_p);
5549   DEFSUBR (Fwindow_leftmost_p);
5550   DEFSUBR (Fwindow_rightmost_p);
5551   DEFSUBR (Fpos_visible_in_window_p);
5552   DEFSUBR (Fwindow_buffer);
5553   DEFSUBR (Fwindow_frame);
5554   DEFSUBR (Fwindow_height);
5555   DEFSUBR (Fwindow_displayed_height);
5556   DEFSUBR (Fwindow_width);
5557   DEFSUBR (Fwindow_pixel_height);
5558   DEFSUBR (Fwindow_pixel_width);
5559   DEFSUBR (Fwindow_text_area_pixel_height);
5560   DEFSUBR (Fwindow_displayed_text_pixel_height);
5561   DEFSUBR (Fwindow_text_area_pixel_width);
5562   DEFSUBR (Fwindow_hscroll);
5563 #ifdef MODELINE_IS_SCROLLABLE
5564   DEFSUBR (Fmodeline_hscroll);
5565   DEFSUBR (Fset_modeline_hscroll);
5566 #endif /* MODELINE_IS_SCROLLABLE */
5567 #if 0 /* bogus FSF crock */
5568   DEFSUBR (Fwindow_redisplay_end_trigger);
5569   DEFSUBR (Fset_window_redisplay_end_trigger);
5570 #endif
5571   DEFSUBR (Fset_window_hscroll);
5572   DEFSUBR (Fwindow_pixel_edges);
5573   DEFSUBR (Fwindow_text_area_pixel_edges);
5574   DEFSUBR (Fwindow_point);
5575   DEFSUBR (Fwindow_start);
5576   DEFSUBR (Fwindow_end);
5577   DEFSUBR (Fset_window_point);
5578   DEFSUBR (Fset_window_start);
5579   DEFSUBR (Fwindow_dedicated_p);
5580   DEFSUBR (Fset_window_dedicated_p);
5581   DEFSUBR (Fnext_window);
5582   DEFSUBR (Fprevious_window);
5583   DEFSUBR (Fnext_vertical_window);
5584   DEFSUBR (Fother_window);
5585   DEFSUBR (Fget_lru_window);
5586   DEFSUBR (Fget_largest_window);
5587   DEFSUBR (Fget_buffer_window);
5588   DEFSUBR (Fwindow_left_margin_pixel_width);
5589   DEFSUBR (Fwindow_right_margin_pixel_width);
5590   DEFSUBR (Fdelete_other_windows);
5591   DEFSUBR (Fdelete_windows_on);
5592   DEFSUBR (Freplace_buffer_in_windows);
5593   DEFSUBR (Fdelete_window);
5594   DEFSUBR (Fset_window_buffer);
5595   DEFSUBR (Fselect_window);
5596   DEFSUBR (Fsplit_window);
5597   DEFSUBR (Fenlarge_window);
5598   DEFSUBR (Fenlarge_window_pixels);
5599   DEFSUBR (Fshrink_window);
5600   DEFSUBR (Fshrink_window_pixels);
5601   DEFSUBR (Fscroll_up);
5602   DEFSUBR (Fscroll_down);
5603   DEFSUBR (Fscroll_left);
5604   DEFSUBR (Fscroll_right);
5605   DEFSUBR (Fother_window_for_scrolling);
5606   DEFSUBR (Fscroll_other_window);
5607   DEFSUBR (Fcenter_to_window_line);
5608   DEFSUBR (Fmove_to_window_line);
5609 #ifdef MEMORY_USAGE_STATS
5610   DEFSUBR (Fwindow_memory_usage);
5611 #endif
5612   DEFSUBR (Fwindow_configuration_p);
5613   DEFSUBR (Fset_window_configuration);
5614   DEFSUBR (Fcurrent_window_configuration);
5615   DEFSUBR (Fsave_window_excursion);
5616 }
5617
5618 void
5619 vars_of_window (void)
5620 {
5621   /* Make sure all windows get marked */
5622   minibuf_window = Qnil;
5623   staticpro (&minibuf_window);
5624
5625   DEFVAR_BOOL ("scroll-on-clipped-lines", &scroll_on_clipped_lines /*
5626 *Non-nil means to scroll if point lands on a line which is clipped.
5627 */ );
5628   scroll_on_clipped_lines = 1;
5629
5630   DEFVAR_LISP ("temp-buffer-show-hook", &Vtemp_buffer_show_hook /*
5631 See `temp-buffer-show-function'.
5632 */ );
5633   Vtemp_buffer_show_hook = Qnil;
5634
5635   DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function /*
5636 Non-nil means call as function to display a help buffer.
5637 The function is called with one argument, the buffer to be displayed.
5638 Used by `with-output-to-temp-buffer'.
5639 If this function is used, then it must do the entire job of showing
5640 the buffer; `temp-buffer-show-hook' is not run unless this function runs it.
5641 */ );
5642   Vtemp_buffer_show_function = Qnil;
5643
5644   DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuffer_scroll_window /*
5645 Non-nil means it is the window that \\<minibuffer-local-map>\\[scroll-other-window] in minibuffer should scroll.
5646 */ );
5647   Vminibuffer_scroll_window = Qnil;
5648
5649   DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer /*
5650 If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.
5651 */ );
5652   Vother_window_scroll_buffer = Qnil;
5653
5654   DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines /*
5655 *Number of lines of continuity when scrolling by screenfuls.
5656 */ );
5657   next_screen_context_lines = 2;
5658
5659   DEFVAR_INT ("window-min-height", &window_min_height /*
5660 *Delete any window less than this tall (including its modeline).
5661 */ );
5662   window_min_height = 4;
5663
5664   DEFVAR_INT ("window-min-width", &window_min_width /*
5665 *Delete any window less than this wide.
5666 */ );
5667   window_min_width = 10;
5668
5669   {
5670     int i;
5671
5672     for (i = 0; i < countof (Vwindow_configuration_free_list); i++)
5673       {
5674         Vwindow_configuration_free_list[i] =
5675           make_lcrecord_list (sizeof_window_config_for_n_windows (i + 1),
5676                               &lrecord_window_configuration);
5677         staticpro (&Vwindow_configuration_free_list[i]);
5678       }
5679   }
5680 }
5681
5682 void
5683 specifier_vars_of_window (void)
5684 {
5685   DEFVAR_SPECIFIER ("modeline-shadow-thickness", &Vmodeline_shadow_thickness /*
5686 *How thick to draw 3D shadows around modelines.
5687 If this is set to 0, modelines will be the traditional 2D.  Sizes above
5688 10 will be accepted but the maximum thickness that will be drawn is 10.
5689 This is a specifier; use `set-specifier' to change it.
5690 */ );
5691   Vmodeline_shadow_thickness = Fmake_specifier (Qinteger);
5692   /* The initial value for modeline-shadow-thickness is 2, but if the
5693      user removes all specifications we provide a fallback value of 0,
5694      which is probably what was expected. */
5695   set_specifier_fallback (Vmodeline_shadow_thickness,
5696                           list1 (Fcons (Qnil, Qzero)));
5697   Fadd_spec_to_specifier (Vmodeline_shadow_thickness, make_int (2),
5698                           Qnil, Qnil, Qnil);
5699   set_specifier_caching (Vmodeline_shadow_thickness,
5700                          slot_offset (struct window,
5701                                       modeline_shadow_thickness),
5702                          modeline_shadow_thickness_changed,
5703                          0, 0);
5704
5705   DEFVAR_SPECIFIER ("has-modeline-p", &Vhas_modeline_p /*
5706 *Whether the modeline should be displayed.
5707 This is a specifier; use `set-specifier' to change it.
5708 */ );
5709   Vhas_modeline_p = Fmake_specifier (Qboolean);
5710   set_specifier_fallback (Vhas_modeline_p,
5711                           list1 (Fcons (Qnil, Qt)));
5712   set_specifier_caching (Vhas_modeline_p,
5713                          slot_offset (struct window,
5714                                       has_modeline_p),
5715                          /* #### It's strange that we need a special
5716                             flag to indicate that the shadow-thickness
5717                             has changed, but not one to indicate that
5718                             the modeline has been turned off or on. */
5719                          some_window_value_changed,
5720                          0, 0);
5721
5722   DEFVAR_SPECIFIER ("vertical-divider-always-visible-p",
5723                     &Vvertical_divider_always_visible_p /*
5724 *Should XEmacs always display vertical dividers between windows.
5725
5726 When this is non-nil, vertical dividers are always shown, and are
5727 draggable.  When it is nil, vertical dividers are shown only when
5728 there are no scrollbars in between windows, and are not draggable.
5729
5730 This is a specifier; use `set-specifier' to change it.
5731 */ );
5732   Vvertical_divider_always_visible_p = Fmake_specifier (Qboolean);
5733   set_specifier_fallback (Vvertical_divider_always_visible_p,
5734                           list1 (Fcons (Qnil, Qt)));
5735   set_specifier_caching (Vvertical_divider_always_visible_p,
5736                          slot_offset (struct window,
5737                                       vertical_divider_always_visible_p),
5738                          vertical_divider_changed_in_window,
5739                          0, 0);
5740
5741   DEFVAR_SPECIFIER ("vertical-divider-shadow-thickness", &Vvertical_divider_shadow_thickness /*
5742 *How thick to draw 3D shadows around vertical dividers.
5743 This is a specifier; use `set-specifier' to change it.
5744 */ );
5745   Vvertical_divider_shadow_thickness = Fmake_specifier (Qinteger);
5746   set_specifier_fallback (Vvertical_divider_shadow_thickness,
5747                           list1 (Fcons (Qnil, Qzero)));
5748   Fadd_spec_to_specifier (Vvertical_divider_shadow_thickness, make_int (2),
5749                           Qnil, Qnil, Qnil);
5750   set_specifier_caching (Vvertical_divider_shadow_thickness,
5751                          slot_offset (struct window,
5752                                       vertical_divider_shadow_thickness),
5753                          vertical_divider_changed_in_window,
5754                          0, 0);
5755   DEFVAR_SPECIFIER ("vertical-divider-line-width", &Vvertical_divider_line_width /*
5756 *The width of the vertical dividers, not including shadows.
5757
5758 For TTY windows, divider line is always one character wide.  When
5759 instance of this specifier is zero in a TTY window, no divider is
5760 drawn at all between windows.  When non-zero, a one character wide
5761 divider is displayed.
5762
5763 This is a specifier; use `set-specifier' to change it.
5764 */ );
5765
5766   Vvertical_divider_line_width = Fmake_specifier (Qnatnum);
5767   {
5768     Lisp_Object fb = Qnil;
5769 #ifdef HAVE_TTY
5770     fb = Fcons (Fcons (list1 (Qtty), make_int (1)), fb);
5771 #endif
5772 #ifdef HAVE_X_WINDOWS
5773     fb = Fcons (Fcons (list1 (Qx), make_int (3)), fb);
5774 #endif
5775 #ifdef HAVE_MS_WINDOWS
5776     /* #### This should be made magic and made to obey system settings */
5777     fb = Fcons (Fcons (list1 (Qmswindows), make_int (3)), fb);
5778 #endif
5779     set_specifier_fallback (Vvertical_divider_line_width, fb);
5780   }
5781   set_specifier_caching (Vvertical_divider_line_width,
5782                          slot_offset (struct window,
5783                                       vertical_divider_line_width),
5784                          vertical_divider_changed_in_window,
5785                          0, 0);
5786
5787   DEFVAR_SPECIFIER ("vertical-divider-spacing", &Vvertical_divider_spacing /*
5788 *How much space to leave around the vertical dividers.
5789
5790 In TTY windows, spacing is always zero, and the value of this
5791 specifier is ignored.
5792
5793 This is a specifier; use `set-specifier' to change it.
5794 */ );
5795   Vvertical_divider_spacing = Fmake_specifier (Qnatnum);
5796   {
5797     Lisp_Object fb = Qnil;
5798 #ifdef HAVE_TTY
5799     fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
5800 #endif
5801 #ifdef HAVE_X_WINDOWS
5802     /* #### 3D dividers look great on MS Windows with spacing = 0.
5803        Should not the same value be the fallback under X? - kkm */
5804     fb = Fcons (Fcons (list1 (Qx), make_int (2)), fb);
5805 #endif
5806 #ifdef HAVE_MS_WINDOWS
5807     fb = Fcons (Fcons (list1 (Qmswindows), Qzero), fb);
5808 #endif
5809     set_specifier_fallback (Vvertical_divider_spacing, fb);
5810   }
5811   set_specifier_caching (Vvertical_divider_spacing,
5812                          slot_offset (struct window,
5813                                       vertical_divider_spacing),
5814                          vertical_divider_changed_in_window,
5815                          0, 0);
5816 }