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