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