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