XEmacs 21.2.29 "Hestia".
[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 if text in 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, 0, 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 DEFUN ("modeline-hscroll", Fmodeline_hscroll, 0, 1, 0, /*
1441 Return the horizontal scrolling ammount of WINDOW's modeline.
1442 If the window has no modeline, return nil.
1443 */
1444        (window))
1445 {
1446   struct window *w = decode_window (window);
1447
1448   return (WINDOW_HAS_MODELINE_P (w)) ? make_int ((int) w->modeline_hscroll) :
1449     Qnil;
1450 }
1451
1452 DEFUN ("set-modeline-hscroll", Fset_modeline_hscroll, 2, 2, 0, /*
1453 Set the horizontal scrolling ammount of WINDOW's modeline to NCOL.
1454 If NCOL is negative, it will silently be forced to 0.
1455 If the window has no modeline, return nil. Otherwise, return the actual
1456 value that was set.
1457 */
1458        (window, ncol))
1459 {
1460   struct window *w = decode_window (window);
1461
1462   if (WINDOW_HAS_MODELINE_P (w))
1463     {
1464       Charcount ncols;
1465
1466       CHECK_INT (ncol);
1467       ncols = (XINT (ncol) <= 0) ? 0 : (Charcount) XINT (ncol);
1468       if (ncols != w->modeline_hscroll)
1469         {
1470           MARK_MODELINE_CHANGED;
1471           w->modeline_hscroll = ncols;
1472         }
1473       return make_int ((int) ncols);
1474     }
1475
1476   return Qnil;
1477 }
1478
1479 DEFUN ("set-window-hscroll", Fset_window_hscroll, 2, 2, 0, /*
1480 Set number of columns WINDOW is scrolled from left margin to NCOL.
1481 NCOL should be zero or positive.
1482 */
1483        (window, ncol))
1484 {
1485   struct window *w;
1486   int ncols;
1487
1488   CHECK_INT (ncol);
1489   ncols = XINT (ncol);
1490   if (ncols < 0) ncols = 0;
1491   w = decode_window (window);
1492   if (w->hscroll != ncols)
1493     MARK_CLIP_CHANGED;  /* FSF marks differently but we aren't FSF. */
1494   w->hscroll = ncols;
1495   return ncol;
1496 }
1497
1498 #if 0 /* bogus FSF crock */
1499
1500 xxDEFUN ("window-redisplay-end-trigger",
1501          Fwindow_redisplay_end_trigger, 0, 1, 0, /*
1502 Return WINDOW's redisplay end trigger value.
1503 See `set-window-redisplay-end-trigger' for more information.
1504 */
1505          (window))
1506 {
1507   return decode_window (window)->redisplay_end_trigger;
1508 }
1509
1510 xxDEFUN ("set-window-redisplay-end-trigger",
1511          Fset_window_redisplay_end_trigger, 2, 2, 0, /*
1512 Set WINDOW's redisplay end trigger value to VALUE.
1513 VALUE should be a buffer position (typically a marker) or nil.
1514 If it is a buffer position, then if redisplay in WINDOW reaches a position
1515 beyond VALUE, the functions in `redisplay-end-trigger-functions' are called
1516 with two arguments: WINDOW, and the end trigger value.
1517 Afterwards the end-trigger value is reset to nil.
1518 */
1519          (window, value))
1520 {
1521   return (decode_window (window)->redisplay_end_trigger = value);
1522 }
1523
1524 #endif /* 0 */
1525
1526 DEFUN ("window-pixel-edges", Fwindow_pixel_edges, 0, 1, 0, /*
1527 Return a list of the pixel edge coordinates of WINDOW.
1528 \(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.
1529 The frame toolbars and menubars are considered to be outside of this area.
1530 */
1531        (window))
1532 {
1533   struct window *w = decode_window (window);
1534   struct frame *f = XFRAME (w->frame);
1535
1536   int left = w->pixel_left - FRAME_LEFT_BORDER_END (f);
1537   int top  = w->pixel_top  - FRAME_TOP_BORDER_END  (f);
1538
1539   return list4 (make_int (left),
1540                 make_int (top),
1541                 make_int (left + w->pixel_width),
1542                 make_int (top + w->pixel_height));
1543 }
1544
1545 DEFUN ("window-text-area-pixel-edges",
1546        Fwindow_text_area_pixel_edges, 0, 1, 0, /*
1547 Return a list of the pixel edge coordinates of the text area of WINDOW.
1548 Returns the list \(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at the
1549 top left corner of the window.
1550 */
1551        (window))
1552 {
1553   struct window *w = decode_window (window);
1554
1555   int left   = window_left_gutter_width (w, /* modeline = */ 0);
1556   int top    = window_top_gutter_height (w);
1557   int right  = WINDOW_WIDTH (w) - window_right_gutter_width (w, 0);
1558   int bottom = WINDOW_HEIGHT (w) - window_bottom_gutter_height (w);
1559
1560   return list4 (make_int (left),
1561                 make_int (top),
1562                 make_int (right),
1563                 make_int (bottom));
1564 }
1565
1566 DEFUN ("window-point", Fwindow_point, 0, 1, 0, /*
1567 Return current value of point in WINDOW.
1568 For a nonselected window, this is the value point would have
1569 if that window were selected.
1570
1571 Note that, when WINDOW is the selected window and its buffer
1572 is also currently selected, the value returned is the same as (point).
1573 It would be more strictly correct to return the `top-level' value
1574 of point, outside of any save-excursion forms.
1575 But that is hard to define.
1576 */
1577        (window))
1578 {
1579   struct window *w = decode_window (window);
1580
1581   /* The special check for current buffer is necessary for this
1582      function to work as defined when called within an excursion. */
1583   if (w == XWINDOW (Fselected_window (XFRAME (w->frame)->device))
1584       && current_buffer == XBUFFER (w->buffer))
1585     return Fpoint (Qnil);
1586   return Fmarker_position (w->pointm[CURRENT_DISP]);
1587 }
1588
1589 DEFUN ("window-start", Fwindow_start, 0, 1, 0, /*
1590 Return position at which display currently starts in WINDOW.
1591 This is updated by redisplay or by calling `set-window-start'.
1592 */
1593        (window))
1594 {
1595   return Fmarker_position (decode_window (window)->start[CURRENT_DISP]);
1596 }
1597
1598 DEFUN ("window-end", Fwindow_end, 0, 2, 0, /*
1599 Return position at which display currently ends in WINDOW.
1600 This is updated by redisplay, when it runs to completion.
1601 Simply changing the buffer text or setting `window-start'
1602 does not update this value.
1603 If GUARANTEE is non-nil, then the return value is guaranteed to be
1604 the value of window-end at the end of the next full redisplay assuming
1605 nothing else changes in the meantime.  This function is potentially much
1606 slower with this flag set.
1607 */
1608        (window, guarantee))
1609 {
1610   struct window *w = decode_window (window);
1611
1612   if (NILP (guarantee))
1613     {
1614       Lisp_Object buf;
1615       buf = w->buffer;
1616       CHECK_BUFFER (buf);
1617       return make_int (BUF_Z (XBUFFER (buf)) - w->window_end_pos[CURRENT_DISP]);
1618     }
1619   else
1620     {
1621       Bufpos startp = marker_position (w->start[CURRENT_DISP]);
1622       return make_int (end_of_last_line (w, startp));
1623     }
1624 }
1625
1626 DEFUN ("window-last-line-visible-height", Fwindow_last_line_visible_height, 0, 1, 0, /*
1627 Return pixel height of visible part of last window line if it is clipped.
1628 If the last line is not clipped, return nil.
1629 */
1630        (window))
1631 {
1632   struct window *w = decode_window (window);
1633   display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
1634   int num_lines = Dynarr_length (dla);
1635   struct display_line *dl;
1636
1637   /* No lines - no clipped lines */
1638   if (num_lines == 0 || (num_lines == 1 && Dynarr_atp (dla, 0)->modeline))
1639     return Qnil;
1640
1641   dl = Dynarr_atp (dla, num_lines - 1);
1642   if (dl->clip == 0)
1643     return Qnil;
1644
1645   return make_int (dl->ascent + dl->descent - dl->clip);
1646 }
1647
1648 DEFUN ("set-window-point", Fset_window_point, 2, 2, 0, /*
1649 Make point value in WINDOW be at position POS in WINDOW's buffer.
1650 */
1651        (window, pos))
1652 {
1653   struct window *w = decode_window (window);
1654
1655   CHECK_INT_COERCE_MARKER (pos);
1656   if (w == XWINDOW (Fselected_window (Qnil)))
1657     Fgoto_char (pos, Qnil);
1658   else
1659     set_marker_restricted (w->pointm[CURRENT_DISP], pos, w->buffer);
1660
1661   MARK_POINT_CHANGED;
1662   return pos;
1663 }
1664
1665 DEFUN ("set-window-start", Fset_window_start, 2, 3, 0, /*
1666 Make display in WINDOW start at position POS in WINDOW's buffer.
1667 Optional third arg NOFORCE non-nil inhibits next redisplay
1668 from overriding motion of point in order to display at this exact start.
1669 */
1670        (window, pos, noforce))
1671 {
1672   struct window *w = decode_window (window);
1673
1674   CHECK_INT_COERCE_MARKER (pos);
1675   set_marker_restricted (w->start[CURRENT_DISP], pos, w->buffer);
1676   /* this is not right, but much easier than doing what is right. */
1677   /* w->start_at_line_beg = 0; */
1678   /* WTF is the above supposed to mean?  GE */
1679   w->start_at_line_beg = beginning_of_line_p (XBUFFER (w->buffer),
1680                                               marker_position (w->start[CURRENT_DISP]));
1681   if (NILP (noforce))
1682     w->force_start = 1;
1683   w->redo_modeline = 1;
1684   SET_LAST_MODIFIED (w, 0);
1685   SET_LAST_FACECHANGE (w);
1686
1687   MARK_WINDOWS_CHANGED (w);
1688
1689   return pos;
1690 }
1691
1692 DEFUN ("window-dedicated-p", Fwindow_dedicated_p, 1, 1, 0, /*
1693 Return WINDOW's dedicated object, usually t or nil.
1694 See also `set-window-dedicated-p'.
1695 */
1696        (window))
1697 {
1698   return decode_window (window)->dedicated;
1699 }
1700
1701 DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p, 2, 2, 0, /*
1702 Control whether WINDOW is dedicated to the buffer it displays.
1703 If it is dedicated, Emacs will not automatically change
1704 which buffer appears in it.
1705 The second argument is the new value for the dedication flag;
1706 non-nil means yes.
1707 */
1708        (window, arg))
1709 {
1710   struct window *w = decode_window (window);
1711
1712   w->dedicated = NILP (arg) ? Qnil : Qt;
1713
1714   return w->dedicated;
1715 }
1716
1717 /* FSFmacs has window-display-table here.  We have display table as a
1718    specifier. */
1719
1720 \f
1721 /* Record info on buffer window w is displaying
1722    when it is about to cease to display that buffer.  */
1723 static void
1724 unshow_buffer (struct window *w)
1725 {
1726   Lisp_Object buf = w->buffer;
1727
1728   if (XBUFFER (buf) != XMARKER (w->pointm[CURRENT_DISP])->buffer)
1729     abort ();
1730
1731   /* FSF disables this check, so I'll do it too.  I hope it won't
1732      break things.  --ben */
1733 #if 0
1734   if (w == XWINDOW (Fselected_window (Qnil))
1735       || ! EQ (buf, XWINDOW (Fselected_window (Qnil))->buffer))
1736     /* Do this except when the selected window's buffer
1737        is being removed from some other window.  */
1738 #endif
1739     /* last_window_start records the start position that this buffer
1740        had in the last window to be disconnected from it.
1741        Now that this statement is unconditional,
1742        it is possible for the buffer to be displayed in the
1743        selected window, while last_window_start reflects another
1744        window which was recently showing the same buffer.
1745        Some people might say that might be a good thing.  Let's see.  */
1746     XBUFFER (buf)->last_window_start =
1747       marker_position (w->start[CURRENT_DISP]);
1748
1749   /* Point in the selected window's buffer
1750      is actually stored in that buffer, and the window's pointm isn't used.
1751      So don't clobber point in that buffer.  */
1752   if (! EQ (buf, XWINDOW (Fselected_window (Qnil))->buffer))
1753     {
1754       struct buffer *b= XBUFFER (buf);
1755       BUF_SET_PT (b, bufpos_clip_to_bounds (BUF_BEGV (b),
1756                                      marker_position (w->pointm[CURRENT_DISP]),
1757                                      BUF_ZV (b)));
1758     }
1759 }
1760
1761 /* Put REPLACEMENT into the window structure in place of OLD. */
1762 static void
1763 replace_window (Lisp_Object old, Lisp_Object replacement)
1764 {
1765   Lisp_Object tem;
1766   struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
1767
1768   /* If OLD is its frame's root_window, then replacement is the new
1769      root_window for that frame.  */
1770
1771   if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
1772     FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
1773
1774   WINDOW_LEFT (p) = WINDOW_LEFT (o);
1775   WINDOW_TOP (p) = WINDOW_TOP (o);
1776   WINDOW_WIDTH (p) = WINDOW_WIDTH (o);
1777   WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o);
1778
1779   p->next = tem = o->next;
1780   if (!NILP (tem))
1781     XWINDOW (tem)->prev = replacement;
1782
1783   p->prev = tem = o->prev;
1784   if (!NILP (tem))
1785     XWINDOW (tem)->next = replacement;
1786
1787   p->parent = tem = o->parent;
1788   if (!NILP (tem))
1789     {
1790       if (EQ (XWINDOW (tem)->vchild, old))
1791         XWINDOW (tem)->vchild = replacement;
1792       if (EQ (XWINDOW (tem)->hchild, old))
1793         XWINDOW (tem)->hchild = replacement;
1794     }
1795
1796   /* #### Here, if replacement is a vertical combination
1797      and so is its new parent, we should make replacement's
1798      children be children of that parent instead. */
1799 }
1800
1801 /* we're deleting W; set the structure of W to indicate this. */
1802
1803 static void
1804 mark_window_as_deleted (struct window *w)
1805 {
1806   /* In the loop
1807      (while t (split-window) (delete-window))
1808      we end up with a tree of deleted windows which are all connected
1809      through the `next' slot.  This might not seem so bad, as they're
1810      deleted, and will presumably be GCed - but if even *one* of those
1811      windows is still being pointed to, by the user, or by a window
1812      configuration, then *all* of those windows stick around.
1813
1814      Since the window-configuration code doesn't need any of the
1815      pointers to other windows (they are all recreated from the
1816      window-config data), we set them all to nil so that we
1817      are able to collect more actual garbage.
1818    */
1819   w->next = Qnil;
1820   w->prev = Qnil;
1821   w->hchild = Qnil;
1822   w->vchild = Qnil;
1823   w->parent = Qnil;
1824
1825   w->dead = 1;
1826
1827   /* Free the extra data structures attached to windows immediately so
1828      they don't sit around consuming excess space.  They will be
1829      reinitialized by the window-configuration code as necessary. */
1830   finalize_window ((void *) w, 0);
1831 }
1832
1833 DEFUN ("delete-window", Fdelete_window, 0, 2, "", /*
1834 Remove WINDOW from the display.  Default is selected window.
1835 If window is the only one on the frame, the frame is destroyed.
1836 Normally, you cannot delete the last non-minibuffer-only frame (you must
1837 use `save-buffers-kill-emacs' or `kill-emacs').  However, if optional
1838 second argument FORCE is non-nil, you can delete the last frame. (This
1839 will automatically call `save-buffers-kill-emacs'.)
1840 */
1841        (window, force))
1842 {
1843   /* This function can GC if this is the only window in the frame */
1844   struct window *w;
1845   Lisp_Object parent;
1846   struct window *par;
1847   Lisp_Object frame;
1848   struct frame *f;
1849   struct device *d;
1850
1851   /* Note: this function is called by other C code on non-leaf
1852      windows. */
1853
1854   /* Do the equivalent of decode_window() but don't error out on
1855      deleted window; it's OK to delete an already-deleted window. */
1856   if (NILP (window))
1857     window = Fselected_window (Qnil);
1858   else
1859     CHECK_WINDOW (window);
1860   w = XWINDOW (window);
1861
1862   /* It's okay to delete an already-deleted window.  */
1863   if (! WINDOW_LIVE_P (w))
1864     return Qnil;
1865
1866   frame = WINDOW_FRAME (w);
1867   f = XFRAME (frame);
1868   d = XDEVICE (FRAME_DEVICE (f));
1869
1870   if (TOP_LEVEL_WINDOW_P (w))
1871     {
1872       if (NILP (memq_no_quit (frame, DEVICE_FRAME_LIST (d))))
1873         /* this frame isn't fully initialized yet; don't blow up. */
1874         return Qnil;
1875
1876       if (MINI_WINDOW_P (XWINDOW (window)))
1877         error ("Attempt to delete the minibuffer window");
1878
1879       /* It has been suggested that it's a good thing for C-x 0 to have this
1880          behavior, but not such a good idea for #'delete-window to have it.
1881          Maybe C-x 0 should be bound to something else, or maybe frame
1882          deletion should only happen when this is called interactively.
1883        */
1884       delete_frame_internal (f, !NILP (force), 0, 0);
1885       return Qnil;
1886     }
1887
1888   /* At this point, we know the window has a parent. */
1889   parent = w->parent;
1890   par = XWINDOW (parent);
1891
1892   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
1893   /* It's quite likely that deleting a window will result in
1894      subwindows needing to be deleted also (since they are cached
1895      per-window). So we mark them as changed, so that the cachels will
1896      get reset by redisplay and thus deleted subwindows can get
1897      GC'd. */
1898   MARK_FRAME_SUBWINDOWS_CHANGED (f);
1899
1900   /* Are we trying to delete any frame's selected window?
1901      Note that we could be dealing with a non-leaf window
1902      where the selected window is one of our children.
1903      So, we check by scanning all the ancestors of the
1904      frame's selected window and comparing each one with
1905      WINDOW.  */
1906   {
1907     Lisp_Object pwindow;
1908
1909     pwindow = FRAME_SELECTED_WINDOW (f);
1910
1911     while (!NILP (pwindow))
1912       {
1913         if (EQ (window, pwindow))
1914           break;
1915         pwindow = XWINDOW (pwindow)->parent;
1916       }
1917
1918     if (EQ (window, pwindow))
1919       {
1920         /* OK, we found it. */
1921         Lisp_Object alternative;
1922         alternative = Fnext_window (window, Qlambda, Qnil, Qnil);
1923
1924         /* If we're about to delete the selected window on the
1925            selected frame, then we should use Fselect_window to select
1926            the new window.  On the other hand, if we're about to
1927            delete the selected window on any other frame, we shouldn't do
1928            anything but set the frame's selected_window slot.  */
1929         if (EQ (frame, Fselected_frame (Qnil)))
1930           Fselect_window (alternative, Qnil);
1931         else
1932           set_frame_selected_window (f, alternative);
1933       }
1934   }
1935
1936   /* w->buffer is nil in a non-leaf window; in this case,
1937      get rid of the markers we maintain that point into that buffer. */
1938   if (!NILP (w->buffer))
1939     {
1940       unshow_buffer (w);
1941       unchain_marker (w->pointm[CURRENT_DISP]);
1942       unchain_marker (w->pointm[DESIRED_DISP]);
1943       unchain_marker (w->pointm[CMOTION_DISP]);
1944       unchain_marker (w->start[CURRENT_DISP]);
1945       unchain_marker (w->start[DESIRED_DISP]);
1946       unchain_marker (w->start[CMOTION_DISP]);
1947       unchain_marker (w->sb_point);
1948       /* This breaks set-window-configuration if windows in the saved
1949          configuration get deleted and multiple frames are in use. */
1950       /* w->buffer = Qnil; */
1951     }
1952
1953   /* close up the hole in the sibling list */
1954   if (!NILP (w->next))
1955     XWINDOW (w->next)->prev = w->prev;
1956   if (!NILP (w->prev))
1957     XWINDOW (w->prev)->next = w->next;
1958   if (EQ (window, par->hchild))
1959     par->hchild = w->next;
1960   if (EQ (window, par->vchild))
1961     par->vchild = w->next;
1962
1963   /* Find one of our siblings to give our space to.  */
1964   {
1965     Lisp_Object sib = w->prev;
1966     if (NILP (sib))
1967       {
1968         /* If w gives its space to its next sibling, that sibling needs
1969            to have its top/left side pulled back to where w's is.
1970            set_window_{height,width} will re-position the sibling's
1971            children.  */
1972         sib = w->next;
1973         WINDOW_TOP (XWINDOW (sib)) = WINDOW_TOP (w);
1974         WINDOW_LEFT (XWINDOW (sib)) = WINDOW_LEFT (w);
1975       }
1976
1977     /* Stretch that sibling.  */
1978     if (!NILP (par->vchild))
1979       set_window_pixheight
1980         (sib, (WINDOW_HEIGHT (XWINDOW (sib)) + WINDOW_HEIGHT (w)), 1);
1981     if (!NILP (par->hchild))
1982       set_window_pixwidth
1983         (sib, (WINDOW_WIDTH (XWINDOW (sib)) + WINDOW_WIDTH (w)), 1);
1984   }
1985
1986   /* If parent now has only one child,
1987      put the child into the parent's place.  */
1988   {
1989     Lisp_Object parchild = par->hchild;
1990     if (NILP (parchild))
1991       parchild = par->vchild;
1992     if (NILP (XWINDOW (parchild)->next))
1993       {
1994         replace_window (parent, parchild);
1995         mark_window_as_deleted (XWINDOW (parent));
1996       }
1997   }
1998
1999   /* Since we may be deleting combination windows, we must make sure that
2000      not only W but all its children have been marked as deleted.  */
2001   if (!NILP (w->hchild))
2002     delete_all_subwindows (XWINDOW (w->hchild));
2003   else if (!NILP (w->vchild))
2004     delete_all_subwindows (XWINDOW (w->vchild));
2005
2006   mark_window_as_deleted (w);
2007
2008   f->mirror_dirty = 1;
2009   return Qnil;
2010 }
2011
2012 \f
2013 DEFUN ("next-window", Fnext_window, 0, 4, 0, /*
2014 Return next window after WINDOW in canonical ordering of windows.
2015 If omitted, WINDOW defaults to the selected window.
2016
2017 Optional second arg MINIBUF t means count the minibuffer window even
2018 if not active.  MINIBUF nil or omitted means count the minibuffer iff
2019 it is active.  MINIBUF neither t nor nil means not to count the
2020 minibuffer even if it is active.
2021
2022 Several frames may share a single minibuffer; if the minibuffer
2023 counts, all windows on all frames that share that minibuffer count
2024 too.  Therefore, `next-window' can be used to iterate through the
2025 set of windows even when the minibuffer is on another frame.  If the
2026 minibuffer does not count, only windows from WINDOW's frame count.
2027
2028 Optional third arg ALL-FRAMES t means include windows on all frames.
2029 ALL-FRAMES nil or omitted means cycle within the frames as specified
2030 above.  ALL-FRAMES = `visible' means include windows on all visible frames.
2031 ALL-FRAMES = 0 means include windows on all visible and iconified frames.
2032 If ALL-FRAMES is a frame, restrict search to windows on that frame.
2033 Anything else means restrict to WINDOW's frame.
2034
2035 Optional fourth argument CONSOLE controls which consoles or devices the
2036 returned window may be on.  If CONSOLE is a console, return windows only
2037 on that console.  If CONSOLE is a device, return windows only on that
2038 device.  If CONSOLE is a console type, return windows only on consoles
2039 of that type.  If CONSOLE is 'window-system, return any windows on any
2040 window-system consoles.  If CONSOLE is nil or omitted, return windows only
2041 on WINDOW's console.  Otherwise, all windows are considered.
2042
2043 If you use consistent values for MINIBUF, ALL-FRAMES, and CONSOLE, you
2044 can use `next-window' to iterate through the entire cycle of acceptable
2045 windows, eventually ending up back at the window you started with.
2046 `previous-window' traverses the same cycle, in the reverse order.
2047 */
2048      (window, minibuf, all_frames, console))
2049 {
2050   Lisp_Object tem;
2051   Lisp_Object start_window;
2052
2053   if (NILP (window))
2054     window = Fselected_window (Qnil);
2055   else
2056     CHECK_LIVE_WINDOW (window);
2057
2058   start_window = window;
2059
2060   /* minibuf == nil may or may not include minibuffers.
2061      Decide if it does.  */
2062   if (NILP (minibuf))
2063     minibuf = (minibuf_level ? minibuf_window : Qlambda);
2064   else if (! EQ (minibuf, Qt))
2065     minibuf = Qlambda;
2066   /* Now minibuf can be t => count all minibuffer windows,
2067      lambda => count none of them,
2068      or a specific minibuffer window (the active one) to count.  */
2069
2070   /* all_frames == nil doesn't specify which frames to include.  */
2071   if (NILP (all_frames))
2072     all_frames = (! EQ (minibuf, Qlambda)
2073                   ? (FRAME_MINIBUF_WINDOW
2074                      (XFRAME
2075                       (WINDOW_FRAME
2076                        (XWINDOW (window)))))
2077                   : Qnil);
2078   else if (EQ (all_frames, Qvisible))
2079     ;
2080   else if (ZEROP (all_frames))
2081     ;
2082   else if (FRAMEP (all_frames) && ! EQ (all_frames, Fwindow_frame (window)))
2083     /* If all_frames is a frame and window arg isn't on that frame, just
2084        return the first window on the frame.  */
2085     return frame_first_window (XFRAME (all_frames));
2086   else if (! EQ (all_frames, Qt))
2087     all_frames = Qnil;
2088   /* Now all_frames is t meaning search all frames,
2089      nil meaning search just current frame,
2090      visible meaning search just visible frames,
2091      0 meaning search visible and iconified frames,
2092      or a window, meaning search the frame that window belongs to.  */
2093
2094   /* Do this loop at least once, to get the next window, and perhaps
2095      again, if we hit the minibuffer and that is not acceptable.  */
2096   do
2097     {
2098       /* Find a window that actually has a next one.  This loop
2099          climbs up the tree.  */
2100       while (tem = XWINDOW (window)->next, NILP (tem))
2101         if (tem = XWINDOW (window)->parent, !NILP (tem))
2102           window = tem;
2103         else  /* window must be minibuffer window now */
2104           {
2105             /* We've reached the end of this frame.
2106                Which other frames are acceptable?  */
2107             tem = WINDOW_FRAME (XWINDOW (window));
2108
2109             if (! NILP (all_frames))
2110               {
2111                 Lisp_Object tem1;
2112
2113                 tem1 = tem;
2114                 tem = next_frame (tem, all_frames, console);
2115                 /* In the case where the minibuffer is active,
2116                    and we include its frame as well as the selected one,
2117                    next_frame may get stuck in that frame.
2118                    If that happens, go back to the selected frame
2119                    so we can complete the cycle.  */
2120                 if (EQ (tem, tem1))
2121                   XSETFRAME (tem, selected_frame ());
2122               }
2123
2124             tem = FRAME_ROOT_WINDOW (XFRAME (tem));
2125             break;
2126           }
2127
2128       window = tem;
2129
2130       /* If we're in a combination window, find its first child and
2131          recurse on that.  Otherwise, we've found the window we want.  */
2132       while (1)
2133         {
2134           if (!NILP (XWINDOW (window)->hchild))
2135             window = XWINDOW (window)->hchild;
2136           else if (!NILP (XWINDOW (window)->vchild))
2137             window = XWINDOW (window)->vchild;
2138           else break;
2139         }
2140     }
2141   /* "acceptable" is the correct spelling. */
2142   /* Which windows are acceptable?
2143      Exit the loop and accept this window if
2144      this isn't a minibuffer window,
2145      or we're accepting all minibuffer windows,
2146      or this is the active minibuffer and we are accepting that one, or
2147      we've come all the way around and we're back at the original window.  */
2148   while (MINI_WINDOW_P (XWINDOW (window))
2149          && ! EQ (minibuf, Qt)
2150          && ! EQ (minibuf, window)
2151          && ! EQ (window, start_window));
2152
2153   return window;
2154 }
2155
2156 DEFUN ("previous-window", Fprevious_window, 0, 4, 0, /*
2157 Return the window preceding WINDOW in canonical ordering of windows.
2158 If omitted, WINDOW defaults to the selected window.
2159
2160 Optional second arg MINIBUF t means count the minibuffer window even
2161 if not active.  MINIBUF nil or omitted means count the minibuffer iff
2162 it is active.  MINIBUF neither t nor nil means not to count the
2163 minibuffer even if it is active.
2164
2165 Several frames may share a single minibuffer; if the minibuffer
2166 counts, all windows on all frames that share that minibuffer count
2167 too.  Therefore, `previous-window' can be used to iterate through
2168 the set of windows even when the minibuffer is on another frame.  If
2169 the minibuffer does not count, only windows from WINDOW's frame count
2170
2171 If optional third arg ALL-FRAMES t means include windows on all frames.
2172 ALL-FRAMES nil or omitted means cycle within the frames as specified
2173 above.  ALL-FRAMES = `visible' means include windows on all visible frames.
2174 ALL-FRAMES = 0 means include windows on all visible and iconified frames.
2175 If ALL-FRAMES is a frame, restrict search to windows on that frame.
2176 Anything else means restrict to WINDOW's frame.
2177
2178 Optional fourth argument CONSOLE controls which consoles or devices the
2179 returned window may be on.  If CONSOLE is a console, return windows only
2180 on that console.  If CONSOLE is a device, return windows only on that
2181 device.  If CONSOLE is a console type, return windows only on consoles
2182 of that type.  If CONSOLE is 'window-system, return any windows on any
2183 window-system consoles.  If CONSOLE is nil or omitted, return windows only
2184 on WINDOW's console.  Otherwise, all windows are considered.
2185
2186 If you use consistent values for MINIBUF, ALL-FRAMES, and CONSOLE, you
2187 can use `previous-window' to iterate through the entire cycle of acceptable
2188 windows, eventually ending up back at the window you started with.
2189 `next-window' traverses the same cycle, in the reverse order.
2190 */
2191      (window, minibuf, all_frames, console))
2192 {
2193   Lisp_Object tem;
2194   Lisp_Object start_window;
2195
2196   if (NILP (window))
2197     window = Fselected_window (Qnil);
2198   else
2199     CHECK_LIVE_WINDOW (window);
2200
2201   start_window = window;
2202
2203   /* minibuf == nil may or may not include minibuffers.
2204      Decide if it does.  */
2205   if (NILP (minibuf))
2206     minibuf = (minibuf_level ? minibuf_window : Qlambda);
2207   else if (! EQ (minibuf, Qt))
2208     minibuf = Qlambda;
2209   /* Now minibuf can be t => count all minibuffer windows,
2210      lambda => count none of them,
2211      or a specific minibuffer window (the active one) to count.  */
2212
2213   /* all_frames == nil doesn't specify which frames to include.
2214      Decide which frames it includes.  */
2215   if (NILP (all_frames))
2216     all_frames = (! EQ (minibuf, Qlambda)
2217                   ? (FRAME_MINIBUF_WINDOW
2218                      (XFRAME
2219                       (WINDOW_FRAME
2220                        (XWINDOW (window)))))
2221                   : Qnil);
2222   else if (EQ (all_frames, Qvisible))
2223     ;
2224   else if (ZEROP (all_frames))
2225     ;
2226   else if (FRAMEP (all_frames) && ! EQ (all_frames, Fwindow_frame (window)))
2227     /* If all_frames is a frame and window arg isn't on that frame, just
2228        return the first window on the frame.  */
2229     return frame_first_window (XFRAME (all_frames));
2230   else if (! EQ (all_frames, Qt))
2231     all_frames = Qnil;
2232   /* Now all_frames is t meaning search all frames,
2233      nil meaning search just current frame,
2234      visible meaning search just visible frames,
2235      0 meaning search visible and iconified frames,
2236      or a window, meaning search the frame that window belongs to.  */
2237
2238   /* Do this loop at least once, to get the next window, and perhaps
2239      again, if we hit the minibuffer and that is not acceptable.  */
2240   do
2241     {
2242       /* Find a window that actually has a next one.  This loop
2243          climbs up the tree.  */
2244       while (tem = XWINDOW (window)->prev, NILP (tem))
2245         if (tem = XWINDOW (window)->parent, !NILP (tem))
2246           window = tem;
2247         else  /* window must be minibuffer window now */
2248           {
2249             /* We have found the top window on the frame.
2250                Which frames are acceptable?  */
2251             tem = WINDOW_FRAME (XWINDOW (window));
2252
2253             if (! NILP (all_frames))
2254               /* It's actually important that we use prev_frame here,
2255                  rather than next_frame.  All the windows acceptable
2256                  according to the given parameters should form a ring;
2257                  Fnext_window and Fprevious_window should go back and
2258                  forth around the ring.  If we use next_frame here,
2259                  then Fnext_window and Fprevious_window take different
2260                  paths through the set of acceptable windows.
2261                  window_loop assumes that these `ring' requirement are
2262                  met.  */
2263               {
2264                 Lisp_Object tem1;
2265
2266                 tem1 = tem;
2267                 tem = prev_frame (tem, all_frames, console);
2268                 /* In the case where the minibuffer is active,
2269                    and we include its frame as well as the selected one,
2270                    next_frame may get stuck in that frame.
2271                    If that happens, go back to the selected frame
2272                    so we can complete the cycle.  */
2273                 if (EQ (tem, tem1))
2274                   XSETFRAME (tem, selected_frame ());
2275               }
2276
2277             /* If this frame has a minibuffer, find that window first,
2278                because it is conceptually the last window in that frame.  */
2279             if (FRAME_HAS_MINIBUF_P (XFRAME (tem)))
2280               tem = FRAME_MINIBUF_WINDOW (XFRAME (tem));
2281             else
2282               tem = FRAME_ROOT_WINDOW (XFRAME (tem));
2283
2284             break;
2285           }
2286
2287       window = tem;
2288
2289       /* If we're in a combination window, find its first child and
2290          recurse on that.  Otherwise, we've found the window we want.  */
2291       while (1)
2292         {
2293           if (!NILP (XWINDOW (window)->hchild))
2294             window = XWINDOW (window)->hchild;
2295           else if (!NILP (XWINDOW (window)->vchild))
2296             window = XWINDOW (window)->vchild;
2297           else break;
2298           while (tem = XWINDOW (window)->next, !NILP (tem))
2299             window = tem;
2300         }
2301     }
2302   /* Which windows are acceptable?
2303      Exit the loop and accept this window if
2304      this isn't a minibuffer window,
2305      or we're accepting all minibuffer windows,
2306      or this is the active minibuffer and we are accepting that one, or
2307      we've come all the way around and we're back at the original window.  */
2308   while (MINI_WINDOW_P (XWINDOW (window))
2309          && ! EQ (minibuf, Qt)
2310          && ! EQ (minibuf, window)
2311          && ! EQ (window, start_window));
2312
2313   return window;
2314 }
2315
2316 DEFUN ("next-vertical-window", Fnext_vertical_window, 0, 1, 0, /*
2317 Return the next window which is vertically after WINDOW.
2318 */
2319        (window))
2320 {
2321   Lisp_Object root;
2322   struct window *w = decode_window (window);
2323   XSETWINDOW (window, w);
2324
2325   if (MINI_WINDOW_P (XWINDOW (window)))
2326     return Qnil;
2327
2328   root = FRAME_ROOT_WINDOW (XFRAME (WINDOW_FRAME (XWINDOW (window))));
2329
2330   if (EQ (window, root))
2331     {
2332       while (1)
2333         if (!NILP (XWINDOW (window)->hchild))
2334           window = XWINDOW (window)->hchild;
2335         else if (!NILP (XWINDOW (window)->vchild))
2336           window = XWINDOW (window)->vchild;
2337         else
2338           return window;
2339     }
2340
2341   do
2342     {
2343       if (!NILP (XWINDOW (window)->parent) &&
2344           !NILP (XWINDOW (XWINDOW (window)->parent)->vchild))
2345         {
2346           if (!NILP (XWINDOW (window)->next))
2347             return XWINDOW (window)->next;
2348           else
2349             window = XWINDOW (window)->parent;
2350         }
2351       else
2352         window = XWINDOW (window)->parent;
2353     }
2354   while (!EQ (window, root));
2355
2356   while (1)
2357     if (!NILP (XWINDOW (window)->hchild))
2358       window = XWINDOW (window)->hchild;
2359     else if (!NILP (XWINDOW (window)->vchild))
2360       window = XWINDOW (window)->vchild;
2361     else
2362       return window;
2363 }
2364
2365 DEFUN ("other-window", Fother_window, 1, 3, "p", /*
2366 Select the N'th different window on this frame.
2367 All windows on current frame are arranged in a cyclic order.
2368 This command selects the window N steps away in that order.
2369 A negative N moves in the opposite order.
2370
2371 If optional argument FRAME is `visible', search all visible frames.
2372 If FRAME is 0, search all visible and iconified frames.
2373 If FRAME is t, search all frames.
2374 If FRAME is nil, search only the selected frame.
2375 If FRAME is a frame, search only that frame.
2376
2377 Optional third argument CONSOLE controls which consoles or devices the
2378 returned window may be on.  If CONSOLE is a console, return windows only
2379 on that console.  If CONSOLE is a device, return windows only on that
2380 device.  If CONSOLE is a console type, return windows only on consoles
2381 of that type.  If CONSOLE is 'window-system, return any windows on any
2382 window-system consoles.  If CONSOLE is nil or omitted, return windows only
2383 on FRAME'S console, or on the selected console if FRAME is not a frame.
2384 Otherwise, all windows are considered.
2385 */
2386        (n, frame, console))
2387 {
2388   int i;
2389   Lisp_Object w;
2390
2391   CHECK_INT (n);
2392   w = Fselected_window (Qnil);
2393   i = XINT (n);
2394
2395   while (i > 0)
2396     {
2397       w = Fnext_window (w, Qnil, frame, console);
2398       i--;
2399     }
2400   while (i < 0)
2401     {
2402       w = Fprevious_window (w, Qnil, frame, console);
2403       i++;
2404     }
2405   Fselect_window (w, Qnil);
2406   return Qnil;
2407 }
2408
2409 \f
2410 /* Look at all windows, performing an operation specified by TYPE
2411    with argument OBJ.
2412
2413    If FRAMES is Qt, look at all frames, if Qnil, look at just the selected
2414    frame.  If FRAMES is a frame, just look at windows on that frame.
2415    If MINI is non-zero, perform the operation on minibuffer windows too.
2416 */
2417
2418 enum window_loop
2419 {
2420   WINDOW_LOOP_UNUSED,
2421   GET_BUFFER_WINDOW,            /* Arg is buffer */
2422   GET_LRU_WINDOW,               /* Arg is t for full-width windows only */
2423   DELETE_OTHER_WINDOWS,         /* Arg is window not to delete */
2424   DELETE_BUFFER_WINDOWS,        /* Arg is buffer */
2425   GET_LARGEST_WINDOW,
2426   UNSHOW_BUFFER,                /* Arg is buffer */
2427   GET_BUFFER_WINDOW_COUNT,      /* Arg is buffer */
2428   GET_BUFFER_MRU_WINDOW         /* Arg is buffer */
2429 };
2430
2431 static Lisp_Object
2432 window_loop (enum window_loop type,
2433              Lisp_Object obj,
2434              int mini,
2435              Lisp_Object frames,
2436              int dedicated_too,
2437              Lisp_Object console)
2438 {
2439   /* This function can GC if type == DELETE_BUFFER_WINDOWS or UNSHOW_BUFFER */
2440   Lisp_Object w;
2441   Lisp_Object best_window = Qnil;
2442   Lisp_Object next_window;
2443   Lisp_Object last_window;
2444   struct frame *frame;
2445   Lisp_Object frame_arg = Qt;
2446   int count = 0;                /* for GET_BUFFER_WINDOW_COUNT */
2447   /* #### I think the change of "precomputing" last_window and next_window
2448    * ####  catch the lossage this is meant(?) to punt on...
2449    */
2450   int lose_lose = 0;
2451   Lisp_Object devcons, concons;
2452
2453   /* FRAME_ARG is Qlambda to stick to one frame,
2454      Qvisible to consider all visible frames,
2455      or Qt otherwise.  */
2456
2457   /* If we're only looping through windows on a particular frame,
2458      FRAME points to that frame.  If we're looping through windows
2459      on all frames, FRAME is 0.  */
2460
2461   if (FRAMEP (frames))
2462     frame = XFRAME (frames);
2463   else if (NILP (frames))
2464     frame = selected_frame ();
2465   else
2466     frame = 0;
2467   if (frame)
2468     frame_arg = Qlambda;
2469   else if (ZEROP (frames))
2470     frame_arg = frames;
2471   else if (EQ (frames, Qvisible))
2472     frame_arg = frames;
2473
2474   DEVICE_LOOP_NO_BREAK (devcons, concons)
2475     {
2476       Lisp_Object device = XCAR (devcons);
2477       Lisp_Object the_frame;
2478
2479       if (frame)
2480         XSETFRAME (the_frame, frame);
2481       else
2482         the_frame = DEVICE_SELECTED_FRAME (XDEVICE (device));
2483
2484       if (NILP (the_frame))
2485         continue;
2486
2487       if (!device_matches_console_spec (the_frame, device, console))
2488         continue;
2489
2490       /* Pick a window to start with.  */
2491       if (WINDOWP (obj))
2492         w = obj;
2493       else
2494         w = FRAME_SELECTED_WINDOW (XFRAME (the_frame));
2495
2496       /* Figure out the last window we're going to mess with.  Since
2497          Fnext_window, given the same options, is guaranteed to go in a
2498          ring, we can just use Fprevious_window to find the last one.
2499
2500          We can't just wait until we hit the first window again,
2501          because it might be deleted.  */
2502
2503       last_window = Fprevious_window (w, mini ? Qt : Qnil, frame_arg, Qt);
2504
2505       best_window = Qnil;
2506       for (;;)
2507         {
2508           struct window *p = XWINDOW (w);
2509           struct frame *w_frame = XFRAME (WINDOW_FRAME (p));
2510
2511           /* Pick the next window now, since some operations will delete
2512              the current window.  */
2513           next_window = Fnext_window (w, mini ? Qt : Qnil, frame_arg, Qt);
2514
2515           /* #### Still needed ?? */
2516           /* Given the outstanding quality of the rest of this code,
2517              I feel no shame about putting this piece of shit in. */
2518           if (++lose_lose >= 500)
2519             return Qnil;
2520
2521           /* Note that we do not pay attention here to whether
2522              the frame is visible, since Fnext_window skips non-visible frames
2523              if that is desired, under the control of frame_arg.  */
2524           if (! MINI_WINDOW_P (p)
2525               || (mini && minibuf_level > 0))
2526             switch (type)
2527               {
2528               case GET_BUFFER_WINDOW:
2529                 {
2530                   if (XBUFFER (p->buffer) == XBUFFER (obj))
2531                     return w;
2532                   break;
2533                 }
2534
2535               case GET_BUFFER_WINDOW_COUNT:
2536                 {
2537                   if (XBUFFER (p->buffer) == XBUFFER (obj))
2538                     count++;
2539                   break;
2540                 }
2541
2542               case GET_LRU_WINDOW:
2543                 {
2544                   /* t as arg means consider only full-width windows */
2545                   if (!NILP (obj)
2546                       && !window_full_width_p (p))
2547                     break;
2548                   /* Ignore dedicated windows and minibuffers.  */
2549                   if (MINI_WINDOW_P (p)
2550                       || (dedicated_too ? 0 : !NILP (p->dedicated)))
2551                     break;
2552                   if (NILP (best_window)
2553                       || (XINT (XWINDOW (best_window)->use_time)
2554                           > XINT (p->use_time)))
2555                     best_window = w;
2556                   break;
2557                 }
2558
2559               case GET_BUFFER_MRU_WINDOW:
2560                 {
2561                   /* #### what about the first check in GET_LRU_WINDOW? */
2562                   /* Ignore dedicated windows and minibuffers. */
2563                   if (MINI_WINDOW_P (p)
2564                       || (dedicated_too ? 0 : !NILP (p->dedicated)))
2565                     break;
2566
2567                   if (XBUFFER (p->buffer) == XBUFFER (obj))
2568                     {
2569                       if (NILP (best_window)
2570                           || (XINT (XWINDOW (best_window)->use_time)
2571                               < XINT (p->use_time)))
2572                         best_window = w;
2573                     }
2574                   break;
2575                 }
2576
2577               case DELETE_OTHER_WINDOWS:
2578                 {
2579                   /* Don't delete the last window on a frame; this can
2580                      happen when the minibuffer is selected, and would
2581                      cause the frame to be deleted. */
2582                   if (p != XWINDOW (obj) && !TOP_LEVEL_WINDOW_P (XWINDOW (w)))
2583                     Fdelete_window (w, Qnil);
2584                   break;
2585                 }
2586
2587               case DELETE_BUFFER_WINDOWS:
2588                 {
2589                   if (EQ (p->buffer, obj))
2590                     {
2591                       struct frame *f = XFRAME (WINDOW_FRAME (p));
2592
2593                       /* If this window is dedicated, and in a frame
2594                          of its own, kill the frame.  */
2595                       if (EQ (w, FRAME_ROOT_WINDOW (f))
2596                           && !NILP (p->dedicated)
2597                           && other_visible_frames (f))
2598                         {
2599                           /* Skip the other windows on this frame.
2600                              There might be one, the minibuffer!  */
2601                           if (! EQ (w, last_window))
2602                             while (f == XFRAME (WINDOW_FRAME
2603                                                 (XWINDOW (next_window))))
2604                               {
2605                                 /* As we go, check for the end of the
2606                                    loop.  We mustn't start going
2607                                    around a second time.  */
2608                                 if (EQ (next_window, last_window))
2609                                   {
2610                                     last_window = w;
2611                                     break;
2612                                   }
2613                                 next_window = Fnext_window (next_window,
2614                                                             mini ? Qt : Qnil,
2615                                                             frame_arg, Qt);
2616                               }
2617                           /* Now we can safely delete the frame.  */
2618                           Fdelete_frame (WINDOW_FRAME (p), Qnil);
2619                         }
2620                       else
2621                         /* If we're deleting the buffer displayed in
2622                            the only window on the frame, find a new
2623                            buffer to display there.  */
2624                         if (NILP (p->parent))
2625                           {
2626                             Lisp_Object new_buffer;
2627                             new_buffer = Fother_buffer (obj, Qnil, Qnil);
2628                             if (NILP (new_buffer))
2629                               new_buffer = Fget_buffer_create (QSscratch);
2630                             Fset_window_buffer (w, new_buffer, Qnil);
2631                             if (EQ (w, Fselected_window (Qnil)))
2632                               Fset_buffer (p->buffer);
2633                           }
2634                         else
2635                           Fdelete_window (w, Qnil);
2636                     }
2637                   break;
2638                 }
2639
2640               case GET_LARGEST_WINDOW:
2641                 {
2642                   /* Ignore dedicated windows and minibuffers.  */
2643                   if (MINI_WINDOW_P (p)
2644                       || (dedicated_too ? 0 : !NILP (p->dedicated)))
2645                     break;
2646                   {
2647                     /* write the check as follows to avoid tripping
2648                        error_check_window() --ben */
2649                     struct window *b = NILP (best_window) ? 0 :
2650                       XWINDOW (best_window);
2651                     if (NILP (best_window)
2652                         || ((WINDOW_HEIGHT (p) * WINDOW_WIDTH (p))
2653                             > (WINDOW_HEIGHT (b) * WINDOW_WIDTH (b))))
2654                       best_window = w;
2655                   }
2656                   break;
2657                 }
2658
2659               case UNSHOW_BUFFER:
2660                 {
2661                   if (EQ (p->buffer, obj))
2662                     {
2663                       /* Find another buffer to show in this window.  */
2664                       Lisp_Object another_buffer =
2665                         Fother_buffer (obj, Qnil, Qnil);
2666                       if (NILP (another_buffer))
2667                         another_buffer
2668                           = Fget_buffer_create (QSscratch);
2669                       /* If this window is dedicated, and in a frame
2670                          of its own, kill the frame.  */
2671                       if (EQ (w, FRAME_ROOT_WINDOW (w_frame))
2672                           && !NILP (p->dedicated)
2673                           && other_visible_frames (w_frame))
2674                         {
2675                           /* Skip the other windows on this frame.
2676                              There might be one, the minibuffer!  */
2677                           if (! EQ (w, last_window))
2678                             while (w_frame == XFRAME (WINDOW_FRAME
2679                                                       (XWINDOW (next_window))))
2680                               {
2681                                 /* As we go, check for the end of the
2682                                    loop.  We mustn't start going
2683                                    around a second time.  */
2684                                 if (EQ (next_window, last_window))
2685                                   {
2686                                     last_window = w;
2687                                     break;
2688                                   }
2689                                 next_window = Fnext_window (next_window,
2690                                                             mini ? Qt : Qnil,
2691                                                             frame_arg, Qt);
2692                               }
2693                           /* Now we can safely delete the frame.  */
2694                           delete_frame_internal (XFRAME (WINDOW_FRAME (p)),
2695                                                  0, 0, 0);
2696                         }
2697                       else
2698                         {
2699                           /* Otherwise show a different buffer in the
2700                              window.  */
2701                           p->dedicated = Qnil;
2702                           Fset_window_buffer (w, another_buffer, Qnil);
2703                           if (EQ (w, Fselected_window (Qnil)))
2704                             Fset_buffer (p->buffer);
2705                         }
2706                     }
2707                   break;
2708                 }
2709
2710               default:
2711                 abort ();
2712               }
2713
2714           if (EQ (w, last_window))
2715             break;
2716
2717           w = next_window;
2718         }
2719     }
2720
2721   return type == GET_BUFFER_WINDOW_COUNT ? make_int (count) : best_window;
2722 }
2723
2724 #if 0 /* not currently used */
2725
2726 int
2727 buffer_window_count (struct buffer *b, struct frame *f)
2728 {
2729   Lisp_Object buffer, frame;
2730
2731   XSETFRAME (frame, f);
2732   XSETBUFFER (buffer, b);
2733
2734   return XINT (window_loop (GET_BUFFER_WINDOW_COUNT, buffer, 0, frame, 1,
2735                             Qnil));
2736 }
2737
2738 int
2739 buffer_window_mru (struct window *w)
2740 {
2741   Lisp_Object window =
2742     window_loop (GET_BUFFER_MRU_WINDOW, w->buffer, 0, w->frame, 1, Qnil);
2743
2744   if (NILP (window))
2745     return 0;
2746   else if (XWINDOW (window) == w)
2747     return 1;
2748   else
2749     return 0;
2750 }
2751
2752 #endif
2753
2754 \f
2755 DEFUN ("get-lru-window", Fget_lru_window, 0, 2, 0, /*
2756 Return the window least recently selected or used for display.
2757 If optional argument FRAME is `visible', search all visible frames.
2758 If FRAME is 0, search all visible and iconified frames.
2759 If FRAME is t, search all frames.
2760 If FRAME is nil, search only the selected frame.
2761 If FRAME is a frame, search only that frame.
2762
2763 Optional second argument CONSOLE controls which consoles or devices the
2764 returned window may be on.  If CONSOLE is a console, return windows only
2765 on that console.  If CONSOLE is a device, return windows only on that
2766 device.  If CONSOLE is a console type, return windows only on consoles
2767 of that type.  If CONSOLE is 'window-system, return any windows on any
2768 window-system consoles.  If CONSOLE is nil or omitted, return windows only
2769 on FRAME'S console, or on the selected console if FRAME is not a frame.
2770 Otherwise, all windows are considered.
2771 */
2772        (frame, console))
2773 {
2774   Lisp_Object w;
2775   /* First try for a non-dedicated window that is full-width */
2776   w = window_loop (GET_LRU_WINDOW, Qt, 0, frame, 0, console);
2777   if (!NILP (w) && !EQ (w, Fselected_window (Qnil)))
2778     return w;
2779
2780   /* Then try for any non-dedicated window */
2781   w = window_loop (GET_LRU_WINDOW, Qnil, 0, frame, 0, console);
2782   if (!NILP (w) && !EQ (w, Fselected_window (Qnil)))
2783     return w;
2784
2785 #if 0
2786   /* FSFmacs never returns a dedicated window here.  If we do,
2787      it makes `display-buffer' not work right.  #### All of this
2788      shit is so disgusting and awful that it needs to be rethought
2789      from scratch. */
2790   /* then try for a dedicated window that is full-width */
2791   w = window_loop (GET_LRU_WINDOW, Qt, 0, frame, 1, console);
2792   if (!NILP (w) && !EQ (w, Fselected_window (Qnil)))
2793     return w;
2794
2795   /* If none of them, then all windows, dedicated or not. */
2796   w = window_loop (GET_LRU_WINDOW, Qnil, 0, frame, 1, console);
2797
2798   /* At this point we damn well better have found something. */
2799   if (NILP (w)) abort ();
2800 #endif
2801
2802   return w;
2803 }
2804
2805 DEFUN ("get-largest-window", Fget_largest_window, 0, 2, 0, /*
2806 Return the window largest in area.
2807 If optional argument FRAME is `visible', search all visible frames.
2808 If 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 second 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        (frame, console))
2823 {
2824   /* Don't search dedicated windows because FSFmacs doesn't.
2825      This stuff is all black magic so don't try to apply common
2826      sense to it. */
2827   return window_loop (GET_LARGEST_WINDOW, Qnil, 0, frame, 0, console);
2828 }
2829
2830 DEFUN ("get-buffer-window", Fget_buffer_window, 1, 3, 0, /*
2831 Return a window currently displaying BUFFER, or nil if none.
2832 If optional argument FRAME is `visible', search all visible frames.
2833 If optional argument FRAME is 0, search all visible and iconified frames.
2834 If FRAME is t, search all frames.
2835 If FRAME is nil, search only the selected frame.
2836 If FRAME is a frame, search only that frame.
2837
2838 Optional third argument CONSOLE controls which consoles or devices the
2839 returned window may be on.  If CONSOLE is a console, return windows only
2840 on that console.  If CONSOLE is a device, return windows only on that
2841 device.  If CONSOLE is a console type, return windows only on consoles
2842 of that type.  If CONSOLE is 'window-system, return any windows on any
2843 window-system consoles.  If CONSOLE is nil or omitted, return windows only
2844 on FRAME'S console, or on the selected console if FRAME is not a frame.
2845 Otherwise, all windows are considered.
2846 */
2847        (buffer, frame, console))
2848 {
2849   buffer = Fget_buffer (buffer);
2850   if (BUFFERP (buffer))
2851     /* Search dedicated windows too. (Doesn't matter here anyway.) */
2852     return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame, 1, console);
2853   else
2854     return Qnil;
2855 }
2856
2857 /* These functions used to be `buffer-left-margin-pixel-width', etc.
2858    but there is no sensible way to implement those functions, since
2859    you can't in general derive a window from a buffer. */
2860
2861 DEFUN ("window-left-margin-pixel-width", Fwindow_left_margin_pixel_width,
2862        0, 1, 0, /*
2863 Return the width in pixels of the left outside margin of window WINDOW.
2864 If WINDOW is nil, the selected window is assumed.
2865 */
2866        (window))
2867 {
2868   return make_int (window_left_margin_width (decode_window (window)));
2869 }
2870
2871 DEFUN ("window-right-margin-pixel-width", Fwindow_right_margin_pixel_width,
2872        0, 1, 0, /*
2873 Return the width in pixels of the right outside margin of window WINDOW.
2874 If WINDOW is nil, the selected window is assumed.
2875 */
2876        (window))
2877 {
2878   return make_int (window_right_margin_width (decode_window (window)));
2879 }
2880
2881 DEFUN ("delete-other-windows", Fdelete_other_windows, 0, 1, "", /*
2882 Make WINDOW (or the selected window) fill its frame.
2883 Only the frame WINDOW is on is affected.
2884 This function tries to reduce display jumps
2885 by keeping the text previously visible in WINDOW
2886 in the same place on the frame.  Doing this depends on
2887 the value of (window-start WINDOW), so if calling this function
2888 in a program gives strange scrolling, make sure the window-start
2889 value is reasonable when this function is called.
2890 */
2891        (window))
2892 {
2893   struct window *w = decode_window (window);
2894   struct buffer *b = XBUFFER (w->buffer);
2895   Bufpos start_pos;
2896   int old_top = WINDOW_TOP (w);
2897
2898   XSETWINDOW (window, w);
2899
2900   if (MINI_WINDOW_P (w) && old_top > 0)
2901     error ("Can't expand minibuffer to full frame");
2902
2903   /* Ignore dedicated windows. */
2904   window_loop (DELETE_OTHER_WINDOWS, window, 0, w->frame, 0, Qnil);
2905
2906   start_pos = marker_position (w->start[CURRENT_DISP]);
2907
2908   /* Try to minimize scrolling, by setting the window start to the
2909      point which will cause the text at the old window start to be at
2910      the same place on the frame.  But don't try to do this if the
2911      window start is outside the visible portion (as might happen when
2912      the display is not current, due to typeahead). */
2913   if (start_pos >= BUF_BEGV (b) && start_pos <= BUF_ZV (b)
2914       && !MINI_WINDOW_P (w))
2915     {
2916       Bufpos new_start = start_with_line_at_pixpos (w, start_pos, old_top);
2917
2918       if (new_start >= BUF_BEGV (b) && new_start <= BUF_ZV (b))
2919         {
2920           Fset_marker (w->start[CURRENT_DISP], make_int (new_start),
2921                        w->buffer);
2922           w->start_at_line_beg = beginning_of_line_p (b, new_start);
2923         }
2924       /* We need to do this, so that the window-scroll-functions
2925          get called.  */
2926       w->force_start = 1;
2927     }
2928
2929   return Qnil;
2930 }
2931
2932 DEFUN ("delete-windows-on", Fdelete_windows_on, 1, 3,
2933        "bDelete windows on (buffer): ", /*
2934 Delete all windows showing BUFFER.
2935 Optional second argument FRAME controls which frames are affected.
2936 If nil or omitted, delete all windows showing BUFFER in any frame.
2937 If t, delete only windows showing BUFFER in the selected frame.
2938 If `visible', delete all windows showing BUFFER in any visible frame.
2939 If a frame, delete only windows showing BUFFER in that frame.
2940
2941 Optional third argument CONSOLE controls which consoles or devices the
2942 returned window may be on.  If CONSOLE is a console, return windows only
2943 on that console.  If CONSOLE is a device, return windows only on that
2944 device.  If CONSOLE is a console type, return windows only on consoles
2945 of that type.  If CONSOLE is 'window-system, return any windows on any
2946 window-system consoles.  If CONSOLE is nil or omitted, return windows only
2947 on FRAME'S console, or on the selected console if FRAME is not a frame.
2948 Otherwise, all windows are considered.
2949 */
2950        (buffer, frame, console))
2951 {
2952   /* This function can GC */
2953   /* FRAME uses t and nil to mean the opposite of what window_loop
2954      expects. */
2955   if (!FRAMEP (frame))
2956     frame = NILP (frame) ? Qt : Qnil;
2957
2958   if (!NILP (buffer))
2959     {
2960       buffer = Fget_buffer (buffer);
2961       CHECK_BUFFER (buffer);
2962       /* Ignore dedicated windows. */
2963       window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame, 0, console);
2964     }
2965   return Qnil;
2966 }
2967
2968 DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows, 1, 1,
2969        "bReplace buffer in windows: ", /*
2970 Replace BUFFER with some other buffer in all windows showing it.
2971 */
2972        (buffer))
2973 {
2974   /* This function can GC */
2975   if (!NILP (buffer))
2976     {
2977       buffer = Fget_buffer (buffer);
2978       CHECK_BUFFER (buffer);
2979       /* Ignore dedicated windows. */
2980       window_loop (UNSHOW_BUFFER, buffer, 0, Qt, 0, Qnil);
2981     }
2982   return Qnil;
2983 }
2984 \f
2985 /* The smallest acceptable dimensions for a window.  Anything smaller
2986    might crash Emacs.  */
2987 #define MIN_SAFE_WINDOW_WIDTH  (2)
2988 #define MIN_SAFE_WINDOW_HEIGHT (2)
2989
2990 /* Make sure that window_min_height and window_min_width are
2991    not too small; if they are, set them to safe minima.  */
2992
2993 static void
2994 check_min_window_sizes (void)
2995 {
2996   /* Smaller values might permit a crash.  */
2997   if (window_min_width < MIN_SAFE_WINDOW_WIDTH)
2998     window_min_width = MIN_SAFE_WINDOW_WIDTH;
2999   if (window_min_height < MIN_SAFE_WINDOW_HEIGHT)
3000     window_min_height = MIN_SAFE_WINDOW_HEIGHT;
3001 }
3002
3003 static int
3004 frame_min_height (struct frame *frame)
3005 {
3006   /* For height, we have to see whether the frame has a minibuffer, and
3007      whether it wants a modeline.  */
3008   return (FRAME_MINIBUF_ONLY_P (frame) ? MIN_SAFE_WINDOW_HEIGHT - 1
3009           : (! FRAME_HAS_MINIBUF_P (frame)) ? MIN_SAFE_WINDOW_HEIGHT
3010           : 2 * MIN_SAFE_WINDOW_HEIGHT - 1);
3011 }
3012
3013 /* Return non-zero if both frame sizes are less than or equal to
3014    minimal allowed values. ROWS and COLS are in characters */
3015 int
3016 frame_size_valid_p (struct frame *frame, int rows, int cols)
3017 {
3018   return (rows >= frame_min_height (frame)
3019           && cols >= MIN_SAFE_WINDOW_WIDTH);
3020 }
3021
3022 /* Return non-zero if both frame sizes are less than or equal to
3023    minimal allowed values. WIDTH and HEIGHT are in pixels */
3024 int
3025 frame_pixsize_valid_p (struct frame *frame, int width, int height)
3026 {
3027   int rows, cols;
3028   pixel_to_real_char_size (frame, width, height, &cols, &rows);
3029   return frame_size_valid_p (frame, rows, cols);
3030 }
3031
3032 /* If *ROWS or *COLS are too small a size for FRAME, set them to the
3033    minimum allowable size.  */
3034 void
3035 check_frame_size (struct frame *frame, int *rows, int *cols)
3036 {
3037   int min_height = frame_min_height (frame);
3038
3039   if (*rows < min_height)
3040     *rows = min_height;
3041   if (*cols  < MIN_SAFE_WINDOW_WIDTH)
3042     *cols = MIN_SAFE_WINDOW_WIDTH;
3043 }
3044
3045 /* Normally the window is deleted if it gets too small.
3046    nodelete nonzero means do not do this.
3047    (The caller should check later and do so if appropriate)  */
3048 static void
3049 set_window_pixsize (Lisp_Object window, int new_pixsize, int nodelete,
3050                     int set_height)
3051 {
3052   struct window *w = XWINDOW (window);
3053   struct frame *f = XFRAME (w->frame);
3054   struct window *c;
3055   int old_pixsize = (set_height ? WINDOW_HEIGHT (w) : WINDOW_WIDTH (w));
3056   Lisp_Object child, minor_kid, major_kid;
3057   int minsize;
3058   int line_size;
3059   int defheight, defwidth;
3060
3061   /* #### This is very likely incorrect and instead the char_to_pixel_
3062      functions should be called. */
3063   default_face_height_and_width (window, &defheight, &defwidth);
3064   line_size = (set_height ? defheight : defwidth);
3065
3066   check_min_window_sizes ();
3067
3068   minsize = (set_height ? window_min_height : window_min_width);
3069   minsize *= line_size;
3070
3071   if (!nodelete
3072       && !TOP_LEVEL_WINDOW_P (w)
3073       && new_pixsize < minsize)
3074     {
3075       Fdelete_window (window, Qnil);
3076       return;
3077     }
3078
3079   SET_LAST_MODIFIED (w, 0);
3080   SET_LAST_FACECHANGE (w);
3081   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);     /* multiple windows affected */
3082   if (set_height)
3083     {
3084       WINDOW_HEIGHT (w) = new_pixsize;
3085       major_kid = w->vchild;
3086       minor_kid = w->hchild;
3087     }
3088   else
3089     {
3090       WINDOW_WIDTH (w) = new_pixsize;
3091       major_kid = w->hchild;
3092       minor_kid = w->vchild;
3093     }
3094
3095   if (!NILP (minor_kid))
3096     {
3097       for (child = minor_kid; !NILP (child); child = XWINDOW (child)->next)
3098         {
3099           if (set_height)
3100             WINDOW_TOP (XWINDOW (child)) = WINDOW_TOP (w);
3101           else
3102             WINDOW_LEFT (XWINDOW (child)) = WINDOW_LEFT (w);
3103
3104           set_window_pixsize (child, new_pixsize, nodelete, set_height);
3105         }
3106     }
3107   else if (!NILP (major_kid))
3108     {
3109       int last_pos, last_old_pos, pos, old_pos, first;
3110       int pixel_adj_left = new_pixsize - old_pixsize;
3111       int div_val = old_pixsize << 1;
3112
3113       /*
3114        * Previously we bailed out here if there was no size change.
3115        * (pixel_adj_left == 0) But this broke toolbar updates.  If a
3116        * toolbar appears or disappears, windows may not change size,
3117        * but their top and left coordinates need to be updated.
3118        *
3119        * So we don't bail until after the loop below.
3120        */
3121
3122       last_pos = first = (set_height ? WINDOW_TOP (w) : WINDOW_LEFT (w));
3123       last_old_pos = 0;
3124
3125       for (child = major_kid; !NILP (child); child = c->next)
3126         {
3127           c = XWINDOW (child);
3128
3129           if (set_height)
3130             {
3131               old_pos = last_old_pos + WINDOW_HEIGHT (c);
3132               WINDOW_TOP (c) = last_pos;
3133             }
3134           else
3135             {
3136               old_pos = last_old_pos + WINDOW_WIDTH (c);
3137               WINDOW_LEFT (c) = last_pos;
3138             }
3139
3140           pos = (((old_pos * new_pixsize) << 1) + old_pixsize) / div_val;
3141           /* All but the last window should have a height which is
3142              a multiple of the default line height. */
3143           if (!NILP (c->next))
3144             pos = (pos / line_size) * line_size;
3145
3146           /* Avoid confusion: don't delete child if it becomes too small */
3147           set_window_pixsize (child, pos + first - last_pos, 1, set_height);
3148
3149           last_pos = pos + first;
3150           last_old_pos = old_pos;
3151         }
3152
3153       /* Sometimes we may get called with our old size.  In that case
3154          we don't need to do anything else. */
3155       if (!pixel_adj_left)
3156         return;
3157
3158       /* Now delete any children that became too small.  */
3159       if (!nodelete)
3160         for (child = major_kid; !NILP (child); child = XWINDOW (child)->next)
3161           {
3162             if (set_height)
3163               set_window_pixheight (child, WINDOW_HEIGHT (XWINDOW (child)), 0);
3164             else
3165               set_window_pixwidth (child, WINDOW_WIDTH (XWINDOW (child)), 0);
3166           }
3167     }
3168 }
3169
3170 /* Set the height of WINDOW and all its inferiors.  */
3171 void
3172 set_window_pixheight (Lisp_Object window, int new_pixheight, int nodelete)
3173 {
3174   set_window_pixsize (window, new_pixheight, nodelete, 1);
3175 }
3176
3177 /* Recursively set width of WINDOW and its inferiors. */
3178 void
3179 set_window_pixwidth (Lisp_Object window, int new_pixwidth, int nodelete)
3180 {
3181   set_window_pixsize (window, new_pixwidth, nodelete, 0);
3182 }
3183
3184 \f
3185 static int window_select_count;
3186
3187 DEFUN ("set-window-buffer", Fset_window_buffer, 2, 3, 0, /*
3188 Make WINDOW display BUFFER as its contents.
3189 BUFFER can be a buffer or buffer name.
3190
3191 With non-nil optional argument `norecord', do not modify the
3192 global or per-frame buffer ordering.
3193 */
3194        (window, buffer, norecord))
3195 {
3196   Lisp_Object tem;
3197   struct window *w = decode_window (window);
3198
3199   buffer = Fget_buffer (buffer);
3200   CHECK_BUFFER (buffer);
3201
3202   if (!BUFFER_LIVE_P (XBUFFER (buffer)))
3203     error ("Attempt to display deleted buffer");
3204
3205   tem = w->buffer;
3206   if (NILP (tem))
3207     error ("Window is deleted");
3208
3209   /* While this seems like a logical thing to do, it causes problems
3210      because of saved window configurations.  It is possible for a
3211      buffer to get restored into a window in which it is already being
3212      displayed, but start and point are actually at completely
3213      different locations.  So we let this function complete fully and
3214      it will then make sure redisplay correctly updates things.
3215
3216      #### This is a kludge.  The correct approach is not to do this
3217      but to fix set-window-configuration. */
3218 #if 0
3219   else if (EQ (tem, buffer))
3220     return Qnil;
3221 #endif
3222   else if (! EQ (tem, Qt))      /* w->buffer is t when the window
3223                                    is first being set up.  */
3224     {
3225       if (!NILP (w->dedicated) && !EQ (tem, buffer))
3226         error ("Window is dedicated to buffer %s",
3227                XSTRING_DATA (XBUFFER (tem)->name));
3228
3229       unshow_buffer (w);
3230     }
3231
3232   w->buffer = buffer;
3233   w->window_end_pos[CURRENT_DISP] = 0;
3234   w->hscroll = 0;
3235   w->modeline_hscroll = 0;
3236   Fset_marker (w->pointm[CURRENT_DISP],
3237                make_int (BUF_PT (XBUFFER (buffer))),
3238                buffer);
3239   set_marker_restricted (w->start[CURRENT_DISP],
3240                          make_int (XBUFFER (buffer)->last_window_start),
3241                          buffer);
3242   Fset_marker (w->sb_point, w->start[CURRENT_DISP], buffer);
3243   /* set start_at_line_beg correctly. GE */
3244   w->start_at_line_beg = beginning_of_line_p (XBUFFER (buffer),
3245                                               marker_position (w->start[CURRENT_DISP]));
3246   w->force_start = 0;           /* Lucid fix */
3247   SET_LAST_MODIFIED (w, 1);
3248   SET_LAST_FACECHANGE (w);
3249   MARK_WINDOWS_CHANGED (w);
3250   recompute_all_cached_specifiers_in_window (w);
3251   if (EQ (window, Fselected_window (Qnil)))
3252     {
3253       if (NILP (norecord))
3254         Frecord_buffer (buffer);
3255
3256       Fset_buffer (buffer);
3257     }
3258   return Qnil;
3259 }
3260
3261 DEFUN ("select-window", Fselect_window, 1, 2, 0, /*
3262 Select WINDOW.  Most editing will apply to WINDOW's buffer.
3263 The main editor command loop selects the buffer of the selected window
3264 before each command.
3265
3266 With non-nil optional argument `norecord', do not modify the
3267 global or per-frame buffer ordering.
3268 */
3269        (window, norecord))
3270 {
3271   struct window *w;
3272   Lisp_Object old_selected_window = Fselected_window (Qnil);
3273
3274   CHECK_LIVE_WINDOW (window);
3275   w = XWINDOW (window);
3276
3277   /* we have already caught dead-window errors */
3278   if (!NILP (w->hchild) || !NILP (w->vchild))
3279     error ("Trying to select non-leaf window");
3280
3281   w->use_time = make_int (++window_select_count);
3282   if (EQ (window, old_selected_window))
3283     return window;
3284
3285   /* deselect the old window, if it exists (it might not exist if
3286      the selected device has no frames, which occurs at startup) */
3287   if (!NILP (old_selected_window))
3288     {
3289       struct window *ow = XWINDOW (old_selected_window);
3290
3291       Fset_marker (ow->pointm[CURRENT_DISP],
3292                    make_int (BUF_PT (XBUFFER (ow->buffer))),
3293                    ow->buffer);
3294
3295       MARK_WINDOWS_CHANGED (ow);
3296     }
3297
3298   /* now select the window's frame */
3299   set_frame_selected_window (XFRAME (WINDOW_FRAME (w)), window);
3300
3301   select_frame_1 (WINDOW_FRAME (w));
3302
3303   /* also select the window's buffer */
3304   if (NILP (norecord))
3305     Frecord_buffer (w->buffer);
3306   Fset_buffer (w->buffer);
3307
3308   /* Go to the point recorded in the window.
3309      This is important when the buffer is in more
3310      than one window.  It also matters when
3311      redisplay_window has altered point after scrolling,
3312      because it makes the change only in the window.  */
3313   {
3314     Bufpos new_point = marker_position (w->pointm[CURRENT_DISP]);
3315     if (new_point < BUF_BEGV (current_buffer))
3316       new_point = BUF_BEGV (current_buffer);
3317     else if (new_point > BUF_ZV (current_buffer))
3318       new_point = BUF_ZV (current_buffer);
3319
3320     BUF_SET_PT (current_buffer, new_point);
3321   }
3322
3323   MARK_WINDOWS_CHANGED (w);
3324
3325   return window;
3326 }
3327
3328 Lisp_Object
3329 display_buffer (Lisp_Object buffer, Lisp_Object not_this_window_p,
3330                 Lisp_Object override_frame)
3331 {
3332   return call3 (Qdisplay_buffer, buffer, not_this_window_p, override_frame);
3333 }
3334
3335 void
3336 temp_output_buffer_show (Lisp_Object buf, Lisp_Object same_frame)
3337 {
3338   /* This function can GC */
3339   Lisp_Object window;
3340   struct window *w;
3341   struct buffer *b = XBUFFER (buf);
3342
3343   BUF_SAVE_MODIFF (XBUFFER (buf)) = BUF_MODIFF (b);
3344   widen_buffer (b, 0);
3345   BUF_SET_PT (b, BUF_BEG (b));
3346
3347   if (!NILP (Vtemp_buffer_show_function))
3348     call1 (Vtemp_buffer_show_function, buf);
3349   else
3350     {
3351       window = display_buffer (buf, Qnil, same_frame);
3352
3353       if (!EQ (XWINDOW (window)->frame, Fselected_frame (Qnil)))
3354         Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
3355
3356       Vminibuffer_scroll_window = window;
3357       w = XWINDOW (window);
3358       w->hscroll = 0;
3359       w->modeline_hscroll = 0;
3360       set_marker_restricted (w->start[CURRENT_DISP], make_int (1), buf);
3361       set_marker_restricted (w->pointm[CURRENT_DISP], make_int (1), buf);
3362       set_marker_restricted (w->sb_point, make_int (1), buf);
3363
3364       /* Run temp-buffer-show-hook, with the chosen window selected.  */
3365       if (!preparing_for_armageddon)
3366         {
3367           Lisp_Object tem;
3368           tem = Fboundp (Qtemp_buffer_show_hook);
3369           if (!NILP (tem))
3370             {
3371               tem = Fsymbol_value (Qtemp_buffer_show_hook);
3372               if (!NILP (tem))
3373                 {
3374                   int count = specpdl_depth ();
3375
3376                   /* Select the window that was chosen, for running
3377                      the hook.  */
3378                   record_unwind_protect (save_window_excursion_unwind,
3379                                          Fcurrent_window_configuration (Qnil));
3380
3381                   Fselect_window (window, Qnil);
3382                   run_hook (Qtemp_buffer_show_hook);
3383                   unbind_to (count, Qnil);
3384                 }
3385             }
3386         }
3387     }
3388 }
3389 \f
3390 static void
3391 make_dummy_parent (Lisp_Object window)
3392 {
3393   Lisp_Object new;
3394   struct window *o = XWINDOW (window);
3395   struct window *p = alloc_lcrecord_type (struct window, &lrecord_window);
3396
3397   XSETWINDOW (new, p);
3398   copy_lcrecord (p, o);
3399
3400   /* Don't copy the pointers to the line start cache or the face
3401      instances. */
3402   p->line_start_cache = Dynarr_new (line_start_cache);
3403   p->face_cachels     = Dynarr_new (face_cachel);
3404   p->glyph_cachels    = Dynarr_new (glyph_cachel);
3405
3406   /* Put new into window structure in place of window */
3407   replace_window (window, new);
3408
3409   o->next = Qnil;
3410   o->prev = Qnil;
3411   o->vchild = Qnil;
3412   o->hchild = Qnil;
3413   o->parent = new;
3414
3415   p->start[CURRENT_DISP] = Qnil;
3416   p->start[DESIRED_DISP] = Qnil;
3417   p->start[CMOTION_DISP] = Qnil;
3418   p->pointm[CURRENT_DISP] = Qnil;
3419   p->pointm[DESIRED_DISP] = Qnil;
3420   p->pointm[CMOTION_DISP] = Qnil;
3421   p->sb_point = Qnil;
3422   p->buffer = Qnil;
3423 }
3424
3425 DEFUN ("split-window", Fsplit_window, 0, 3, "", /*
3426 Split WINDOW, putting SIZE lines in the first of the pair.
3427 WINDOW defaults to selected one and SIZE to half its size.
3428 If optional third arg HOR-FLAG is non-nil, split side by side
3429 and put SIZE columns in the first of the pair.
3430 */
3431        (window, chsize, horflag))
3432 {
3433   Lisp_Object new;
3434   struct window *o, *p;
3435   struct frame *f;
3436   int size;
3437   int psize;
3438
3439   if (NILP (window))
3440     window = Fselected_window (Qnil);
3441   else
3442     CHECK_LIVE_WINDOW (window);
3443
3444   o = XWINDOW (window);
3445   f = XFRAME (WINDOW_FRAME (o));
3446
3447   if (NILP (chsize))
3448     {
3449       if (!NILP (horflag))
3450         /* In the new scheme, we are symmetric with respect to separators
3451            so there is no need to do weird things here. */
3452         {
3453           psize = WINDOW_WIDTH (o) >> 1;
3454           size = window_pixel_width_to_char_width (o, psize, 0);
3455         }
3456       else
3457         {
3458           psize = WINDOW_HEIGHT (o) >> 1;
3459           size = window_pixel_height_to_char_height (o, psize, 1);
3460         }
3461     }
3462   else
3463     {
3464       CHECK_INT (chsize);
3465       size = XINT (chsize);
3466       if (!NILP (horflag))
3467         psize = window_char_width_to_pixel_width (o, size, 0);
3468       else
3469         psize = window_char_height_to_pixel_height (o, size, 1);
3470     }
3471
3472   if (MINI_WINDOW_P (o))
3473     error ("Attempt to split minibuffer window");
3474   else if (FRAME_NO_SPLIT_P (XFRAME (WINDOW_FRAME (o))))
3475     error ("Attempt to split unsplittable frame");
3476
3477   check_min_window_sizes ();
3478
3479   if (NILP (horflag))
3480     {
3481       if (size < window_min_height)
3482         error ("Window height %d too small (after splitting)", size);
3483       if (size + window_min_height > window_char_height (o, 1))
3484         error ("Window height %d too small (after splitting)",
3485                window_char_height (o, 1) - size);
3486       if (NILP (o->parent)
3487           || NILP (XWINDOW (o->parent)->vchild))
3488         {
3489           make_dummy_parent (window);
3490           reset_face_cachels (XWINDOW (window));
3491           new = o->parent;
3492           XWINDOW (new)->vchild = window;
3493           XFRAME (o->frame)->mirror_dirty = 1;
3494         }
3495     }
3496   else
3497     {
3498       if (size < window_min_width)
3499         error ("Window width %d too small (after splitting)", size);
3500       if (size + window_min_width > window_char_width (o, 0))
3501         error ("Window width %d too small (after splitting)",
3502                window_char_width (o, 0) - size);
3503       if (NILP (o->parent)
3504           || NILP (XWINDOW (o->parent)->hchild))
3505         {
3506           make_dummy_parent (window);
3507           reset_face_cachels (XWINDOW (window));
3508           new = o->parent;
3509           XWINDOW (new)->hchild = window;
3510           XFRAME (o->frame)->mirror_dirty = 1;
3511         }
3512     }
3513
3514   /* Now we know that window's parent is a vertical combination
3515      if we are dividing vertically, or a horizontal combination
3516      if we are making side-by-side windows */
3517
3518   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
3519   new = allocate_window ();
3520   p = XWINDOW (new);
3521
3522   p->frame = o->frame;
3523   p->next = o->next;
3524   if (!NILP (p->next))
3525     XWINDOW (p->next)->prev = new;
3526   p->prev = window;
3527   o->next = new;
3528   p->parent = o->parent;
3529   p->buffer = Qt;
3530
3531   reset_face_cachels (p);
3532   reset_glyph_cachels (p);
3533
3534
3535   /* Apportion the available frame space among the two new windows */
3536
3537   if (!NILP (horflag))
3538     {
3539       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o);
3540       WINDOW_TOP (p) = WINDOW_TOP (o);
3541       WINDOW_WIDTH (p) = WINDOW_WIDTH (o) - psize;
3542       WINDOW_WIDTH (o) = psize;
3543       WINDOW_LEFT (p) = WINDOW_LEFT (o) + psize;
3544     }
3545   else
3546     {
3547       WINDOW_LEFT (p) = WINDOW_LEFT (o);
3548       WINDOW_WIDTH (p) = WINDOW_WIDTH (o);
3549       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o) - psize;
3550       WINDOW_HEIGHT (o) = psize;
3551       WINDOW_TOP (p) = WINDOW_TOP (o) + psize;
3552     }
3553
3554   XFRAME (p->frame)->mirror_dirty = 1;
3555   /* do this last (after the window is completely initialized and
3556      the mirror-dirty flag is set) so that specifier recomputation
3557      caused as a result of this will work properly and not abort. */
3558   Fset_window_buffer (new, o->buffer, Qt);
3559   return new;
3560 }
3561 \f
3562
3563 DEFUN ("enlarge-window", Fenlarge_window, 1, 3, "_p", /*
3564 Make the selected window N lines bigger.
3565 From program, optional second arg SIDE non-nil means grow sideways N columns,
3566 and optional third arg WINDOW specifies the window to change instead of the
3567 selected window.
3568 */
3569        (n, side, window))
3570 {
3571   struct window *w = decode_window (window);
3572   CHECK_INT (n);
3573   change_window_height (w, XINT (n), !NILP (side), /* inpixels */ 0);
3574   return Qnil;
3575 }
3576
3577 DEFUN ("enlarge-window-pixels", Fenlarge_window_pixels, 1, 3, "_p", /*
3578 Make the selected window N pixels bigger.
3579 From program, optional second arg SIDE non-nil means grow sideways N pixels,
3580 and optional third arg WINDOW specifies the window to change instead of the
3581 selected window.
3582 */
3583        (n, side, window))
3584 {
3585   struct window *w = decode_window (window);
3586   CHECK_INT (n);
3587   change_window_height (w, XINT (n), !NILP (side), /* inpixels */ 1);
3588   return Qnil;
3589 }
3590
3591 DEFUN ("shrink-window", Fshrink_window, 1, 3, "_p", /*
3592 Make the selected window N lines smaller.
3593 From program, optional second arg SIDE non-nil means shrink sideways N columns,
3594 and optional third arg WINDOW specifies the window to change instead of the
3595 selected window.
3596 */
3597        (n, side, window))
3598 {
3599   CHECK_INT (n);
3600   change_window_height (decode_window (window), -XINT (n), !NILP (side),
3601                         /* inpixels */ 0);
3602   return Qnil;
3603 }
3604
3605 DEFUN ("shrink-window-pixels", Fshrink_window_pixels, 1, 3, "_p", /*
3606 Make the selected window N pixels smaller.
3607 From program, optional second arg SIDE non-nil means shrink sideways N pixels,
3608 and optional third arg WINDOW specifies the window to change instead of the
3609 selected window.
3610 */
3611        (n, side, window))
3612 {
3613   CHECK_INT (n);
3614   change_window_height (decode_window (window), -XINT (n), !NILP (side),
3615                         /* inpixels */ 1);
3616   return Qnil;
3617 }
3618
3619 static int
3620 window_pixel_height (Lisp_Object window)
3621 {
3622   return WINDOW_HEIGHT (XWINDOW (window));
3623 }
3624
3625 static int
3626 window_pixel_height_to_char_height (struct window *w, int pixel_height,
3627                                     int include_gutters_p)
3628 {
3629   int avail_height;
3630   int defheight, defwidth;
3631   int char_height;
3632   Lisp_Object window;
3633
3634   XSETWINDOW (window, w);
3635
3636   avail_height = (pixel_height -
3637                   (include_gutters_p ? 0 :
3638                    window_top_gutter_height (w) +
3639                    window_bottom_gutter_height (w)));
3640
3641   default_face_height_and_width (window, &defheight, &defwidth);
3642
3643   char_height = avail_height / defheight;
3644
3645   /* It's the calling function's responsibility to check these values
3646      and make sure they're not out of range.
3647
3648      #### We need to go through the calling functions and actually
3649      do this. */
3650   return max (0, char_height);
3651 }
3652
3653 static int
3654 window_char_height_to_pixel_height (struct window *w, int char_height,
3655                                     int include_gutters_p)
3656 {
3657   int avail_height;
3658   int defheight, defwidth;
3659   int pixel_height;
3660
3661   Lisp_Object window;
3662
3663   XSETWINDOW (window, w);
3664
3665   default_face_height_and_width (window, &defheight, &defwidth);
3666
3667   avail_height = char_height * defheight;
3668   pixel_height = (avail_height +
3669                   (include_gutters_p ? 0 :
3670                    window_top_gutter_height (w) +
3671                    window_bottom_gutter_height (w)));
3672
3673   /* It's the calling function's responsibility to check these values
3674      and make sure they're not out of range.
3675
3676      #### We need to go through the calling functions and actually
3677      do this. */
3678   return max (0, pixel_height);
3679 }
3680
3681 /* Return number of default lines of text can fit in the window W.
3682    If INCLUDE_GUTTERS_P is 1, include "gutter" space (modeline plus
3683    horizontal scrollbar) in the space that is used for the calculation.
3684    */
3685 int
3686 window_char_height (struct window *w, int include_gutters_p)
3687 {
3688   return window_pixel_height_to_char_height (w, WINDOW_HEIGHT (w),
3689                                              include_gutters_p);
3690 }
3691
3692 /*
3693  * Return number of lines currently displayed in window w.  If
3694  * end-of-buffer is displayed then the area below end-of-buffer is assume
3695  * to be blank lines of default height.
3696  * Does not include the modeline.
3697  */
3698 int
3699 window_displayed_height (struct window *w)
3700 {
3701   struct buffer *b = XBUFFER (w->buffer);
3702   display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
3703   int num_lines;
3704   Charcount end_pos = (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b)
3705                        ? -1
3706                        : w->window_end_pos[CURRENT_DISP]);
3707
3708   if (!Dynarr_length (dla))
3709     return window_char_height (w, 0);
3710
3711   num_lines = Dynarr_length (dla);
3712
3713   /* #### Document and assert somewhere that w->window_end_pos == -1
3714      indicates that end-of-buffer is being displayed. */
3715   if (end_pos == -1)
3716     {
3717       struct display_line *dl = Dynarr_atp (dla, 0);
3718       int ypos1 = dl->ypos + dl->descent;
3719       int ypos2 = WINDOW_TEXT_BOTTOM (w);
3720       Lisp_Object window;
3721       int defheight, defwidth;
3722
3723       XSETWINDOW (window, w);
3724
3725       if (dl->modeline)
3726         {
3727           num_lines--;
3728
3729           if (Dynarr_length (dla) == 1)
3730             ypos1 = WINDOW_TEXT_TOP (w);
3731           else
3732             {
3733               dl = Dynarr_atp (dla, Dynarr_length (dla) - 1);
3734               /* If this line is clipped then we know that there is no
3735                  blank room between eob and the modeline.  If we are
3736                  scrolling on clipped lines just know off the clipped
3737                  line and return .*/
3738               if (scroll_on_clipped_lines && dl->clip)
3739                 return num_lines - 1;
3740               ypos1 = dl->ypos + dl->descent - dl->clip;
3741             }
3742         }
3743
3744       default_face_height_and_width (window, &defheight, &defwidth);
3745       /* #### This probably needs to know about the clipping area once a
3746          final definition is decided on. */
3747       num_lines += ((ypos2 - ypos1) / defheight);
3748     }
3749   else
3750     {
3751       if (num_lines > 1 && Dynarr_atp (dla, 0)->modeline)
3752         num_lines--;
3753
3754       if (scroll_on_clipped_lines
3755           && Dynarr_atp (dla, Dynarr_length (dla) - 1)->clip)
3756         num_lines--;
3757     }
3758
3759   return num_lines;
3760 }
3761
3762 static int
3763 window_pixel_width (Lisp_Object window)
3764 {
3765   return WINDOW_WIDTH (XWINDOW (window));
3766 }
3767
3768 static int
3769 window_pixel_width_to_char_width (struct window *w, int pixel_width,
3770                                   int include_margins_p)
3771 {
3772   int avail_width;
3773   int char_width;
3774   int defheight, defwidth;
3775   Lisp_Object window;
3776
3777   XSETWINDOW (window, w);
3778
3779   avail_width = (pixel_width -
3780                  window_left_gutter_width (w, 0) -
3781                  window_right_gutter_width (w, 0) -
3782                  (include_margins_p ? 0 : window_left_margin_width (w)) -
3783                  (include_margins_p ? 0 : window_right_margin_width (w)));
3784
3785   default_face_height_and_width (window, &defheight, &defwidth);
3786
3787   char_width = (avail_width / defwidth);
3788
3789   /* It's the calling function's responsibility to check these values
3790      and make sure they're not out of range.
3791
3792      #### We need to go through the calling functions and actually
3793      do this. */
3794   return max (0, char_width);
3795 }
3796
3797 static int
3798 window_char_width_to_pixel_width (struct window *w, int char_width,
3799                                   int include_margins_p)
3800 {
3801   int avail_width;
3802   int pixel_width;
3803   int defheight, defwidth;
3804   Lisp_Object window;
3805
3806   XSETWINDOW (window, w);
3807
3808   default_face_height_and_width (window, &defheight, &defwidth);
3809
3810   avail_width = char_width * defwidth;
3811   pixel_width = (avail_width +
3812                  window_left_gutter_width (w, 0) +
3813                  window_right_gutter_width (w, 0) +
3814                  (include_margins_p ? 0 : window_left_margin_width (w)) +
3815                  (include_margins_p ? 0 : window_right_margin_width (w)));
3816
3817   /* It's the calling function's responsibility to check these values
3818      and make sure they're not out of range.
3819
3820      #### We need to go through the calling functions and actually
3821      do this. */
3822   return max (0, pixel_width);
3823 }
3824
3825 /* This returns the usable space which doesn't include space needed by
3826    scrollbars or divider lines. */
3827 int
3828 window_char_width (struct window *w, int include_margins_p)
3829 {
3830   return window_pixel_width_to_char_width (w, WINDOW_WIDTH (w),
3831                                            include_margins_p);
3832 }
3833
3834 #define MINSIZE(w)                                              \
3835   (widthflag                                                    \
3836    ? window_min_width * defwidth                                \
3837    : (defheight * (MINI_WINDOW_P (XWINDOW (w)) ? 1 : window_min_height)))
3838
3839 #define CURBEG(w) \
3840   *(widthflag ? (int *) &WINDOW_LEFT (w) : (int *) &WINDOW_TOP (w))
3841
3842 #define CURSIZE(w) \
3843   *(widthflag ? (int *) &WINDOW_WIDTH (w) : (int *) &WINDOW_HEIGHT (w))
3844
3845 #define CURCHARSIZE(w) \
3846   (widthflag ? window_char_width (w, 0) : window_char_height (w, 1))
3847
3848 #define MINCHARSIZE(window) \
3849   (widthflag ? window_min_width : MINI_WINDOW_P (XWINDOW (window)) \
3850    ? 1 : window_min_height)
3851
3852 /* Unlike set_window_pixheight, this function
3853    also changes the heights of the siblings so as to
3854    keep everything consistent. */
3855
3856 static void
3857 change_window_height (struct window *win, int delta, int widthflag,
3858                       int inpixels)
3859 {
3860   Lisp_Object parent;
3861   Lisp_Object window;
3862   struct window *w;
3863   struct frame *f;
3864   int *sizep;
3865   int (*sizefun) (Lisp_Object) = (widthflag
3866                                   ? window_pixel_width
3867                                   : window_pixel_height);
3868   void (*setsizefun) (Lisp_Object, int, int) = (widthflag
3869                                                 ? set_window_pixwidth
3870                                                 : set_window_pixheight);
3871   int dim;
3872   int defheight, defwidth;
3873
3874   if (delta == 0)
3875     return;
3876
3877   check_min_window_sizes ();
3878
3879   XSETWINDOW (window, win);
3880   f = XFRAME (win->frame);
3881   if (EQ (window, FRAME_ROOT_WINDOW (f)))
3882     error ("Won't change only window");
3883
3884   /* #### This is very likely incorrect and instead the char_to_pixel_
3885      functions should be called. */
3886   default_face_height_and_width (window, &defheight, &defwidth);
3887
3888   while (1)
3889     {
3890       w = XWINDOW (window);
3891       parent = w->parent;
3892       if (NILP (parent))
3893         {
3894           if (widthflag)
3895             error ("No other window to side of this one");
3896           break;
3897         }
3898       if (widthflag
3899           ? !NILP (XWINDOW (parent)->hchild)
3900           : !NILP (XWINDOW (parent)->vchild))
3901         break;
3902       window = parent;
3903     }
3904
3905   sizep = &CURSIZE (w);
3906   dim = CURCHARSIZE (w);
3907
3908   if ((inpixels  && (*sizep + delta) < MINSIZE (window)) ||
3909       (!inpixels && (dim + delta) < MINCHARSIZE (window)))
3910     {
3911       if (MINI_WINDOW_P (XWINDOW (window)))
3912         return;
3913       else if (!NILP (parent))
3914         {
3915           Fdelete_window (window, Qnil);
3916           return;
3917         }
3918     }
3919
3920   if (!inpixels)
3921     delta *= (widthflag ? defwidth : defheight);
3922
3923   {
3924     int maxdelta;
3925
3926     maxdelta = ((!NILP (parent))
3927                 ? (*sizefun) (parent) - *sizep
3928                 : ((!NILP (w->next))
3929                    ? (*sizefun) (w->next) - MINSIZE (w->next)
3930                    : ((!NILP (w->prev))
3931                       ? (*sizefun) (w->prev) - MINSIZE (w->prev)
3932                       /* This is a frame with only one window,
3933                          a minibuffer-only or a minibufferless frame.  */
3934                       : (delta = 0))));
3935
3936     if (delta > maxdelta)
3937       /* This case traps trying to make the minibuffer
3938          the full frame, or make the only window aside from the
3939          minibuffer the full frame.  */
3940       delta = maxdelta;
3941
3942     if (delta == 0)
3943       return;
3944
3945 #if 0 /* FSFmacs */
3946     /* #### Chuck: is this correct? */
3947     if (*sizep + delta < MINSIZE (window))
3948       {
3949         Fdelete_window (window);
3950         return;
3951       }
3952 #endif
3953   }
3954
3955   if (!NILP (w->next) &&
3956       (*sizefun) (w->next) - delta >= (int) MINSIZE (w->next))
3957     {
3958       CURBEG (XWINDOW (w->next)) += delta;
3959       (*setsizefun) (w->next, (*sizefun) (w->next) - delta, 0);
3960       (*setsizefun) (window, *sizep + delta, 0);
3961     }
3962   else if (!NILP (w->prev) &&
3963            (*sizefun) (w->prev) - delta >= (int) MINSIZE (w->prev))
3964     {
3965       (*setsizefun) (w->prev, (*sizefun) (w->prev) - delta, 0);
3966       CURBEG (w) -= delta;
3967       (*setsizefun) (window, *sizep + delta, 0);
3968     }
3969   else
3970     {
3971       int delta1;
3972       int opht = (*sizefun) (parent);
3973
3974       /* If trying to grow this window to or beyond size of the parent,
3975          make delta1 so big that, on shrinking back down,
3976          all the siblings end up with less than one line and are deleted.  */
3977       if (opht <= *sizep + delta)
3978         delta1 = opht * opht * 2;
3979       /* Otherwise, make delta1 just right so that if we add delta1
3980          lines to this window and to the parent, and then shrink
3981          the parent back to its original size, the new proportional
3982          size of this window will increase by delta.  */
3983       else
3984         delta1 = (delta * opht * 100) / ((opht - *sizep - delta) * 100);
3985
3986       /* Add delta1 lines or columns to this window, and to the parent,
3987          keeping things consistent while not affecting siblings.  */
3988       CURSIZE (XWINDOW (parent)) = opht + delta1;
3989       (*setsizefun) (window, *sizep + delta1, 0);
3990
3991       /* Squeeze out delta1 lines or columns from our parent,
3992          shrinking this window and siblings proportionately.
3993          This brings parent back to correct size.
3994          Delta1 was calculated so this makes this window the desired size,
3995          taking it all out of the siblings.  */
3996       (*setsizefun) (parent, opht, 0);
3997     }
3998
3999   SET_LAST_MODIFIED (w, 0);
4000   SET_LAST_FACECHANGE (w);
4001   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
4002   /* overkill maybe, but better to be correct */
4003   MARK_FRAME_GUTTERS_CHANGED (f);
4004 }
4005 #undef MINSIZE
4006 #undef CURBEG
4007 #undef CURSIZE
4008 #undef CURCHARSIZE
4009 #undef MINCHARSIZE
4010
4011 \f
4012
4013 /* Scroll contents of window WINDOW up N lines. If N < (top line height /
4014    average line height) then we just adjust the top clip.  */
4015 void
4016 window_scroll (Lisp_Object window, Lisp_Object n, int direction,
4017                Error_behavior errb)
4018 {
4019   struct window *w = XWINDOW (window);
4020   struct buffer *b = XBUFFER (w->buffer);
4021   int selected = EQ (window, Fselected_window (Qnil));
4022   int value = 0;
4023   Lisp_Object point, tem;
4024   display_line_dynarr *dla;
4025   int fheight, fwidth, modeline = 0;
4026   struct display_line* dl;
4027
4028   if (selected)
4029     point = make_int (BUF_PT (b));
4030   else
4031     {
4032       Bufpos pos = marker_position (w->pointm[CURRENT_DISP]);
4033
4034       if (pos < BUF_BEGV (b))
4035         pos = BUF_BEGV (b);
4036       else if (pos > BUF_ZV (b))
4037         pos = BUF_ZV (b);
4038
4039       point = make_int (pos);
4040     }
4041
4042   /* Always set force_start so that redisplay_window will run
4043      the window-scroll-functions.  */
4044   w->force_start = 1;
4045
4046   /* #### When the fuck does this happen?  I'm so glad that history has
4047      completely documented the behavior of the scrolling functions under
4048      all circumstances. */
4049   tem = Fpos_visible_in_window_p (point, window);
4050   if (NILP (tem))
4051     {
4052       Fvertical_motion (make_int (-window_char_height (w, 0) / 2),
4053                         window, Qnil);
4054       Fset_marker (w->start[CURRENT_DISP], point, w->buffer);
4055       w->start_at_line_beg = beginning_of_line_p (b, XINT (point));
4056       WINDOW_TEXT_TOP_CLIP (w) = 0;
4057       MARK_WINDOWS_CHANGED (w);
4058     }
4059
4060   if (!NILP (n))
4061     {
4062       if (EQ (n, Qminus))
4063         direction *= -1;
4064       else
4065         {
4066           n = Fprefix_numeric_value (n);
4067           value = XINT (n) * direction;
4068
4069           if (!value)
4070             return;     /* someone just made a pointless call */
4071         }
4072     }
4073
4074   /* If the user didn't specify how far to scroll then we have to figure it
4075      out by ourselves. */
4076   if (NILP (n) || EQ (n, Qminus))
4077     {
4078       /* Going forwards is easy.  If that is what we are doing then just
4079          set value and the section which handles the user specifying a
4080          positive value will work. */
4081       if (direction == 1)
4082         {
4083           value = window_displayed_height (w) - next_screen_context_lines;
4084           value = (value < 1 ? 1 : value);
4085         }
4086
4087       /* Going backwards is hard.  We can't use the same loop used if the
4088          user specified a negative value because we care about
4089          next_screen_context_lines.  In a variable height world you don't
4090          know how many lines above you can actually be displayed and still
4091          have the context lines appear.  So we leave value set to 0 and add
4092          a separate section to deal with this. */
4093
4094     }
4095
4096   if (direction == 1 && !value)
4097     {
4098       return;
4099     }
4100
4101   /* Determine parameters to test for partial line scrolling with. */
4102   dla = window_display_lines (w, CURRENT_DISP);
4103
4104   if (INTP (Vwindow_pixel_scroll_increment))
4105     fheight = XINT (Vwindow_pixel_scroll_increment);
4106   else if (!NILP (Vwindow_pixel_scroll_increment))
4107     default_face_height_and_width (window, &fheight, &fwidth);
4108
4109   if (Dynarr_length (dla) >= 1)
4110     modeline = Dynarr_atp (dla, 0)->modeline;
4111
4112   dl = Dynarr_atp (dla, modeline);
4113
4114   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 > 0)
4124         {
4125           WINDOW_TEXT_TOP_CLIP (w) += value * fheight;
4126           MARK_WINDOWS_CHANGED (w);
4127         }
4128       else
4129         {
4130           int vtarget;
4131           Bufpos startp, old_start;
4132
4133           if (WINDOW_TEXT_TOP_CLIP (w))
4134             {
4135               WINDOW_TEXT_TOP_CLIP (w) = 0;
4136               MARK_WINDOWS_CHANGED (w);
4137             }
4138
4139           old_start = marker_position (w->start[CURRENT_DISP]);
4140           startp = vmotion (w, old_start, value, &vtarget);
4141
4142           if (vtarget < value &&
4143               (w->window_end_pos[CURRENT_DISP] == -1
4144                || (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b))))
4145             {
4146               maybe_signal_error (Qend_of_buffer, Qnil, Qwindow, errb);
4147               return;
4148             }
4149           else
4150             {
4151               set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4152                                      w->buffer);
4153               w->force_start = 1;
4154               w->start_at_line_beg = beginning_of_line_p (b, startp);
4155               MARK_WINDOWS_CHANGED (w);
4156
4157               if (!point_would_be_visible (w, startp, XINT (point)))
4158                 {
4159                   if (selected)
4160                     BUF_SET_PT (b, startp);
4161                   else
4162                     set_marker_restricted (w->pointm[CURRENT_DISP],
4163                                            make_int (startp),
4164                                            w->buffer);
4165                 }
4166             }
4167         }
4168     }
4169   else if (value < 0)
4170     {
4171       /* Go for partial display line scrolling. This just means bumping
4172          the clip by a reasonable amount and redisplaying, everything else
4173          remains unchanged. */
4174       if (!NILP (Vwindow_pixel_scroll_increment)
4175           &&
4176           Dynarr_length (dla) >= (1 + modeline)
4177           &&
4178           (dl->ascent - dl->top_clip) - fheight * value <
4179           (dl->ascent + dl->descent - dl->clip)
4180           &&
4181           WINDOW_TEXT_TOP_CLIP (w) + value * fheight > 0)
4182         {
4183           WINDOW_TEXT_TOP_CLIP (w) += value * fheight;
4184           MARK_WINDOWS_CHANGED (w);
4185         }
4186       else
4187         {
4188           int vtarget;
4189           Bufpos startp, old_start;
4190
4191           if (WINDOW_TEXT_TOP_CLIP (w))
4192             {
4193               WINDOW_TEXT_TOP_CLIP (w) = 0;
4194               MARK_WINDOWS_CHANGED (w);
4195             }
4196
4197           old_start = marker_position (w->start[CURRENT_DISP]);
4198           startp = vmotion (w, old_start, value, &vtarget);
4199
4200           if (vtarget > value
4201               && marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b))
4202             {
4203               maybe_signal_error (Qbeginning_of_buffer, Qnil, Qwindow, errb);
4204               return;
4205             }
4206           else
4207             {
4208               set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4209                                      w->buffer);
4210               w->force_start = 1;
4211               w->start_at_line_beg = beginning_of_line_p (b, startp);
4212               MARK_WINDOWS_CHANGED (w);
4213
4214               /* #### Scroll back by less than a line. This code was
4215                  originally for scrolling over large pixmaps and it
4216                  loses when a line being *exposed* at the top of the
4217                  window is bigger than the current one. However, for
4218                  pixel based scrolling in general we can guess that
4219                  the line we are going to display is probably the same
4220                  size as the one we are on. In that instance we can
4221                  have a reasonable stab at a suitable top clip. Fixing
4222                  this properly is hard (and probably slow) as we would
4223                  have to call redisplay to figure out the exposed line
4224                  size. */
4225               if (!NILP (Vwindow_pixel_scroll_increment)
4226                   && Dynarr_length (dla) >= (1 + modeline)
4227                   && dl->ascent + fheight * value > 0)
4228                 {
4229                   WINDOW_TEXT_TOP_CLIP (w) = (dl->ascent + fheight * value);
4230                 }
4231
4232               if (!point_would_be_visible (w, startp, XINT (point)))
4233                 {
4234                   Bufpos new_point;
4235
4236                   if (MINI_WINDOW_P (w))
4237                     new_point = startp;
4238                   else
4239                     new_point = start_of_last_line (w, startp);
4240
4241                   if (selected)
4242                     BUF_SET_PT (b, new_point);
4243                   else
4244                     set_marker_restricted (w->pointm[CURRENT_DISP],
4245                                            make_int (new_point),
4246                                            w->buffer);
4247                 }
4248             }
4249         }
4250     }
4251   else  /* value == 0 && direction == -1 */
4252     {
4253       if (WINDOW_TEXT_TOP_CLIP (w))
4254         {
4255           WINDOW_TEXT_TOP_CLIP (w) = 0;
4256           MARK_WINDOWS_CHANGED (w);
4257         }
4258       if (marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b))
4259         {
4260           maybe_signal_error (Qbeginning_of_buffer, Qnil, Qwindow, errb);
4261           return;
4262         }
4263       else
4264         {
4265           int vtarget;
4266           int movement = next_screen_context_lines - 1;
4267           Bufpos old_startp = marker_position (w->start[CURRENT_DISP]);
4268           Bufpos bottom = vmotion (w, old_startp, movement, &vtarget);
4269           Bufpos startp =
4270             start_with_point_on_display_line (w, bottom,
4271                                               -1 - (movement - vtarget));
4272
4273           if (startp >= old_startp)
4274             startp = vmotion (w, old_startp, -1, NULL);
4275
4276           set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4277                                  w->buffer);
4278           w->force_start = 1;
4279           w->start_at_line_beg = beginning_of_line_p (b, startp);
4280           MARK_WINDOWS_CHANGED (w);
4281
4282           if (!point_would_be_visible (w, startp, XINT (point)))
4283             {
4284               Bufpos new_point = start_of_last_line (w, startp);
4285
4286               if (selected)
4287                 BUF_SET_PT (b, new_point);
4288               else
4289                 set_marker_restricted (w->pointm[CURRENT_DISP],
4290                                        make_int (new_point),
4291                                        w->buffer);
4292             }
4293         }
4294     }
4295 }
4296 \f
4297 DEFUN ("scroll-up", Fscroll_up, 0, 1, "_P", /*
4298 Scroll text of current window upward N lines; or near full screen if no arg.
4299 A near full screen is `next-screen-context-lines' less than a full screen.
4300 Negative N means scroll downward.
4301 When calling from a program, supply an integer as argument or nil.
4302 On attempt to scroll past end of buffer, `end-of-buffer' is signaled.
4303 On attempt to scroll past beginning of buffer, `beginning-of-buffer' is
4304 signaled.
4305 */
4306        (n))
4307 {
4308   window_scroll (Fselected_window (Qnil), n, 1, ERROR_ME);
4309   return Qnil;
4310 }
4311
4312 DEFUN ("scroll-down", Fscroll_down, 0, 1, "_P", /*
4313 Scroll text of current window downward N lines; or near full screen if no arg.
4314 A near full screen is `next-screen-context-lines' less than a full screen.
4315 Negative N means scroll upward.
4316 When calling from a program, supply a number as argument or nil.
4317 On attempt to scroll past end of buffer, `end-of-buffer' is signaled.
4318 On attempt to scroll past beginning of buffer, `beginning-of-buffer' is
4319 signaled.
4320 */
4321        (n))
4322 {
4323   window_scroll (Fselected_window (Qnil), n, -1, ERROR_ME);
4324   return Qnil;
4325 }
4326 \f
4327 DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, 0, 0, 0, /*
4328 Return the other window for "other window scroll" commands.
4329 If in the minibuffer, `minibuffer-scroll-window' if non-nil
4330 specifies the window.
4331 If `other-window-scroll-buffer' is non-nil, a window
4332 showing that buffer is used.
4333 */
4334        ())
4335 {
4336   Lisp_Object window;
4337   Lisp_Object selected_window = Fselected_window (Qnil);
4338
4339   if (MINI_WINDOW_P (XWINDOW (selected_window))
4340       && !NILP (Vminibuffer_scroll_window))
4341     window = Vminibuffer_scroll_window;
4342   /* If buffer is specified, scroll that buffer.  */
4343   else if (!NILP (Vother_window_scroll_buffer))
4344     {
4345       window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil, Qnil);
4346       if (NILP (window))
4347         window = display_buffer (Vother_window_scroll_buffer, Qt, Qnil);
4348     }
4349   else
4350     {
4351       /* Nothing specified; look for a neighboring window on the same
4352          frame.  */
4353       window = Fnext_window (selected_window, Qnil, Qnil, Qnil);
4354
4355       if (EQ (window, selected_window))
4356         /* That didn't get us anywhere; look for a window on another
4357            visible frame.  */
4358         do
4359           window = Fnext_window (window, Qnil, Qt, Qnil);
4360         while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
4361                && ! EQ (window, selected_window));
4362     }
4363
4364   CHECK_LIVE_WINDOW (window);
4365
4366   if (EQ (window, selected_window))
4367     error ("There is no other window");
4368
4369   return window;
4370  }
4371
4372 DEFUN ("scroll-other-window", Fscroll_other_window, 0, 1, "_P", /*
4373 Scroll next window upward N lines; or near full frame if no arg.
4374 The next window is the one below the current one; or the one at the top
4375 if the current one is at the bottom.  Negative N means scroll downward.
4376 When calling from a program, supply a number as argument or nil.
4377
4378 If in the minibuffer, `minibuffer-scroll-window' if non-nil
4379 specifies the window to scroll.
4380 If `other-window-scroll-buffer' is non-nil, scroll the window
4381 showing that buffer, popping the buffer up if necessary.
4382 */
4383        (n))
4384 {
4385   window_scroll (Fother_window_for_scrolling (), n, 1, ERROR_ME);
4386   return Qnil;
4387 }
4388 \f
4389 DEFUN ("scroll-left", Fscroll_left, 0, 1, "_P", /*
4390 Scroll selected window display N columns left.
4391 Default for N is window width minus 2.
4392 */
4393        (n))
4394 {
4395   Lisp_Object window = Fselected_window (Qnil);
4396   struct window *w = XWINDOW (window);
4397   int count = (NILP (n) ?
4398                window_char_width (w, 0) - 2 :
4399                XINT (Fprefix_numeric_value (n)));
4400
4401   return Fset_window_hscroll (window, make_int (w->hscroll + count));
4402 }
4403
4404 DEFUN ("scroll-right", Fscroll_right, 0, 1, "_P", /*
4405 Scroll selected window display N columns right.
4406 Default for N is window width minus 2.
4407 */
4408        (n))
4409 {
4410   Lisp_Object window = Fselected_window (Qnil);
4411   struct window *w = XWINDOW (window);
4412   int count = (NILP (n) ?
4413                window_char_width (w, 0) - 2 :
4414                XINT (Fprefix_numeric_value (n)));
4415
4416   return Fset_window_hscroll (window, make_int (w->hscroll - count));
4417 }
4418 \f
4419 DEFUN ("center-to-window-line", Fcenter_to_window_line, 0, 2, "_P", /*
4420 Center point in WINDOW.  With N, put point on line N.
4421 The desired position of point is always relative to the window.
4422 If WINDOW is nil, the selected window is used.
4423 */
4424        (n, window))
4425 {
4426   struct window *w = decode_window (window);
4427   struct buffer *b = XBUFFER (w->buffer);
4428   Bufpos opoint = BUF_PT (b);
4429   Bufpos startp;
4430
4431   if (NILP (n))
4432     startp = start_with_line_at_pixpos (w, opoint, window_half_pixpos (w));
4433   else
4434     {
4435       n = Fprefix_numeric_value (n);
4436       CHECK_INT (n);
4437       startp = start_with_point_on_display_line (w, opoint, XINT (n));
4438     }
4439
4440   Fset_marker (w->start[CURRENT_DISP], make_int (startp), w->buffer);
4441
4442   w->start_at_line_beg = beginning_of_line_p (b, startp);
4443   w->force_start = 1;
4444   MARK_WINDOWS_CHANGED (w);
4445   return Qnil;
4446 }
4447
4448 DEFUN ("move-to-window-line", Fmove_to_window_line, 1, 2, "_P", /*
4449 Position point relative to WINDOW.
4450 With no argument, position text at center of window.
4451 An argument specifies window line; zero means top of window,
4452 negative means relative to bottom of window.
4453 If WINDOW is nil, the selected window is used.
4454 */
4455        (arg, window))
4456 {
4457   struct window *w;
4458   struct buffer *b;
4459   int height;
4460   Bufpos start, new_point;
4461   int selected;
4462
4463   /* Don't use decode_window() because we need the new value of
4464      WINDOW.  */
4465   if (NILP (window))
4466     window = Fselected_window (Qnil);
4467   else
4468     CHECK_LIVE_WINDOW (window);
4469   w = XWINDOW (window);
4470   b = XBUFFER (w->buffer);
4471
4472   height = window_displayed_height (w);
4473   selected = EQ (window, Fselected_window (w->frame));
4474
4475   if (NILP (arg))
4476     {
4477       int retval;
4478
4479       if (XINT (w->last_modified[CURRENT_DISP]) >= BUF_MODIFF (b)
4480           && XINT (w->last_facechange[CURRENT_DISP]) >= BUF_FACECHANGE (b))
4481         {
4482           new_point = point_at_center (w, CURRENT_DISP, 0, 0);
4483
4484           if (selected)
4485             BUF_SET_PT (b, new_point);
4486           else
4487             Fset_window_point (window, make_int (new_point));
4488
4489           retval = line_at_center (w, CURRENT_DISP, 0, 0);
4490         }
4491       else
4492         {
4493           start = marker_position (w->start[CURRENT_DISP]);
4494           if (start < BUF_BEGV (b))
4495             start = BUF_BEGV (b);
4496           else if (start > BUF_ZV (b))
4497             start = BUF_ZV (b);
4498
4499           if (selected)
4500             new_point = BUF_PT (b);
4501           else
4502             new_point = marker_position (w->pointm[CURRENT_DISP]);
4503
4504           new_point = point_at_center (w, CMOTION_DISP, start, BUF_PT (b));
4505
4506           if (selected)
4507             BUF_SET_PT (b, new_point);
4508           else
4509             Fset_window_point (window, make_int (new_point));
4510
4511           retval = line_at_center (w, CMOTION_DISP, start, BUF_PT (b));
4512         }
4513
4514       return make_int (retval);
4515     }
4516   else
4517     {
4518       /* #### Is this going to work right when at eob? */
4519       arg = Fprefix_numeric_value (arg);
4520       if (XINT (arg) < 0)
4521         XSETINT (arg, XINT (arg) + height);
4522     }
4523
4524   start = marker_position (w->start[CURRENT_DISP]);
4525   if (start < BUF_BEGV (b) || start > BUF_ZV (b))
4526     {
4527       if (selected)
4528         new_point = BUF_PT (b);
4529       else
4530         new_point = marker_position (w->pointm[CURRENT_DISP]);
4531
4532       new_point = vmotion (XWINDOW (window), new_point, -height / 2, 0);
4533
4534       if (selected)
4535         BUF_SET_PT (b, new_point);
4536       else
4537         Fset_window_point (window, make_int (new_point));
4538
4539       Fset_marker (w->start[CURRENT_DISP], make_int (new_point),
4540                    w->buffer);
4541       w->start_at_line_beg = beginning_of_line_p (b, new_point);
4542       w->force_start = 1;
4543     }
4544   else
4545     {
4546       if (selected)
4547         BUF_SET_PT (b, start);
4548       else
4549         Fset_window_point (window, make_int (start));
4550     }
4551
4552   if (selected)
4553     return Fvertical_motion (arg, window, Qnil);
4554   else
4555     {
4556       int vpos;
4557       new_point = vmotion (XWINDOW (window),
4558                            marker_position (w->pointm[CURRENT_DISP]),
4559                            XINT (arg), &vpos);
4560       Fset_window_point (window, make_int (new_point));
4561       return make_int (vpos);
4562     }
4563 }
4564
4565 \f
4566 static int
4567 map_windows_1 (Lisp_Object window,
4568                int (*mapfun) (struct window *w, void *closure),
4569                void *closure)
4570 {
4571   for (; !NILP (window); window = XWINDOW (window)->next)
4572     {
4573       int retval;
4574       struct window *w = XWINDOW (window);
4575
4576       if (!NILP (w->vchild))
4577         retval = map_windows_1 (w->vchild, mapfun, closure);
4578       else if (!NILP (w->hchild))
4579         retval = map_windows_1 (w->hchild, mapfun, closure);
4580       else
4581         retval = (mapfun) (w, closure);
4582
4583       if (retval)
4584         return retval;
4585     }
4586
4587   return 0;
4588 }
4589
4590 /* Map MAPFUN over the windows in F.  CLOSURE is passed to each
4591    invocation of MAPFUN.  If any invocation of MAPFUN returns
4592    non-zero, the mapping is halted.  Otherwise, map_windows() maps
4593    over all windows in F.
4594
4595    If MAPFUN creates or deletes windows, the behavior is undefined.  */
4596
4597 int
4598 map_windows (struct frame *f, int (*mapfun) (struct window *w, void *closure),
4599              void *closure)
4600 {
4601   if (f)
4602     return map_windows_1 (FRAME_ROOT_WINDOW (f), mapfun, closure);
4603   else
4604     {
4605       Lisp_Object frmcons, devcons, concons;
4606
4607       FRAME_LOOP_NO_BREAK(frmcons, devcons, concons)
4608         {
4609           int v = map_windows_1 (FRAME_ROOT_WINDOW (XFRAME (XCAR (frmcons))),
4610                                  mapfun, closure);
4611           if (v)
4612             return v;
4613         }
4614     }
4615
4616   return 0;
4617 }
4618
4619 \f
4620 static void
4621 modeline_shadow_thickness_changed (Lisp_Object specifier, struct window *w,
4622                                    Lisp_Object oldval)
4623 {
4624   w->shadow_thickness_changed = 1;
4625   MARK_WINDOWS_CHANGED (w);
4626 }
4627
4628 static void
4629 vertical_divider_changed_in_window (Lisp_Object specifier,
4630                                     struct window *w,
4631                                     Lisp_Object oldval)
4632 {
4633   MARK_WINDOWS_CHANGED (w);
4634   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (XFRAME (WINDOW_FRAME (w)));
4635 }
4636
4637 /* also used in scrollbar.c */
4638 void
4639 some_window_value_changed (Lisp_Object specifier, struct window *w,
4640                            Lisp_Object oldval)
4641 {
4642   MARK_WINDOWS_CHANGED (w);
4643 }
4644
4645 #ifdef MEMORY_USAGE_STATS
4646
4647 struct window_stats
4648 {
4649   int face;
4650   int glyph;
4651 #ifdef HAVE_SCROLLBARS
4652   int scrollbar;
4653 #endif
4654   int line_start;
4655   int other_redisplay;
4656   int other;
4657 };
4658
4659 static void
4660 compute_window_mirror_usage (struct window_mirror *mir,
4661                              struct window_stats *stats,
4662                              struct overhead_stats *ovstats)
4663 {
4664   if (!mir)
4665     return;
4666   stats->other += malloced_storage_size (mir, sizeof (struct window_mirror),
4667                                          ovstats);
4668 #ifdef HAVE_SCROLLBARS
4669   {
4670     struct device *d = XDEVICE (FRAME_DEVICE (mir->frame));
4671
4672     stats->scrollbar +=
4673       compute_scrollbar_instance_usage (d, mir->scrollbar_vertical_instance,
4674                                         ovstats);
4675     stats->scrollbar +=
4676       compute_scrollbar_instance_usage (d, mir->scrollbar_horizontal_instance,
4677                                         ovstats);
4678   }
4679 #endif /* HAVE_SCROLLBARS */
4680   stats->other_redisplay +=
4681     compute_display_line_dynarr_usage (mir->current_display_lines, ovstats);
4682   stats->other_redisplay +=
4683     compute_display_line_dynarr_usage (mir->desired_display_lines, ovstats);
4684 }
4685
4686 static void
4687 compute_window_usage (struct window *w, struct window_stats *stats,
4688                       struct overhead_stats *ovstats)
4689 {
4690   xzero (*stats);
4691   stats->other += malloced_storage_size (w, sizeof (struct window), ovstats);
4692   stats->face += compute_face_cachel_usage (w->face_cachels, ovstats);
4693   stats->glyph += compute_glyph_cachel_usage (w->glyph_cachels, ovstats);
4694   stats->line_start +=
4695     compute_line_start_cache_dynarr_usage (w->line_start_cache, ovstats);
4696   compute_window_mirror_usage (find_window_mirror (w), stats, ovstats);
4697 }
4698
4699 DEFUN ("window-memory-usage", Fwindow_memory_usage, 1, 1, 0, /*
4700 Return stats about the memory usage of window WINDOW.
4701 The values returned are in the form of an alist of usage types and byte
4702 counts.  The byte counts attempt to encompass all the memory used
4703 by the window (separate from the memory logically associated with a
4704 buffer or frame), including internal structures and any malloc()
4705 overhead associated with them.  In practice, the byte counts are
4706 underestimated because certain memory usage is very hard to determine
4707 \(e.g. the amount of memory used inside the Xt library or inside the
4708 X server) and because there is other stuff that might logically
4709 be associated with a window, buffer, or frame (e.g. window configurations,
4710 glyphs) but should not obviously be included in the usage counts.
4711
4712 Multiple slices of the total memory usage may be returned, separated
4713 by a nil.  Each slice represents a particular view of the memory, a
4714 particular way of partitioning it into groups.  Within a slice, there
4715 is no overlap between the groups of memory, and each slice collectively
4716 represents all the memory concerned.
4717 */
4718        (window))
4719 {
4720   struct window_stats stats;
4721   struct overhead_stats ovstats;
4722   Lisp_Object val = Qnil;
4723
4724   CHECK_WINDOW (window); /* dead windows should be allowed, no? */
4725   xzero (ovstats);
4726   compute_window_usage (XWINDOW (window), &stats, &ovstats);
4727
4728   val = acons (Qface_cache,          make_int (stats.face),              val);
4729   val = acons (Qglyph_cache,         make_int (stats.glyph),             val);
4730 #ifdef HAVE_SCROLLBARS
4731   val = acons (Qscrollbar_instances, make_int (stats.scrollbar),         val);
4732 #endif
4733   val = acons (Qline_start_cache,    make_int (stats.line_start),        val);
4734   val = acons (Qother_redisplay,     make_int (stats.other_redisplay),   val);
4735   val = acons (Qother,               make_int (stats.other),             val);
4736   val = Fcons (Qnil, val);
4737   val = acons (Qactually_requested,  make_int (ovstats.was_requested),   val);
4738   val = acons (Qmalloc_overhead,     make_int (ovstats.malloc_overhead), val);
4739   val = acons (Qdynarr_overhead,     make_int (ovstats.dynarr_overhead), val);
4740
4741   return Fnreverse (val);
4742 }
4743
4744 #endif /* MEMORY_USAGE_STATS */
4745
4746 \f
4747 /************************************************************************/
4748 /*                         Window configurations                        */
4749 /************************************************************************/
4750
4751 /* #### This window configuration stuff has had serious bugs lurking in it
4752    for years; it would be a -huge- win if this was reimplemented in lisp.
4753  */
4754
4755 /* If you add anything to this structure make sure saved_window_equal
4756    knows about it. */
4757 struct saved_window
4758 {
4759   Lisp_Object window;         /* window */
4760   Lisp_Object buffer;         /* buffer */
4761   Lisp_Object start;          /* copied marker */
4762   Lisp_Object pointm;         /* copied marker */
4763   Lisp_Object sb_point;       /* copied marker */
4764   Lisp_Object mark;           /* copied marker */
4765   int pixel_left;
4766   int pixel_top;
4767   int pixel_width;
4768   int pixel_height;
4769   int hscroll;
4770   Charcount modeline_hscroll;
4771   int parent_index;           /* index into saved_windows */
4772   int prev_index;             /* index into saved_windows */
4773   char start_at_line_beg; /* boolean */
4774
4775 #define WINDOW_SLOT_DECLARATION
4776 #define WINDOW_SLOT(slot, compare) Lisp_Object slot
4777 #include "winslots.h"
4778 };
4779
4780 /* If you add anything to this structure make sure window_config_equal
4781    knows about it. */
4782 struct window_config
4783 {
4784   struct lcrecord_header header;
4785   /*  int frame_width; No longer needed, JV
4786       int frame_height; */
4787 #if 0 /* FSFmacs */
4788   Lisp_Object selected_frame;
4789 #endif
4790   Lisp_Object current_window;
4791   Lisp_Object current_buffer;
4792   Lisp_Object minibuffer_scroll_window;
4793   Lisp_Object root_window;
4794   int minibuf_height; /* 0 = no minibuffer, <0, size in lines, >0 in pixels */
4795   /* Record the values of window-min-width and window-min-height
4796      so that window sizes remain consistent with them.  */
4797   int min_width, min_height;
4798   int saved_windows_count;
4799   /* Zero-sized arrays aren't ANSI C */
4800   struct saved_window saved_windows[1];
4801 };
4802
4803 #define SAVED_WINDOW_N(conf, n) (&((conf)->saved_windows[(n)]))
4804 #define XWINDOW_CONFIGURATION(x) XRECORD (x, window_configuration, struct window_config)
4805 #define XSETWINDOW_CONFIGURATION(x, p) XSETRECORD (x, p, window_configuration)
4806 #define WINDOW_CONFIGURATIONP(x) RECORDP (x, window_configuration)
4807 #define CHECK_WINDOW_CONFIGURATION(x) CHECK_RECORD (x, window_configuration)
4808
4809 static Lisp_Object
4810 mark_window_config (Lisp_Object obj)
4811 {
4812   struct window_config *config = XWINDOW_CONFIGURATION (obj);
4813   int i;
4814   mark_object (config->current_window);
4815   mark_object (config->current_buffer);
4816   mark_object (config->minibuffer_scroll_window);
4817   mark_object (config->root_window);
4818
4819   for (i = 0; i < config->saved_windows_count; i++)
4820     {
4821       struct saved_window *s = SAVED_WINDOW_N (config, i);
4822       mark_object (s->window);
4823       mark_object (s->buffer);
4824       mark_object (s->start);
4825       mark_object (s->pointm);
4826       mark_object (s->sb_point);
4827       mark_object (s->mark);
4828 #if 0
4829       /* #### This looked like this. I do not see why specifier cached
4830          values should not be marked, as such specifiers as toolbars
4831          might have GC-able instances. Freed configs are not marked,
4832          aren't they?  -- kkm */
4833       mark_object (s->dedicated);
4834 #else
4835 #define WINDOW_SLOT(slot, compare) mark_object (s->slot)
4836 #include "winslots.h"
4837 #endif
4838     }
4839   return Qnil;
4840 }
4841
4842 static size_t
4843 sizeof_window_config_for_n_windows (int n)
4844 {
4845   return (sizeof (struct window_config) +
4846           /* n - 1 because zero-sized arrays aren't ANSI C */
4847           (n - 1) *sizeof (struct saved_window));
4848 }
4849
4850 static size_t
4851 sizeof_window_config (const void *h)
4852 {
4853   const struct window_config *c = (const struct window_config *) h;
4854   return sizeof_window_config_for_n_windows (c->saved_windows_count);
4855 }
4856
4857 static void
4858 print_window_config (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
4859 {
4860   struct window_config *config = XWINDOW_CONFIGURATION (obj);
4861   char buf[200];
4862   if (print_readably)
4863     error ("printing unreadable object #<window-configuration 0x%x>",
4864            config->header.uid);
4865   write_c_string ("#<window-configuration ", printcharfun);
4866   sprintf (buf, "0x%x>", config->header.uid);
4867   write_c_string (buf, printcharfun);
4868 }
4869
4870 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION ("window-configuration",
4871                                         window_configuration,
4872                                         mark_window_config,
4873                                         print_window_config,
4874                                         0, 0, 0, 0, sizeof_window_config,
4875                                         struct window_config);
4876
4877
4878 /* Returns a boolean indicating whether the two saved windows are
4879    identical. */
4880 static int
4881 saved_window_equal (struct saved_window *win1, struct saved_window *win2)
4882 {
4883 #define WINDOW_SLOT(slot, compare)              \
4884   if (!compare (win1->slot, win2->slot))        \
4885     return 0;
4886 #include "winslots.h"
4887
4888   return
4889     EQ (win1->window, win2->window) &&
4890     EQ (win1->buffer, win2->buffer) &&
4891     internal_equal (win1->start,    win2->start, 0) &&
4892     internal_equal (win1->pointm,   win2->pointm, 0) &&
4893     internal_equal (win1->sb_point, win2->sb_point, 0) &&
4894     internal_equal (win1->mark,     win2->mark, 0) &&
4895     win1->pixel_left   == win2->pixel_left &&
4896     win1->pixel_top    == win2->pixel_top &&
4897     win1->pixel_width  == win2->pixel_width &&
4898     win1->pixel_height == win2->pixel_height &&
4899     win1->hscroll      == win2->hscroll &&
4900     win1->modeline_hscroll == win2->modeline_hscroll &&
4901     win1->parent_index == win2->parent_index &&
4902     win1->prev_index   == win2->prev_index &&
4903     win1->start_at_line_beg == win2->start_at_line_beg;
4904 }
4905
4906 /* Returns a boolean indicating whether the two given configurations
4907    are identical. */
4908 static int
4909 window_config_equal (Lisp_Object conf1, Lisp_Object conf2)
4910 {
4911   struct window_config *fig1, *fig2;
4912   int i;
4913
4914   /* First check if they are truly the same. */
4915   if (EQ (conf1, conf2))
4916     return 1;
4917
4918   fig1 = XWINDOW_CONFIGURATION (conf1);
4919   fig2 = XWINDOW_CONFIGURATION (conf2);
4920
4921   if (!((fig1->saved_windows_count == fig2->saved_windows_count) &&
4922         EQ (fig1->current_window,           fig2->current_window) &&
4923         EQ (fig1->current_buffer,           fig2->current_buffer) &&
4924         EQ (fig1->root_window,              fig2->root_window) &&
4925         EQ (fig1->minibuffer_scroll_window, fig2->minibuffer_scroll_window)))
4926         /* &&
4927         fig1->frame_width  == fig2->frame_width &&
4928         fig1->frame_height == fig2->frame_height)) */
4929     return 0;
4930
4931   for (i = 0; i < fig1->saved_windows_count; i++)
4932     {
4933       if (!saved_window_equal (SAVED_WINDOW_N (fig1, i),
4934                                SAVED_WINDOW_N (fig2, i)))
4935         return 0;
4936     }
4937
4938   return 1;
4939 }
4940
4941 DEFUN ("window-configuration-p", Fwindow_configuration_p, 1, 1, 0, /*
4942 Return t if OBJECT is a window-configuration object.
4943 */
4944        (obj))
4945 {
4946   return WINDOW_CONFIGURATIONP (obj) ? Qt : Qnil;
4947 }
4948
4949 static int
4950 mark_windows_in_use_closure (struct window *w, void *closure)
4951 {
4952   int mark = *(int *)closure;
4953   w->config_mark = mark;
4954   return 0;
4955 }
4956
4957 static void
4958 mark_windows_in_use (struct frame *f, int mark)
4959 {
4960   map_windows (f, mark_windows_in_use_closure, &mark);
4961 }
4962
4963 /* Lisp_Object return value so it can be used in record_unwind_protect() */
4964 static Lisp_Object
4965 free_window_configuration (Lisp_Object window_config)
4966 {
4967   int i;
4968   struct window_config *config = XWINDOW_CONFIGURATION (window_config);
4969
4970   /* Free all the markers.  It's not completely necessary that
4971      we do this (window configs sitting in a free list aren't
4972      marked normally so the markers wouldn't be marked anyway)
4973      but it's more efficient. */
4974   for (i = 0; i < config->saved_windows_count; i++)
4975     {
4976       struct saved_window *p = SAVED_WINDOW_N (config, i);
4977
4978       if (!NILP (p->pointm))
4979         {
4980           free_marker (XMARKER (p->pointm));
4981           p->pointm = Qnil;
4982         }
4983       if (!NILP (p->start))
4984         {
4985           free_marker (XMARKER (p->start));
4986           p->start = Qnil;
4987         }
4988       if (!NILP (p->sb_point))
4989         {
4990           free_marker (XMARKER (p->sb_point));
4991           p->sb_point = Qnil;
4992         }
4993       if (!NILP (p->mark))
4994         {
4995           free_marker (XMARKER (p->mark));
4996           p->mark = Qnil;
4997         }
4998     }
4999
5000   if (config->saved_windows_count <= countof (Vwindow_configuration_free_list))
5001     free_managed_lcrecord (Vwindow_configuration_free_list
5002                            [config->saved_windows_count - 1],
5003                            window_config);
5004
5005   return Qnil;
5006 }
5007
5008 DEFUN ("set-window-configuration", Fset_window_configuration, 1, 1, 0, /*
5009 Set the configuration of windows and buffers as specified by CONFIGURATION.
5010 CONFIGURATION must be a value previously returned
5011 by `current-window-configuration' (which see).
5012 */
5013        (configuration))
5014 {
5015   struct window *w;
5016   struct window_config *config;
5017   struct saved_window *p;
5018   Lisp_Object new_current_buffer;
5019   int k;
5020   Lisp_Object frame;
5021   struct frame *f;
5022   struct gcpro gcpro1;
5023   Lisp_Object old_window_config;
5024   /*  int previous_frame_height;
5025       int previous_frame_width;*/
5026   int previous_pixel_top;
5027   int previous_pixel_height;
5028   int previous_pixel_left;
5029   int previous_pixel_width;
5030   int previous_minibuf_height, previous_minibuf_top,previous_minibuf_width;
5031   int real_font_height;
5032   int converted_minibuf_height,target_minibuf_height;
5033   int specpdl_count = specpdl_depth ();
5034
5035   GCPRO1 (configuration);
5036
5037   CHECK_WINDOW_CONFIGURATION (configuration);
5038   config = XWINDOW_CONFIGURATION (configuration);
5039
5040   frame = XWINDOW (SAVED_WINDOW_N (config, 0)->window)->frame;
5041   f = XFRAME (frame);
5042
5043   /* Do not signal an error here if the frame was deleted.  There are
5044      reasonable cases where we could get here with a deleted frame and
5045      just want to do close to nothing instead. */
5046
5047   if (FRAME_LIVE_P (f))
5048     {
5049       /* restore the frame characteristics */
5050
5051       new_current_buffer = config->current_buffer;
5052       if (!BUFFER_LIVE_P (XBUFFER (new_current_buffer)))
5053         new_current_buffer = Qnil;
5054
5055       /*
5056        * Assumed precondition:  w->config_mark = 0 for all w
5057        * This procedure should ensure this is true by the time it exits
5058        * to ensure the precondition for future calls.
5059        *
5060        * We use w->config_mark to know whether we're modifying a
5061        * window that is currently visible on the frame (#### we
5062        * should just be able to check whether the window is dead
5063        * or not, but this way is safer?).  As we process each
5064        * window, we set its config_mark to 0.  At the end, we
5065        * go through all the windows that used to be on the frame,
5066        * set each one's config_mark to 0 (to maintain the
5067        * assumed precondition) and delete each one that's no
5068        * longer in use.
5069        *
5070        * #### Using a window-configuration to keep track of
5071        * the current windows is wasteful.  All we need is the
5072        * list of windows, so we could just use a dynarr.
5073        */
5074       old_window_config = Fcurrent_window_configuration (frame);
5075
5076       /* If the new configuration is already equal to the old, then stop
5077          right here.  This saves the work below and it also saves
5078          triggering a full redisplay of this window.  This is a huge win
5079          when using the mouse since the mode motion code uses
5080          save-window-excursion extensively but will rarely cause the
5081          configuration to actually change. */
5082       if (window_config_equal (configuration, old_window_config))
5083         {
5084           free_window_configuration (old_window_config);
5085           UNGCPRO;
5086           return Qnil;
5087         }
5088
5089       /* We can't quit or even check for quit because that may cause
5090          investigation of the frame state, which may crash if the frame is
5091          in an inconsistent state. */
5092       begin_dont_check_for_quit ();
5093       record_unwind_protect (free_window_configuration, old_window_config);
5094
5095       mark_windows_in_use (f, 1);
5096
5097 #if 0
5098       /* JV: This is bogus,
5099          First of all, the units are inconsistent. The frame sizes are measured
5100          in characters but the window sizes are stored in pixels. So if a
5101          font size change happened between saving and restoring, the
5102          frame "sizes" maybe equal but the windows still should be
5103          resized. This is tickled alot by the new "character size
5104          stays constant" policy in 21.0. It leads to very wierd
5105          glitches (and possibly craches when asserts are tickled).
5106
5107          Just changing the units doens't help because changing the
5108          toolbar configuration can also change the pixel positions.
5109          Luckily there is a much simpler way of doing this, see below.
5110        */
5111       previous_frame_width = FRAME_WIDTH (f);
5112       previous_frame_height = FRAME_HEIGHT (f);
5113       /* If the frame has been resized since this window configuration was
5114          made, we change the frame to the size specified in the
5115          configuration, restore the configuration, and then resize it
5116          back.  We keep track of the prevailing height in these variables.  */
5117       if (config->frame_height != FRAME_HEIGHT (f)
5118           || config->frame_width != FRAME_WIDTH (f))
5119         change_frame_size (f, config->frame_height, config->frame_width, 0);
5120 #endif
5121
5122       previous_pixel_top = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_top;
5123       previous_pixel_height = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_height;
5124       previous_pixel_left = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_left;
5125       previous_pixel_width = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_width;
5126
5127       /* remember some properties of the minibuffer */
5128
5129       default_face_height_and_width (frame, &real_font_height, 0);
5130       assert(real_font_height > 0);
5131
5132       if (FRAME_HAS_MINIBUF_P (f) && ! FRAME_MINIBUF_ONLY_P (f))
5133         {
5134           previous_minibuf_height
5135             = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_height;
5136           previous_minibuf_top
5137             = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_top;
5138           previous_minibuf_width
5139             = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_width;
5140         }
5141       else
5142         {
5143           previous_minibuf_height = 0;
5144           previous_minibuf_top = 0;
5145           previous_minibuf_width = 0;
5146         }
5147       converted_minibuf_height =
5148         (previous_minibuf_height % real_font_height) == 0 ?
5149         - (previous_minibuf_height / real_font_height ) :    /* lines */
5150             previous_minibuf_height;   /* pixels */
5151
5152       /* Temporarily avoid any problems with windows that are smaller
5153          than they are supposed to be.  */
5154       window_min_height = 1;
5155       window_min_width = 1;
5156
5157       /* OK, now restore all the windows in the window config.
5158          This may involve "undeleting" windows, since the
5159          windows in the window config may be deleted.
5160          */
5161       for (k = 0; k < config->saved_windows_count; k++)
5162         {
5163           p = SAVED_WINDOW_N (config, k);
5164           w = XWINDOW (p->window);
5165           w->next = Qnil;
5166
5167           /* The window might be dead.  In this case, its redisplay
5168              structures were freed, so we need to reallocate them. */
5169           if (!w->face_cachels)
5170             {
5171               w->face_cachels = Dynarr_new (face_cachel);
5172               reset_face_cachels (w);
5173             }
5174           if (!w->glyph_cachels)
5175             w->glyph_cachels = Dynarr_new (glyph_cachel);
5176           if (!w->line_start_cache)
5177             w->line_start_cache = Dynarr_new (line_start_cache);
5178           w->dead = 0;
5179
5180           if (p->parent_index >= 0)
5181             w->parent = SAVED_WINDOW_N (config, p->parent_index)->window;
5182           else
5183             w->parent = Qnil;
5184
5185           if (p->prev_index >= 0)
5186             {
5187               w->prev = SAVED_WINDOW_N (config, p->prev_index)->window;
5188
5189               /* This is true for a minibuffer-only frame. */
5190               if (!NILP (w->mini_p) && EQ (w->prev, p->window))
5191                 w->next = Qnil;
5192               else
5193                 XWINDOW (w->prev)->next = p->window;
5194             }
5195           else
5196             {
5197               w->prev = Qnil;
5198               if (!NILP (w->parent))
5199                 {
5200                   if (WINDOW_WIDTH (p) == WINDOW_WIDTH (XWINDOW (w->parent)))
5201                     {
5202                       XWINDOW (w->parent)->vchild = p->window;
5203                       XWINDOW (w->parent)->hchild = Qnil;
5204                     }
5205                   else
5206                     {
5207                       XWINDOW (w->parent)->hchild = p->window;
5208                       XWINDOW (w->parent)->vchild = Qnil;
5209                     }
5210                 }
5211             }
5212           if (!w->config_mark)
5213             {
5214               /* #### This should be equivalent to the window previously
5215                  having been dead.  If we're brave, we'll put in an
5216                  assertion to this effect. */
5217               MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
5218             }
5219           else /* if (!EQ (w->buffer, p->buffer)) */
5220             {
5221               /* With the new redisplay we let it know that a change has
5222                  been made and it will take care of the rest.  If we don't
5223                  tell it something has possibly changed it could lead to
5224                  incorrect display. */
5225               MARK_WINDOWS_CHANGED (w);
5226             }
5227
5228           WINDOW_LEFT (w) = WINDOW_LEFT (p);
5229           WINDOW_TOP (w) = WINDOW_TOP (p);
5230           WINDOW_WIDTH (w) = WINDOW_WIDTH (p);
5231           WINDOW_HEIGHT (w) = WINDOW_HEIGHT (p);
5232           w->hscroll = p->hscroll;
5233           w->modeline_hscroll = p->modeline_hscroll;
5234           w->line_cache_last_updated = Qzero;
5235           SET_LAST_MODIFIED (w, 1);
5236           SET_LAST_FACECHANGE (w);
5237           w->config_mark = 0;
5238
5239 #define WINDOW_SLOT(slot, compare) w->slot = p->slot
5240 #include "winslots.h"
5241
5242           /* Reinstall the saved buffer and pointers into it.  */
5243           if (NILP (p->buffer))
5244             w->buffer = p->buffer;
5245           else
5246             {
5247               if (BUFFER_LIVE_P (XBUFFER (p->buffer)))
5248                 /* If saved buffer is alive, install it.  */
5249                 {
5250                   w->buffer = p->buffer;
5251                   w->start_at_line_beg = p->start_at_line_beg;
5252                   set_marker_restricted (w->start[CURRENT_DISP],
5253                                          Fmarker_position (p->start),
5254                                          w->buffer);
5255                   set_marker_restricted (w->pointm[CURRENT_DISP],
5256                                          Fmarker_position (p->pointm),
5257                                          w->buffer);
5258                   set_marker_restricted (w->sb_point,
5259                                          Fmarker_position (p->sb_point),
5260                                          w->buffer);
5261                   Fset_marker (XBUFFER (w->buffer)->mark,
5262                                Fmarker_position (p->mark), w->buffer);
5263
5264                   /* As documented in Fcurrent_window_configuration, don't
5265                      save the location of point in the buffer which was current
5266                      when the window configuration was recorded.  */
5267                   if (!EQ (p->buffer, new_current_buffer) &&
5268                       XBUFFER (p->buffer) == current_buffer)
5269                     Fgoto_char (w->pointm[CURRENT_DISP], Qnil);
5270                 }
5271               else if (NILP (w->buffer) ||
5272                        !BUFFER_LIVE_P (XBUFFER (w->buffer)))
5273                 /* Else if window's old buffer is dead too, get a live one.  */
5274                 {
5275                   /* #### The following line makes me nervous... */
5276                   /* w->buffer = Fcdr (Fcar (XFRAME (w->frame)->buffer_alist));*/
5277                   w->buffer = Fget_buffer_create (QSscratch);
5278                   /* w->buffer = Fother_buffer (Qnil, w->frame, Qnil); */
5279                   /* This will set the markers to beginning of visible
5280                      range.  */
5281                   set_marker_restricted (w->start[CURRENT_DISP], Qzero, w->buffer);
5282                   set_marker_restricted (w->pointm[CURRENT_DISP], Qzero,
5283                                          w->buffer);
5284                   set_marker_restricted (w->sb_point, Qzero, w->buffer);
5285                   w->start_at_line_beg = 1;
5286                 }
5287               else
5288                 /* Keeping window's old buffer; make sure the markers
5289                    are real.  */
5290                 {
5291                   /* Set window markers at start of visible range.  */
5292                   if (XMARKER (w->start[CURRENT_DISP])->buffer == 0)
5293                     set_marker_restricted (w->start[CURRENT_DISP], Qzero,
5294                                            w->buffer);
5295                   if (XMARKER (w->sb_point)->buffer == 0)
5296                     set_marker_restricted (w->sb_point, Qzero, w->buffer);
5297                   if (XMARKER (w->pointm[CURRENT_DISP])->buffer == 0)
5298                     set_marker_restricted (w->pointm[CURRENT_DISP],
5299                                            make_int
5300                                            (BUF_PT (XBUFFER (w->buffer))),
5301                                            w->buffer);
5302                   w->start_at_line_beg = 1;
5303                 }
5304             }
5305         }
5306
5307       FRAME_ROOT_WINDOW (f) = config->root_window;
5308       /* Note that FSFmacs unilaterally calls Fselect_window() here, and
5309          then calls do_switch_frame() below to select the frame that was
5310          recorded in the window config as being selected.
5311
5312          Instead, we don't ever change the selected frame, and either
5313          call Fselect_window() below if the window config's frame is
5314          currently selected, or just set the selected window of the
5315          window config's frame. */
5316
5317 #if 0
5318       /* Set the frame height to the value it had before this function.  */
5319       if (previous_frame_height != FRAME_HEIGHT (f)
5320           || previous_frame_width != FRAME_WIDTH (f))
5321         change_frame_size (f, previous_frame_height, previous_frame_width, 0);
5322 #endif
5323       /* We just reset the size and position of the minibuffer, to its old
5324          value, which needn't be valid. So we do some magic to see which value
5325          to actually take. Then we set it.
5326
5327          The magic:
5328          We take the old value if is in the same units but differs from the
5329          current value.
5330
5331          #### Now we get more cases correct then ever before, but
5332          are we treating all? For instance what if the frames minibuf window
5333          is no longer the same one?
5334       */
5335       target_minibuf_height = previous_minibuf_height;
5336       if (converted_minibuf_height &&
5337           (converted_minibuf_height * config->minibuf_height) > 0 &&
5338           (converted_minibuf_height !=  config->minibuf_height))
5339         {
5340           target_minibuf_height = config->minibuf_height < 0 ?
5341             - (config->minibuf_height * real_font_height) :
5342             config->minibuf_height;
5343           target_minibuf_height =
5344             max(target_minibuf_height,real_font_height);
5345         }
5346       if (previous_minibuf_height)
5347         {
5348           XWINDOW (FRAME_MINIBUF_WINDOW (f))->pixel_top
5349             = previous_minibuf_top -
5350                   (target_minibuf_height - previous_minibuf_height);
5351           set_window_pixheight (FRAME_MINIBUF_WINDOW (f),
5352                                 target_minibuf_height, 0);
5353           set_window_pixwidth  (FRAME_MINIBUF_WINDOW (f),
5354                             previous_minibuf_width, 0);
5355         }
5356
5357       /* This is a better way to deal with frame resizing, etc.
5358          What we _actually_ want is for the old (just restored)
5359          root window to fit
5360          into the place of the new one. So we just do that. Simple! */
5361       XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_top = previous_pixel_top;
5362       /* Note that this function also updates the subwindow
5363          "pixel_top"s */
5364       set_window_pixheight (FRAME_ROOT_WINDOW (f),
5365           previous_pixel_height -
5366                   (target_minibuf_height - previous_minibuf_height), 0);
5367       XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_left = previous_pixel_left;
5368       /* Note that this function also updates the subwindow
5369          "pixel_left"s */
5370       set_window_pixwidth (FRAME_ROOT_WINDOW (f), previous_pixel_width, 0);
5371
5372       /* If restoring in the current frame make the window current,
5373          otherwise just update the frame selected_window slot to be
5374          the restored current_window. */
5375       if (f == selected_frame ())
5376         {
5377           /* When using `pop-window-configuration', often the minibuffer
5378              ends up as the selected window even though it's not active ...
5379              I really don't know the cause of this, but it should never
5380              happen.  This kludge should fix it.
5381
5382              #### Find out why this is really going wrong. */
5383           if (!minibuf_level &&
5384               MINI_WINDOW_P (XWINDOW (config->current_window)))
5385             Fselect_window (Fnext_window (config->current_window,
5386                                           Qnil, Qnil, Qnil),
5387                             Qnil);
5388           else
5389             Fselect_window (config->current_window, Qnil);
5390           if (!NILP (new_current_buffer))
5391             Fset_buffer (new_current_buffer);
5392           else
5393             Fset_buffer (XWINDOW (Fselected_window (Qnil))->buffer);
5394         }
5395       else
5396         set_frame_selected_window (f, config->current_window);
5397     }
5398   else
5399     old_window_config = Qnil; /* Warning suppression */
5400
5401   /* Restore the minimum heights recorded in the configuration.  */
5402   window_min_height = config->min_height;
5403   window_min_width = config->min_width;
5404
5405 #if 0 /* FSFmacs */
5406   /* see above comment */
5407   /* Fselect_window will have made f the selected frame, so we
5408      reselect the proper frame here.  Fhandle_switch_frame will change the
5409      selected window too, but that doesn't make the call to
5410      Fselect_window above totally superfluous; it still sets f's
5411      selected window.  */
5412   if (FRAME_LIVE_P (XFRAME (config->selected_frame)))
5413     do_switch_frame (config->selected_frame, Qnil, 0);
5414 #endif
5415
5416   Vminibuffer_scroll_window = config->minibuffer_scroll_window;
5417
5418   if (FRAME_LIVE_P (f))
5419     {
5420       /* Do this before calling recompute_all_cached_specifiers_in_window()
5421          so that things like redisplay_redraw_cursor() won't abort due
5422          to no window mirror present. */
5423       f->mirror_dirty = 1;
5424
5425       config = XWINDOW_CONFIGURATION (old_window_config);
5426       for (k = 0; k < config->saved_windows_count; k++)
5427         {
5428           p = SAVED_WINDOW_N (config, k);
5429           w = XWINDOW (p->window);
5430           /* Remember, we set w->config_mark on all currently visible
5431              windows, and reset it on all newly visible windows.
5432              Any windows still marked need to be deleted. */
5433           if (w->config_mark)
5434             {
5435               mark_window_as_deleted (w);
5436               w->config_mark = 0;
5437             }
5438           else
5439             {
5440               /* We just potentially changed the window's buffer and
5441                  potentially turned a dead window into a live one,
5442                  so we need to recompute the cached specifier values. */
5443               recompute_all_cached_specifiers_in_window (w);
5444             }
5445         }
5446     }
5447
5448   /* Now restore things, when everything else if OK. */
5449
5450   unbind_to (specpdl_count, Qnil);
5451
5452   UNGCPRO;
5453
5454   return Qnil;
5455 }
5456
5457 /* Mark all subwindows of a window as deleted.  The argument
5458    W is actually the subwindow tree of the window in question. */
5459
5460 void
5461 delete_all_subwindows (struct window *w)
5462 {
5463   if (!NILP (w->next))   delete_all_subwindows (XWINDOW (w->next));
5464   if (!NILP (w->vchild)) delete_all_subwindows (XWINDOW (w->vchild));
5465   if (!NILP (w->hchild)) delete_all_subwindows (XWINDOW (w->hchild));
5466
5467   mark_window_as_deleted (w);
5468 }
5469
5470 \f
5471 static int
5472 count_windows (struct window *window)
5473 {
5474   return 1 +
5475     (!NILP (window->next)   ? count_windows (XWINDOW (window->next))   : 0) +
5476     (!NILP (window->vchild) ? count_windows (XWINDOW (window->vchild)) : 0) +
5477     (!NILP (window->hchild) ? count_windows (XWINDOW (window->hchild)) : 0);
5478 }
5479
5480 static int
5481 saved_window_index (Lisp_Object window, struct window_config *config, int lim)
5482 {
5483   int j;
5484   for (j = 0; j < lim; j++)
5485     {
5486       if (EQ (SAVED_WINDOW_N (config, j)->window, window))
5487         return j;
5488     }
5489   abort ();
5490   return 0;     /* suppress compiler warning */
5491 }
5492
5493 static int
5494 save_window_save (Lisp_Object window, struct window_config *config, int i)
5495 {
5496   struct window *w;
5497
5498   for (; !NILP (window); window = w->next)
5499     {
5500       struct saved_window *p = SAVED_WINDOW_N (config, i);
5501
5502       w = XWINDOW (window);
5503       i++;
5504       p->window = window;
5505       p->buffer = w->buffer;
5506       WINDOW_LEFT (p) = WINDOW_LEFT (w);
5507       WINDOW_TOP (p) = WINDOW_TOP (w);
5508       WINDOW_WIDTH (p) = WINDOW_WIDTH (w);
5509       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (w);
5510       p->hscroll = w->hscroll;
5511       p->modeline_hscroll = w->modeline_hscroll;
5512
5513 #define WINDOW_SLOT(slot, compare) p->slot = w->slot
5514 #include "winslots.h"
5515
5516       if (!NILP (w->buffer))
5517         {
5518           /* Save w's value of point in the window configuration.
5519              If w is the selected window, then get the value of point
5520              from the buffer; pointm is garbage in the selected window.  */
5521           if (EQ (window, Fselected_window (Qnil)))
5522             {
5523               p->pointm = noseeum_make_marker ();
5524               Fset_marker (p->pointm,
5525                            make_int (BUF_PT (XBUFFER (w->buffer))),
5526                            w->buffer);
5527             }
5528           else
5529             p->pointm = noseeum_copy_marker (w->pointm[CURRENT_DISP], Qnil);
5530
5531           p->start = noseeum_copy_marker (w->start[CURRENT_DISP], Qnil);
5532           p->sb_point = noseeum_copy_marker (w->sb_point, Qnil);
5533           p->start_at_line_beg = w->start_at_line_beg;
5534
5535           p->mark = noseeum_copy_marker (XBUFFER (w->buffer)->mark, Qnil);
5536         }
5537       else
5538         {
5539           p->pointm = Qnil;
5540           p->start = Qnil;
5541           p->sb_point = Qnil;
5542           p->mark = Qnil;
5543           p->start_at_line_beg = 0;
5544         }
5545
5546       if (NILP (w->parent))
5547         p->parent_index = -1;
5548       else
5549         p->parent_index = saved_window_index (w->parent, config, i);
5550       if (NILP (w->prev))
5551         p->prev_index = -1;
5552       else
5553         p->prev_index = saved_window_index (w->prev, config, i);
5554       if (!NILP (w->vchild))
5555         i = save_window_save (w->vchild, config, i);
5556       if (!NILP (w->hchild))
5557         i = save_window_save (w->hchild, config, i);
5558     }
5559
5560   return i;
5561 }
5562
5563 #if 0 /* FSFmacs */
5564 /* Added to doc string:
5565
5566 This also records the currently selected frame, and FRAME's focus
5567 redirection (see `redirect-frame-focus').
5568
5569 */
5570 #endif
5571
5572 DEFUN ("current-window-configuration", Fcurrent_window_configuration, 0, 1, 0, /*
5573 Return an object representing the current window configuration of FRAME.
5574 If FRAME is nil or omitted, use the selected frame.
5575 This describes the number of windows, their sizes and current buffers,
5576 and for each displayed buffer, where display starts, and the positions of
5577 point and mark.  An exception is made for point in the current buffer:
5578 its value is -not- saved.
5579 */
5580        (frame))
5581 {
5582   Lisp_Object result;
5583   struct frame *f = decode_frame (frame);
5584   struct window_config *config;
5585   int n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
5586   int minibuf_height;
5587   int real_font_height;
5588
5589   if (n_windows <= countof (Vwindow_configuration_free_list))
5590     config = XWINDOW_CONFIGURATION (allocate_managed_lcrecord
5591                                     (Vwindow_configuration_free_list
5592                                      [n_windows - 1]));
5593   else
5594     /* More than ten windows; just allocate directly */
5595     config = (struct window_config *)
5596       alloc_lcrecord (sizeof_window_config_for_n_windows (n_windows),
5597                       &lrecord_window_configuration);
5598   XSETWINDOW_CONFIGURATION (result, config);
5599   /*
5600   config->frame_width = FRAME_WIDTH (f);
5601   config->frame_height = FRAME_HEIGHT (f); */
5602   config->current_window = FRAME_SELECTED_WINDOW (f);
5603   XSETBUFFER (config->current_buffer, current_buffer);
5604   config->minibuffer_scroll_window = Vminibuffer_scroll_window;
5605   config->root_window = FRAME_ROOT_WINDOW (f);
5606   config->min_height = window_min_height;
5607   config->min_width = window_min_width;
5608   config->saved_windows_count = n_windows;
5609   save_window_save (FRAME_ROOT_WINDOW (f), config, 0);
5610
5611   /* save the minibuffer height using the heuristics from
5612      change_frame_size_1 */
5613
5614   XSETFRAME (frame, f); /* frame could have been nil ! */
5615   default_face_height_and_width (frame, &real_font_height, 0);
5616   assert(real_font_height > 0);
5617
5618   if (FRAME_HAS_MINIBUF_P (f) && ! FRAME_MINIBUF_ONLY_P (f))
5619     minibuf_height = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_height;
5620   else
5621     minibuf_height = 0;
5622   config->minibuf_height = (minibuf_height % real_font_height) == 0 ?
5623     - (minibuf_height / real_font_height ) :    /* lines */
5624     minibuf_height;   /* pixels */
5625
5626   return result;
5627 }
5628
5629 Lisp_Object
5630 save_window_excursion_unwind (Lisp_Object window_config)
5631 {
5632   Lisp_Object val = Fset_window_configuration (window_config);
5633   free_window_configuration (window_config);
5634   return val;
5635 }
5636
5637 DEFUN ("save-window-excursion", Fsave_window_excursion, 0, UNEVALLED, 0, /*
5638 Execute body, preserving window sizes and contents.
5639 Restores which buffer appears in which window, where display starts,
5640 as well as the current buffer.
5641 Does not restore the value of point in current buffer.
5642 */
5643        (args))
5644 {
5645   /* This function can GC */
5646   Lisp_Object val;
5647   int speccount = specpdl_depth ();
5648
5649   record_unwind_protect (save_window_excursion_unwind,
5650                          Fcurrent_window_configuration (Qnil));
5651   val = Fprogn (args);
5652   return unbind_to (speccount, val);
5653 }
5654
5655 DEFUN ("current-pixel-column", Fcurrent_pixel_column, 0, 2, 0, /*
5656 Return the horizontal pixel position of POS in window.
5657 Beginning of line is column 0. This is calculated using the redisplay
5658 display tables.  If WINDOW is nil, the current window is assumed.
5659 If POS is nil, point is assumed. Note that POS must be visible for
5660 a non-nil result to be returned.
5661 */
5662        (window, pos))
5663 {
5664   struct window* w = decode_window (window);
5665   display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
5666
5667   struct display_line *dl = 0;
5668   struct display_block *db = 0;
5669   struct rune* rb = 0;
5670   int y = w->last_point_y[CURRENT_DISP];
5671   int x = w->last_point_x[CURRENT_DISP];
5672
5673   if (MINI_WINDOW_P (w))
5674     return Qnil;
5675
5676   if (y<0 || x<0 || y >= Dynarr_length (dla) || !NILP (pos))
5677     {
5678       int first_line, i;
5679       Bufpos point;
5680
5681       if (NILP (pos))
5682         pos = Fwindow_point (window);
5683
5684       CHECK_INT (pos);
5685       point = XINT (pos);
5686
5687       if (Dynarr_length (dla) && Dynarr_atp (dla, 0)->modeline)
5688         first_line = 1;
5689       else
5690         first_line = 0;
5691
5692       for (i = first_line; i < Dynarr_length (dla); i++)
5693         {
5694           dl = Dynarr_atp (dla, i);
5695           /* find the vertical location first */
5696           if (point >= dl->bufpos && point <= dl->end_bufpos)
5697             {
5698               db = get_display_block_from_line (dl, TEXT);
5699               for (i = 0; i < Dynarr_length (db->runes); i++)
5700                 {
5701                   rb = Dynarr_atp (db->runes, i);
5702                   if (point <= rb->bufpos)
5703                     goto found_bufpos;
5704                 }
5705               return Qnil;
5706             }
5707         }
5708       return Qnil;
5709     found_bufpos:
5710       ;
5711     }
5712   else
5713     {
5714       /* optimised case */
5715       dl = Dynarr_atp (dla, y);
5716       db = get_display_block_from_line (dl, TEXT);
5717
5718       if (x >= Dynarr_length (db->runes))
5719         return Qnil;
5720
5721       rb = Dynarr_atp (db->runes, x);
5722     }
5723
5724   return make_int (rb->xpos - WINDOW_LEFT (w));
5725 }
5726
5727 \f
5728 #ifdef DEBUG_XEMACS
5729 /* This is short and simple in elisp, but... it was written to debug
5730    problems purely on the C side.  That is where we need to call it so
5731    here it is. */
5732 static void
5733 debug_print_window (Lisp_Object window, int level)
5734 {
5735   int i;
5736   Lisp_Object child = Fwindow_first_vchild (window);
5737
5738   if (NILP (child))
5739     child = Fwindow_first_hchild (window);
5740
5741   for (i = level; i > 0; i--)
5742     putc ('\t', stderr);
5743
5744   fputs ("#<window", stderr);
5745   {
5746     Lisp_Object buffer = XWINDOW (window)->buffer;
5747     if (!NILP (buffer) && BUFFERP (buffer))
5748       fprintf (stderr, " on %s", XSTRING_DATA (XBUFFER (buffer)->name));
5749   }
5750   fprintf (stderr, " 0x%x>", XWINDOW (window)->header.uid);
5751
5752   while (!NILP (child))
5753     {
5754       debug_print_window (child, level + 1);
5755       child = Fwindow_next_child (child);
5756     }
5757 }
5758
5759 void debug_print_windows (struct frame *f);
5760 void
5761 debug_print_windows (struct frame *f)
5762 {
5763   debug_print_window (f->root_window, 0);
5764   putc ('\n', stderr);
5765 }
5766 #endif /* DEBUG_XEMACS */
5767
5768 \f
5769 /************************************************************************/
5770 /*                            initialization                            */
5771 /************************************************************************/
5772
5773 void
5774 syms_of_window (void)
5775 {
5776   defsymbol (&Qwindowp, "windowp");
5777   defsymbol (&Qwindow_live_p, "window-live-p");
5778   defsymbol (&Qwindow_configurationp, "window-configuration-p");
5779   defsymbol (&Qtemp_buffer_show_hook, "temp-buffer-show-hook");
5780   defsymbol (&Qdisplay_buffer, "display-buffer");
5781
5782 #ifdef MEMORY_USAGE_STATS
5783   defsymbol (&Qface_cache, "face-cache");
5784   defsymbol (&Qglyph_cache, "glyph-cache");
5785   defsymbol (&Qline_start_cache, "line-start-cache");
5786 #ifdef HAVE_SCROLLBARS
5787   defsymbol (&Qscrollbar_instances, "scrollbar-instances");
5788 #endif
5789   defsymbol (&Qother_redisplay, "other-redisplay");
5790   /* Qother in general.c */
5791 #endif
5792
5793   DEFSUBR (Fselected_window);
5794   DEFSUBR (Flast_nonminibuf_window);
5795   DEFSUBR (Fminibuffer_window);
5796   DEFSUBR (Fwindow_minibuffer_p);
5797   DEFSUBR (Fwindowp);
5798   DEFSUBR (Fwindow_live_p);
5799   DEFSUBR (Fwindow_first_hchild);
5800   DEFSUBR (Fwindow_first_vchild);
5801   DEFSUBR (Fwindow_next_child);
5802   DEFSUBR (Fwindow_previous_child);
5803   DEFSUBR (Fwindow_parent);
5804   DEFSUBR (Fwindow_lowest_p);
5805   DEFSUBR (Fwindow_truncated_p);
5806   DEFSUBR (Fwindow_highest_p);
5807   DEFSUBR (Fwindow_leftmost_p);
5808   DEFSUBR (Fwindow_rightmost_p);
5809   DEFSUBR (Fpos_visible_in_window_p);
5810   DEFSUBR (Fwindow_buffer);
5811   DEFSUBR (Fwindow_frame);
5812   DEFSUBR (Fwindow_height);
5813   DEFSUBR (Fwindow_displayed_height);
5814   DEFSUBR (Fwindow_width);
5815   DEFSUBR (Fwindow_pixel_height);
5816   DEFSUBR (Fwindow_pixel_width);
5817   DEFSUBR (Fwindow_text_area_pixel_height);
5818   DEFSUBR (Fwindow_displayed_text_pixel_height);
5819   DEFSUBR (Fwindow_text_area_pixel_width);
5820   DEFSUBR (Fwindow_hscroll);
5821   DEFSUBR (Fset_window_hscroll);
5822   DEFSUBR (Fmodeline_hscroll);
5823   DEFSUBR (Fset_modeline_hscroll);
5824 #if 0 /* bogus FSF crock */
5825   DEFSUBR (Fwindow_redisplay_end_trigger);
5826   DEFSUBR (Fset_window_redisplay_end_trigger);
5827 #endif
5828   DEFSUBR (Fwindow_pixel_edges);
5829   DEFSUBR (Fwindow_text_area_pixel_edges);
5830   DEFSUBR (Fwindow_point);
5831   DEFSUBR (Fwindow_start);
5832   DEFSUBR (Fwindow_end);
5833   DEFSUBR (Fwindow_last_line_visible_height);
5834   DEFSUBR (Fset_window_point);
5835   DEFSUBR (Fset_window_start);
5836   DEFSUBR (Fwindow_dedicated_p);
5837   DEFSUBR (Fset_window_dedicated_p);
5838   DEFSUBR (Fnext_window);
5839   DEFSUBR (Fprevious_window);
5840   DEFSUBR (Fnext_vertical_window);
5841   DEFSUBR (Fother_window);
5842   DEFSUBR (Fget_lru_window);
5843   DEFSUBR (Fget_largest_window);
5844   DEFSUBR (Fget_buffer_window);
5845   DEFSUBR (Fwindow_left_margin_pixel_width);
5846   DEFSUBR (Fwindow_right_margin_pixel_width);
5847   DEFSUBR (Fdelete_other_windows);
5848   DEFSUBR (Fdelete_windows_on);
5849   DEFSUBR (Freplace_buffer_in_windows);
5850   DEFSUBR (Fdelete_window);
5851   DEFSUBR (Fset_window_buffer);
5852   DEFSUBR (Fselect_window);
5853   DEFSUBR (Fsplit_window);
5854   DEFSUBR (Fenlarge_window);
5855   DEFSUBR (Fenlarge_window_pixels);
5856   DEFSUBR (Fshrink_window);
5857   DEFSUBR (Fshrink_window_pixels);
5858   DEFSUBR (Fscroll_up);
5859   DEFSUBR (Fscroll_down);
5860   DEFSUBR (Fscroll_left);
5861   DEFSUBR (Fscroll_right);
5862   DEFSUBR (Fother_window_for_scrolling);
5863   DEFSUBR (Fscroll_other_window);
5864   DEFSUBR (Fcenter_to_window_line);
5865   DEFSUBR (Fmove_to_window_line);
5866 #ifdef MEMORY_USAGE_STATS
5867   DEFSUBR (Fwindow_memory_usage);
5868 #endif
5869   DEFSUBR (Fwindow_configuration_p);
5870   DEFSUBR (Fset_window_configuration);
5871   DEFSUBR (Fcurrent_window_configuration);
5872   DEFSUBR (Fsave_window_excursion);
5873   DEFSUBR (Fcurrent_pixel_column);
5874 }
5875
5876 void
5877 reinit_vars_of_window (void)
5878 {
5879   int i;
5880   /* Make sure all windows get marked */
5881   minibuf_window = Qnil;
5882   staticpro_nodump (&minibuf_window);
5883
5884   for (i = 0; i < countof (Vwindow_configuration_free_list); i++)
5885     {
5886       Vwindow_configuration_free_list[i] =
5887         make_lcrecord_list (sizeof_window_config_for_n_windows (i + 1),
5888                             &lrecord_window_configuration);
5889       staticpro_nodump (&Vwindow_configuration_free_list[i]);
5890     }
5891 }
5892
5893 void
5894 vars_of_window (void)
5895 {
5896   reinit_vars_of_window ();
5897
5898   DEFVAR_BOOL ("scroll-on-clipped-lines", &scroll_on_clipped_lines /*
5899 *Non-nil means to scroll if point lands on a line which is clipped.
5900 */ );
5901   scroll_on_clipped_lines = 1;
5902
5903   DEFVAR_LISP ("temp-buffer-show-hook", &Vtemp_buffer_show_hook /*
5904 See `temp-buffer-show-function'.
5905 */ );
5906   Vtemp_buffer_show_hook = Qnil;
5907
5908   DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function /*
5909 Non-nil means call as function to display a help buffer.
5910 The function is called with one argument, the buffer to be displayed.
5911 Used by `with-output-to-temp-buffer'.
5912 If this function is used, then it must do the entire job of showing
5913 the buffer; `temp-buffer-show-hook' is not run unless this function runs it.
5914 */ );
5915   Vtemp_buffer_show_function = Qnil;
5916
5917   DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuffer_scroll_window /*
5918 Non-nil means it is the window that \\<minibuffer-local-map>\\[scroll-other-window] in minibuffer should scroll.
5919 */ );
5920   Vminibuffer_scroll_window = Qnil;
5921
5922   DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer /*
5923 If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.
5924 */ );
5925   Vother_window_scroll_buffer = Qnil;
5926
5927   DEFVAR_LISP ("window-pixel-scroll-increment", &Vwindow_pixel_scroll_increment /*
5928 *Number of pixels to scroll by per requested line.
5929 If nil then normal line scrolling occurs regardless of line height.
5930 If t then scrolling is done in increments equal to the height of the default face.
5931 */ );
5932   Vwindow_pixel_scroll_increment = Qt;
5933
5934   DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines /*
5935 *Number of lines of continuity when scrolling by screenfuls.
5936 */ );
5937   next_screen_context_lines = 2;
5938
5939   DEFVAR_INT ("window-min-height", &window_min_height /*
5940 *Delete any window less than this tall (including its modeline).
5941 */ );
5942   window_min_height = 4;
5943
5944   DEFVAR_INT ("window-min-width", &window_min_width /*
5945 *Delete any window less than this wide.
5946 */ );
5947   window_min_width = 10;
5948 }
5949
5950 void
5951 specifier_vars_of_window (void)
5952 {
5953   DEFVAR_SPECIFIER ("modeline-shadow-thickness", &Vmodeline_shadow_thickness /*
5954 *How thick to draw 3D shadows around modelines.
5955 If this is set to 0, modelines will be the traditional 2D.  Sizes above
5956 10 will be accepted but the maximum thickness that will be drawn is 10.
5957 This is a specifier; use `set-specifier' to change it.
5958 */ );
5959   Vmodeline_shadow_thickness = Fmake_specifier (Qinteger);
5960   /* The initial value for modeline-shadow-thickness is 2, but if the
5961      user removes all specifications we provide a fallback value of 0,
5962      which is probably what was expected. */
5963   set_specifier_fallback (Vmodeline_shadow_thickness,
5964                           list1 (Fcons (Qnil, Qzero)));
5965   Fadd_spec_to_specifier (Vmodeline_shadow_thickness, make_int (2),
5966                           Qnil, Qnil, Qnil);
5967   set_specifier_caching (Vmodeline_shadow_thickness,
5968                          offsetof (struct window, modeline_shadow_thickness),
5969                          modeline_shadow_thickness_changed,
5970                          0, 0);
5971
5972   DEFVAR_SPECIFIER ("has-modeline-p", &Vhas_modeline_p /*
5973 *Whether the modeline should be displayed.
5974 This is a specifier; use `set-specifier' to change it.
5975 */ );
5976   Vhas_modeline_p = Fmake_specifier (Qboolean);
5977   set_specifier_fallback (Vhas_modeline_p,
5978                           list1 (Fcons (Qnil, Qt)));
5979   set_specifier_caching (Vhas_modeline_p,
5980                          offsetof (struct window, has_modeline_p),
5981                          /* #### It's strange that we need a special
5982                             flag to indicate that the shadow-thickness
5983                             has changed, but not one to indicate that
5984                             the modeline has been turned off or on. */
5985                          some_window_value_changed,
5986                          0, 0);
5987
5988   DEFVAR_SPECIFIER ("vertical-divider-always-visible-p",
5989                     &Vvertical_divider_always_visible_p /*
5990 *Should XEmacs always display vertical dividers between windows.
5991
5992 When this is non-nil, vertical dividers are always shown, and are
5993 draggable.  When it is nil, vertical dividers are shown only when
5994 there are no scrollbars in between windows, and are not draggable.
5995
5996 This is a specifier; use `set-specifier' to change it.
5997 */ );
5998   Vvertical_divider_always_visible_p = Fmake_specifier (Qboolean);
5999   set_specifier_fallback (Vvertical_divider_always_visible_p,
6000                           list1 (Fcons (Qnil, Qt)));
6001   set_specifier_caching (Vvertical_divider_always_visible_p,
6002                          offsetof (struct window,
6003                                    vertical_divider_always_visible_p),
6004                          vertical_divider_changed_in_window,
6005                          0, 0);
6006
6007   DEFVAR_SPECIFIER ("vertical-divider-shadow-thickness", &Vvertical_divider_shadow_thickness /*
6008 *How thick to draw 3D shadows around vertical dividers.
6009 This is a specifier; use `set-specifier' to change it.
6010 */ );
6011   Vvertical_divider_shadow_thickness = Fmake_specifier (Qinteger);
6012   set_specifier_fallback (Vvertical_divider_shadow_thickness,
6013                           list1 (Fcons (Qnil, Qzero)));
6014   Fadd_spec_to_specifier (Vvertical_divider_shadow_thickness, make_int (2),
6015                           Qnil, Qnil, Qnil);
6016   set_specifier_caching (Vvertical_divider_shadow_thickness,
6017                          offsetof (struct window,
6018                                    vertical_divider_shadow_thickness),
6019                          vertical_divider_changed_in_window,
6020                          0, 0);
6021   DEFVAR_SPECIFIER ("vertical-divider-line-width", &Vvertical_divider_line_width /*
6022 *The width of the vertical dividers, not including shadows.
6023
6024 For TTY windows, divider line is always one character wide.  When
6025 instance of this specifier is zero in a TTY window, no divider is
6026 drawn at all between windows.  When non-zero, a one character wide
6027 divider is displayed.
6028
6029 This is a specifier; use `set-specifier' to change it.
6030 */ );
6031
6032   Vvertical_divider_line_width = Fmake_specifier (Qnatnum);
6033   {
6034     Lisp_Object fb = Qnil;
6035 #ifdef HAVE_TTY
6036     fb = Fcons (Fcons (list1 (Qtty), make_int (1)), fb);
6037 #endif
6038 #ifdef HAVE_X_WINDOWS
6039     fb = Fcons (Fcons (list1 (Qx), make_int (3)), fb);
6040 #endif
6041 #ifdef HAVE_MS_WINDOWS
6042     /* #### This should be made magic and made to obey system settings */
6043     fb = Fcons (Fcons (list1 (Qmswindows), make_int (3)), fb);
6044 #endif
6045     set_specifier_fallback (Vvertical_divider_line_width, fb);
6046   }
6047   set_specifier_caching (Vvertical_divider_line_width,
6048                          offsetof (struct window,
6049                                    vertical_divider_line_width),
6050                          vertical_divider_changed_in_window,
6051                          0, 0);
6052
6053   DEFVAR_SPECIFIER ("vertical-divider-spacing", &Vvertical_divider_spacing /*
6054 *How much space to leave around the vertical dividers.
6055
6056 In TTY windows, spacing is always zero, and the value of this
6057 specifier is ignored.
6058
6059 This is a specifier; use `set-specifier' to change it.
6060 */ );
6061   Vvertical_divider_spacing = Fmake_specifier (Qnatnum);
6062   {
6063     Lisp_Object fb = Qnil;
6064 #ifdef HAVE_TTY
6065     fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
6066 #endif
6067 #ifdef HAVE_X_WINDOWS
6068     /* #### 3D dividers look great on MS Windows with spacing = 0.
6069        Should not the same value be the fallback under X? - kkm */
6070     fb = Fcons (Fcons (list1 (Qx), make_int (2)), fb);
6071 #endif
6072 #ifdef HAVE_MS_WINDOWS
6073     fb = Fcons (Fcons (list1 (Qmswindows), Qzero), fb);
6074 #endif
6075     set_specifier_fallback (Vvertical_divider_spacing, fb);
6076   }
6077   set_specifier_caching (Vvertical_divider_spacing,
6078                          offsetof (struct window, vertical_divider_spacing),
6079                          vertical_divider_changed_in_window,
6080                          0, 0);
6081 }