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