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