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