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