XEmacs 21.2.43 "Terspichore".
[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   unsigned 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   unsigned 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 inline static size_t
5054 sizeof_window_config_for_n_windows (unsigned int n)
5055 {
5056   return FLEXIBLE_ARRAY_STRUCT_SIZEOF (struct window_config,
5057                                        struct saved_window, saved_windows, n);
5058 }
5059
5060 static size_t
5061 sizeof_window_config (const void *h)
5062 {
5063   const struct window_config *c = (const struct window_config *) h;
5064   return sizeof_window_config_for_n_windows (c->saved_windows_count);
5065 }
5066
5067 static void
5068 print_window_config (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
5069 {
5070   struct window_config *config = XWINDOW_CONFIGURATION (obj);
5071   char buf[200];
5072   if (print_readably)
5073     error ("printing unreadable object #<window-configuration 0x%x>",
5074            config->header.uid);
5075   write_c_string ("#<window-configuration ", printcharfun);
5076   sprintf (buf, "0x%x>", config->header.uid);
5077   write_c_string (buf, printcharfun);
5078 }
5079
5080 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION ("window-configuration",
5081                                         window_configuration,
5082                                         mark_window_config,
5083                                         print_window_config,
5084                                         0, 0, 0, 0, sizeof_window_config,
5085                                         struct window_config);
5086
5087
5088 /* Returns a boolean indicating whether the two saved windows are
5089    identical. */
5090 static int
5091 saved_window_equal (struct saved_window *win1, struct saved_window *win2)
5092 {
5093 #define WINDOW_SLOT(slot, compare)              \
5094   if (!compare (win1->slot, win2->slot))        \
5095     return 0;
5096 #include "winslots.h"
5097
5098   return
5099     EQ (win1->window, win2->window) &&
5100     EQ (win1->buffer, win2->buffer) &&
5101     internal_equal (win1->start,    win2->start, 0) &&
5102     internal_equal (win1->pointm,   win2->pointm, 0) &&
5103     internal_equal (win1->sb_point, win2->sb_point, 0) &&
5104     internal_equal (win1->mark,     win2->mark, 0) &&
5105     win1->pixel_left   == win2->pixel_left &&
5106     win1->pixel_top    == win2->pixel_top &&
5107     win1->pixel_width  == win2->pixel_width &&
5108     win1->pixel_height == win2->pixel_height &&
5109     win1->hscroll      == win2->hscroll &&
5110     win1->modeline_hscroll == win2->modeline_hscroll &&
5111     win1->parent_index == win2->parent_index &&
5112     win1->prev_index   == win2->prev_index &&
5113     win1->start_at_line_beg == win2->start_at_line_beg;
5114 }
5115
5116 /* Returns a boolean indicating whether the two given configurations
5117    are identical. */
5118 static int
5119 window_config_equal (Lisp_Object conf1, Lisp_Object conf2)
5120 {
5121   struct window_config *fig1, *fig2;
5122   unsigned int i;
5123
5124   /* First check if they are truly the same. */
5125   if (EQ (conf1, conf2))
5126     return 1;
5127
5128   fig1 = XWINDOW_CONFIGURATION (conf1);
5129   fig2 = XWINDOW_CONFIGURATION (conf2);
5130
5131   if (!((fig1->saved_windows_count == fig2->saved_windows_count) &&
5132         EQ (fig1->current_window,           fig2->current_window) &&
5133         EQ (fig1->current_buffer,           fig2->current_buffer) &&
5134         EQ (fig1->root_window,              fig2->root_window) &&
5135         EQ (fig1->minibuffer_scroll_window, fig2->minibuffer_scroll_window)))
5136         /* &&
5137         fig1->frame_width  == fig2->frame_width &&
5138         fig1->frame_height == fig2->frame_height)) */
5139     return 0;
5140
5141   for (i = 0; i < fig1->saved_windows_count; i++)
5142     {
5143       if (!saved_window_equal (SAVED_WINDOW_N (fig1, i),
5144                                SAVED_WINDOW_N (fig2, i)))
5145         return 0;
5146     }
5147
5148   return 1;
5149 }
5150
5151 DEFUN ("window-configuration-p", Fwindow_configuration_p, 1, 1, 0, /*
5152 Return t if OBJECT is a window-configuration object.
5153 */
5154        (object))
5155 {
5156   return WINDOW_CONFIGURATIONP (object) ? Qt : Qnil;
5157 }
5158
5159 static int
5160 mark_windows_in_use_closure (struct window *w, void *closure)
5161 {
5162   int mark = *(int *)closure;
5163   w->config_mark = mark;
5164   return 0;
5165 }
5166
5167 static void
5168 mark_windows_in_use (struct frame *f, int mark)
5169 {
5170   map_windows (f, mark_windows_in_use_closure, &mark);
5171 }
5172
5173 /* Lisp_Object return value so it can be used in record_unwind_protect() */
5174 static Lisp_Object
5175 free_window_configuration (Lisp_Object window_config)
5176 {
5177   unsigned int i;
5178   struct window_config *config = XWINDOW_CONFIGURATION (window_config);
5179
5180   /* Free all the markers.  It's not completely necessary that
5181      we do this (window configs sitting in a free list aren't
5182      marked normally so the markers wouldn't be marked anyway)
5183      but it's more efficient. */
5184   for (i = 0; i < config->saved_windows_count; i++)
5185     {
5186       struct saved_window *p = SAVED_WINDOW_N (config, i);
5187
5188       if (!NILP (p->pointm))
5189         {
5190           free_marker (XMARKER (p->pointm));
5191           p->pointm = Qnil;
5192         }
5193       if (!NILP (p->start))
5194         {
5195           free_marker (XMARKER (p->start));
5196           p->start = Qnil;
5197         }
5198       if (!NILP (p->sb_point))
5199         {
5200           free_marker (XMARKER (p->sb_point));
5201           p->sb_point = Qnil;
5202         }
5203       if (!NILP (p->mark))
5204         {
5205           free_marker (XMARKER (p->mark));
5206           p->mark = Qnil;
5207         }
5208     }
5209
5210   if (config->saved_windows_count <= countof (Vwindow_configuration_free_list))
5211     free_managed_lcrecord (Vwindow_configuration_free_list
5212                            [config->saved_windows_count - 1],
5213                            window_config);
5214
5215   return Qnil;
5216 }
5217
5218 DEFUN ("set-window-configuration", Fset_window_configuration, 1, 1, 0, /*
5219 Set the configuration of windows and buffers as specified by CONFIGURATION.
5220 CONFIGURATION must be a value previously returned
5221 by `current-window-configuration' (which see).
5222 */
5223        (configuration))
5224 {
5225   struct window *w;
5226   struct window_config *config;
5227   struct saved_window *p;
5228   Lisp_Object new_current_buffer;
5229   unsigned int k;
5230   Lisp_Object frame;
5231   struct frame *f;
5232   struct gcpro gcpro1;
5233   Lisp_Object old_window_config;
5234   /*  int previous_frame_height;
5235       int previous_frame_width;*/
5236   int previous_pixel_top;
5237   int previous_pixel_height;
5238   int previous_pixel_left;
5239   int previous_pixel_width;
5240   int previous_minibuf_height, previous_minibuf_top,previous_minibuf_width;
5241   int real_font_height;
5242   int converted_minibuf_height,target_minibuf_height;
5243   int specpdl_count = specpdl_depth ();
5244
5245   GCPRO1 (configuration);
5246
5247   CHECK_WINDOW_CONFIGURATION (configuration);
5248   config = XWINDOW_CONFIGURATION (configuration);
5249
5250   frame = XWINDOW (SAVED_WINDOW_N (config, 0)->window)->frame;
5251   f = XFRAME (frame);
5252
5253   /* Do not signal an error here if the frame was deleted.  There are
5254      reasonable cases where we could get here with a deleted frame and
5255      just want to do close to nothing instead. */
5256
5257   if (FRAME_LIVE_P (f))
5258     {
5259       /* restore the frame characteristics */
5260
5261       new_current_buffer = config->current_buffer;
5262       if (!BUFFER_LIVE_P (XBUFFER (new_current_buffer)))
5263         new_current_buffer = Qnil;
5264
5265       /*
5266        * Assumed precondition:  w->config_mark = 0 for all w
5267        * This procedure should ensure this is true by the time it exits
5268        * to ensure the precondition for future calls.
5269        *
5270        * We use w->config_mark to know whether we're modifying a
5271        * window that is currently visible on the frame (#### we
5272        * should just be able to check whether the window is dead
5273        * or not, but this way is safer?).  As we process each
5274        * window, we set its config_mark to 0.  At the end, we
5275        * go through all the windows that used to be on the frame,
5276        * set each one's config_mark to 0 (to maintain the
5277        * assumed precondition) and delete each one that's no
5278        * longer in use.
5279        *
5280        * #### Using a window-configuration to keep track of
5281        * the current windows is wasteful.  All we need is the
5282        * list of windows, so we could just use a dynarr.
5283        */
5284       old_window_config = Fcurrent_window_configuration (frame);
5285
5286       /* If the new configuration is already equal to the old, then stop
5287          right here.  This saves the work below and it also saves
5288          triggering a full redisplay of this window.  This is a huge win
5289          when using the mouse since the mode motion code uses
5290          save-window-excursion extensively but will rarely cause the
5291          configuration to actually change. */
5292       if (window_config_equal (configuration, old_window_config))
5293         {
5294           free_window_configuration (old_window_config);
5295           UNGCPRO;
5296           return Qnil;
5297         }
5298
5299       /* We can't quit or even check for quit because that may cause
5300          investigation of the frame state, which may crash if the frame is
5301          in an inconsistent state. */
5302       begin_dont_check_for_quit ();
5303       record_unwind_protect (free_window_configuration, old_window_config);
5304
5305       mark_windows_in_use (f, 1);
5306 #ifdef BROKEN_SUBWINDOW_REDISPLAY
5307       /* Force subwindows to be remapped. This is overkill but saves
5308         us having to rely on the redisplay code to unmap any extant
5309         subwindows.
5310
5311         #### It does cause some extra flashing though which we could
5312         possibly avoid. So consider trying to get redisplay to work
5313         correctly.
5314
5315         Removing the instances from the frame cache is wrong because
5316         an instance is only put in the frame cache when it is
5317         instantiated. So if we do this there is a chance that stuff
5318         will never get put back in the frame cache. */
5319       reset_frame_subwindow_instance_cache (f);
5320 #endif
5321 #if 0
5322       /* JV: This is bogus,
5323          First of all, the units are inconsistent. The frame sizes are measured
5324          in characters but the window sizes are stored in pixels. So if a
5325          font size change happened between saving and restoring, the
5326          frame "sizes" maybe equal but the windows still should be
5327          resized. This is tickled a lot by the new "character size
5328          stays constant" policy in 21.0. It leads to very weird
5329          glitches (and possibly crashes when asserts are tickled).
5330
5331          Just changing the units doesn't help because changing the
5332          toolbar configuration can also change the pixel positions.
5333          Luckily there is a much simpler way of doing this, see below.
5334        */
5335       previous_frame_width = FRAME_WIDTH (f);
5336       previous_frame_height = FRAME_HEIGHT (f);
5337       /* If the frame has been resized since this window configuration was
5338          made, we change the frame to the size specified in the
5339          configuration, restore the configuration, and then resize it
5340          back.  We keep track of the prevailing height in these variables.  */
5341       if (config->frame_height != FRAME_HEIGHT (f)
5342           || config->frame_width != FRAME_WIDTH (f))
5343         change_frame_size (f, config->frame_height, config->frame_width, 0);
5344 #endif
5345
5346       previous_pixel_top = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_top;
5347       previous_pixel_height = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_height;
5348       previous_pixel_left = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_left;
5349       previous_pixel_width = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_width;
5350
5351       /* remember some properties of the minibuffer */
5352
5353       default_face_height_and_width (frame, &real_font_height, 0);
5354       assert(real_font_height > 0);
5355
5356       if (FRAME_HAS_MINIBUF_P (f) && ! FRAME_MINIBUF_ONLY_P (f))
5357         {
5358           previous_minibuf_height
5359             = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_height;
5360           previous_minibuf_top
5361             = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_top;
5362           previous_minibuf_width
5363             = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_width;
5364         }
5365       else
5366         {
5367           previous_minibuf_height = 0;
5368           previous_minibuf_top = 0;
5369           previous_minibuf_width = 0;
5370         }
5371       converted_minibuf_height =
5372         (previous_minibuf_height % real_font_height) == 0 ?
5373         - (previous_minibuf_height / real_font_height ) :    /* lines */
5374             previous_minibuf_height;   /* pixels */
5375
5376       /* Temporarily avoid any problems with windows that are smaller
5377          than they are supposed to be.  */
5378       window_min_height = 1;
5379       window_min_width = 1;
5380
5381       /* OK, now restore all the windows in the window config.
5382          This may involve "undeleting" windows, since the
5383          windows in the window config may be deleted.
5384          */
5385       for (k = 0; k < config->saved_windows_count; k++)
5386         {
5387           p = SAVED_WINDOW_N (config, k);
5388           w = XWINDOW (p->window);
5389           w->next = Qnil;
5390
5391           /* The window might be dead.  In this case, its redisplay
5392              structures were freed, so we need to reallocate them. */
5393           if (!w->face_cachels)
5394             {
5395               w->face_cachels = Dynarr_new (face_cachel);
5396               reset_face_cachels (w);
5397             }
5398           if (!w->glyph_cachels)
5399             w->glyph_cachels = Dynarr_new (glyph_cachel);
5400           if (!w->line_start_cache)
5401             w->line_start_cache = Dynarr_new (line_start_cache);
5402           w->gutter_extent_modiff[0] = 0;
5403           w->gutter_extent_modiff[1] = 0;
5404           w->gutter_extent_modiff[2] = 0;
5405           w->gutter_extent_modiff[3] = 0;
5406           w->dead = 0;
5407
5408           if (p->parent_index >= 0)
5409             w->parent = SAVED_WINDOW_N (config, p->parent_index)->window;
5410           else
5411             w->parent = Qnil;
5412
5413           if (p->prev_index >= 0)
5414             {
5415               w->prev = SAVED_WINDOW_N (config, p->prev_index)->window;
5416
5417               /* This is true for a minibuffer-only frame. */
5418               if (!NILP (w->mini_p) && EQ (w->prev, p->window))
5419                 w->next = Qnil;
5420               else
5421                 XWINDOW (w->prev)->next = p->window;
5422             }
5423           else
5424             {
5425               w->prev = Qnil;
5426               if (!NILP (w->parent))
5427                 {
5428                   if (WINDOW_WIDTH (p) == WINDOW_WIDTH (XWINDOW (w->parent)))
5429                     {
5430                       XWINDOW (w->parent)->vchild = p->window;
5431                       XWINDOW (w->parent)->hchild = Qnil;
5432                     }
5433                   else
5434                     {
5435                       XWINDOW (w->parent)->hchild = p->window;
5436                       XWINDOW (w->parent)->vchild = Qnil;
5437                     }
5438                 }
5439             }
5440           if (!w->config_mark)
5441             {
5442               /* #### This should be equivalent to the window previously
5443                  having been dead.  If we're brave, we'll put in an
5444                  assertion to this effect. */
5445               MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
5446             }
5447           else /* if (!EQ (w->buffer, p->buffer)) */
5448             {
5449               /* With the new redisplay we let it know that a change has
5450                  been made and it will take care of the rest.  If we don't
5451                  tell it something has possibly changed it could lead to
5452                  incorrect display. */
5453               MARK_WINDOWS_CHANGED (w);
5454             }
5455
5456           WINDOW_LEFT (w) = WINDOW_LEFT (p);
5457           WINDOW_TOP (w) = WINDOW_TOP (p);
5458           WINDOW_WIDTH (w) = WINDOW_WIDTH (p);
5459           WINDOW_HEIGHT (w) = WINDOW_HEIGHT (p);
5460           w->hscroll = p->hscroll;
5461           w->modeline_hscroll = p->modeline_hscroll;
5462           w->line_cache_last_updated = Qzero;
5463           /* When we restore a window's configuration, the identity of
5464              the window hasn't actually changed - so there is no
5465              reason why we shouldn't preserve the instance cache for
5466              it - unless it was originally deleted. This will often
5467              buy us something as we will not have to re-instantiate
5468              all the instances. This is because this is an instance
5469              cache - not a display cache. Preserving the display cache
5470              would definitely be wrong.
5471
5472              We specifically want to do this for tabs, since for some
5473              reason finding a file will cause the configuration to be
5474              set. */
5475           if (NILP (w->subwindow_instance_cache))
5476             w->subwindow_instance_cache =
5477               make_image_instance_cache_hash_table ();
5478
5479           SET_LAST_MODIFIED (w, 1);
5480           SET_LAST_FACECHANGE (w);
5481           w->config_mark = 0;
5482
5483           /* #### Consider making the instance cache a winslot. */
5484 #define WINDOW_SLOT(slot, compare) w->slot = p->slot
5485 #include "winslots.h"
5486
5487           /* Reinstall the saved buffer and pointers into it.  */
5488           if (NILP (p->buffer))
5489             w->buffer = p->buffer;
5490           else
5491             {
5492               if (BUFFER_LIVE_P (XBUFFER (p->buffer)))
5493                 /* If saved buffer is alive, install it.  */
5494                 {
5495                   w->buffer = p->buffer;
5496                   w->start_at_line_beg = p->start_at_line_beg;
5497                   set_marker_restricted (w->start[CURRENT_DISP],
5498                                          Fmarker_position (p->start),
5499                                          w->buffer);
5500                   set_marker_restricted (w->pointm[CURRENT_DISP],
5501                                          Fmarker_position (p->pointm),
5502                                          w->buffer);
5503                   set_marker_restricted (w->sb_point,
5504                                          Fmarker_position (p->sb_point),
5505                                          w->buffer);
5506                   Fset_marker (XBUFFER (w->buffer)->mark,
5507                                Fmarker_position (p->mark), w->buffer);
5508
5509                   /* As documented in Fcurrent_window_configuration, don't
5510                      save the location of point in the buffer which was current
5511                      when the window configuration was recorded.  */
5512                   if (!EQ (p->buffer, new_current_buffer) &&
5513                       XBUFFER (p->buffer) == current_buffer)
5514                     Fgoto_char (w->pointm[CURRENT_DISP], Qnil);
5515                 }
5516               else if (NILP (w->buffer) ||
5517                        !BUFFER_LIVE_P (XBUFFER (w->buffer)))
5518                 /* Else if window's old buffer is dead too, get a live one.  */
5519                 {
5520                   /* #### The following line makes me nervous... */
5521                   /* w->buffer = Fcdr (Fcar (XFRAME (w->frame)->buffer_alist));*/
5522                   w->buffer = Fget_buffer_create (QSscratch);
5523                   /* w->buffer = Fother_buffer (Qnil, w->frame, Qnil); */
5524                   /* This will set the markers to beginning of visible
5525                      range.  */
5526                   set_marker_restricted (w->start[CURRENT_DISP], Qzero, w->buffer);
5527                   set_marker_restricted (w->pointm[CURRENT_DISP], Qzero,
5528                                          w->buffer);
5529                   set_marker_restricted (w->sb_point, Qzero, w->buffer);
5530                   w->start_at_line_beg = 1;
5531                 }
5532               else
5533                 /* Keeping window's old buffer; make sure the markers
5534                    are real.  */
5535                 {
5536                   /* Set window markers at start of visible range.  */
5537                   if (XMARKER (w->start[CURRENT_DISP])->buffer == 0)
5538                     set_marker_restricted (w->start[CURRENT_DISP], Qzero,
5539                                            w->buffer);
5540                   if (XMARKER (w->sb_point)->buffer == 0)
5541                     set_marker_restricted (w->sb_point, Qzero, w->buffer);
5542                   if (XMARKER (w->pointm[CURRENT_DISP])->buffer == 0)
5543                     set_marker_restricted (w->pointm[CURRENT_DISP],
5544                                            make_int
5545                                            (BUF_PT (XBUFFER (w->buffer))),
5546                                            w->buffer);
5547                   w->start_at_line_beg = 1;
5548                 }
5549             }
5550         }
5551
5552       FRAME_ROOT_WINDOW (f) = config->root_window;
5553       /* Note that FSFmacs unilaterally calls Fselect_window() here, and
5554          then calls do_switch_frame() below to select the frame that was
5555          recorded in the window config as being selected.
5556
5557          Instead, we don't ever change the selected frame, and either
5558          call Fselect_window() below if the window config's frame is
5559          currently selected, or just set the selected window of the
5560          window config's frame. */
5561
5562 #if 0
5563       /* Set the frame height to the value it had before this function.  */
5564       if (previous_frame_height != FRAME_HEIGHT (f)
5565           || previous_frame_width != FRAME_WIDTH (f))
5566         change_frame_size (f, previous_frame_height, previous_frame_width, 0);
5567 #endif
5568       /* We just reset the size and position of the minibuffer, to its old
5569          value, which needn't be valid. So we do some magic to see which value
5570          to actually take. Then we set it.
5571
5572          The magic:
5573          We take the old value if is in the same units but differs from the
5574          current value.
5575
5576          #### Now we get more cases correct then ever before, but
5577          are we treating all? For instance what if the frames minibuf window
5578          is no longer the same one?
5579       */
5580       target_minibuf_height = previous_minibuf_height;
5581       if (converted_minibuf_height &&
5582           (converted_minibuf_height * config->minibuf_height) > 0 &&
5583           (converted_minibuf_height !=  config->minibuf_height))
5584         {
5585           target_minibuf_height = config->minibuf_height < 0 ?
5586             - (config->minibuf_height * real_font_height) :
5587             config->minibuf_height;
5588           target_minibuf_height =
5589             max(target_minibuf_height,real_font_height);
5590         }
5591       if (previous_minibuf_height)
5592         {
5593           XWINDOW (FRAME_MINIBUF_WINDOW (f))->pixel_top
5594             = previous_minibuf_top -
5595                   (target_minibuf_height - previous_minibuf_height);
5596           set_window_pixheight (FRAME_MINIBUF_WINDOW (f),
5597                                 target_minibuf_height, 0);
5598           set_window_pixwidth  (FRAME_MINIBUF_WINDOW (f),
5599                             previous_minibuf_width, 0);
5600         }
5601
5602       /* This is a better way to deal with frame resizing, etc.
5603          What we _actually_ want is for the old (just restored)
5604          root window to fit
5605          into the place of the new one. So we just do that. Simple! */
5606       XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_top = previous_pixel_top;
5607       /* Note that this function also updates the subwindow
5608          "pixel_top"s */
5609       set_window_pixheight (FRAME_ROOT_WINDOW (f),
5610           previous_pixel_height -
5611                   (target_minibuf_height - previous_minibuf_height), 0);
5612       XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_left = previous_pixel_left;
5613       /* Note that this function also updates the subwindow
5614          "pixel_left"s */
5615       set_window_pixwidth (FRAME_ROOT_WINDOW (f), previous_pixel_width, 0);
5616
5617       /* If restoring in the current frame make the window current,
5618          otherwise just update the frame selected_window slot to be
5619          the restored current_window. */
5620       if (f == selected_frame ())
5621         {
5622 #if 0
5623           /* When using `pop-window-configuration', often the minibuffer
5624              ends up as the selected window even though it's not active ...
5625              I really don't know the cause of this, but it should never
5626              happen.  This kludge should fix it.
5627
5628              #### Find out why this is really going wrong. */
5629           if (!minibuf_level &&
5630               MINI_WINDOW_P (XWINDOW (config->current_window)))
5631             window_to_select = Fnext_window (config->current_window,
5632                                              Qnil, Qnil, Qnil);
5633           else
5634             window_to_select = config->current_window;
5635 #endif
5636           /* Do this last so that buffer stacking is calculated
5637              correctly. */
5638           Fselect_window (config->current_window, Qnil);
5639
5640           if (!NILP (new_current_buffer))
5641             {
5642               Fset_buffer (new_current_buffer);
5643               Frecord_buffer (new_current_buffer);
5644             }
5645           else
5646             {
5647               Fset_buffer (XWINDOW (config->current_window)->buffer);
5648               Frecord_buffer (XWINDOW (config->current_window)->buffer);
5649             }
5650         }
5651       else
5652         set_frame_selected_window (f, config->current_window);
5653     }
5654   else
5655     old_window_config = Qnil; /* Warning suppression */
5656
5657   /* Restore the minimum heights recorded in the configuration.  */
5658   window_min_height = config->min_height;
5659   window_min_width = config->min_width;
5660
5661 #if 0 /* FSFmacs */
5662   /* see above comment */
5663   /* Fselect_window will have made f the selected frame, so we
5664      reselect the proper frame here.  Fhandle_switch_frame will change the
5665      selected window too, but that doesn't make the call to
5666      Fselect_window above totally superfluous; it still sets f's
5667      selected window.  */
5668   if (FRAME_LIVE_P (XFRAME (config->selected_frame)))
5669     do_switch_frame (config->selected_frame, Qnil, 0);
5670 #endif
5671
5672   Vminibuffer_scroll_window = config->minibuffer_scroll_window;
5673
5674   if (FRAME_LIVE_P (f))
5675     {
5676       /* Do this before calling recompute_all_cached_specifiers_in_window()
5677          so that things like redisplay_redraw_cursor() won't abort due
5678          to no window mirror present. */
5679       f->mirror_dirty = 1;
5680
5681       config = XWINDOW_CONFIGURATION (old_window_config);
5682       for (k = 0; k < config->saved_windows_count; k++)
5683         {
5684           p = SAVED_WINDOW_N (config, k);
5685           w = XWINDOW (p->window);
5686           /* Remember, we set w->config_mark on all currently visible
5687              windows, and reset it on all newly visible windows.
5688              Any windows still marked need to be deleted. */
5689           if (w->config_mark)
5690             {
5691               mark_window_as_deleted (w);
5692               w->config_mark = 0;
5693             }
5694           else
5695             {
5696               /* We just potentially changed the window's buffer and
5697                  potentially turned a dead window into a live one,
5698                  so we need to recompute the cached specifier values. */
5699               recompute_all_cached_specifiers_in_window (w);
5700             }
5701         }
5702     }
5703
5704   /* Now restore things, when everything else if OK. */
5705
5706   unbind_to (specpdl_count, Qnil);
5707
5708   UNGCPRO;
5709
5710   return Qnil;
5711 }
5712
5713 /* Mark all subwindows of a window as deleted.  The argument
5714    W is actually the subwindow tree of the window in question. */
5715
5716 void
5717 delete_all_subwindows (struct window *w)
5718 {
5719   if (!NILP (w->next))   delete_all_subwindows (XWINDOW (w->next));
5720   if (!NILP (w->vchild)) delete_all_subwindows (XWINDOW (w->vchild));
5721   if (!NILP (w->hchild)) delete_all_subwindows (XWINDOW (w->hchild));
5722
5723   mark_window_as_deleted (w);
5724 }
5725
5726 \f
5727 static unsigned int
5728 count_windows (struct window *window)
5729 {
5730   return 1 +
5731     (!NILP (window->next)   ? count_windows (XWINDOW (window->next))   : 0) +
5732     (!NILP (window->vchild) ? count_windows (XWINDOW (window->vchild)) : 0) +
5733     (!NILP (window->hchild) ? count_windows (XWINDOW (window->hchild)) : 0);
5734 }
5735
5736 static int
5737 saved_window_index (Lisp_Object window, struct window_config *config, int lim)
5738 {
5739   int j;
5740   for (j = 0; j < lim; j++)
5741     {
5742       if (EQ (SAVED_WINDOW_N (config, j)->window, window))
5743         return j;
5744     }
5745   abort ();
5746   return 0;     /* suppress compiler warning */
5747 }
5748
5749 static int
5750 save_window_save (Lisp_Object window, struct window_config *config, int i)
5751 {
5752   struct window *w;
5753
5754   for (; !NILP (window); window = w->next)
5755     {
5756       struct saved_window *p = SAVED_WINDOW_N (config, i);
5757
5758       w = XWINDOW (window);
5759       i++;
5760       p->window = window;
5761       p->buffer = w->buffer;
5762       WINDOW_LEFT (p) = WINDOW_LEFT (w);
5763       WINDOW_TOP (p) = WINDOW_TOP (w);
5764       WINDOW_WIDTH (p) = WINDOW_WIDTH (w);
5765       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (w);
5766       p->hscroll = w->hscroll;
5767       p->modeline_hscroll = w->modeline_hscroll;
5768
5769 #define WINDOW_SLOT(slot, compare) p->slot = w->slot
5770 #include "winslots.h"
5771
5772       if (!NILP (w->buffer))
5773         {
5774           /* Save w's value of point in the window configuration.
5775              If w is the selected window, then get the value of point
5776              from the buffer; pointm is garbage in the selected window.  */
5777           if (EQ (window, Fselected_window (Qnil)))
5778             {
5779               p->pointm = noseeum_make_marker ();
5780               Fset_marker (p->pointm,
5781                            make_int (BUF_PT (XBUFFER (w->buffer))),
5782                            w->buffer);
5783             }
5784           else
5785             p->pointm = noseeum_copy_marker (w->pointm[CURRENT_DISP], Qnil);
5786
5787           p->start = noseeum_copy_marker (w->start[CURRENT_DISP], Qnil);
5788           p->sb_point = noseeum_copy_marker (w->sb_point, Qnil);
5789           p->start_at_line_beg = w->start_at_line_beg;
5790
5791           p->mark = noseeum_copy_marker (XBUFFER (w->buffer)->mark, Qnil);
5792         }
5793       else
5794         {
5795           p->pointm = Qnil;
5796           p->start = Qnil;
5797           p->sb_point = Qnil;
5798           p->mark = Qnil;
5799           p->start_at_line_beg = 0;
5800         }
5801
5802       if (NILP (w->parent))
5803         p->parent_index = -1;
5804       else
5805         p->parent_index = saved_window_index (w->parent, config, i);
5806       if (NILP (w->prev))
5807         p->prev_index = -1;
5808       else
5809         p->prev_index = saved_window_index (w->prev, config, i);
5810       if (!NILP (w->vchild))
5811         i = save_window_save (w->vchild, config, i);
5812       if (!NILP (w->hchild))
5813         i = save_window_save (w->hchild, config, i);
5814     }
5815
5816   return i;
5817 }
5818
5819 #if 0 /* FSFmacs */
5820 /* Added to doc string:
5821
5822 This also records the currently selected frame, and FRAME's focus
5823 redirection (see `redirect-frame-focus').
5824
5825 */
5826 #endif
5827
5828 DEFUN ("current-window-configuration", Fcurrent_window_configuration, 0, 1, 0, /*
5829 Return an object representing the current window configuration of FRAME.
5830 If FRAME is nil or omitted, use the selected frame.
5831 This describes the number of windows, their sizes and current buffers,
5832 and for each window on FRAME the displayed buffer, where display
5833 starts, and the positions of point and mark.
5834 An exception is made for point in the current buffer:
5835 its value is -not- saved.
5836 */
5837        (frame))
5838 {
5839   Lisp_Object result;
5840   struct frame *f = decode_frame (frame);
5841   struct window_config *config;
5842   unsigned int n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
5843   int minibuf_height;
5844   int real_font_height;
5845
5846   if (n_windows <= countof (Vwindow_configuration_free_list))
5847     config = XWINDOW_CONFIGURATION (allocate_managed_lcrecord
5848                                     (Vwindow_configuration_free_list
5849                                      [n_windows - 1]));
5850   else
5851     /* More than ten windows; just allocate directly */
5852     config = (struct window_config *)
5853       alloc_lcrecord (sizeof_window_config_for_n_windows (n_windows),
5854                       &lrecord_window_configuration);
5855   XSETWINDOW_CONFIGURATION (result, config);
5856   /*
5857   config->frame_width = FRAME_WIDTH (f);
5858   config->frame_height = FRAME_HEIGHT (f); */
5859   /* #### When using `push-window-configuration', often the minibuffer ends
5860      up as the selected window because functions run as the result of
5861      user interaction e.g. hyper-apropos. It seems to me the sensible
5862      thing to do is not record the minibuffer here. 
5863
5864      #### Unfortunately this is a change to previous behaviour, however logical
5865      it may be, so revert for the moment. */
5866 #if 0
5867   if (FRAME_MINIBUF_ONLY_P (f) || minibuf_level)
5868     config->current_window = FRAME_SELECTED_WINDOW (f);
5869   else
5870     config->current_window = FRAME_LAST_NONMINIBUF_WINDOW (f);
5871 #endif
5872   config->current_window = FRAME_SELECTED_WINDOW (f);
5873   XSETBUFFER (config->current_buffer, current_buffer);
5874   config->minibuffer_scroll_window = Vminibuffer_scroll_window;
5875   config->root_window = FRAME_ROOT_WINDOW (f);
5876   config->min_height = window_min_height;
5877   config->min_width = window_min_width;
5878   config->saved_windows_count = n_windows;
5879   save_window_save (FRAME_ROOT_WINDOW (f), config, 0);
5880
5881   /* save the minibuffer height using the heuristics from
5882      change_frame_size_1 */
5883
5884   XSETFRAME (frame, f); /* frame could have been nil ! */
5885   default_face_height_and_width (frame, &real_font_height, 0);
5886   assert(real_font_height > 0);
5887
5888   if (FRAME_HAS_MINIBUF_P (f) && ! FRAME_MINIBUF_ONLY_P (f))
5889     minibuf_height = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_height;
5890   else
5891     minibuf_height = 0;
5892   config->minibuf_height = (minibuf_height % real_font_height) == 0 ?
5893     - (minibuf_height / real_font_height ) :    /* lines */
5894     minibuf_height;   /* pixels */
5895
5896   return result;
5897 }
5898
5899 Lisp_Object
5900 save_window_excursion_unwind (Lisp_Object window_config)
5901 {
5902   Lisp_Object val = Fset_window_configuration (window_config);
5903   free_window_configuration (window_config);
5904   return val;
5905 }
5906
5907 DEFUN ("save-window-excursion", Fsave_window_excursion, 0, UNEVALLED, 0, /*
5908 Execute body, preserving window sizes and contents.
5909 Restores which buffer appears in which window, where display starts,
5910 as well as the current buffer.
5911 Does not restore the value of point in current buffer.
5912 */
5913        (args))
5914 {
5915   /* This function can GC */
5916   Lisp_Object val;
5917   int speccount = specpdl_depth ();
5918
5919   record_unwind_protect (save_window_excursion_unwind,
5920                          Fcurrent_window_configuration (Qnil));
5921   val = Fprogn (args);
5922   return unbind_to (speccount, val);
5923 }
5924
5925 DEFUN ("current-pixel-column", Fcurrent_pixel_column, 0, 2, 0, /*
5926 Return the horizontal pixel position of POS in window.
5927 Beginning of line is column 0. This is calculated using the redisplay
5928 display tables.  If WINDOW is nil, the current window is assumed.
5929 If POS is nil, point is assumed. Note that POS must be visible for
5930 a non-nil result to be returned.
5931 */
5932        (window, pos))
5933 {
5934   struct window* w = decode_window (window);
5935   display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
5936
5937   struct display_line *dl = 0;
5938   struct display_block *db = 0;
5939   struct rune* rb = 0;
5940   int y = w->last_point_y[CURRENT_DISP];
5941   int x = w->last_point_x[CURRENT_DISP];
5942
5943   if (MINI_WINDOW_P (w))
5944     return Qnil;
5945
5946   if (y<0 || x<0 || y >= Dynarr_length (dla) || !NILP (pos))
5947     {
5948       int first_line, i;
5949       Bufpos point;
5950
5951       if (NILP (pos))
5952         pos = Fwindow_point (window);
5953
5954       CHECK_INT (pos);
5955       point = XINT (pos);
5956
5957       if (Dynarr_length (dla) && Dynarr_atp (dla, 0)->modeline)
5958         first_line = 1;
5959       else
5960         first_line = 0;
5961
5962       for (i = first_line; i < Dynarr_length (dla); i++)
5963         {
5964           dl = Dynarr_atp (dla, i);
5965           /* find the vertical location first */
5966           if (point >= dl->bufpos && point <= dl->end_bufpos)
5967             {
5968               db = get_display_block_from_line (dl, TEXT);
5969               for (i = 0; i < Dynarr_length (db->runes); i++)
5970                 {
5971                   rb = Dynarr_atp (db->runes, i);
5972                   if (point <= rb->bufpos)
5973                     goto found_bufpos;
5974                 }
5975               return Qnil;
5976             }
5977         }
5978       return Qnil;
5979     found_bufpos:
5980       ;
5981     }
5982   else
5983     {
5984       /* optimized case */
5985       dl = Dynarr_atp (dla, y);
5986       db = get_display_block_from_line (dl, TEXT);
5987
5988       if (x >= Dynarr_length (db->runes))
5989         return Qnil;
5990
5991       rb = Dynarr_atp (db->runes, x);
5992     }
5993
5994   return make_int (rb->xpos - WINDOW_LEFT (w));
5995 }
5996
5997 \f
5998 #ifdef DEBUG_XEMACS
5999 /* This is short and simple in elisp, but... it was written to debug
6000    problems purely on the C side.  That is where we need to call it so
6001    here it is. */
6002 static void
6003 debug_print_window (Lisp_Object window, int level)
6004 {
6005   int i;
6006   Lisp_Object child = Fwindow_first_vchild (window);
6007
6008   if (NILP (child))
6009     child = Fwindow_first_hchild (window);
6010
6011   for (i = level; i > 0; i--)
6012     stderr_out ("\t");
6013
6014   stderr_out ("#<window");
6015   {
6016     Lisp_Object buffer = XWINDOW (window)->buffer;
6017     if (!NILP (buffer) && BUFFERP (buffer))
6018       stderr_out (" on %s", XSTRING_DATA (XBUFFER (buffer)->name));
6019   }
6020   stderr_out (" 0x%x>", XWINDOW (window)->header.uid);
6021
6022   while (!NILP (child))
6023     {
6024       debug_print_window (child, level + 1);
6025       child = Fwindow_next_child (child);
6026     }
6027 }
6028
6029 void debug_print_windows (struct frame *f);
6030 void
6031 debug_print_windows (struct frame *f)
6032 {
6033   debug_print_window (f->root_window, 0);
6034   putc ('\n', stderr);
6035 }
6036 #endif /* DEBUG_XEMACS */
6037
6038 \f
6039 /************************************************************************/
6040 /*                            initialization                            */
6041 /************************************************************************/
6042
6043 void
6044 syms_of_window (void)
6045 {
6046   INIT_LRECORD_IMPLEMENTATION (window);
6047   INIT_LRECORD_IMPLEMENTATION (window_configuration);
6048
6049   defsymbol (&Qwindowp, "windowp");
6050   defsymbol (&Qwindow_live_p, "window-live-p");
6051   defsymbol (&Qwindow_configurationp, "window-configuration-p");
6052   defsymbol (&Qtemp_buffer_show_hook, "temp-buffer-show-hook");
6053   defsymbol (&Qdisplay_buffer, "display-buffer");
6054
6055 #ifdef MEMORY_USAGE_STATS
6056   defsymbol (&Qface_cache, "face-cache");
6057   defsymbol (&Qglyph_cache, "glyph-cache");
6058   defsymbol (&Qline_start_cache, "line-start-cache");
6059 #ifdef HAVE_SCROLLBARS
6060   defsymbol (&Qscrollbar_instances, "scrollbar-instances");
6061 #endif
6062   defsymbol (&Qother_redisplay, "other-redisplay");
6063   /* Qother in general.c */
6064 #endif
6065
6066   DEFSUBR (Fselected_window);
6067   DEFSUBR (Flast_nonminibuf_window);
6068   DEFSUBR (Fminibuffer_window);
6069   DEFSUBR (Fwindow_minibuffer_p);
6070   DEFSUBR (Fwindowp);
6071   DEFSUBR (Fwindow_live_p);
6072   DEFSUBR (Fwindow_first_hchild);
6073   DEFSUBR (Fwindow_first_vchild);
6074   DEFSUBR (Fwindow_next_child);
6075   DEFSUBR (Fwindow_previous_child);
6076   DEFSUBR (Fwindow_parent);
6077   DEFSUBR (Fwindow_lowest_p);
6078   DEFSUBR (Fwindow_truncated_p);
6079   DEFSUBR (Fwindow_highest_p);
6080   DEFSUBR (Fwindow_leftmost_p);
6081   DEFSUBR (Fwindow_rightmost_p);
6082   DEFSUBR (Fpos_visible_in_window_p);
6083   DEFSUBR (Fwindow_buffer);
6084   DEFSUBR (Fwindow_frame);
6085   DEFSUBR (Fwindow_height);
6086   DEFSUBR (Fwindow_displayed_height);
6087   DEFSUBR (Fwindow_width);
6088   DEFSUBR (Fwindow_full_width);
6089   DEFSUBR (Fwindow_pixel_height);
6090   DEFSUBR (Fwindow_pixel_width);
6091   DEFSUBR (Fwindow_text_area_height);
6092   DEFSUBR (Fwindow_text_area_pixel_height);
6093   DEFSUBR (Fwindow_displayed_text_pixel_height);
6094   DEFSUBR (Fwindow_text_area_pixel_width);
6095   DEFSUBR (Fwindow_hscroll);
6096   DEFSUBR (Fset_window_hscroll);
6097   DEFSUBR (Fmodeline_hscroll);
6098   DEFSUBR (Fset_modeline_hscroll);
6099 #if 0 /* bogus FSF crock */
6100   DEFSUBR (Fwindow_redisplay_end_trigger);
6101   DEFSUBR (Fset_window_redisplay_end_trigger);
6102 #endif
6103   DEFSUBR (Fwindow_pixel_edges);
6104   DEFSUBR (Fwindow_text_area_pixel_edges);
6105   DEFSUBR (Fwindow_point);
6106   DEFSUBR (Fwindow_start);
6107   DEFSUBR (Fwindow_end);
6108   DEFSUBR (Fwindow_last_line_visible_height);
6109   DEFSUBR (Fset_window_point);
6110   DEFSUBR (Fset_window_start);
6111   DEFSUBR (Fwindow_dedicated_p);
6112   DEFSUBR (Fset_window_dedicated_p);
6113   DEFSUBR (Fnext_window);
6114   DEFSUBR (Fprevious_window);
6115   DEFSUBR (Fnext_vertical_window);
6116   DEFSUBR (Fother_window);
6117   DEFSUBR (Fget_lru_window);
6118   DEFSUBR (Fget_largest_window);
6119   DEFSUBR (Fget_buffer_window);
6120   DEFSUBR (Fwindow_left_margin_pixel_width);
6121   DEFSUBR (Fwindow_right_margin_pixel_width);
6122   DEFSUBR (Fdelete_other_windows);
6123   DEFSUBR (Fdelete_windows_on);
6124   DEFSUBR (Freplace_buffer_in_windows);
6125   DEFSUBR (Fdelete_window);
6126   DEFSUBR (Fset_window_buffer);
6127   DEFSUBR (Fselect_window);
6128   DEFSUBR (Fsplit_window);
6129   DEFSUBR (Fenlarge_window);
6130   DEFSUBR (Fenlarge_window_pixels);
6131   DEFSUBR (Fshrink_window);
6132   DEFSUBR (Fshrink_window_pixels);
6133   DEFSUBR (Fscroll_up);
6134   DEFSUBR (Fscroll_down);
6135   DEFSUBR (Fscroll_left);
6136   DEFSUBR (Fscroll_right);
6137   DEFSUBR (Fother_window_for_scrolling);
6138   DEFSUBR (Fscroll_other_window);
6139   DEFSUBR (Fcenter_to_window_line);
6140   DEFSUBR (Fmove_to_window_line);
6141 #ifdef MEMORY_USAGE_STATS
6142   DEFSUBR (Fwindow_memory_usage);
6143 #endif
6144   DEFSUBR (Fwindow_configuration_p);
6145   DEFSUBR (Fset_window_configuration);
6146   DEFSUBR (Fcurrent_window_configuration);
6147   DEFSUBR (Fsave_window_excursion);
6148   DEFSUBR (Fcurrent_pixel_column);
6149 }
6150
6151 void
6152 reinit_vars_of_window (void)
6153 {
6154   unsigned int i;
6155   /* Make sure all windows get marked */
6156   minibuf_window = Qnil;
6157   staticpro_nodump (&minibuf_window);
6158
6159   for (i = 0; i < countof (Vwindow_configuration_free_list); i++)
6160     {
6161       Vwindow_configuration_free_list[i] =
6162         make_lcrecord_list (sizeof_window_config_for_n_windows (i + 1),
6163                             &lrecord_window_configuration);
6164       staticpro_nodump (&Vwindow_configuration_free_list[i]);
6165     }
6166 }
6167
6168 void
6169 vars_of_window (void)
6170 {
6171   reinit_vars_of_window ();
6172
6173   DEFVAR_BOOL ("scroll-on-clipped-lines", &scroll_on_clipped_lines /*
6174 *Non-nil means to scroll if point lands on a line which is clipped.
6175 */ );
6176   scroll_on_clipped_lines = 1;
6177
6178   DEFVAR_LISP ("temp-buffer-show-hook", &Vtemp_buffer_show_hook /*
6179 See `temp-buffer-show-function'.
6180 */ );
6181   Vtemp_buffer_show_hook = Qnil;
6182
6183   DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function /*
6184 Non-nil means call as function to display a help buffer.
6185 The function is called with one argument, the buffer to be displayed.
6186 Used by `with-output-to-temp-buffer'.
6187 If this function is used, then it must do the entire job of showing
6188 the buffer; `temp-buffer-show-hook' is not run unless this function runs it.
6189 \(`temp-buffer-show-hook' is obsolete.  Do not use in new code.)
6190 */ );
6191   Vtemp_buffer_show_function = Qnil;
6192
6193   DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuffer_scroll_window /*
6194 Non-nil means it is the window that \\<minibuffer-local-map>\\[scroll-other-window] in minibuffer should scroll.
6195 */ );
6196   Vminibuffer_scroll_window = Qnil;
6197
6198   DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer /*
6199 If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.
6200 */ );
6201   Vother_window_scroll_buffer = Qnil;
6202
6203   DEFVAR_LISP ("window-pixel-scroll-increment", &Vwindow_pixel_scroll_increment /*
6204 *Number of pixels to scroll by per requested line.
6205 If nil then normal line scrolling occurs regardless of line height.
6206 If t then scrolling is done in increments equal to the height of the default face.
6207 */ );
6208   Vwindow_pixel_scroll_increment = Qt;
6209
6210   DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines /*
6211 *Number of lines of continuity when scrolling by screenfuls.
6212 */ );
6213   next_screen_context_lines = 2;
6214
6215   DEFVAR_INT ("window-min-height", &window_min_height /*
6216 *Delete any window less than this tall (including its modeline).
6217 */ );
6218   window_min_height = 4;
6219
6220   DEFVAR_INT ("window-min-width", &window_min_width /*
6221 *Delete any window less than this wide.
6222 */ );
6223   window_min_width = 10;
6224 }
6225
6226 void
6227 specifier_vars_of_window (void)
6228 {
6229   DEFVAR_SPECIFIER ("modeline-shadow-thickness", &Vmodeline_shadow_thickness /*
6230 *How thick to draw 3D shadows around modelines.
6231 If this is set to 0, modelines will be the traditional 2D.  Sizes above
6232 10 will be accepted but the maximum thickness that will be drawn is 10.
6233 This is a specifier; use `set-specifier' to change it.
6234 */ );
6235   Vmodeline_shadow_thickness = Fmake_specifier (Qinteger);
6236   /* The initial value for modeline-shadow-thickness is 2, but if the
6237      user removes all specifications we provide a fallback value of 0,
6238      which is probably what was expected. */
6239   set_specifier_fallback (Vmodeline_shadow_thickness,
6240                           list1 (Fcons (Qnil, Qzero)));
6241   Fadd_spec_to_specifier (Vmodeline_shadow_thickness, make_int (2),
6242                           Qnil, Qnil, Qnil);
6243   set_specifier_caching (Vmodeline_shadow_thickness,
6244                          offsetof (struct window, modeline_shadow_thickness),
6245                          modeline_shadow_thickness_changed,
6246                          0, 0, 0);
6247
6248   DEFVAR_SPECIFIER ("has-modeline-p", &Vhas_modeline_p /*
6249 *Whether the modeline should be displayed.
6250 This is a specifier; use `set-specifier' to change it.
6251 */ );
6252   Vhas_modeline_p = Fmake_specifier (Qboolean);
6253   set_specifier_fallback (Vhas_modeline_p,
6254                           list1 (Fcons (Qnil, Qt)));
6255   set_specifier_caching (Vhas_modeline_p,
6256                          offsetof (struct window, has_modeline_p),
6257                          /* #### It's strange that we need a special
6258                             flag to indicate that the shadow-thickness
6259                             has changed, but not one to indicate that
6260                             the modeline has been turned off or on. */
6261                          some_window_value_changed,
6262                          0, 0, 0);
6263
6264   DEFVAR_SPECIFIER ("vertical-divider-always-visible-p",
6265                     &Vvertical_divider_always_visible_p /*
6266 *Should XEmacs always display vertical dividers between windows.
6267
6268 When this is non-nil, vertical dividers are always shown, and are
6269 draggable.  When it is nil, vertical dividers are shown only when
6270 there are no scrollbars in between windows, and are not draggable.
6271
6272 This is a specifier; use `set-specifier' to change it.
6273 */ );
6274   Vvertical_divider_always_visible_p = Fmake_specifier (Qboolean);
6275   set_specifier_fallback (Vvertical_divider_always_visible_p,
6276                           list1 (Fcons (Qnil, Qt)));
6277   set_specifier_caching (Vvertical_divider_always_visible_p,
6278                          offsetof (struct window,
6279                                    vertical_divider_always_visible_p),
6280                          vertical_divider_changed_in_window,
6281                          0, 0, 0);
6282
6283   DEFVAR_SPECIFIER ("vertical-divider-shadow-thickness", &Vvertical_divider_shadow_thickness /*
6284 *How thick to draw 3D shadows around vertical dividers.
6285 This is a specifier; use `set-specifier' to change it.
6286 */ );
6287   Vvertical_divider_shadow_thickness = Fmake_specifier (Qinteger);
6288   set_specifier_fallback (Vvertical_divider_shadow_thickness,
6289                           list1 (Fcons (Qnil, Qzero)));
6290   Fadd_spec_to_specifier (Vvertical_divider_shadow_thickness, make_int (2),
6291                           Qnil, Qnil, Qnil);
6292   set_specifier_caching (Vvertical_divider_shadow_thickness,
6293                          offsetof (struct window,
6294                                    vertical_divider_shadow_thickness),
6295                          vertical_divider_changed_in_window,
6296                          0, 0, 0);
6297   DEFVAR_SPECIFIER ("vertical-divider-line-width", &Vvertical_divider_line_width /*
6298 *The width of the vertical dividers, not including shadows.
6299
6300 For TTY windows, divider line is always one character wide.  When
6301 instance of this specifier is zero in a TTY window, no divider is
6302 drawn at all between windows.  When non-zero, a one character wide
6303 divider is displayed.
6304
6305 This is a specifier; use `set-specifier' to change it.
6306 */ );
6307
6308   Vvertical_divider_line_width = Fmake_specifier (Qnatnum);
6309   {
6310     Lisp_Object fb = Qnil;
6311 #ifdef HAVE_TTY
6312     fb = Fcons (Fcons (list1 (Qtty), make_int (1)), fb);
6313 #endif
6314 #ifdef HAVE_X_WINDOWS
6315     fb = Fcons (Fcons (list1 (Qx), make_int (3)), fb);
6316 #endif
6317 #ifdef HAVE_MS_WINDOWS
6318     /* #### This should be made magic and made to obey system settings */
6319     fb = Fcons (Fcons (list1 (Qmswindows), make_int (3)), fb);
6320 #endif
6321     set_specifier_fallback (Vvertical_divider_line_width, fb);
6322   }
6323   set_specifier_caching (Vvertical_divider_line_width,
6324                          offsetof (struct window,
6325                                    vertical_divider_line_width),
6326                          vertical_divider_changed_in_window,
6327                          0, 0, 0);
6328
6329   DEFVAR_SPECIFIER ("vertical-divider-spacing", &Vvertical_divider_spacing /*
6330 *How much space to leave around the vertical dividers.
6331
6332 In TTY windows, spacing is always zero, and the value of this
6333 specifier is ignored.
6334
6335 This is a specifier; use `set-specifier' to change it.
6336 */ );
6337   Vvertical_divider_spacing = Fmake_specifier (Qnatnum);
6338   {
6339     Lisp_Object fb = Qnil;
6340 #ifdef HAVE_TTY
6341     fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
6342 #endif
6343 #ifdef HAVE_X_WINDOWS
6344     /* #### 3D dividers look great on MS Windows with spacing = 0.
6345        Should not the same value be the fallback under X? - kkm */
6346     fb = Fcons (Fcons (list1 (Qx), make_int (2)), fb);
6347 #endif
6348 #ifdef HAVE_MS_WINDOWS
6349     fb = Fcons (Fcons (list1 (Qmswindows), Qzero), fb);
6350 #endif
6351     set_specifier_fallback (Vvertical_divider_spacing, fb);
6352   }
6353   set_specifier_caching (Vvertical_divider_spacing,
6354                          offsetof (struct window, vertical_divider_spacing),
6355                          vertical_divider_changed_in_window,
6356                          0, 0, 0);
6357 }