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