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