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