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