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