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