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