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