3a86d72e0beba53f84655ac50b7a4f548cb19f04
[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, Qnil);
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, Qnil);
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 static int
2982 frame_min_height (struct frame *frame)
2983 {
2984   /* For height, we have to see whether the frame has a minibuffer, and
2985      whether it wants a modeline.  */
2986   return (FRAME_MINIBUF_ONLY_P (frame) ? MIN_SAFE_WINDOW_HEIGHT - 1
2987           : (! FRAME_HAS_MINIBUF_P (frame)) ? MIN_SAFE_WINDOW_HEIGHT
2988           : 2 * MIN_SAFE_WINDOW_HEIGHT - 1);
2989 }
2990
2991 /* Return non-zero if both frame sizes are less than or equal to
2992    minimal allowed values. ROWS and COLS are in characters */
2993 int
2994 frame_size_valid_p (struct frame *frame, int rows, int cols)
2995 {
2996   return (rows >= frame_min_height (frame)
2997           && cols >= MIN_SAFE_WINDOW_WIDTH);
2998 }
2999
3000 /* Return non-zero if both frame sizes are less than or equal to
3001    minimal allowed values. WIDTH and HEIGHT are in pixels */
3002 int
3003 frame_pixsize_valid_p (struct frame *frame, int width, int height)
3004 {
3005   int rows, cols;
3006   pixel_to_real_char_size (frame, width, height, &cols, &rows);
3007   return frame_size_valid_p (frame, rows, cols);
3008 }
3009
3010 /* If *ROWS or *COLS are too small a size for FRAME, set them to the
3011    minimum allowable size.  */
3012 void
3013 check_frame_size (struct frame *frame, int *rows, int *cols)
3014 {
3015   int min_height = frame_min_height (frame);
3016
3017   if (*rows < min_height)
3018     *rows = min_height;
3019   if (*cols  < MIN_SAFE_WINDOW_WIDTH)
3020     *cols = MIN_SAFE_WINDOW_WIDTH;
3021 }
3022
3023 /* Normally the window is deleted if it gets too small.
3024    nodelete nonzero means do not do this.
3025    (The caller should check later and do so if appropriate)  */
3026 static void
3027 set_window_pixsize (Lisp_Object window, int new_pixsize, int nodelete,
3028                     int set_height)
3029 {
3030   struct window *w = XWINDOW (window);
3031   struct frame *f = XFRAME (w->frame);
3032   struct window *c;
3033   int old_pixsize = (set_height ? WINDOW_HEIGHT (w) : WINDOW_WIDTH (w));
3034   Lisp_Object child, minor_kid, major_kid;
3035   int minsize;
3036   int line_size;
3037   int defheight, defwidth;
3038
3039   /* #### This is very likely incorrect and instead the char_to_pixel_
3040      functions should be called. */
3041   default_face_height_and_width (window, &defheight, &defwidth);
3042   line_size = (set_height ? defheight : defwidth);
3043
3044   check_min_window_sizes ();
3045
3046   minsize = (set_height ? window_min_height : window_min_width);
3047   minsize *= line_size;
3048
3049   if (!nodelete
3050       && !TOP_LEVEL_WINDOW_P (w)
3051       && new_pixsize < minsize)
3052     {
3053       Fdelete_window (window, Qnil);
3054       return;
3055     }
3056
3057   SET_LAST_MODIFIED (w, 0);
3058   SET_LAST_FACECHANGE (w);
3059   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);     /* multiple windows affected */
3060   if (set_height)
3061     {
3062       WINDOW_HEIGHT (w) = new_pixsize;
3063       major_kid = w->vchild;
3064       minor_kid = w->hchild;
3065     }
3066   else
3067     {
3068       WINDOW_WIDTH (w) = new_pixsize;
3069       major_kid = w->hchild;
3070       minor_kid = w->vchild;
3071     }
3072
3073   if (!NILP (minor_kid))
3074     {
3075       for (child = minor_kid; !NILP (child); child = XWINDOW (child)->next)
3076         {
3077           if (set_height)
3078             WINDOW_TOP (XWINDOW (child)) = WINDOW_TOP (w);
3079           else
3080             WINDOW_LEFT (XWINDOW (child)) = WINDOW_LEFT (w);
3081
3082           set_window_pixsize (child, new_pixsize, nodelete, set_height);
3083         }
3084     }
3085   else if (!NILP (major_kid))
3086     {
3087       int last_pos, last_old_pos, pos, old_pos, first;
3088       int pixel_adj_left = new_pixsize - old_pixsize;
3089       int div_val = old_pixsize << 1;
3090
3091       /*
3092        * Previously we bailed out here if there was no size change.
3093        * (pixel_adj_left == 0) But this broke toolbar updates.  If a
3094        * toolbar appears or disappears, windows may not change size,
3095        * but their top and left coordinates need to be updated.
3096        *
3097        * So we don't bail until after the loop below.
3098        */
3099
3100       last_pos = first = (set_height ? WINDOW_TOP (w) : WINDOW_LEFT (w));
3101       last_old_pos = 0;
3102
3103       for (child = major_kid; !NILP (child); child = c->next)
3104         {
3105           c = XWINDOW (child);
3106
3107           if (set_height)
3108             {
3109               old_pos = last_old_pos + WINDOW_HEIGHT (c);
3110               WINDOW_TOP (c) = last_pos;
3111             }
3112           else
3113             {
3114               old_pos = last_old_pos + WINDOW_WIDTH (c);
3115               WINDOW_LEFT (c) = last_pos;
3116             }
3117
3118           pos = (((old_pos * new_pixsize) << 1) + old_pixsize) / div_val;
3119           /* All but the last window should have a height which is
3120              a multiple of the default line height. */
3121           if (!NILP (c->next))
3122             pos = (pos / line_size) * line_size;
3123
3124           /* Avoid confusion: don't delete child if it becomes too small */
3125           set_window_pixsize (child, pos + first - last_pos, 1, set_height);
3126
3127           last_pos = pos + first;
3128           last_old_pos = old_pos;
3129         }
3130
3131       /* Sometimes we may get called with our old size.  In that case
3132          we don't need to do anything else. */
3133       if (!pixel_adj_left)
3134         return;
3135
3136       /* Now delete any children that became too small.  */
3137       if (!nodelete)
3138         for (child = major_kid; !NILP (child); child = XWINDOW (child)->next)
3139           {
3140             if (set_height)
3141               set_window_pixheight (child, WINDOW_HEIGHT (XWINDOW (child)), 0);
3142             else
3143               set_window_pixwidth (child, WINDOW_WIDTH (XWINDOW (child)), 0);
3144           }
3145     }
3146 }
3147
3148 /* Set the height of WINDOW and all its inferiors.  */
3149 void
3150 set_window_pixheight (Lisp_Object window, int new_pixheight, int nodelete)
3151 {
3152   set_window_pixsize (window, new_pixheight, nodelete, 1);
3153 }
3154
3155 /* Recursively set width of WINDOW and its inferiors. */
3156 void
3157 set_window_pixwidth (Lisp_Object window, int new_pixwidth, int nodelete)
3158 {
3159   set_window_pixsize (window, new_pixwidth, nodelete, 0);
3160 }
3161
3162 \f
3163 static int window_select_count;
3164
3165 DEFUN ("set-window-buffer", Fset_window_buffer, 2, 3, 0, /*
3166 Make WINDOW display BUFFER as its contents.
3167 BUFFER can be a buffer or buffer name.
3168
3169 With non-nil optional argument `norecord', do not modify the
3170 global or per-frame buffer ordering.
3171 */
3172        (window, buffer, norecord))
3173 {
3174   Lisp_Object tem;
3175   struct window *w = decode_window (window);
3176
3177   buffer = Fget_buffer (buffer);
3178   CHECK_BUFFER (buffer);
3179
3180   if (!BUFFER_LIVE_P (XBUFFER (buffer)))
3181     error ("Attempt to display deleted buffer");
3182
3183   tem = w->buffer;
3184   if (NILP (tem))
3185     error ("Window is deleted");
3186
3187   /* While this seems like a logical thing to do, it causes problems
3188      because of saved window configurations.  It is possible for a
3189      buffer to get restored into a window in which it is already being
3190      displayed, but start and point are actually at completely
3191      different locations.  So we let this function complete fully and
3192      it will then make sure redisplay correctly updates things.
3193
3194      #### This is a kludge.  The correct approach is not to do this
3195      but to fix set-window-configuration. */
3196 #if 0
3197   else if (EQ (tem, buffer))
3198     return Qnil;
3199 #endif
3200   else if (! EQ (tem, Qt))      /* w->buffer is t when the window
3201                                    is first being set up.  */
3202     {
3203       if (!NILP (w->dedicated) && !EQ (tem, buffer))
3204         error ("Window is dedicated to buffer %s",
3205                XSTRING_DATA (XBUFFER (tem)->name));
3206
3207       unshow_buffer (w);
3208     }
3209
3210   w->buffer = buffer;
3211   w->window_end_pos[CURRENT_DISP] = 0;
3212   w->hscroll = 0;
3213   w->modeline_hscroll = 0;
3214   Fset_marker (w->pointm[CURRENT_DISP],
3215                make_int (BUF_PT (XBUFFER (buffer))),
3216                buffer);
3217   set_marker_restricted (w->start[CURRENT_DISP],
3218                          make_int (XBUFFER (buffer)->last_window_start),
3219                          buffer);
3220   Fset_marker (w->sb_point, w->start[CURRENT_DISP], buffer);
3221   /* set start_at_line_beg correctly. GE */
3222   w->start_at_line_beg = beginning_of_line_p (XBUFFER (buffer),
3223                                               marker_position (w->start[CURRENT_DISP]));
3224   w->force_start = 0;           /* Lucid fix */
3225   SET_LAST_MODIFIED (w, 1);
3226   SET_LAST_FACECHANGE (w);
3227   MARK_WINDOWS_CHANGED (w);
3228   recompute_all_cached_specifiers_in_window (w);
3229   if (EQ (window, Fselected_window (Qnil)))
3230     {
3231       if (NILP (norecord))
3232         Frecord_buffer (buffer);
3233
3234       Fset_buffer (buffer);
3235     }
3236   return Qnil;
3237 }
3238
3239 DEFUN ("select-window", Fselect_window, 1, 2, 0, /*
3240 Select WINDOW.  Most editing will apply to WINDOW's buffer.
3241 The main editor command loop selects the buffer of the selected window
3242 before each command.
3243
3244 With non-nil optional argument `norecord', do not modify the
3245 global or per-frame buffer ordering.
3246 */
3247        (window, norecord))
3248 {
3249   struct window *w;
3250   Lisp_Object old_selected_window = Fselected_window (Qnil);
3251
3252   CHECK_LIVE_WINDOW (window);
3253   w = XWINDOW (window);
3254
3255   /* we have already caught dead-window errors */
3256   if (!NILP (w->hchild) || !NILP (w->vchild))
3257     error ("Trying to select non-leaf window");
3258
3259   w->use_time = make_int (++window_select_count);
3260   if (EQ (window, old_selected_window))
3261     return window;
3262
3263   /* deselect the old window, if it exists (it might not exist if
3264      the selected device has no frames, which occurs at startup) */
3265   if (!NILP (old_selected_window))
3266     {
3267       struct window *ow = XWINDOW (old_selected_window);
3268
3269       Fset_marker (ow->pointm[CURRENT_DISP],
3270                    make_int (BUF_PT (XBUFFER (ow->buffer))),
3271                    ow->buffer);
3272
3273       MARK_WINDOWS_CHANGED (ow);
3274     }
3275
3276   /* now select the window's frame */
3277   set_frame_selected_window (XFRAME (WINDOW_FRAME (w)), window);
3278
3279   select_frame_1 (WINDOW_FRAME (w));
3280
3281   /* also select the window's buffer */
3282   if (NILP (norecord))
3283     Frecord_buffer (w->buffer);
3284   Fset_buffer (w->buffer);
3285
3286   /* Go to the point recorded in the window.
3287      This is important when the buffer is in more
3288      than one window.  It also matters when
3289      redisplay_window has altered point after scrolling,
3290      because it makes the change only in the window.  */
3291   {
3292     Bufpos new_point = marker_position (w->pointm[CURRENT_DISP]);
3293     if (new_point < BUF_BEGV (current_buffer))
3294       new_point = BUF_BEGV (current_buffer);
3295     else if (new_point > BUF_ZV (current_buffer))
3296       new_point = BUF_ZV (current_buffer);
3297
3298     BUF_SET_PT (current_buffer, new_point);
3299   }
3300
3301   MARK_WINDOWS_CHANGED (w);
3302
3303   return window;
3304 }
3305
3306 Lisp_Object
3307 display_buffer (Lisp_Object buffer, Lisp_Object not_this_window_p,
3308                 Lisp_Object override_frame)
3309 {
3310   return call3 (Qdisplay_buffer, buffer, not_this_window_p, override_frame);
3311 }
3312
3313 void
3314 temp_output_buffer_show (Lisp_Object buf, Lisp_Object same_frame)
3315 {
3316   /* This function can GC */
3317   Lisp_Object window;
3318   struct window *w;
3319   struct buffer *b = XBUFFER (buf);
3320
3321   BUF_SAVE_MODIFF (XBUFFER (buf)) = BUF_MODIFF (b);
3322   widen_buffer (b, 0);
3323   BUF_SET_PT (b, BUF_BEG (b));
3324
3325   if (!NILP (Vtemp_buffer_show_function))
3326     call1 (Vtemp_buffer_show_function, buf);
3327   else
3328     {
3329       window = display_buffer (buf, Qnil, same_frame);
3330
3331       if (!EQ (XWINDOW (window)->frame, Fselected_frame (Qnil)))
3332         Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
3333
3334       Vminibuffer_scroll_window = window;
3335       w = XWINDOW (window);
3336       w->hscroll = 0;
3337       w->modeline_hscroll = 0;
3338       set_marker_restricted (w->start[CURRENT_DISP], make_int (1), buf);
3339       set_marker_restricted (w->pointm[CURRENT_DISP], make_int (1), buf);
3340       set_marker_restricted (w->sb_point, make_int (1), buf);
3341
3342       /* Run temp-buffer-show-hook, with the chosen window selected.  */
3343       if (!preparing_for_armageddon)
3344         {
3345           Lisp_Object tem;
3346           tem = Fboundp (Qtemp_buffer_show_hook);
3347           if (!NILP (tem))
3348             {
3349               tem = Fsymbol_value (Qtemp_buffer_show_hook);
3350               if (!NILP (tem))
3351                 {
3352                   int count = specpdl_depth ();
3353
3354                   /* Select the window that was chosen, for running
3355                      the hook.  */
3356                   record_unwind_protect (save_window_excursion_unwind,
3357                                          Fcurrent_window_configuration (Qnil));
3358
3359                   Fselect_window (window, Qnil);
3360                   run_hook (Qtemp_buffer_show_hook);
3361                   unbind_to (count, Qnil);
3362                 }
3363             }
3364         }
3365     }
3366 }
3367 \f
3368 static void
3369 make_dummy_parent (Lisp_Object window)
3370 {
3371   Lisp_Object new;
3372   struct window *o = XWINDOW (window);
3373   struct window *p = alloc_lcrecord_type (struct window, &lrecord_window);
3374
3375   XSETWINDOW (new, p);
3376   copy_lcrecord (p, o);
3377
3378   /* Don't copy the pointers to the line start cache or the face
3379      instances. */
3380   p->line_start_cache = Dynarr_new (line_start_cache);
3381   p->face_cachels     = Dynarr_new (face_cachel);
3382   p->glyph_cachels    = Dynarr_new (glyph_cachel);
3383
3384   /* Put new into window structure in place of window */
3385   replace_window (window, new);
3386
3387   o->next = Qnil;
3388   o->prev = Qnil;
3389   o->vchild = Qnil;
3390   o->hchild = Qnil;
3391   o->parent = new;
3392
3393   p->start[CURRENT_DISP] = Qnil;
3394   p->start[DESIRED_DISP] = Qnil;
3395   p->start[CMOTION_DISP] = Qnil;
3396   p->pointm[CURRENT_DISP] = Qnil;
3397   p->pointm[DESIRED_DISP] = Qnil;
3398   p->pointm[CMOTION_DISP] = Qnil;
3399   p->sb_point = Qnil;
3400   p->buffer = Qnil;
3401 }
3402
3403 DEFUN ("split-window", Fsplit_window, 0, 3, "", /*
3404 Split WINDOW, putting SIZE lines in the first of the pair.
3405 WINDOW defaults to selected one and SIZE to half its size.
3406 If optional third arg HOR-FLAG is non-nil, split side by side
3407 and put SIZE columns in the first of the pair.
3408 */
3409        (window, chsize, horflag))
3410 {
3411   Lisp_Object new;
3412   struct window *o, *p;
3413   struct frame *f;
3414   int size;
3415   int psize;
3416
3417   if (NILP (window))
3418     window = Fselected_window (Qnil);
3419   else
3420     CHECK_LIVE_WINDOW (window);
3421
3422   o = XWINDOW (window);
3423   f = XFRAME (WINDOW_FRAME (o));
3424
3425   if (NILP (chsize))
3426     {
3427       if (!NILP (horflag))
3428         /* In the new scheme, we are symmetric with respect to separators
3429            so there is no need to do weird things here. */
3430         {
3431           psize = WINDOW_WIDTH (o) >> 1;
3432           size = window_pixel_width_to_char_width (o, psize, 0);
3433         }
3434       else
3435         {
3436           psize = WINDOW_HEIGHT (o) >> 1;
3437           size = window_pixel_height_to_char_height (o, psize, 1);
3438         }
3439     }
3440   else
3441     {
3442       CHECK_INT (chsize);
3443       size = XINT (chsize);
3444       if (!NILP (horflag))
3445         psize = window_char_width_to_pixel_width (o, size, 0);
3446       else
3447         psize = window_char_height_to_pixel_height (o, size, 1);
3448     }
3449
3450   if (MINI_WINDOW_P (o))
3451     error ("Attempt to split minibuffer window");
3452   else if (FRAME_NO_SPLIT_P (XFRAME (WINDOW_FRAME (o))))
3453     error ("Attempt to split unsplittable frame");
3454
3455   check_min_window_sizes ();
3456
3457   if (NILP (horflag))
3458     {
3459       if (size < window_min_height)
3460         error ("Window height %d too small (after splitting)", size);
3461       if (size + window_min_height > window_char_height (o, 1))
3462         error ("Window height %d too small (after splitting)",
3463                window_char_height (o, 1) - size);
3464       if (NILP (o->parent)
3465           || NILP (XWINDOW (o->parent)->vchild))
3466         {
3467           make_dummy_parent (window);
3468           reset_face_cachels (XWINDOW (window));
3469           new = o->parent;
3470           XWINDOW (new)->vchild = window;
3471           XFRAME (o->frame)->mirror_dirty = 1;
3472         }
3473     }
3474   else
3475     {
3476       if (size < window_min_width)
3477         error ("Window width %d too small (after splitting)", size);
3478       if (size + window_min_width > window_char_width (o, 0))
3479         error ("Window width %d too small (after splitting)",
3480                window_char_width (o, 0) - size);
3481       if (NILP (o->parent)
3482           || NILP (XWINDOW (o->parent)->hchild))
3483         {
3484           make_dummy_parent (window);
3485           reset_face_cachels (XWINDOW (window));
3486           new = o->parent;
3487           XWINDOW (new)->hchild = window;
3488           XFRAME (o->frame)->mirror_dirty = 1;
3489         }
3490     }
3491
3492   /* Now we know that window's parent is a vertical combination
3493      if we are dividing vertically, or a horizontal combination
3494      if we are making side-by-side windows */
3495
3496   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
3497   new = allocate_window ();
3498   p = XWINDOW (new);
3499
3500   p->frame = o->frame;
3501   p->next = o->next;
3502   if (!NILP (p->next))
3503     XWINDOW (p->next)->prev = new;
3504   p->prev = window;
3505   o->next = new;
3506   p->parent = o->parent;
3507   p->buffer = Qt;
3508
3509   reset_face_cachels (p);
3510   reset_glyph_cachels (p);
3511
3512
3513   /* Apportion the available frame space among the two new windows */
3514
3515   if (!NILP (horflag))
3516     {
3517       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o);
3518       WINDOW_TOP (p) = WINDOW_TOP (o);
3519       WINDOW_WIDTH (p) = WINDOW_WIDTH (o) - psize;
3520       WINDOW_WIDTH (o) = psize;
3521       WINDOW_LEFT (p) = WINDOW_LEFT (o) + psize;
3522     }
3523   else
3524     {
3525       WINDOW_LEFT (p) = WINDOW_LEFT (o);
3526       WINDOW_WIDTH (p) = WINDOW_WIDTH (o);
3527       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o) - psize;
3528       WINDOW_HEIGHT (o) = psize;
3529       WINDOW_TOP (p) = WINDOW_TOP (o) + psize;
3530     }
3531
3532   XFRAME (p->frame)->mirror_dirty = 1;
3533   /* do this last (after the window is completely initialized and
3534      the mirror-dirty flag is set) so that specifier recomputation
3535      caused as a result of this will work properly and not abort. */
3536   Fset_window_buffer (new, o->buffer, Qt);
3537   return new;
3538 }
3539 \f
3540
3541 DEFUN ("enlarge-window", Fenlarge_window, 1, 3, "_p", /*
3542 Make the selected window N lines bigger.
3543 From program, optional second arg SIDE non-nil means grow sideways N columns,
3544 and optional third arg WINDOW specifies the window to change instead of the
3545 selected window.
3546 */
3547        (n, side, window))
3548 {
3549   struct window *w = decode_window (window);
3550   CHECK_INT (n);
3551   change_window_height (w, XINT (n), !NILP (side), /* inpixels */ 0);
3552   return Qnil;
3553 }
3554
3555 DEFUN ("enlarge-window-pixels", Fenlarge_window_pixels, 1, 3, "_p", /*
3556 Make the selected window N pixels bigger.
3557 From program, optional second arg SIDE non-nil means grow sideways N pixels,
3558 and optional third arg WINDOW specifies the window to change instead of the
3559 selected window.
3560 */
3561        (n, side, window))
3562 {
3563   struct window *w = decode_window (window);
3564   CHECK_INT (n);
3565   change_window_height (w, XINT (n), !NILP (side), /* inpixels */ 1);
3566   return Qnil;
3567 }
3568
3569 DEFUN ("shrink-window", Fshrink_window, 1, 3, "_p", /*
3570 Make the selected window N lines smaller.
3571 From program, optional second arg SIDE non-nil means shrink sideways N columns,
3572 and optional third arg WINDOW specifies the window to change instead of the
3573 selected window.
3574 */
3575        (n, side, window))
3576 {
3577   CHECK_INT (n);
3578   change_window_height (decode_window (window), -XINT (n), !NILP (side),
3579                         /* inpixels */ 0);
3580   return Qnil;
3581 }
3582
3583 DEFUN ("shrink-window-pixels", Fshrink_window_pixels, 1, 3, "_p", /*
3584 Make the selected window N pixels smaller.
3585 From program, optional second arg SIDE non-nil means shrink sideways N pixels,
3586 and optional third arg WINDOW specifies the window to change instead of the
3587 selected window.
3588 */
3589        (n, side, window))
3590 {
3591   CHECK_INT (n);
3592   change_window_height (decode_window (window), -XINT (n), !NILP (side),
3593                         /* inpixels */ 1);
3594   return Qnil;
3595 }
3596
3597 static int
3598 window_pixel_height (Lisp_Object window)
3599 {
3600   return WINDOW_HEIGHT (XWINDOW (window));
3601 }
3602
3603 static int
3604 window_pixel_height_to_char_height (struct window *w, int pixel_height,
3605                                     int include_gutters_p)
3606 {
3607   int avail_height;
3608   int defheight, defwidth;
3609   int char_height;
3610   Lisp_Object window;
3611
3612   XSETWINDOW (window, w);
3613
3614   avail_height = (pixel_height -
3615                   (include_gutters_p ? 0 :
3616                    window_top_gutter_height (w) +
3617                    window_bottom_gutter_height (w)));
3618
3619   default_face_height_and_width (window, &defheight, &defwidth);
3620
3621   char_height = avail_height / defheight;
3622
3623   /* It's the calling function's responsibility to check these values
3624      and make sure they're not out of range.
3625
3626      #### We need to go through the calling functions and actually
3627      do this. */
3628   return max (0, char_height);
3629 }
3630
3631 static int
3632 window_char_height_to_pixel_height (struct window *w, int char_height,
3633                                     int include_gutters_p)
3634 {
3635   int avail_height;
3636   int defheight, defwidth;
3637   int pixel_height;
3638
3639   Lisp_Object window;
3640
3641   XSETWINDOW (window, w);
3642
3643   default_face_height_and_width (window, &defheight, &defwidth);
3644
3645   avail_height = char_height * defheight;
3646   pixel_height = (avail_height +
3647                   (include_gutters_p ? 0 :
3648                    window_top_gutter_height (w) +
3649                    window_bottom_gutter_height (w)));
3650
3651   /* It's the calling function's responsibility to check these values
3652      and make sure they're not out of range.
3653
3654      #### We need to go through the calling functions and actually
3655      do this. */
3656   return max (0, pixel_height);
3657 }
3658
3659 /* Return number of default lines of text can fit in the window W.
3660    If INCLUDE_GUTTERS_P is 1, include "gutter" space (modeline plus
3661    horizontal scrollbar) in the space that is used for the calculation.
3662    */
3663 int
3664 window_char_height (struct window *w, int include_gutters_p)
3665 {
3666   return window_pixel_height_to_char_height (w, WINDOW_HEIGHT (w),
3667                                              include_gutters_p);
3668 }
3669
3670 /*
3671  * Return number of lines currently displayed in window w.  If
3672  * end-of-buffer is displayed then the area below end-of-buffer is assume
3673  * to be blank lines of default height.
3674  * Does not include the modeline.
3675  */
3676 int
3677 window_displayed_height (struct window *w)
3678 {
3679   struct buffer *b = XBUFFER (w->buffer);
3680   display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
3681   int num_lines;
3682   Charcount end_pos = (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b)
3683                        ? -1
3684                        : w->window_end_pos[CURRENT_DISP]);
3685
3686   if (!Dynarr_length (dla))
3687     return window_char_height (w, 0);
3688
3689   num_lines = Dynarr_length (dla);
3690
3691   /* #### Document and assert somewhere that w->window_end_pos == -1
3692      indicates that end-of-buffer is being displayed. */
3693   if (end_pos == -1)
3694     {
3695       struct display_line *dl = Dynarr_atp (dla, 0);
3696       int ypos1 = dl->ypos + dl->descent;
3697       int ypos2 = WINDOW_TEXT_BOTTOM (w);
3698       Lisp_Object window;
3699       int defheight, defwidth;
3700
3701       XSETWINDOW (window, w);
3702
3703       if (dl->modeline)
3704         {
3705           num_lines--;
3706
3707           if (Dynarr_length (dla) == 1)
3708             ypos1 = WINDOW_TEXT_TOP (w);
3709           else
3710             {
3711               dl = Dynarr_atp (dla, Dynarr_length (dla) - 1);
3712               /* If this line is clipped then we know that there is no
3713                  blank room between eob and the modeline.  If we are
3714                  scrolling on clipped lines just know off the clipped
3715                  line and return .*/
3716               if (scroll_on_clipped_lines && dl->clip)
3717                 return num_lines - 1;
3718               ypos1 = dl->ypos + dl->descent - dl->clip;
3719             }
3720         }
3721
3722       default_face_height_and_width (window, &defheight, &defwidth);
3723       /* #### This probably needs to know about the clipping area once a
3724          final definition is decided on. */
3725       num_lines += ((ypos2 - ypos1) / defheight);
3726     }
3727   else
3728     {
3729       if (num_lines > 1 && Dynarr_atp (dla, 0)->modeline)
3730         num_lines--;
3731
3732       if (scroll_on_clipped_lines
3733           && Dynarr_atp (dla, Dynarr_length (dla) - 1)->clip)
3734         num_lines--;
3735     }
3736
3737   return num_lines;
3738 }
3739
3740 static int
3741 window_pixel_width (Lisp_Object window)
3742 {
3743   return WINDOW_WIDTH (XWINDOW (window));
3744 }
3745
3746 static int
3747 window_pixel_width_to_char_width (struct window *w, int pixel_width,
3748                                   int include_margins_p)
3749 {
3750   int avail_width;
3751   int char_width;
3752   int defheight, defwidth;
3753   Lisp_Object window;
3754
3755   XSETWINDOW (window, w);
3756
3757   avail_width = (pixel_width -
3758                  window_left_gutter_width (w, 0) -
3759                  window_right_gutter_width (w, 0) -
3760                  (include_margins_p ? 0 : window_left_margin_width (w)) -
3761                  (include_margins_p ? 0 : window_right_margin_width (w)));
3762
3763   default_face_height_and_width (window, &defheight, &defwidth);
3764
3765   char_width = (avail_width / defwidth);
3766
3767   /* It's the calling function's responsibility to check these values
3768      and make sure they're not out of range.
3769
3770      #### We need to go through the calling functions and actually
3771      do this. */
3772   return max (0, char_width);
3773 }
3774
3775 static int
3776 window_char_width_to_pixel_width (struct window *w, int char_width,
3777                                   int include_margins_p)
3778 {
3779   int avail_width;
3780   int pixel_width;
3781   int defheight, defwidth;
3782   Lisp_Object window;
3783
3784   XSETWINDOW (window, w);
3785
3786   default_face_height_and_width (window, &defheight, &defwidth);
3787
3788   avail_width = char_width * defwidth;
3789   pixel_width = (avail_width +
3790                  window_left_gutter_width (w, 0) +
3791                  window_right_gutter_width (w, 0) +
3792                  (include_margins_p ? 0 : window_left_margin_width (w)) +
3793                  (include_margins_p ? 0 : window_right_margin_width (w)));
3794
3795   /* It's the calling function's responsibility to check these values
3796      and make sure they're not out of range.
3797
3798      #### We need to go through the calling functions and actually
3799      do this. */
3800   return max (0, pixel_width);
3801 }
3802
3803 /* This returns the usable space which doesn't include space needed by
3804    scrollbars or divider lines. */
3805 int
3806 window_char_width (struct window *w, int include_margins_p)
3807 {
3808   return window_pixel_width_to_char_width (w, WINDOW_WIDTH (w),
3809                                            include_margins_p);
3810 }
3811
3812 #define MINSIZE(w)                                              \
3813   (widthflag                                                    \
3814    ? window_min_width * defwidth                                \
3815    : (defheight * (MINI_WINDOW_P (XWINDOW (w)) ? 1 : window_min_height)))
3816
3817 #define CURBEG(w) \
3818   *(widthflag ? (int *) &WINDOW_LEFT (w) : (int *) &WINDOW_TOP (w))
3819
3820 #define CURSIZE(w) \
3821   *(widthflag ? (int *) &WINDOW_WIDTH (w) : (int *) &WINDOW_HEIGHT (w))
3822
3823 #define CURCHARSIZE(w) \
3824   (widthflag ? window_char_width (w, 0) : window_char_height (w, 1))
3825
3826 #define MINCHARSIZE(window) \
3827   (widthflag ? window_min_width : MINI_WINDOW_P (XWINDOW (window)) \
3828    ? 1 : window_min_height)
3829
3830 /* Unlike set_window_pixheight, this function
3831    also changes the heights of the siblings so as to
3832    keep everything consistent. */
3833
3834 static void
3835 change_window_height (struct window *win, int delta, int widthflag,
3836                       int inpixels)
3837 {
3838   Lisp_Object parent;
3839   Lisp_Object window;
3840   struct window *w;
3841   struct frame *f;
3842   int *sizep;
3843   int (*sizefun) (Lisp_Object) = (widthflag
3844                                   ? window_pixel_width
3845                                   : window_pixel_height);
3846   void (*setsizefun) (Lisp_Object, int, int) = (widthflag
3847                                                 ? set_window_pixwidth
3848                                                 : set_window_pixheight);
3849   int dim;
3850   int defheight, defwidth;
3851
3852   if (delta == 0)
3853     return;
3854
3855   check_min_window_sizes ();
3856
3857   XSETWINDOW (window, win);
3858   f = XFRAME (win->frame);
3859   if (EQ (window, FRAME_ROOT_WINDOW (f)))
3860     error ("Won't change only window");
3861
3862   /* #### This is very likely incorrect and instead the char_to_pixel_
3863      functions should be called. */
3864   default_face_height_and_width (window, &defheight, &defwidth);
3865
3866   while (1)
3867     {
3868       w = XWINDOW (window);
3869       parent = w->parent;
3870       if (NILP (parent))
3871         {
3872           if (widthflag)
3873             error ("No other window to side of this one");
3874           break;
3875         }
3876       if (widthflag
3877           ? !NILP (XWINDOW (parent)->hchild)
3878           : !NILP (XWINDOW (parent)->vchild))
3879         break;
3880       window = parent;
3881     }
3882
3883   sizep = &CURSIZE (w);
3884   dim = CURCHARSIZE (w);
3885
3886   if ((inpixels  && (*sizep + delta) < MINSIZE (window)) ||
3887       (!inpixels && (dim + delta) < MINCHARSIZE (window)))
3888     {
3889       if (MINI_WINDOW_P (XWINDOW (window)))
3890         return;
3891       else if (!NILP (parent))
3892         {
3893           Fdelete_window (window, Qnil);
3894           return;
3895         }
3896     }
3897
3898   if (!inpixels)
3899     delta *= (widthflag ? defwidth : defheight);
3900
3901   {
3902     int maxdelta;
3903
3904     maxdelta = ((!NILP (parent))
3905                 ? (*sizefun) (parent) - *sizep
3906                 : ((!NILP (w->next))
3907                    ? (*sizefun) (w->next) - MINSIZE (w->next)
3908                    : ((!NILP (w->prev))
3909                       ? (*sizefun) (w->prev) - MINSIZE (w->prev)
3910                       /* This is a frame with only one window,
3911                          a minibuffer-only or a minibufferless frame.  */
3912                       : (delta = 0))));
3913
3914     if (delta > maxdelta)
3915       /* This case traps trying to make the minibuffer
3916          the full frame, or make the only window aside from the
3917          minibuffer the full frame.  */
3918       delta = maxdelta;
3919
3920     if (delta == 0)
3921       return;
3922
3923 #if 0 /* FSFmacs */
3924     /* #### Chuck: is this correct? */
3925     if (*sizep + delta < MINSIZE (window))
3926       {
3927         Fdelete_window (window);
3928         return;
3929       }
3930 #endif
3931   }
3932
3933   if (!NILP (w->next) &&
3934       (*sizefun) (w->next) - delta >= (int) MINSIZE (w->next))
3935     {
3936       CURBEG (XWINDOW (w->next)) += delta;
3937       (*setsizefun) (w->next, (*sizefun) (w->next) - delta, 0);
3938       (*setsizefun) (window, *sizep + delta, 0);
3939     }
3940   else if (!NILP (w->prev) &&
3941            (*sizefun) (w->prev) - delta >= (int) MINSIZE (w->prev))
3942     {
3943       (*setsizefun) (w->prev, (*sizefun) (w->prev) - delta, 0);
3944       CURBEG (w) -= delta;
3945       (*setsizefun) (window, *sizep + delta, 0);
3946     }
3947   else
3948     {
3949       int delta1;
3950       int opht = (*sizefun) (parent);
3951
3952       /* If trying to grow this window to or beyond size of the parent,
3953          make delta1 so big that, on shrinking back down,
3954          all the siblings end up with less than one line and are deleted.  */
3955       if (opht <= *sizep + delta)
3956         delta1 = opht * opht * 2;
3957       /* Otherwise, make delta1 just right so that if we add delta1
3958          lines to this window and to the parent, and then shrink
3959          the parent back to its original size, the new proportional
3960          size of this window will increase by delta.  */
3961       else
3962         delta1 = (delta * opht * 100) / ((opht - *sizep - delta) * 100);
3963
3964       /* Add delta1 lines or columns to this window, and to the parent,
3965          keeping things consistent while not affecting siblings.  */
3966       CURSIZE (XWINDOW (parent)) = opht + delta1;
3967       (*setsizefun) (window, *sizep + delta1, 0);
3968
3969       /* Squeeze out delta1 lines or columns from our parent,
3970          shrinking this window and siblings proportionately.
3971          This brings parent back to correct size.
3972          Delta1 was calculated so this makes this window the desired size,
3973          taking it all out of the siblings.  */
3974       (*setsizefun) (parent, opht, 0);
3975     }
3976
3977   SET_LAST_MODIFIED (w, 0);
3978   SET_LAST_FACECHANGE (w);
3979   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
3980   /* overkill maybe, but better to be correct */
3981   MARK_FRAME_GUTTERS_CHANGED (f);
3982 }
3983 #undef MINSIZE
3984 #undef CURBEG
3985 #undef CURSIZE
3986 #undef CURCHARSIZE
3987 #undef MINCHARSIZE
3988
3989 \f
3990
3991 /* Scroll contents of window WINDOW up N lines. If N < (top line height /
3992    average line height) then we just adjust the top clip.  */
3993 void
3994 window_scroll (Lisp_Object window, Lisp_Object n, int direction,
3995                Error_behavior errb)
3996 {
3997   struct window *w = XWINDOW (window);
3998   struct buffer *b = XBUFFER (w->buffer);
3999   int selected = EQ (window, Fselected_window (Qnil));
4000   int value = 0;
4001   Lisp_Object point, tem;
4002   display_line_dynarr *dla;
4003   int fheight, fwidth, modeline = 0;
4004   struct display_line* dl;
4005
4006   if (selected)
4007     point = make_int (BUF_PT (b));
4008   else
4009     {
4010       Bufpos pos = marker_position (w->pointm[CURRENT_DISP]);
4011
4012       if (pos < BUF_BEGV (b))
4013         pos = BUF_BEGV (b);
4014       else if (pos > BUF_ZV (b))
4015         pos = BUF_ZV (b);
4016
4017       point = make_int (pos);
4018     }
4019
4020   /* Always set force_start so that redisplay_window will run
4021      the window-scroll-functions.  */
4022   w->force_start = 1;
4023
4024   /* #### When the fuck does this happen?  I'm so glad that history has
4025      completely documented the behavior of the scrolling functions under
4026      all circumstances. */
4027   tem = Fpos_visible_in_window_p (point, window);
4028   if (NILP (tem))
4029     {
4030       Fvertical_motion (make_int (-window_char_height (w, 0) / 2),
4031                         window, Qnil);
4032       Fset_marker (w->start[CURRENT_DISP], point, w->buffer);
4033       w->start_at_line_beg = beginning_of_line_p (b, XINT (point));
4034       WINDOW_TEXT_TOP_CLIP (w) = 0;
4035       MARK_WINDOWS_CHANGED (w);
4036     }
4037
4038   if (!NILP (n))
4039     {
4040       if (EQ (n, Qminus))
4041         direction *= -1;
4042       else
4043         {
4044           n = Fprefix_numeric_value (n);
4045           value = XINT (n) * direction;
4046
4047           if (!value)
4048             return;     /* someone just made a pointless call */
4049         }
4050     }
4051
4052   /* If the user didn't specify how far to scroll then we have to figure it
4053      out by ourselves. */
4054   if (NILP (n) || EQ (n, Qminus))
4055     {
4056       /* Going forwards is easy.  If that is what we are doing then just
4057          set value and the section which handles the user specifying a
4058          positive value will work. */
4059       if (direction == 1)
4060         {
4061           value = window_displayed_height (w) - next_screen_context_lines;
4062           value = (value < 1 ? 1 : value);
4063         }
4064
4065       /* Going backwards is hard.  We can't use the same loop used if the
4066          user specified a negative value because we care about
4067          next_screen_context_lines.  In a variable height world you don't
4068          know how many lines above you can actually be displayed and still
4069          have the context lines appear.  So we leave value set to 0 and add
4070          a separate section to deal with this. */
4071
4072     }
4073
4074   if (direction == 1 && !value)
4075     {
4076       return;
4077     }
4078
4079   /* Determine parameters to test for partial line scrolling with. */
4080   dla = window_display_lines (w, CURRENT_DISP);
4081
4082   if (INTP (Vwindow_pixel_scroll_increment))
4083     fheight = XINT (Vwindow_pixel_scroll_increment);
4084   else if (!NILP (Vwindow_pixel_scroll_increment))
4085     default_face_height_and_width (window, &fheight, &fwidth);
4086
4087   if (Dynarr_length (dla) >= 1)
4088     modeline = Dynarr_atp (dla, 0)->modeline;
4089
4090   dl = Dynarr_atp (dla, modeline);
4091
4092   if (value > 0)
4093     {
4094       /* Go for partial display line scrolling. This just means bumping
4095          the clip by a reasonable amount and redisplaying, everything else
4096          remains unchanged. */
4097       if (!NILP (Vwindow_pixel_scroll_increment)
4098           &&
4099           Dynarr_length (dla) >= (1 + modeline)
4100           &&
4101           (dl->ascent - dl->top_clip) - fheight * value > 0)
4102         {
4103           WINDOW_TEXT_TOP_CLIP (w) += value * fheight;
4104           MARK_WINDOWS_CHANGED (w);
4105         }
4106       else
4107         {
4108           int vtarget;
4109           Bufpos startp, old_start;
4110
4111           if (WINDOW_TEXT_TOP_CLIP (w))
4112             {
4113               WINDOW_TEXT_TOP_CLIP (w) = 0;
4114               MARK_WINDOWS_CHANGED (w);
4115             }
4116
4117           old_start = marker_position (w->start[CURRENT_DISP]);
4118           startp = vmotion (w, old_start, value, &vtarget);
4119
4120           if (vtarget < value &&
4121               (w->window_end_pos[CURRENT_DISP] == -1
4122                || (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b))))
4123             {
4124               maybe_signal_error (Qend_of_buffer, Qnil, Qwindow, errb);
4125               return;
4126             }
4127           else
4128             {
4129               set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4130                                      w->buffer);
4131               w->force_start = 1;
4132               w->start_at_line_beg = beginning_of_line_p (b, startp);
4133               MARK_WINDOWS_CHANGED (w);
4134
4135               if (!point_would_be_visible (w, startp, XINT (point)))
4136                 {
4137                   if (selected)
4138                     BUF_SET_PT (b, startp);
4139                   else
4140                     set_marker_restricted (w->pointm[CURRENT_DISP],
4141                                            make_int (startp),
4142                                            w->buffer);
4143                 }
4144             }
4145         }
4146     }
4147   else if (value < 0)
4148     {
4149       /* Go for partial display line scrolling. This just means bumping
4150          the clip by a reasonable amount and redisplaying, everything else
4151          remains unchanged. */
4152       if (!NILP (Vwindow_pixel_scroll_increment)
4153           &&
4154           Dynarr_length (dla) >= (1 + modeline)
4155           &&
4156           (dl->ascent - dl->top_clip) - fheight * value <
4157           (dl->ascent + dl->descent - dl->clip)
4158           &&
4159           WINDOW_TEXT_TOP_CLIP (w) + value * fheight > 0)
4160         {
4161           WINDOW_TEXT_TOP_CLIP (w) += value * fheight;
4162           MARK_WINDOWS_CHANGED (w);
4163         }
4164       else
4165         {
4166           int vtarget;
4167           Bufpos startp, old_start;
4168
4169           if (WINDOW_TEXT_TOP_CLIP (w))
4170             {
4171               WINDOW_TEXT_TOP_CLIP (w) = 0;
4172               MARK_WINDOWS_CHANGED (w);
4173             }
4174
4175           old_start = marker_position (w->start[CURRENT_DISP]);
4176           startp = vmotion (w, old_start, value, &vtarget);
4177
4178           if (vtarget > value
4179               && marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b))
4180             {
4181               maybe_signal_error (Qbeginning_of_buffer, Qnil, Qwindow, errb);
4182               return;
4183             }
4184           else
4185             {
4186               set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4187                                      w->buffer);
4188               w->force_start = 1;
4189               w->start_at_line_beg = beginning_of_line_p (b, startp);
4190               MARK_WINDOWS_CHANGED (w);
4191
4192               /* #### Scroll back by less than a line. This code was
4193                  originally for scrolling over large pixmaps and it
4194                  loses when a line being *exposed* at the top of the
4195                  window is bigger than the current one. However, for
4196                  pixel based scrolling in general we can guess that
4197                  the line we are going to display is probably the same
4198                  size as the one we are on. In that instance we can
4199                  have a reasonable stab at a suitable top clip. Fixing
4200                  this properly is hard (and probably slow) as we would
4201                  have to call redisplay to figure out the exposed line
4202                  size. */
4203               if (!NILP (Vwindow_pixel_scroll_increment)
4204                   && Dynarr_length (dla) >= (1 + modeline)
4205                   && dl->ascent + fheight * value > 0)
4206                 {
4207                   WINDOW_TEXT_TOP_CLIP (w) = (dl->ascent + fheight * value);
4208                 }
4209
4210               if (!point_would_be_visible (w, startp, XINT (point)))
4211                 {
4212                   Bufpos new_point;
4213
4214                   if (MINI_WINDOW_P (w))
4215                     new_point = startp;
4216                   else
4217                     new_point = start_of_last_line (w, startp);
4218
4219                   if (selected)
4220                     BUF_SET_PT (b, new_point);
4221                   else
4222                     set_marker_restricted (w->pointm[CURRENT_DISP],
4223                                            make_int (new_point),
4224                                            w->buffer);
4225                 }
4226             }
4227         }
4228     }
4229   else  /* value == 0 && direction == -1 */
4230     {
4231       if (WINDOW_TEXT_TOP_CLIP (w))
4232         {
4233           WINDOW_TEXT_TOP_CLIP (w) = 0;
4234           MARK_WINDOWS_CHANGED (w);
4235         }
4236       if (marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b))
4237         {
4238           maybe_signal_error (Qbeginning_of_buffer, Qnil, Qwindow, errb);
4239           return;
4240         }
4241       else
4242         {
4243           int vtarget;
4244           int movement = next_screen_context_lines - 1;
4245           Bufpos old_startp = marker_position (w->start[CURRENT_DISP]);
4246           Bufpos bottom = vmotion (w, old_startp, movement, &vtarget);
4247           Bufpos startp =
4248             start_with_point_on_display_line (w, bottom,
4249                                               -1 - (movement - vtarget));
4250
4251           if (startp >= old_startp)
4252             startp = vmotion (w, old_startp, -1, NULL);
4253
4254           set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4255                                  w->buffer);
4256           w->force_start = 1;
4257           w->start_at_line_beg = beginning_of_line_p (b, startp);
4258           MARK_WINDOWS_CHANGED (w);
4259
4260           if (!point_would_be_visible (w, startp, XINT (point)))
4261             {
4262               Bufpos new_point = start_of_last_line (w, startp);
4263
4264               if (selected)
4265                 BUF_SET_PT (b, new_point);
4266               else
4267                 set_marker_restricted (w->pointm[CURRENT_DISP],
4268                                        make_int (new_point),
4269                                        w->buffer);
4270             }
4271         }
4272     }
4273 }
4274 \f
4275 DEFUN ("scroll-up", Fscroll_up, 0, 1, "_P", /*
4276 Scroll text of current window upward N lines; or near full screen if no arg.
4277 A near full screen is `next-screen-context-lines' less than a full screen.
4278 Negative N means scroll downward.
4279 When calling from a program, supply an integer as argument or nil.
4280 On attempt to scroll past end of buffer, `end-of-buffer' is signaled.
4281 On attempt to scroll past beginning of buffer, `beginning-of-buffer' is
4282 signaled.
4283 */
4284        (n))
4285 {
4286   window_scroll (Fselected_window (Qnil), n, 1, ERROR_ME);
4287   return Qnil;
4288 }
4289
4290 DEFUN ("scroll-down", Fscroll_down, 0, 1, "_P", /*
4291 Scroll text of current window downward N lines; or near full screen if no arg.
4292 A near full screen is `next-screen-context-lines' less than a full screen.
4293 Negative N means scroll upward.
4294 When calling from a program, supply a number as argument or nil.
4295 On attempt to scroll past end of buffer, `end-of-buffer' is signaled.
4296 On attempt to scroll past beginning of buffer, `beginning-of-buffer' is
4297 signaled.
4298 */
4299        (n))
4300 {
4301   window_scroll (Fselected_window (Qnil), n, -1, ERROR_ME);
4302   return Qnil;
4303 }
4304 \f
4305 DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, 0, 0, 0, /*
4306 Return the other window for "other window scroll" commands.
4307 If in the minibuffer, `minibuffer-scroll-window' if non-nil
4308 specifies the window.
4309 If `other-window-scroll-buffer' is non-nil, a window
4310 showing that buffer is used.
4311 */
4312        ())
4313 {
4314   Lisp_Object window;
4315   Lisp_Object selected_window = Fselected_window (Qnil);
4316
4317   if (MINI_WINDOW_P (XWINDOW (selected_window))
4318       && !NILP (Vminibuffer_scroll_window))
4319     window = Vminibuffer_scroll_window;
4320   /* If buffer is specified, scroll that buffer.  */
4321   else if (!NILP (Vother_window_scroll_buffer))
4322     {
4323       window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil, Qnil);
4324       if (NILP (window))
4325         window = display_buffer (Vother_window_scroll_buffer, Qt, Qnil);
4326     }
4327   else
4328     {
4329       /* Nothing specified; look for a neighboring window on the same
4330          frame.  */
4331       window = Fnext_window (selected_window, Qnil, Qnil, Qnil);
4332
4333       if (EQ (window, selected_window))
4334         /* That didn't get us anywhere; look for a window on another
4335            visible frame.  */
4336         do
4337           window = Fnext_window (window, Qnil, Qt, Qnil);
4338         while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
4339                && ! EQ (window, selected_window));
4340     }
4341
4342   CHECK_LIVE_WINDOW (window);
4343
4344   if (EQ (window, selected_window))
4345     error ("There is no other window");
4346
4347   return window;
4348  }
4349
4350 DEFUN ("scroll-other-window", Fscroll_other_window, 0, 1, "_P", /*
4351 Scroll next window upward N lines; or near full frame if no arg.
4352 The next window is the one below the current one; or the one at the top
4353 if the current one is at the bottom.  Negative N means scroll downward.
4354 When calling from a program, supply a number as argument or nil.
4355
4356 If in the minibuffer, `minibuffer-scroll-window' if non-nil
4357 specifies the window to scroll.
4358 If `other-window-scroll-buffer' is non-nil, scroll the window
4359 showing that buffer, popping the buffer up if necessary.
4360 */
4361        (n))
4362 {
4363   window_scroll (Fother_window_for_scrolling (), n, 1, ERROR_ME);
4364   return Qnil;
4365 }
4366 \f
4367 DEFUN ("scroll-left", Fscroll_left, 0, 1, "_P", /*
4368 Scroll selected window display N columns left.
4369 Default for N is window width minus 2.
4370 */
4371        (n))
4372 {
4373   Lisp_Object window = Fselected_window (Qnil);
4374   struct window *w = XWINDOW (window);
4375   int count = (NILP (n) ?
4376                window_char_width (w, 0) - 2 :
4377                XINT (Fprefix_numeric_value (n)));
4378
4379   return Fset_window_hscroll (window, make_int (w->hscroll + count));
4380 }
4381
4382 DEFUN ("scroll-right", Fscroll_right, 0, 1, "_P", /*
4383 Scroll selected window display N columns right.
4384 Default for N is window width minus 2.
4385 */
4386        (n))
4387 {
4388   Lisp_Object window = Fselected_window (Qnil);
4389   struct window *w = XWINDOW (window);
4390   int count = (NILP (n) ?
4391                window_char_width (w, 0) - 2 :
4392                XINT (Fprefix_numeric_value (n)));
4393
4394   return Fset_window_hscroll (window, make_int (w->hscroll - count));
4395 }
4396 \f
4397 DEFUN ("center-to-window-line", Fcenter_to_window_line, 0, 2, "_P", /*
4398 Center point in WINDOW.  With N, put point on line N.
4399 The desired position of point is always relative to the window.
4400 If WINDOW is nil, the selected window is used.
4401 */
4402        (n, window))
4403 {
4404   struct window *w = decode_window (window);
4405   struct buffer *b = XBUFFER (w->buffer);
4406   Bufpos opoint = BUF_PT (b);
4407   Bufpos startp;
4408
4409   if (NILP (n))
4410     startp = start_with_line_at_pixpos (w, opoint, window_half_pixpos (w));
4411   else
4412     {
4413       n = Fprefix_numeric_value (n);
4414       CHECK_INT (n);
4415       startp = start_with_point_on_display_line (w, opoint, XINT (n));
4416     }
4417
4418   Fset_marker (w->start[CURRENT_DISP], make_int (startp), w->buffer);
4419
4420   w->start_at_line_beg = beginning_of_line_p (b, startp);
4421   w->force_start = 1;
4422   MARK_WINDOWS_CHANGED (w);
4423   return Qnil;
4424 }
4425
4426 DEFUN ("move-to-window-line", Fmove_to_window_line, 1, 2, "_P", /*
4427 Position point relative to WINDOW.
4428 With no argument, position text at center of window.
4429 An argument specifies window line; zero means top of window,
4430 negative means relative to bottom of window.
4431 If WINDOW is nil, the selected window is used.
4432 */
4433        (arg, window))
4434 {
4435   struct window *w;
4436   struct buffer *b;
4437   int height;
4438   Bufpos start, new_point;
4439   int selected;
4440
4441   /* Don't use decode_window() because we need the new value of
4442      WINDOW.  */
4443   if (NILP (window))
4444     window = Fselected_window (Qnil);
4445   else
4446     CHECK_LIVE_WINDOW (window);
4447   w = XWINDOW (window);
4448   b = XBUFFER (w->buffer);
4449
4450   height = window_displayed_height (w);
4451   selected = EQ (window, Fselected_window (w->frame));
4452
4453   if (NILP (arg))
4454     {
4455       int retval;
4456
4457       if (XINT (w->last_modified[CURRENT_DISP]) >= BUF_MODIFF (b)
4458           && XINT (w->last_facechange[CURRENT_DISP]) >= BUF_FACECHANGE (b))
4459         {
4460           new_point = point_at_center (w, CURRENT_DISP, 0, 0);
4461
4462           if (selected)
4463             BUF_SET_PT (b, new_point);
4464           else
4465             Fset_window_point (window, make_int (new_point));
4466
4467           retval = line_at_center (w, CURRENT_DISP, 0, 0);
4468         }
4469       else
4470         {
4471           start = marker_position (w->start[CURRENT_DISP]);
4472           if (start < BUF_BEGV (b))
4473             start = BUF_BEGV (b);
4474           else if (start > BUF_ZV (b))
4475             start = BUF_ZV (b);
4476
4477           if (selected)
4478             new_point = BUF_PT (b);
4479           else
4480             new_point = marker_position (w->pointm[CURRENT_DISP]);
4481
4482           new_point = point_at_center (w, CMOTION_DISP, start, BUF_PT (b));
4483
4484           if (selected)
4485             BUF_SET_PT (b, new_point);
4486           else
4487             Fset_window_point (window, make_int (new_point));
4488
4489           retval = line_at_center (w, CMOTION_DISP, start, BUF_PT (b));
4490         }
4491
4492       return make_int (retval);
4493     }
4494   else
4495     {
4496       /* #### Is this going to work right when at eob? */
4497       arg = Fprefix_numeric_value (arg);
4498       if (XINT (arg) < 0)
4499         XSETINT (arg, XINT (arg) + height);
4500     }
4501
4502   start = marker_position (w->start[CURRENT_DISP]);
4503   if (start < BUF_BEGV (b) || start > BUF_ZV (b))
4504     {
4505       if (selected)
4506         new_point = BUF_PT (b);
4507       else
4508         new_point = marker_position (w->pointm[CURRENT_DISP]);
4509
4510       new_point = vmotion (XWINDOW (window), new_point, -height / 2, 0);
4511
4512       if (selected)
4513         BUF_SET_PT (b, new_point);
4514       else
4515         Fset_window_point (window, make_int (new_point));
4516
4517       Fset_marker (w->start[CURRENT_DISP], make_int (new_point),
4518                    w->buffer);
4519       w->start_at_line_beg = beginning_of_line_p (b, new_point);
4520       w->force_start = 1;
4521     }
4522   else
4523     {
4524       if (selected)
4525         BUF_SET_PT (b, start);
4526       else
4527         Fset_window_point (window, make_int (start));
4528     }
4529
4530   if (selected)
4531     return Fvertical_motion (arg, window, Qnil);
4532   else
4533     {
4534       int vpos;
4535       new_point = vmotion (XWINDOW (window),
4536                            marker_position (w->pointm[CURRENT_DISP]),
4537                            XINT (arg), &vpos);
4538       Fset_window_point (window, make_int (new_point));
4539       return make_int (vpos);
4540     }
4541 }
4542
4543 \f
4544 static int
4545 map_windows_1 (Lisp_Object window,
4546                int (*mapfun) (struct window *w, void *closure),
4547                void *closure)
4548 {
4549   for (; !NILP (window); window = XWINDOW (window)->next)
4550     {
4551       int retval;
4552       struct window *w = XWINDOW (window);
4553
4554       if (!NILP (w->vchild))
4555         retval = map_windows_1 (w->vchild, mapfun, closure);
4556       else if (!NILP (w->hchild))
4557         retval = map_windows_1 (w->hchild, mapfun, closure);
4558       else
4559         retval = (mapfun) (w, closure);
4560
4561       if (retval)
4562         return retval;
4563     }
4564
4565   return 0;
4566 }
4567
4568 /* Map MAPFUN over the windows in F.  CLOSURE is passed to each
4569    invocation of MAPFUN.  If any invocation of MAPFUN returns
4570    non-zero, the mapping is halted.  Otherwise, map_windows() maps
4571    over all windows in F.
4572
4573    If MAPFUN creates or deletes windows, the behavior is undefined.  */
4574
4575 int
4576 map_windows (struct frame *f, int (*mapfun) (struct window *w, void *closure),
4577              void *closure)
4578 {
4579   if (f)
4580     return map_windows_1 (FRAME_ROOT_WINDOW (f), mapfun, closure);
4581   else
4582     {
4583       Lisp_Object frmcons, devcons, concons;
4584
4585       FRAME_LOOP_NO_BREAK(frmcons, devcons, concons)
4586         {
4587           int v = map_windows_1 (FRAME_ROOT_WINDOW (XFRAME (XCAR (frmcons))),
4588                                  mapfun, closure);
4589           if (v)
4590             return v;
4591         }
4592     }
4593
4594   return 0;
4595 }
4596
4597 \f
4598 static void
4599 modeline_shadow_thickness_changed (Lisp_Object specifier, struct window *w,
4600                                    Lisp_Object oldval)
4601 {
4602   w->shadow_thickness_changed = 1;
4603   MARK_WINDOWS_CHANGED (w);
4604 }
4605
4606 static void
4607 vertical_divider_changed_in_window (Lisp_Object specifier,
4608                                     struct window *w,
4609                                     Lisp_Object oldval)
4610 {
4611   MARK_WINDOWS_CHANGED (w);
4612   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (XFRAME (WINDOW_FRAME (w)));
4613 }
4614
4615 /* also used in scrollbar.c */
4616 void
4617 some_window_value_changed (Lisp_Object specifier, struct window *w,
4618                            Lisp_Object oldval)
4619 {
4620   MARK_WINDOWS_CHANGED (w);
4621 }
4622
4623 #ifdef MEMORY_USAGE_STATS
4624
4625 struct window_stats
4626 {
4627   int face;
4628   int glyph;
4629 #ifdef HAVE_SCROLLBARS
4630   int scrollbar;
4631 #endif
4632   int line_start;
4633   int other_redisplay;
4634   int other;
4635 };
4636
4637 static void
4638 compute_window_mirror_usage (struct window_mirror *mir,
4639                              struct window_stats *stats,
4640                              struct overhead_stats *ovstats)
4641 {
4642   if (!mir)
4643     return;
4644   stats->other += malloced_storage_size (mir, sizeof (struct window_mirror),
4645                                          ovstats);
4646 #ifdef HAVE_SCROLLBARS
4647   {
4648     struct device *d = XDEVICE (FRAME_DEVICE (mir->frame));
4649
4650     stats->scrollbar +=
4651       compute_scrollbar_instance_usage (d, mir->scrollbar_vertical_instance,
4652                                         ovstats);
4653     stats->scrollbar +=
4654       compute_scrollbar_instance_usage (d, mir->scrollbar_horizontal_instance,
4655                                         ovstats);
4656   }
4657 #endif /* HAVE_SCROLLBARS */
4658   stats->other_redisplay +=
4659     compute_display_line_dynarr_usage (mir->current_display_lines, ovstats);
4660   stats->other_redisplay +=
4661     compute_display_line_dynarr_usage (mir->desired_display_lines, ovstats);
4662 }
4663
4664 static void
4665 compute_window_usage (struct window *w, struct window_stats *stats,
4666                       struct overhead_stats *ovstats)
4667 {
4668   xzero (*stats);
4669   stats->other += malloced_storage_size (w, sizeof (struct window), ovstats);
4670   stats->face += compute_face_cachel_usage (w->face_cachels, ovstats);
4671   stats->glyph += compute_glyph_cachel_usage (w->glyph_cachels, ovstats);
4672   stats->line_start +=
4673     compute_line_start_cache_dynarr_usage (w->line_start_cache, ovstats);
4674   compute_window_mirror_usage (find_window_mirror (w), stats, ovstats);
4675 }
4676
4677 DEFUN ("window-memory-usage", Fwindow_memory_usage, 1, 1, 0, /*
4678 Return stats about the memory usage of window WINDOW.
4679 The values returned are in the form of an alist of usage types and byte
4680 counts.  The byte counts attempt to encompass all the memory used
4681 by the window (separate from the memory logically associated with a
4682 buffer or frame), including internal structures and any malloc()
4683 overhead associated with them.  In practice, the byte counts are
4684 underestimated because certain memory usage is very hard to determine
4685 \(e.g. the amount of memory used inside the Xt library or inside the
4686 X server) and because there is other stuff that might logically
4687 be associated with a window, buffer, or frame (e.g. window configurations,
4688 glyphs) but should not obviously be included in the usage counts.
4689
4690 Multiple slices of the total memory usage may be returned, separated
4691 by a nil.  Each slice represents a particular view of the memory, a
4692 particular way of partitioning it into groups.  Within a slice, there
4693 is no overlap between the groups of memory, and each slice collectively
4694 represents all the memory concerned.
4695 */
4696        (window))
4697 {
4698   struct window_stats stats;
4699   struct overhead_stats ovstats;
4700   Lisp_Object val = Qnil;
4701
4702   CHECK_WINDOW (window); /* dead windows should be allowed, no? */
4703   xzero (ovstats);
4704   compute_window_usage (XWINDOW (window), &stats, &ovstats);
4705
4706   val = acons (Qface_cache,          make_int (stats.face),              val);
4707   val = acons (Qglyph_cache,         make_int (stats.glyph),             val);
4708 #ifdef HAVE_SCROLLBARS
4709   val = acons (Qscrollbar_instances, make_int (stats.scrollbar),         val);
4710 #endif
4711   val = acons (Qline_start_cache,    make_int (stats.line_start),        val);
4712   val = acons (Qother_redisplay,     make_int (stats.other_redisplay),   val);
4713   val = acons (Qother,               make_int (stats.other),             val);
4714   val = Fcons (Qnil, val);
4715   val = acons (Qactually_requested,  make_int (ovstats.was_requested),   val);
4716   val = acons (Qmalloc_overhead,     make_int (ovstats.malloc_overhead), val);
4717   val = acons (Qdynarr_overhead,     make_int (ovstats.dynarr_overhead), val);
4718
4719   return Fnreverse (val);
4720 }
4721
4722 #endif /* MEMORY_USAGE_STATS */
4723
4724 \f
4725 /************************************************************************/
4726 /*                         Window configurations                        */
4727 /************************************************************************/
4728
4729 /* #### This window configuration stuff has had serious bugs lurking in it
4730    for years; it would be a -huge- win if this was reimplemented in lisp.
4731  */
4732
4733 /* If you add anything to this structure make sure saved_window_equal
4734    knows about it. */
4735 struct saved_window
4736 {
4737   Lisp_Object window;         /* window */
4738   Lisp_Object buffer;         /* buffer */
4739   Lisp_Object start;          /* copied marker */
4740   Lisp_Object pointm;         /* copied marker */
4741   Lisp_Object sb_point;       /* copied marker */
4742   Lisp_Object mark;           /* copied marker */
4743   int pixel_left;
4744   int pixel_top;
4745   int pixel_width;
4746   int pixel_height;
4747   int hscroll;
4748   Charcount modeline_hscroll;
4749   int parent_index;           /* index into saved_windows */
4750   int prev_index;             /* index into saved_windows */
4751   char start_at_line_beg; /* boolean */
4752
4753 #define WINDOW_SLOT_DECLARATION
4754 #define WINDOW_SLOT(slot, compare) Lisp_Object slot
4755 #include "winslots.h"
4756 };
4757
4758 /* If you add anything to this structure make sure window_config_equal
4759    knows about it. */
4760 struct window_config
4761 {
4762   struct lcrecord_header header;
4763   /*  int frame_width; No longer needed, JV
4764       int frame_height; */
4765 #if 0 /* FSFmacs */
4766   Lisp_Object selected_frame;
4767 #endif
4768   Lisp_Object current_window;
4769   Lisp_Object current_buffer;
4770   Lisp_Object minibuffer_scroll_window;
4771   Lisp_Object root_window;
4772   int minibuf_height; /* 0 = no minibuffer, <0, size in lines, >0 in pixels */
4773   /* Record the values of window-min-width and window-min-height
4774      so that window sizes remain consistent with them.  */
4775   int min_width, min_height;
4776   int saved_windows_count;
4777   /* Zero-sized arrays aren't ANSI C */
4778   struct saved_window saved_windows[1];
4779 };
4780
4781 #define SAVED_WINDOW_N(conf, n) (&((conf)->saved_windows[(n)]))
4782 #define XWINDOW_CONFIGURATION(x) XRECORD (x, window_configuration, struct window_config)
4783 #define XSETWINDOW_CONFIGURATION(x, p) XSETRECORD (x, p, window_configuration)
4784 #define WINDOW_CONFIGURATIONP(x) RECORDP (x, window_configuration)
4785 #define CHECK_WINDOW_CONFIGURATION(x) CHECK_RECORD (x, window_configuration)
4786
4787 static Lisp_Object
4788 mark_window_config (Lisp_Object obj)
4789 {
4790   struct window_config *config = XWINDOW_CONFIGURATION (obj);
4791   int i;
4792   mark_object (config->current_window);
4793   mark_object (config->current_buffer);
4794   mark_object (config->minibuffer_scroll_window);
4795   mark_object (config->root_window);
4796
4797   for (i = 0; i < config->saved_windows_count; i++)
4798     {
4799       struct saved_window *s = SAVED_WINDOW_N (config, i);
4800       mark_object (s->window);
4801       mark_object (s->buffer);
4802       mark_object (s->start);
4803       mark_object (s->pointm);
4804       mark_object (s->sb_point);
4805       mark_object (s->mark);
4806 #if 0
4807       /* #### This looked like this. I do not see why specifier cached
4808          values should not be marked, as such specifiers as toolbars
4809          might have GC-able instances. Freed configs are not marked,
4810          aren't they?  -- kkm */
4811       mark_object (s->dedicated);
4812 #else
4813 #define WINDOW_SLOT(slot, compare) mark_object (s->slot)
4814 #include "winslots.h"
4815 #endif
4816     }
4817   return Qnil;
4818 }
4819
4820 static size_t
4821 sizeof_window_config_for_n_windows (int n)
4822 {
4823   return (sizeof (struct window_config) +
4824           /* n - 1 because zero-sized arrays aren't ANSI C */
4825           (n - 1) *sizeof (struct saved_window));
4826 }
4827
4828 static size_t
4829 sizeof_window_config (CONST void *h)
4830 {
4831   CONST struct window_config *c = (CONST struct window_config *) h;
4832   return sizeof_window_config_for_n_windows (c->saved_windows_count);
4833 }
4834
4835 static void
4836 print_window_config (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
4837 {
4838   struct window_config *config = XWINDOW_CONFIGURATION (obj);
4839   char buf[200];
4840   if (print_readably)
4841     error ("printing unreadable object #<window-configuration 0x%x>",
4842            config->header.uid);
4843   write_c_string ("#<window-configuration ", printcharfun);
4844   sprintf (buf, "0x%x>", config->header.uid);
4845   write_c_string (buf, printcharfun);
4846 }
4847
4848 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION ("window-configuration",
4849                                         window_configuration,
4850                                         mark_window_config,
4851                                         print_window_config,
4852                                         0, 0, 0, 0, sizeof_window_config,
4853                                         struct window_config);
4854
4855
4856 /* Returns a boolean indicating whether the two saved windows are
4857    identical. */
4858 static int
4859 saved_window_equal (struct saved_window *win1, struct saved_window *win2)
4860 {
4861 #define WINDOW_SLOT(slot, compare)              \
4862   if (!compare (win1->slot, win2->slot))        \
4863     return 0;
4864 #include "winslots.h"
4865
4866   return
4867     EQ (win1->window, win2->window) &&
4868     EQ (win1->buffer, win2->buffer) &&
4869     internal_equal (win1->start,    win2->start, 0) &&
4870     internal_equal (win1->pointm,   win2->pointm, 0) &&
4871     internal_equal (win1->sb_point, win2->sb_point, 0) &&
4872     internal_equal (win1->mark,     win2->mark, 0) &&
4873     win1->pixel_left   == win2->pixel_left &&
4874     win1->pixel_top    == win2->pixel_top &&
4875     win1->pixel_width  == win2->pixel_width &&
4876     win1->pixel_height == win2->pixel_height &&
4877     win1->hscroll      == win2->hscroll &&
4878     win1->modeline_hscroll == win2->modeline_hscroll &&
4879     win1->parent_index == win2->parent_index &&
4880     win1->prev_index   == win2->prev_index &&
4881     win1->start_at_line_beg == win2->start_at_line_beg;
4882 }
4883
4884 /* Returns a boolean indicating whether the two given configurations
4885    are identical. */
4886 static int
4887 window_config_equal (Lisp_Object conf1, Lisp_Object conf2)
4888 {
4889   struct window_config *fig1, *fig2;
4890   int i;
4891
4892   /* First check if they are truly the same. */
4893   if (EQ (conf1, conf2))
4894     return 1;
4895
4896   fig1 = XWINDOW_CONFIGURATION (conf1);
4897   fig2 = XWINDOW_CONFIGURATION (conf2);
4898
4899   if (!((fig1->saved_windows_count == fig2->saved_windows_count) &&
4900         EQ (fig1->current_window,           fig2->current_window) &&
4901         EQ (fig1->current_buffer,           fig2->current_buffer) &&
4902         EQ (fig1->root_window,              fig2->root_window) &&
4903         EQ (fig1->minibuffer_scroll_window, fig2->minibuffer_scroll_window)))
4904         /* &&
4905         fig1->frame_width  == fig2->frame_width &&
4906         fig1->frame_height == fig2->frame_height)) */
4907     return 0;
4908
4909   for (i = 0; i < fig1->saved_windows_count; i++)
4910     {
4911       if (!saved_window_equal (SAVED_WINDOW_N (fig1, i),
4912                                SAVED_WINDOW_N (fig2, i)))
4913         return 0;
4914     }
4915
4916   return 1;
4917 }
4918
4919 DEFUN ("window-configuration-p", Fwindow_configuration_p, 1, 1, 0, /*
4920 Return t if OBJECT is a window-configuration object.
4921 */
4922        (obj))
4923 {
4924   return WINDOW_CONFIGURATIONP (obj) ? Qt : Qnil;
4925 }
4926
4927 static int
4928 mark_windows_in_use_closure (struct window *w, void *closure)
4929 {
4930   int mark = *(int *)closure;
4931   w->config_mark = mark;
4932   return 0;
4933 }
4934
4935 static void
4936 mark_windows_in_use (struct frame *f, int mark)
4937 {
4938   map_windows (f, mark_windows_in_use_closure, &mark);
4939 }
4940
4941 /* Lisp_Object return value so it can be used in record_unwind_protect() */
4942 static Lisp_Object
4943 free_window_configuration (Lisp_Object window_config)
4944 {
4945   int i;
4946   struct window_config *config = XWINDOW_CONFIGURATION (window_config);
4947
4948   /* Free all the markers.  It's not completely necessary that
4949      we do this (window configs sitting in a free list aren't
4950      marked normally so the markers wouldn't be marked anyway)
4951      but it's more efficient. */
4952   for (i = 0; i < config->saved_windows_count; i++)
4953     {
4954       struct saved_window *p = SAVED_WINDOW_N (config, i);
4955
4956       if (!NILP (p->pointm))
4957         {
4958           free_marker (XMARKER (p->pointm));
4959           p->pointm = Qnil;
4960         }
4961       if (!NILP (p->start))
4962         {
4963           free_marker (XMARKER (p->start));
4964           p->start = Qnil;
4965         }
4966       if (!NILP (p->sb_point))
4967         {
4968           free_marker (XMARKER (p->sb_point));
4969           p->sb_point = Qnil;
4970         }
4971       if (!NILP (p->mark))
4972         {
4973           free_marker (XMARKER (p->mark));
4974           p->mark = Qnil;
4975         }
4976     }
4977
4978   if (config->saved_windows_count <= countof (Vwindow_configuration_free_list))
4979     free_managed_lcrecord (Vwindow_configuration_free_list
4980                            [config->saved_windows_count - 1],
4981                            window_config);
4982
4983   return Qnil;
4984 }
4985
4986 DEFUN ("set-window-configuration", Fset_window_configuration, 1, 1, 0, /*
4987 Set the configuration of windows and buffers as specified by CONFIGURATION.
4988 CONFIGURATION must be a value previously returned
4989 by `current-window-configuration' (which see).
4990 */
4991        (configuration))
4992 {
4993   struct window *w;
4994   struct window_config *config;
4995   struct saved_window *p;
4996   Lisp_Object new_current_buffer;
4997   int k;
4998   Lisp_Object frame;
4999   struct frame *f;
5000   struct gcpro gcpro1;
5001   Lisp_Object old_window_config;
5002   /*  int previous_frame_height;
5003       int previous_frame_width;*/
5004   int previous_pixel_top;
5005   int previous_pixel_height;
5006   int previous_pixel_left;
5007   int previous_pixel_width;
5008   int previous_minibuf_height, previous_minibuf_top,previous_minibuf_width;
5009   int real_font_height;
5010   int converted_minibuf_height,target_minibuf_height;
5011   int specpdl_count = specpdl_depth ();
5012
5013   GCPRO1 (configuration);
5014
5015   CHECK_WINDOW_CONFIGURATION (configuration);
5016   config = XWINDOW_CONFIGURATION (configuration);
5017
5018   frame = XWINDOW (SAVED_WINDOW_N (config, 0)->window)->frame;
5019   f = XFRAME (frame);
5020
5021   /* Do not signal an error here if the frame was deleted.  There are
5022      reasonable cases where we could get here with a deleted frame and
5023      just want to do close to nothing instead. */
5024
5025   if (FRAME_LIVE_P (f))
5026     {
5027       /* restore the frame characteristics */
5028
5029       new_current_buffer = config->current_buffer;
5030       if (!BUFFER_LIVE_P (XBUFFER (new_current_buffer)))
5031         new_current_buffer = Qnil;
5032
5033       /*
5034        * Assumed precondition:  w->config_mark = 0 for all w
5035        * This procedure should ensure this is true by the time it exits
5036        * to ensure the precondition for future calls.
5037        *
5038        * We use w->config_mark to know whether we're modifying a
5039        * window that is currently visible on the frame (#### we
5040        * should just be able to check whether the window is dead
5041        * or not, but this way is safer?).  As we process each
5042        * window, we set its config_mark to 0.  At the end, we
5043        * go through all the windows that used to be on the frame,
5044        * set each one's config_mark to 0 (to maintain the
5045        * assumed precondition) and delete each one that's no
5046        * longer in use.
5047        *
5048        * #### Using a window-configuration to keep track of
5049        * the current windows is wasteful.  All we need is the
5050        * list of windows, so we could just use a dynarr.
5051        */
5052       old_window_config = Fcurrent_window_configuration (frame);
5053
5054       /* If the new configuration is already equal to the old, then stop
5055          right here.  This saves the work below and it also saves
5056          triggering a full redisplay of this window.  This is a huge win
5057          when using the mouse since the mode motion code uses
5058          save-window-excursion extensively but will rarely cause the
5059          configuration to actually change. */
5060       if (window_config_equal (configuration, old_window_config))
5061         {
5062           free_window_configuration (old_window_config);
5063           UNGCPRO;
5064           return Qnil;
5065         }
5066
5067       /* We can't quit or even check for quit because that may cause
5068          investigation of the frame state, which may crash if the frame is
5069          in an inconsistent state. */
5070       begin_dont_check_for_quit ();
5071       record_unwind_protect (free_window_configuration, old_window_config);
5072
5073       mark_windows_in_use (f, 1);
5074
5075 #if 0
5076       /* JV: This is bogus,
5077          First of all, the units are inconsistent. The frame sizes are measured
5078          in characters but the window sizes are stored in pixels. So if a
5079          font size change happened between saving and restoring, the
5080          frame "sizes" maybe equal but the windows still should be
5081          resized. This is tickled alot by the new "character size
5082          stays constant" policy in 21.0. It leads to very wierd
5083          glitches (and possibly craches when asserts are tickled).
5084
5085          Just changing the units doens't help because changing the
5086          toolbar configuration can also change the pixel positions.
5087          Luckily there is a much simpler way of doing this, see below.
5088        */
5089       previous_frame_width = FRAME_WIDTH (f);
5090       previous_frame_height = FRAME_HEIGHT (f);
5091       /* If the frame has been resized since this window configuration was
5092          made, we change the frame to the size specified in the
5093          configuration, restore the configuration, and then resize it
5094          back.  We keep track of the prevailing height in these variables.  */
5095       if (config->frame_height != FRAME_HEIGHT (f)
5096           || config->frame_width != FRAME_WIDTH (f))
5097         change_frame_size (f, config->frame_height, config->frame_width, 0);
5098 #endif
5099
5100       previous_pixel_top = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_top;
5101       previous_pixel_height = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_height;
5102       previous_pixel_left = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_left;
5103       previous_pixel_width = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_width;
5104
5105       /* remember some properties of the minibuffer */
5106
5107       default_face_height_and_width (frame, &real_font_height, 0);
5108       assert(real_font_height > 0);
5109
5110       if (FRAME_HAS_MINIBUF_P (f) && ! FRAME_MINIBUF_ONLY_P (f))
5111         {
5112           previous_minibuf_height
5113             = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_height;
5114           previous_minibuf_top
5115             = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_top;
5116           previous_minibuf_width
5117             = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_width;
5118         }
5119       else
5120         {
5121           previous_minibuf_height = 0;
5122           previous_minibuf_top = 0;
5123           previous_minibuf_width = 0;
5124         }
5125       converted_minibuf_height =
5126         (previous_minibuf_height % real_font_height) == 0 ?
5127         - (previous_minibuf_height / real_font_height ) :    /* lines */
5128             previous_minibuf_height;   /* pixels */
5129
5130       /* Temporarily avoid any problems with windows that are smaller
5131          than they are supposed to be.  */
5132       window_min_height = 1;
5133       window_min_width = 1;
5134
5135       /* OK, now restore all the windows in the window config.
5136          This may involve "undeleting" windows, since the
5137          windows in the window config may be deleted.
5138          */
5139       for (k = 0; k < config->saved_windows_count; k++)
5140         {
5141           p = SAVED_WINDOW_N (config, k);
5142           w = XWINDOW (p->window);
5143           w->next = Qnil;
5144
5145           /* The window might be dead.  In this case, its redisplay
5146              structures were freed, so we need to reallocate them. */
5147           if (!w->face_cachels)
5148             {
5149               w->face_cachels = Dynarr_new (face_cachel);
5150               reset_face_cachels (w);
5151             }
5152           if (!w->glyph_cachels)
5153             w->glyph_cachels = Dynarr_new (glyph_cachel);
5154           if (!w->line_start_cache)
5155             w->line_start_cache = Dynarr_new (line_start_cache);
5156           w->dead = 0;
5157
5158           if (p->parent_index >= 0)
5159             w->parent = SAVED_WINDOW_N (config, p->parent_index)->window;
5160           else
5161             w->parent = Qnil;
5162
5163           if (p->prev_index >= 0)
5164             {
5165               w->prev = SAVED_WINDOW_N (config, p->prev_index)->window;
5166
5167               /* This is true for a minibuffer-only frame. */
5168               if (!NILP (w->mini_p) && EQ (w->prev, p->window))
5169                 w->next = Qnil;
5170               else
5171                 XWINDOW (w->prev)->next = p->window;
5172             }
5173           else
5174             {
5175               w->prev = Qnil;
5176               if (!NILP (w->parent))
5177                 {
5178                   if (WINDOW_WIDTH (p) == WINDOW_WIDTH (XWINDOW (w->parent)))
5179                     {
5180                       XWINDOW (w->parent)->vchild = p->window;
5181                       XWINDOW (w->parent)->hchild = Qnil;
5182                     }
5183                   else
5184                     {
5185                       XWINDOW (w->parent)->hchild = p->window;
5186                       XWINDOW (w->parent)->vchild = Qnil;
5187                     }
5188                 }
5189             }
5190           if (!w->config_mark)
5191             {
5192               /* #### This should be equivalent to the window previously
5193                  having been dead.  If we're brave, we'll put in an
5194                  assertion to this effect. */
5195               MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
5196             }
5197           else /* if (!EQ (w->buffer, p->buffer)) */
5198             {
5199               /* With the new redisplay we let it know that a change has
5200                  been made and it will take care of the rest.  If we don't
5201                  tell it something has possibly changed it could lead to
5202                  incorrect display. */
5203               MARK_WINDOWS_CHANGED (w);
5204             }
5205
5206           WINDOW_LEFT (w) = WINDOW_LEFT (p);
5207           WINDOW_TOP (w) = WINDOW_TOP (p);
5208           WINDOW_WIDTH (w) = WINDOW_WIDTH (p);
5209           WINDOW_HEIGHT (w) = WINDOW_HEIGHT (p);
5210           w->hscroll = p->hscroll;
5211           w->modeline_hscroll = p->modeline_hscroll;
5212           w->line_cache_last_updated = Qzero;
5213           SET_LAST_MODIFIED (w, 1);
5214           SET_LAST_FACECHANGE (w);
5215           w->config_mark = 0;
5216
5217 #define WINDOW_SLOT(slot, compare) w->slot = p->slot
5218 #include "winslots.h"
5219
5220           /* Reinstall the saved buffer and pointers into it.  */
5221           if (NILP (p->buffer))
5222             w->buffer = p->buffer;
5223           else
5224             {
5225               if (BUFFER_LIVE_P (XBUFFER (p->buffer)))
5226                 /* If saved buffer is alive, install it.  */
5227                 {
5228                   w->buffer = p->buffer;
5229                   w->start_at_line_beg = p->start_at_line_beg;
5230                   set_marker_restricted (w->start[CURRENT_DISP],
5231                                          Fmarker_position (p->start),
5232                                          w->buffer);
5233                   set_marker_restricted (w->pointm[CURRENT_DISP],
5234                                          Fmarker_position (p->pointm),
5235                                          w->buffer);
5236                   set_marker_restricted (w->sb_point,
5237                                          Fmarker_position (p->sb_point),
5238                                          w->buffer);
5239                   Fset_marker (XBUFFER (w->buffer)->mark,
5240                                Fmarker_position (p->mark), w->buffer);
5241
5242                   /* As documented in Fcurrent_window_configuration, don't
5243                      save the location of point in the buffer which was current
5244                      when the window configuration was recorded.  */
5245                   if (!EQ (p->buffer, new_current_buffer) &&
5246                       XBUFFER (p->buffer) == current_buffer)
5247                     Fgoto_char (w->pointm[CURRENT_DISP], Qnil);
5248                 }
5249               else if (NILP (w->buffer) ||
5250                        !BUFFER_LIVE_P (XBUFFER (w->buffer)))
5251                 /* Else if window's old buffer is dead too, get a live one.  */
5252                 {
5253                   /* #### The following line makes me nervous... */
5254                   /* w->buffer = Fcdr (Fcar (XFRAME (w->frame)->buffer_alist));*/
5255                   w->buffer = Fget_buffer_create (QSscratch);
5256                   /* w->buffer = Fother_buffer (Qnil, w->frame, Qnil); */
5257                   /* This will set the markers to beginning of visible
5258                      range.  */
5259                   set_marker_restricted (w->start[CURRENT_DISP], Qzero, w->buffer);
5260                   set_marker_restricted (w->pointm[CURRENT_DISP], Qzero,
5261                                          w->buffer);
5262                   set_marker_restricted (w->sb_point, Qzero, w->buffer);
5263                   w->start_at_line_beg = 1;
5264                 }
5265               else
5266                 /* Keeping window's old buffer; make sure the markers
5267                    are real.  */
5268                 {
5269                   /* Set window markers at start of visible range.  */
5270                   if (XMARKER (w->start[CURRENT_DISP])->buffer == 0)
5271                     set_marker_restricted (w->start[CURRENT_DISP], Qzero,
5272                                            w->buffer);
5273                   if (XMARKER (w->sb_point)->buffer == 0)
5274                     set_marker_restricted (w->sb_point, Qzero, w->buffer);
5275                   if (XMARKER (w->pointm[CURRENT_DISP])->buffer == 0)
5276                     set_marker_restricted (w->pointm[CURRENT_DISP],
5277                                            make_int
5278                                            (BUF_PT (XBUFFER (w->buffer))),
5279                                            w->buffer);
5280                   w->start_at_line_beg = 1;
5281                 }
5282             }
5283         }
5284
5285       FRAME_ROOT_WINDOW (f) = config->root_window;
5286       /* Note that FSFmacs unilaterally calls Fselect_window() here, and
5287          then calls do_switch_frame() below to select the frame that was
5288          recorded in the window config as being selected.
5289
5290          Instead, we don't ever change the selected frame, and either
5291          call Fselect_window() below if the window config's frame is
5292          currently selected, or just set the selected window of the
5293          window config's frame. */
5294
5295 #if 0
5296       /* Set the frame height to the value it had before this function.  */
5297       if (previous_frame_height != FRAME_HEIGHT (f)
5298           || previous_frame_width != FRAME_WIDTH (f))
5299         change_frame_size (f, previous_frame_height, previous_frame_width, 0);
5300 #endif
5301       /* We just reset the size and position of the minibuffer, to its old
5302          value, which needn't be valid. So we do some magic to see which value
5303          to actually take. Then we set it.
5304
5305          The magic:
5306          We take the old value if is in the same units but differs from the
5307          current value.
5308
5309          #### Now we get more cases correct then ever before, but
5310          are we treating all? For instance what if the frames minibuf window
5311          is no longer the same one?
5312       */
5313       target_minibuf_height = previous_minibuf_height;
5314       if (converted_minibuf_height &&
5315           (converted_minibuf_height * config->minibuf_height) > 0 &&
5316           (converted_minibuf_height !=  config->minibuf_height))
5317         {
5318           target_minibuf_height = config->minibuf_height < 0 ?
5319             - (config->minibuf_height * real_font_height) :
5320             config->minibuf_height;
5321           target_minibuf_height =
5322             max(target_minibuf_height,real_font_height);
5323         }
5324       if (previous_minibuf_height)
5325         {
5326           XWINDOW (FRAME_MINIBUF_WINDOW (f))->pixel_top
5327             = previous_minibuf_top -
5328                   (target_minibuf_height - previous_minibuf_height);
5329           set_window_pixheight (FRAME_MINIBUF_WINDOW (f),
5330                                 target_minibuf_height, 0);
5331           set_window_pixwidth  (FRAME_MINIBUF_WINDOW (f),
5332                             previous_minibuf_width, 0);
5333         }
5334
5335       /* This is a better way to deal with frame resizing, etc.
5336          What we _actually_ want is for the old (just restored)
5337          root window to fit
5338          into the place of the new one. So we just do that. Simple! */
5339       XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_top = previous_pixel_top;
5340       /* Note that this function also updates the subwindow
5341          "pixel_top"s */
5342       set_window_pixheight (FRAME_ROOT_WINDOW (f),
5343           previous_pixel_height -
5344                   (target_minibuf_height - previous_minibuf_height), 0);
5345       XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_left = previous_pixel_left;
5346       /* Note that this function also updates the subwindow
5347          "pixel_left"s */
5348       set_window_pixwidth (FRAME_ROOT_WINDOW (f), previous_pixel_width, 0);
5349
5350       /* If restoring in the current frame make the window current,
5351          otherwise just update the frame selected_window slot to be
5352          the restored current_window. */
5353       if (f == selected_frame ())
5354         {
5355           /* When using `pop-window-configuration', often the minibuffer
5356              ends up as the selected window even though it's not active ...
5357              I really don't know the cause of this, but it should never
5358              happen.  This kludge should fix it.
5359
5360              #### Find out why this is really going wrong. */
5361           if (!minibuf_level &&
5362               MINI_WINDOW_P (XWINDOW (config->current_window)))
5363             Fselect_window (Fnext_window (config->current_window,
5364                                           Qnil, Qnil, Qnil),
5365                             Qnil);
5366           else
5367             Fselect_window (config->current_window, Qnil);
5368           if (!NILP (new_current_buffer))
5369             Fset_buffer (new_current_buffer);
5370           else
5371             Fset_buffer (XWINDOW (Fselected_window (Qnil))->buffer);
5372         }
5373       else
5374         set_frame_selected_window (f, config->current_window);
5375     }
5376   else
5377     old_window_config = Qnil; /* Warning suppression */
5378
5379   /* Restore the minimum heights recorded in the configuration.  */
5380   window_min_height = config->min_height;
5381   window_min_width = config->min_width;
5382
5383 #if 0 /* FSFmacs */
5384   /* see above comment */
5385   /* Fselect_window will have made f the selected frame, so we
5386      reselect the proper frame here.  Fhandle_switch_frame will change the
5387      selected window too, but that doesn't make the call to
5388      Fselect_window above totally superfluous; it still sets f's
5389      selected window.  */
5390   if (FRAME_LIVE_P (XFRAME (config->selected_frame)))
5391     do_switch_frame (config->selected_frame, Qnil, 0);
5392 #endif
5393
5394   Vminibuffer_scroll_window = config->minibuffer_scroll_window;
5395
5396   if (FRAME_LIVE_P (f))
5397     {
5398       /* Do this before calling recompute_all_cached_specifiers_in_window()
5399          so that things like redisplay_redraw_cursor() won't abort due
5400          to no window mirror present. */
5401       f->mirror_dirty = 1;
5402
5403       config = XWINDOW_CONFIGURATION (old_window_config);
5404       for (k = 0; k < config->saved_windows_count; k++)
5405         {
5406           p = SAVED_WINDOW_N (config, k);
5407           w = XWINDOW (p->window);
5408           /* Remember, we set w->config_mark on all currently visible
5409              windows, and reset it on all newly visible windows.
5410              Any windows still marked need to be deleted. */
5411           if (w->config_mark)
5412             {
5413               mark_window_as_deleted (w);
5414               w->config_mark = 0;
5415             }
5416           else
5417             {
5418               /* We just potentially changed the window's buffer and
5419                  potentially turned a dead window into a live one,
5420                  so we need to recompute the cached specifier values. */
5421               recompute_all_cached_specifiers_in_window (w);
5422             }
5423         }
5424     }
5425
5426   /* Now restore things, when everything else if OK. */
5427
5428   unbind_to (specpdl_count, Qnil);
5429
5430   UNGCPRO;
5431
5432   return Qnil;
5433 }
5434
5435 /* Mark all subwindows of a window as deleted.  The argument
5436    W is actually the subwindow tree of the window in question. */
5437
5438 void
5439 delete_all_subwindows (struct window *w)
5440 {
5441   if (!NILP (w->next))   delete_all_subwindows (XWINDOW (w->next));
5442   if (!NILP (w->vchild)) delete_all_subwindows (XWINDOW (w->vchild));
5443   if (!NILP (w->hchild)) delete_all_subwindows (XWINDOW (w->hchild));
5444
5445   mark_window_as_deleted (w);
5446 }
5447
5448 \f
5449 static int
5450 count_windows (struct window *window)
5451 {
5452   return 1 +
5453     (!NILP (window->next)   ? count_windows (XWINDOW (window->next))   : 0) +
5454     (!NILP (window->vchild) ? count_windows (XWINDOW (window->vchild)) : 0) +
5455     (!NILP (window->hchild) ? count_windows (XWINDOW (window->hchild)) : 0);
5456 }
5457
5458 static int
5459 saved_window_index (Lisp_Object window, struct window_config *config, int lim)
5460 {
5461   int j;
5462   for (j = 0; j < lim; j++)
5463     {
5464       if (EQ (SAVED_WINDOW_N (config, j)->window, window))
5465         return j;
5466     }
5467   abort ();
5468   return 0;     /* suppress compiler warning */
5469 }
5470
5471 static int
5472 save_window_save (Lisp_Object window, struct window_config *config, int i)
5473 {
5474   struct window *w;
5475
5476   for (; !NILP (window); window = w->next)
5477     {
5478       struct saved_window *p = SAVED_WINDOW_N (config, i);
5479
5480       w = XWINDOW (window);
5481       i++;
5482       p->window = window;
5483       p->buffer = w->buffer;
5484       WINDOW_LEFT (p) = WINDOW_LEFT (w);
5485       WINDOW_TOP (p) = WINDOW_TOP (w);
5486       WINDOW_WIDTH (p) = WINDOW_WIDTH (w);
5487       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (w);
5488       p->hscroll = w->hscroll;
5489       p->modeline_hscroll = w->modeline_hscroll;
5490
5491 #define WINDOW_SLOT(slot, compare) p->slot = w->slot
5492 #include "winslots.h"
5493
5494       if (!NILP (w->buffer))
5495         {
5496           /* Save w's value of point in the window configuration.
5497              If w is the selected window, then get the value of point
5498              from the buffer; pointm is garbage in the selected window.  */
5499           if (EQ (window, Fselected_window (Qnil)))
5500             {
5501               p->pointm = noseeum_make_marker ();
5502               Fset_marker (p->pointm,
5503                            make_int (BUF_PT (XBUFFER (w->buffer))),
5504                            w->buffer);
5505             }
5506           else
5507             p->pointm = noseeum_copy_marker (w->pointm[CURRENT_DISP], Qnil);
5508
5509           p->start = noseeum_copy_marker (w->start[CURRENT_DISP], Qnil);
5510           p->sb_point = noseeum_copy_marker (w->sb_point, Qnil);
5511           p->start_at_line_beg = w->start_at_line_beg;
5512
5513           p->mark = noseeum_copy_marker (XBUFFER (w->buffer)->mark, Qnil);
5514         }
5515       else
5516         {
5517           p->pointm = Qnil;
5518           p->start = Qnil;
5519           p->sb_point = Qnil;
5520           p->mark = Qnil;
5521           p->start_at_line_beg = 0;
5522         }
5523
5524       if (NILP (w->parent))
5525         p->parent_index = -1;
5526       else
5527         p->parent_index = saved_window_index (w->parent, config, i);
5528       if (NILP (w->prev))
5529         p->prev_index = -1;
5530       else
5531         p->prev_index = saved_window_index (w->prev, config, i);
5532       if (!NILP (w->vchild))
5533         i = save_window_save (w->vchild, config, i);
5534       if (!NILP (w->hchild))
5535         i = save_window_save (w->hchild, config, i);
5536     }
5537
5538   return i;
5539 }
5540
5541 #if 0 /* FSFmacs */
5542 /* Added to doc string:
5543
5544 This also records the currently selected frame, and FRAME's focus
5545 redirection (see `redirect-frame-focus').
5546
5547 */
5548 #endif
5549
5550 DEFUN ("current-window-configuration", Fcurrent_window_configuration, 0, 1, 0, /*
5551 Return an object representing the current window configuration of FRAME.
5552 If FRAME is nil or omitted, use the selected frame.
5553 This describes the number of windows, their sizes and current buffers,
5554 and for each displayed buffer, where display starts, and the positions of
5555 point and mark.  An exception is made for point in the current buffer:
5556 its value is -not- saved.
5557 */
5558        (frame))
5559 {
5560   Lisp_Object result;
5561   struct frame *f = decode_frame (frame);
5562   struct window_config *config;
5563   int n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
5564   int minibuf_height;
5565   int real_font_height;
5566
5567   if (n_windows <= countof (Vwindow_configuration_free_list))
5568     config = XWINDOW_CONFIGURATION (allocate_managed_lcrecord
5569                                     (Vwindow_configuration_free_list
5570                                      [n_windows - 1]));
5571   else
5572     /* More than ten windows; just allocate directly */
5573     config = (struct window_config *)
5574       alloc_lcrecord (sizeof_window_config_for_n_windows (n_windows),
5575                       &lrecord_window_configuration);
5576   XSETWINDOW_CONFIGURATION (result, config);
5577   /*
5578   config->frame_width = FRAME_WIDTH (f);
5579   config->frame_height = FRAME_HEIGHT (f); */
5580   config->current_window = FRAME_SELECTED_WINDOW (f);
5581   XSETBUFFER (config->current_buffer, current_buffer);
5582   config->minibuffer_scroll_window = Vminibuffer_scroll_window;
5583   config->root_window = FRAME_ROOT_WINDOW (f);
5584   config->min_height = window_min_height;
5585   config->min_width = window_min_width;
5586   config->saved_windows_count = n_windows;
5587   save_window_save (FRAME_ROOT_WINDOW (f), config, 0);
5588
5589   /* save the minibuffer height using the heuristics from
5590      change_frame_size_1 */
5591
5592   XSETFRAME (frame, f); /* frame could have been nil ! */
5593   default_face_height_and_width (frame, &real_font_height, 0);
5594   assert(real_font_height > 0);
5595
5596   if (FRAME_HAS_MINIBUF_P (f) && ! FRAME_MINIBUF_ONLY_P (f))
5597     minibuf_height = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_height;
5598   else
5599     minibuf_height = 0;
5600   config->minibuf_height = (minibuf_height % real_font_height) == 0 ?
5601     - (minibuf_height / real_font_height ) :    /* lines */
5602     minibuf_height;   /* pixels */
5603
5604   return result;
5605 }
5606
5607 Lisp_Object
5608 save_window_excursion_unwind (Lisp_Object window_config)
5609 {
5610   Lisp_Object val = Fset_window_configuration (window_config);
5611   free_window_configuration (window_config);
5612   return val;
5613 }
5614
5615 DEFUN ("save-window-excursion", Fsave_window_excursion, 0, UNEVALLED, 0, /*
5616 Execute body, preserving window sizes and contents.
5617 Restores which buffer appears in which window, where display starts,
5618 as well as the current buffer.
5619 Does not restore the value of point in current buffer.
5620 */
5621        (args))
5622 {
5623   /* This function can GC */
5624   Lisp_Object val;
5625   int speccount = specpdl_depth ();
5626
5627   record_unwind_protect (save_window_excursion_unwind,
5628                          Fcurrent_window_configuration (Qnil));
5629   val = Fprogn (args);
5630   return unbind_to (speccount, val);
5631 }
5632
5633 DEFUN ("current-pixel-column", Fcurrent_pixel_column, 0, 2, 0, /*
5634 Return the horizontal pixel position of POS in window.
5635 Beginning of line is column 0. This is calculated using the redisplay
5636 display tables.  If WINDOW is nil, the current window is assumed.
5637 If POS is nil, point is assumed. Note that POS must be visible for
5638 a non-nil result to be returned.
5639 */
5640        (window, pos))
5641 {
5642   struct window* w = decode_window (window);
5643   display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
5644
5645   struct display_line *dl = 0;
5646   struct display_block *db = 0;
5647   struct rune* rb = 0;
5648   int y = w->last_point_y[CURRENT_DISP];
5649   int x = w->last_point_x[CURRENT_DISP];
5650
5651   if (MINI_WINDOW_P (w))
5652     return Qnil;
5653
5654   if (y<0 || x<0 || y >= Dynarr_length (dla) || !NILP (pos))
5655     {
5656       int first_line, i;
5657       Bufpos point;
5658
5659       if (NILP (pos))
5660         pos = Fwindow_point (window);
5661
5662       CHECK_INT (pos);
5663       point = XINT (pos);
5664
5665       if (Dynarr_length (dla) && Dynarr_atp (dla, 0)->modeline)
5666         first_line = 1;
5667       else
5668         first_line = 0;
5669
5670       for (i = first_line; i < Dynarr_length (dla); i++)
5671         {
5672           dl = Dynarr_atp (dla, i);
5673           /* find the vertical location first */
5674           if (point >= dl->bufpos && point <= dl->end_bufpos)
5675             {
5676               db = get_display_block_from_line (dl, TEXT);
5677               for (i = 0; i < Dynarr_length (db->runes); i++)
5678                 {
5679                   rb = Dynarr_atp (db->runes, i);
5680                   if (point <= rb->bufpos)
5681                     goto found_bufpos;
5682                 }
5683               return Qnil;
5684             }
5685         }
5686       return Qnil;
5687     found_bufpos:
5688       ;
5689     }
5690   else
5691     {
5692       /* optimised case */
5693       dl = Dynarr_atp (dla, y);
5694       db = get_display_block_from_line (dl, TEXT);
5695
5696       if (x >= Dynarr_length (db->runes))
5697         return Qnil;
5698
5699       rb = Dynarr_atp (db->runes, x);
5700     }
5701
5702   return make_int (rb->xpos - WINDOW_LEFT (w));
5703 }
5704
5705 \f
5706 #ifdef DEBUG_XEMACS
5707 /* This is short and simple in elisp, but... it was written to debug
5708    problems purely on the C side.  That is where we need to call it so
5709    here it is. */
5710 static void
5711 debug_print_window (Lisp_Object window, int level)
5712 {
5713   int i;
5714   Lisp_Object child = Fwindow_first_vchild (window);
5715
5716   if (NILP (child))
5717     child = Fwindow_first_hchild (window);
5718
5719   for (i = level; i > 0; i--)
5720     putc ('\t', stderr);
5721
5722   fputs ("#<window", stderr);
5723   {
5724     Lisp_Object buffer = XWINDOW (window)->buffer;
5725     if (!NILP (buffer) && BUFFERP (buffer))
5726       fprintf (stderr, " on %s", XSTRING_DATA (XBUFFER (buffer)->name));
5727   }
5728   fprintf (stderr, " 0x%x>", XWINDOW (window)->header.uid);
5729
5730   while (!NILP (child))
5731     {
5732       debug_print_window (child, level + 1);
5733       child = Fwindow_next_child (child);
5734     }
5735 }
5736
5737 void debug_print_windows (struct frame *f);
5738 void
5739 debug_print_windows (struct frame *f)
5740 {
5741   debug_print_window (f->root_window, 0);
5742   putc ('\n', stderr);
5743 }
5744 #endif /* DEBUG_XEMACS */
5745
5746 \f
5747 /************************************************************************/
5748 /*                            initialization                            */
5749 /************************************************************************/
5750
5751 void
5752 syms_of_window (void)
5753 {
5754   defsymbol (&Qwindowp, "windowp");
5755   defsymbol (&Qwindow_live_p, "window-live-p");
5756   defsymbol (&Qwindow_configurationp, "window-configuration-p");
5757   defsymbol (&Qtemp_buffer_show_hook, "temp-buffer-show-hook");
5758   defsymbol (&Qdisplay_buffer, "display-buffer");
5759
5760 #ifdef MEMORY_USAGE_STATS
5761   defsymbol (&Qface_cache, "face-cache");
5762   defsymbol (&Qglyph_cache, "glyph-cache");
5763   defsymbol (&Qline_start_cache, "line-start-cache");
5764 #ifdef HAVE_SCROLLBARS
5765   defsymbol (&Qscrollbar_instances, "scrollbar-instances");
5766 #endif
5767   defsymbol (&Qother_redisplay, "other-redisplay");
5768   /* Qother in general.c */
5769 #endif
5770
5771   DEFSUBR (Fselected_window);
5772   DEFSUBR (Flast_nonminibuf_window);
5773   DEFSUBR (Fminibuffer_window);
5774   DEFSUBR (Fwindow_minibuffer_p);
5775   DEFSUBR (Fwindowp);
5776   DEFSUBR (Fwindow_live_p);
5777   DEFSUBR (Fwindow_first_hchild);
5778   DEFSUBR (Fwindow_first_vchild);
5779   DEFSUBR (Fwindow_next_child);
5780   DEFSUBR (Fwindow_previous_child);
5781   DEFSUBR (Fwindow_parent);
5782   DEFSUBR (Fwindow_lowest_p);
5783   DEFSUBR (Fwindow_truncated_p);
5784   DEFSUBR (Fwindow_highest_p);
5785   DEFSUBR (Fwindow_leftmost_p);
5786   DEFSUBR (Fwindow_rightmost_p);
5787   DEFSUBR (Fpos_visible_in_window_p);
5788   DEFSUBR (Fwindow_buffer);
5789   DEFSUBR (Fwindow_frame);
5790   DEFSUBR (Fwindow_height);
5791   DEFSUBR (Fwindow_displayed_height);
5792   DEFSUBR (Fwindow_width);
5793   DEFSUBR (Fwindow_pixel_height);
5794   DEFSUBR (Fwindow_pixel_width);
5795   DEFSUBR (Fwindow_text_area_pixel_height);
5796   DEFSUBR (Fwindow_displayed_text_pixel_height);
5797   DEFSUBR (Fwindow_text_area_pixel_width);
5798   DEFSUBR (Fwindow_hscroll);
5799   DEFSUBR (Fset_window_hscroll);
5800   DEFSUBR (Fmodeline_hscroll);
5801   DEFSUBR (Fset_modeline_hscroll);
5802 #if 0 /* bogus FSF crock */
5803   DEFSUBR (Fwindow_redisplay_end_trigger);
5804   DEFSUBR (Fset_window_redisplay_end_trigger);
5805 #endif
5806   DEFSUBR (Fwindow_pixel_edges);
5807   DEFSUBR (Fwindow_text_area_pixel_edges);
5808   DEFSUBR (Fwindow_point);
5809   DEFSUBR (Fwindow_start);
5810   DEFSUBR (Fwindow_end);
5811   DEFSUBR (Fset_window_point);
5812   DEFSUBR (Fset_window_start);
5813   DEFSUBR (Fwindow_dedicated_p);
5814   DEFSUBR (Fset_window_dedicated_p);
5815   DEFSUBR (Fnext_window);
5816   DEFSUBR (Fprevious_window);
5817   DEFSUBR (Fnext_vertical_window);
5818   DEFSUBR (Fother_window);
5819   DEFSUBR (Fget_lru_window);
5820   DEFSUBR (Fget_largest_window);
5821   DEFSUBR (Fget_buffer_window);
5822   DEFSUBR (Fwindow_left_margin_pixel_width);
5823   DEFSUBR (Fwindow_right_margin_pixel_width);
5824   DEFSUBR (Fdelete_other_windows);
5825   DEFSUBR (Fdelete_windows_on);
5826   DEFSUBR (Freplace_buffer_in_windows);
5827   DEFSUBR (Fdelete_window);
5828   DEFSUBR (Fset_window_buffer);
5829   DEFSUBR (Fselect_window);
5830   DEFSUBR (Fsplit_window);
5831   DEFSUBR (Fenlarge_window);
5832   DEFSUBR (Fenlarge_window_pixels);
5833   DEFSUBR (Fshrink_window);
5834   DEFSUBR (Fshrink_window_pixels);
5835   DEFSUBR (Fscroll_up);
5836   DEFSUBR (Fscroll_down);
5837   DEFSUBR (Fscroll_left);
5838   DEFSUBR (Fscroll_right);
5839   DEFSUBR (Fother_window_for_scrolling);
5840   DEFSUBR (Fscroll_other_window);
5841   DEFSUBR (Fcenter_to_window_line);
5842   DEFSUBR (Fmove_to_window_line);
5843 #ifdef MEMORY_USAGE_STATS
5844   DEFSUBR (Fwindow_memory_usage);
5845 #endif
5846   DEFSUBR (Fwindow_configuration_p);
5847   DEFSUBR (Fset_window_configuration);
5848   DEFSUBR (Fcurrent_window_configuration);
5849   DEFSUBR (Fsave_window_excursion);
5850   DEFSUBR (Fcurrent_pixel_column);
5851 }
5852
5853 void
5854 reinit_vars_of_window (void)
5855 {
5856   int i;
5857   /* Make sure all windows get marked */
5858   minibuf_window = Qnil;
5859   staticpro_nodump (&minibuf_window);
5860
5861   for (i = 0; i < countof (Vwindow_configuration_free_list); i++)
5862     {
5863       Vwindow_configuration_free_list[i] =
5864         make_lcrecord_list (sizeof_window_config_for_n_windows (i + 1),
5865                             &lrecord_window_configuration);
5866       staticpro_nodump (&Vwindow_configuration_free_list[i]);
5867     }
5868 }
5869
5870 void
5871 vars_of_window (void)
5872 {
5873   reinit_vars_of_window ();
5874
5875   DEFVAR_BOOL ("scroll-on-clipped-lines", &scroll_on_clipped_lines /*
5876 *Non-nil means to scroll if point lands on a line which is clipped.
5877 */ );
5878   scroll_on_clipped_lines = 1;
5879
5880   DEFVAR_LISP ("temp-buffer-show-hook", &Vtemp_buffer_show_hook /*
5881 See `temp-buffer-show-function'.
5882 */ );
5883   Vtemp_buffer_show_hook = Qnil;
5884
5885   DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function /*
5886 Non-nil means call as function to display a help buffer.
5887 The function is called with one argument, the buffer to be displayed.
5888 Used by `with-output-to-temp-buffer'.
5889 If this function is used, then it must do the entire job of showing
5890 the buffer; `temp-buffer-show-hook' is not run unless this function runs it.
5891 */ );
5892   Vtemp_buffer_show_function = Qnil;
5893
5894   DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuffer_scroll_window /*
5895 Non-nil means it is the window that \\<minibuffer-local-map>\\[scroll-other-window] in minibuffer should scroll.
5896 */ );
5897   Vminibuffer_scroll_window = Qnil;
5898
5899   DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer /*
5900 If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.
5901 */ );
5902   Vother_window_scroll_buffer = Qnil;
5903
5904   DEFVAR_LISP ("window-pixel-scroll-increment", &Vwindow_pixel_scroll_increment /*
5905 *Number of pixels to scroll by per requested line.
5906 If nil then normal line scrolling occurs regardless of line height.
5907 If t then scrolling is done in increments equal to the height of the default face.
5908 */ );
5909   Vwindow_pixel_scroll_increment = Qt;
5910
5911   DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines /*
5912 *Number of lines of continuity when scrolling by screenfuls.
5913 */ );
5914   next_screen_context_lines = 2;
5915
5916   DEFVAR_INT ("window-min-height", &window_min_height /*
5917 *Delete any window less than this tall (including its modeline).
5918 */ );
5919   window_min_height = 4;
5920
5921   DEFVAR_INT ("window-min-width", &window_min_width /*
5922 *Delete any window less than this wide.
5923 */ );
5924   window_min_width = 10;
5925 }
5926
5927 void
5928 specifier_vars_of_window (void)
5929 {
5930   DEFVAR_SPECIFIER ("modeline-shadow-thickness", &Vmodeline_shadow_thickness /*
5931 *How thick to draw 3D shadows around modelines.
5932 If this is set to 0, modelines will be the traditional 2D.  Sizes above
5933 10 will be accepted but the maximum thickness that will be drawn is 10.
5934 This is a specifier; use `set-specifier' to change it.
5935 */ );
5936   Vmodeline_shadow_thickness = Fmake_specifier (Qinteger);
5937   /* The initial value for modeline-shadow-thickness is 2, but if the
5938      user removes all specifications we provide a fallback value of 0,
5939      which is probably what was expected. */
5940   set_specifier_fallback (Vmodeline_shadow_thickness,
5941                           list1 (Fcons (Qnil, Qzero)));
5942   Fadd_spec_to_specifier (Vmodeline_shadow_thickness, make_int (2),
5943                           Qnil, Qnil, Qnil);
5944   set_specifier_caching (Vmodeline_shadow_thickness,
5945                          offsetof (struct window, modeline_shadow_thickness),
5946                          modeline_shadow_thickness_changed,
5947                          0, 0);
5948
5949   DEFVAR_SPECIFIER ("has-modeline-p", &Vhas_modeline_p /*
5950 *Whether the modeline should be displayed.
5951 This is a specifier; use `set-specifier' to change it.
5952 */ );
5953   Vhas_modeline_p = Fmake_specifier (Qboolean);
5954   set_specifier_fallback (Vhas_modeline_p,
5955                           list1 (Fcons (Qnil, Qt)));
5956   set_specifier_caching (Vhas_modeline_p,
5957                          offsetof (struct window, has_modeline_p),
5958                          /* #### It's strange that we need a special
5959                             flag to indicate that the shadow-thickness
5960                             has changed, but not one to indicate that
5961                             the modeline has been turned off or on. */
5962                          some_window_value_changed,
5963                          0, 0);
5964
5965   DEFVAR_SPECIFIER ("vertical-divider-always-visible-p",
5966                     &Vvertical_divider_always_visible_p /*
5967 *Should XEmacs always display vertical dividers between windows.
5968
5969 When this is non-nil, vertical dividers are always shown, and are
5970 draggable.  When it is nil, vertical dividers are shown only when
5971 there are no scrollbars in between windows, and are not draggable.
5972
5973 This is a specifier; use `set-specifier' to change it.
5974 */ );
5975   Vvertical_divider_always_visible_p = Fmake_specifier (Qboolean);
5976   set_specifier_fallback (Vvertical_divider_always_visible_p,
5977                           list1 (Fcons (Qnil, Qt)));
5978   set_specifier_caching (Vvertical_divider_always_visible_p,
5979                          offsetof (struct window,
5980                                    vertical_divider_always_visible_p),
5981                          vertical_divider_changed_in_window,
5982                          0, 0);
5983
5984   DEFVAR_SPECIFIER ("vertical-divider-shadow-thickness", &Vvertical_divider_shadow_thickness /*
5985 *How thick to draw 3D shadows around vertical dividers.
5986 This is a specifier; use `set-specifier' to change it.
5987 */ );
5988   Vvertical_divider_shadow_thickness = Fmake_specifier (Qinteger);
5989   set_specifier_fallback (Vvertical_divider_shadow_thickness,
5990                           list1 (Fcons (Qnil, Qzero)));
5991   Fadd_spec_to_specifier (Vvertical_divider_shadow_thickness, make_int (2),
5992                           Qnil, Qnil, Qnil);
5993   set_specifier_caching (Vvertical_divider_shadow_thickness,
5994                          offsetof (struct window,
5995                                    vertical_divider_shadow_thickness),
5996                          vertical_divider_changed_in_window,
5997                          0, 0);
5998   DEFVAR_SPECIFIER ("vertical-divider-line-width", &Vvertical_divider_line_width /*
5999 *The width of the vertical dividers, not including shadows.
6000
6001 For TTY windows, divider line is always one character wide.  When
6002 instance of this specifier is zero in a TTY window, no divider is
6003 drawn at all between windows.  When non-zero, a one character wide
6004 divider is displayed.
6005
6006 This is a specifier; use `set-specifier' to change it.
6007 */ );
6008
6009   Vvertical_divider_line_width = Fmake_specifier (Qnatnum);
6010   {
6011     Lisp_Object fb = Qnil;
6012 #ifdef HAVE_TTY
6013     fb = Fcons (Fcons (list1 (Qtty), make_int (1)), fb);
6014 #endif
6015 #ifdef HAVE_X_WINDOWS
6016     fb = Fcons (Fcons (list1 (Qx), make_int (3)), fb);
6017 #endif
6018 #ifdef HAVE_MS_WINDOWS
6019     /* #### This should be made magic and made to obey system settings */
6020     fb = Fcons (Fcons (list1 (Qmswindows), make_int (3)), fb);
6021 #endif
6022     set_specifier_fallback (Vvertical_divider_line_width, fb);
6023   }
6024   set_specifier_caching (Vvertical_divider_line_width,
6025                          offsetof (struct window,
6026                                    vertical_divider_line_width),
6027                          vertical_divider_changed_in_window,
6028                          0, 0);
6029
6030   DEFVAR_SPECIFIER ("vertical-divider-spacing", &Vvertical_divider_spacing /*
6031 *How much space to leave around the vertical dividers.
6032
6033 In TTY windows, spacing is always zero, and the value of this
6034 specifier is ignored.
6035
6036 This is a specifier; use `set-specifier' to change it.
6037 */ );
6038   Vvertical_divider_spacing = Fmake_specifier (Qnatnum);
6039   {
6040     Lisp_Object fb = Qnil;
6041 #ifdef HAVE_TTY
6042     fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
6043 #endif
6044 #ifdef HAVE_X_WINDOWS
6045     /* #### 3D dividers look great on MS Windows with spacing = 0.
6046        Should not the same value be the fallback under X? - kkm */
6047     fb = Fcons (Fcons (list1 (Qx), make_int (2)), fb);
6048 #endif
6049 #ifdef HAVE_MS_WINDOWS
6050     fb = Fcons (Fcons (list1 (Qmswindows), Qzero), fb);
6051 #endif
6052     set_specifier_fallback (Vvertical_divider_spacing, fb);
6053   }
6054   set_specifier_caching (Vvertical_divider_spacing,
6055                          offsetof (struct window, vertical_divider_spacing),
6056                          vertical_divider_changed_in_window,
6057                          0, 0);
6058 }