XEmacs 21.4.9 "Informed Management".
[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 and put
3658 SIZE columns in the first of the pair. The newly created window is
3659 returned.
3660 */
3661        (window, size, horflag))
3662 {
3663   Lisp_Object new;
3664   struct window *o, *p;
3665   struct frame *f;
3666   int csize;
3667   int psize;
3668
3669   if (NILP (window))
3670     window = Fselected_window (Qnil);
3671   else
3672     CHECK_LIVE_WINDOW (window);
3673
3674   o = XWINDOW (window);
3675   f = XFRAME (WINDOW_FRAME (o));
3676
3677   if (NILP (size))
3678     {
3679       if (!NILP (horflag))
3680         /* In the new scheme, we are symmetric with respect to separators
3681            so there is no need to do weird things here. */
3682         {
3683           psize = (WINDOW_WIDTH (o) + window_divider_width (o)) >> 1;
3684           csize = window_pixel_width_to_char_width (o, psize, 0);
3685         }
3686       else
3687         {
3688           psize = WINDOW_HEIGHT (o) >> 1;
3689           csize = window_pixel_height_to_char_height (o, psize, 1);
3690         }
3691     }
3692   else
3693     {
3694       CHECK_INT (size);
3695       csize = XINT (size);
3696       if (!NILP (horflag))
3697         psize = window_char_width_to_pixel_width (o, csize, 0);
3698       else
3699         psize = window_char_height_to_pixel_height (o, csize, 1);
3700     }
3701
3702   if (MINI_WINDOW_P (o))
3703     error ("Attempt to split minibuffer window");
3704   else if (FRAME_NO_SPLIT_P (XFRAME (WINDOW_FRAME (o))))
3705     error ("Attempt to split unsplittable frame");
3706
3707   check_min_window_sizes ();
3708
3709   if (NILP (horflag))
3710     {
3711       if (csize < window_min_height)
3712         error ("Window height %d too small (after splitting)", csize);
3713       if (csize + window_min_height > window_char_height (o, 1))
3714         error ("Window height %d too small (after splitting)",
3715                window_char_height (o, 1) - csize);
3716       if (NILP (o->parent)
3717           || NILP (XWINDOW (o->parent)->vchild))
3718         {
3719           make_dummy_parent (window);
3720 #if 0
3721           /* #### I can't understand why you have to reset face
3722              cachels here.  This can cause crash so let's disable it
3723              and see the difference.  See redisplay-tests.el  --yh */
3724           reset_face_cachels (XWINDOW (window));
3725 #endif
3726           new = o->parent;
3727           XWINDOW (new)->vchild = window;
3728           XFRAME (o->frame)->mirror_dirty = 1;
3729         }
3730     }
3731   else
3732     {
3733       if (csize < window_min_width)
3734         error ("Window width %d too small (after splitting)", csize);
3735       if (csize + window_min_width > window_char_width (o, 0))
3736         error ("Window width %d too small (after splitting)",
3737                window_char_width (o, 0) - csize);
3738       if (NILP (o->parent)
3739           || NILP (XWINDOW (o->parent)->hchild))
3740         {
3741           make_dummy_parent (window);
3742 #if 0
3743           /* #### See above. */
3744           reset_face_cachels (XWINDOW (window));
3745 #endif
3746           new = o->parent;
3747           XWINDOW (new)->hchild = window;
3748           XFRAME (o->frame)->mirror_dirty = 1;
3749         }
3750     }
3751
3752   /* Now we know that window's parent is a vertical combination
3753      if we are dividing vertically, or a horizontal combination
3754      if we are making side-by-side windows */
3755
3756   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
3757   new = allocate_window ();
3758   p = XWINDOW (new);
3759
3760   p->frame = o->frame;
3761   p->next = o->next;
3762   if (!NILP (p->next))
3763     XWINDOW (p->next)->prev = new;
3764   p->prev = window;
3765   o->next = new;
3766   p->parent = o->parent;
3767   p->buffer = Qt;
3768
3769   reset_face_cachels (p);
3770   reset_glyph_cachels (p);
3771
3772
3773   /* Apportion the available frame space among the two new windows */
3774
3775   if (!NILP (horflag))
3776     {
3777       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o);
3778       WINDOW_TOP (p) = WINDOW_TOP (o);
3779       WINDOW_WIDTH (p) = WINDOW_WIDTH (o) - psize;
3780       WINDOW_WIDTH (o) = psize;
3781       WINDOW_LEFT (p) = WINDOW_LEFT (o) + psize;
3782     }
3783   else
3784     {
3785       WINDOW_LEFT (p) = WINDOW_LEFT (o);
3786       WINDOW_WIDTH (p) = WINDOW_WIDTH (o);
3787       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o) - psize;
3788       WINDOW_HEIGHT (o) = psize;
3789       WINDOW_TOP (p) = WINDOW_TOP (o) + psize;
3790     }
3791
3792   XFRAME (p->frame)->mirror_dirty = 1;
3793   /* do this last (after the window is completely initialized and
3794      the mirror-dirty flag is set) so that specifier recomputation
3795      caused as a result of this will work properly and not abort. */
3796   Fset_window_buffer (new, o->buffer, Qt);
3797   return new;
3798 }
3799 \f
3800
3801 DEFUN ("enlarge-window", Fenlarge_window, 1, 3, "_p", /*
3802 Make the selected window COUNT lines taller.
3803 From program, optional second arg HORIZONTALP non-nil means grow
3804 sideways COUNT columns, and optional third arg WINDOW specifies the
3805 window to change instead of the selected window.
3806 */
3807        (count, horizontalp, window))
3808 {
3809   CHECK_INT (count);
3810   change_window_height (window, XINT (count), horizontalp, /* inpixels */ 0);
3811   return Qnil;
3812 }
3813
3814 DEFUN ("enlarge-window-pixels", Fenlarge_window_pixels, 1, 3, "_p", /*
3815 Make the selected window COUNT pixels taller.
3816 From program, optional second arg HORIZONTALP non-nil means grow
3817 sideways COUNT pixels, and optional third arg WINDOW specifies the
3818 window to change instead of the selected window.
3819 */
3820        (count, horizontalp, window))
3821 {
3822   CHECK_INT (count);
3823   change_window_height (window, XINT (count), horizontalp, /* inpixels */ 1);
3824   return Qnil;
3825 }
3826
3827 DEFUN ("shrink-window", Fshrink_window, 1, 3, "_p", /*
3828 Make the selected window COUNT lines shorter.
3829 From program, optional second arg HORIZONTALP non-nil means shrink
3830 sideways COUNT columns, and optional third arg WINDOW specifies the
3831 window to change instead of the selected window.
3832 */
3833        (count, horizontalp, window))
3834 {
3835   CHECK_INT (count);
3836   change_window_height (window, -XINT (count), horizontalp, /* inpixels */ 0);
3837   return Qnil;
3838 }
3839
3840 DEFUN ("shrink-window-pixels", Fshrink_window_pixels, 1, 3, "_p", /*
3841 Make the selected window COUNT pixels smaller.
3842 From program, optional second arg HORIZONTALP non-nil means shrink
3843 sideways COUNT pixels, and optional third arg WINDOW specifies the
3844 window to change instead of the selected window.
3845 */
3846        (count, horizontalp, window))
3847 {
3848   CHECK_INT (count);
3849   change_window_height (window, -XINT (count), horizontalp, /* inpixels */ 1);
3850   return Qnil;
3851 }
3852
3853 static int
3854 window_pixel_height_to_char_height (struct window *w, int pixel_height,
3855                                     int include_gutters_p)
3856 {
3857   int avail_height;
3858   int defheight, defwidth;
3859   int char_height;
3860   Lisp_Object window;
3861
3862   XSETWINDOW (window, w);
3863
3864   avail_height = (pixel_height -
3865                   (include_gutters_p ? 0 :
3866                    window_top_window_gutter_height (w) +
3867                    window_bottom_window_gutter_height (w)));
3868
3869   default_face_height_and_width (window, &defheight, &defwidth);
3870
3871   char_height = avail_height / defheight;
3872
3873   /* It's the calling function's responsibility to check these values
3874      and make sure they're not out of range.
3875
3876      #### We need to go through the calling functions and actually
3877      do this. */
3878   return max (0, char_height);
3879 }
3880
3881 static int
3882 window_char_height_to_pixel_height (struct window *w, int char_height,
3883                                     int include_gutters_p)
3884 {
3885   int avail_height;
3886   int defheight, defwidth;
3887   int pixel_height;
3888
3889   Lisp_Object window;
3890
3891   XSETWINDOW (window, w);
3892
3893   default_face_height_and_width (window, &defheight, &defwidth);
3894
3895   avail_height = char_height * defheight;
3896   pixel_height = (avail_height +
3897                   (include_gutters_p ? 0 :
3898                    window_top_window_gutter_height (w) +
3899                    window_bottom_window_gutter_height (w)));
3900
3901   /* It's the calling function's responsibility to check these values
3902      and make sure they're not out of range.
3903
3904      #### We need to go through the calling functions and actually
3905      do this. */
3906   return max (0, pixel_height);
3907 }
3908
3909 /* Return number of default lines of text can fit in the window W.
3910    If INCLUDE_GUTTERS_P is 1, include "gutter" space (modeline plus
3911    horizontal scrollbar) in the space that is used for the calculation.
3912    This doesn't include space used by the frame gutters.
3913    */
3914 int
3915 window_char_height (struct window *w, int include_gutters_p)
3916 {
3917   return window_pixel_height_to_char_height (w, window_pixel_height (w),
3918                                              include_gutters_p);
3919 }
3920
3921 /*
3922  * Return number of lines currently displayed in window w.  If
3923  * end-of-buffer is displayed then the area below end-of-buffer is assume
3924  * to be blank lines of default height.
3925  * Does not include the modeline.
3926  */
3927 int
3928 window_displayed_height (struct window *w)
3929 {
3930   struct buffer *b = XBUFFER (w->buffer);
3931   display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
3932   int num_lines;
3933   Charcount end_pos = (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b)
3934                        ? -1
3935                        : w->window_end_pos[CURRENT_DISP]);
3936
3937   if (!Dynarr_length (dla))
3938     return window_char_height (w, 0);
3939
3940   num_lines = Dynarr_length (dla);
3941
3942   /* #### Document and assert somewhere that w->window_end_pos == -1
3943      indicates that end-of-buffer is being displayed. */
3944   if (end_pos == -1)
3945     {
3946       struct display_line *dl = Dynarr_atp (dla, 0);
3947       int ypos1 = dl->ypos + dl->descent;
3948       int ypos2 = WINDOW_TEXT_BOTTOM (w);
3949       Lisp_Object window;
3950       int defheight, defwidth;
3951
3952       XSETWINDOW (window, w);
3953
3954       if (dl->modeline)
3955         {
3956           num_lines--;
3957
3958           if (Dynarr_length (dla) == 1)
3959             ypos1 = WINDOW_TEXT_TOP (w);
3960           else
3961             {
3962               dl = Dynarr_atp (dla, Dynarr_length (dla) - 1);
3963               /* If this line is clipped then we know that there is no
3964                  blank room between eob and the modeline.  If we are
3965                  scrolling on clipped lines just know off the clipped
3966                  line and return .*/
3967               if (scroll_on_clipped_lines && dl->clip)
3968                 return num_lines - 1;
3969               ypos1 = dl->ypos + dl->descent - dl->clip;
3970             }
3971         }
3972
3973       default_face_height_and_width (window, &defheight, &defwidth);
3974       /* #### This probably needs to know about the clipping area once a
3975          final definition is decided on. */
3976       num_lines += ((ypos2 - ypos1) / defheight);
3977     }
3978   else
3979     {
3980       if (num_lines > 1 && Dynarr_atp (dla, 0)->modeline)
3981         num_lines--;
3982
3983       if (scroll_on_clipped_lines
3984           && Dynarr_atp (dla, Dynarr_length (dla) - 1)->clip)
3985         num_lines--;
3986     }
3987
3988   return num_lines;
3989 }
3990
3991 static int
3992 window_pixel_width (Lisp_Object window)
3993 {
3994   return WINDOW_WIDTH (XWINDOW (window));
3995 }
3996
3997 /* Calculate the pixel of a window, optionally including margin space
3998    but no vertical gutters. */
3999 static int
4000 window_pixel_width_to_char_width (struct window *w, int pixel_width,
4001                                   int include_margins_p)
4002 {
4003   int avail_width;
4004   int char_width;
4005   int defheight, defwidth;
4006   Lisp_Object window;
4007
4008   XSETWINDOW (window, w);
4009
4010   avail_width = (pixel_width -
4011                  window_left_gutter_width (w, 0) -
4012                  window_right_gutter_width (w, 0) -
4013                  (include_margins_p ? 0 : window_left_margin_width (w)) -
4014                  (include_margins_p ? 0 : window_right_margin_width (w)));
4015
4016   default_face_height_and_width (window, &defheight, &defwidth);
4017
4018   char_width = (avail_width / defwidth);
4019
4020   /* It's the calling function's responsibility to check these values
4021      and make sure they're not out of range.
4022
4023      #### We need to go through the calling functions and actually
4024      do this. */
4025   return max (0, char_width);
4026 }
4027
4028 static int
4029 window_char_width_to_pixel_width (struct window *w, int char_width,
4030                                   int include_margins_p)
4031 {
4032   int avail_width;
4033   int pixel_width;
4034   int defheight, defwidth;
4035   Lisp_Object window;
4036
4037   XSETWINDOW (window, w);
4038
4039   default_face_height_and_width (window, &defheight, &defwidth);
4040
4041   avail_width = char_width * defwidth;
4042   pixel_width = (avail_width +
4043                  window_left_window_gutter_width (w, 0) +
4044                  window_right_window_gutter_width (w, 0) +
4045                  (include_margins_p ? 0 : window_left_margin_width (w)) +
4046                  (include_margins_p ? 0 : window_right_margin_width (w)));
4047
4048   /* It's the calling function's responsibility to check these values
4049      and make sure they're not out of range.
4050
4051      #### We need to go through the calling functions and actually
4052      do this. */
4053   return max (0, pixel_width);
4054 }
4055
4056 /* This returns the usable space which doesn't include space needed by
4057    scrollbars or divider lines. */
4058 int
4059 window_char_width (struct window *w, int include_margins_p)
4060 {
4061   return window_pixel_width_to_char_width (w, WINDOW_WIDTH (w),
4062                                            include_margins_p);
4063 }
4064
4065 #define MINSIZE(w)                                              \
4066   (widthflag                                                    \
4067    ? window_min_width * defwidth                                \
4068    : (defheight * (MINI_WINDOW_P (XWINDOW (w)) ? 1 : window_min_height)))
4069
4070 #define CURBEG(w) \
4071   *(widthflag ? (int *) &WINDOW_LEFT (w) : (int *) &WINDOW_TOP (w))
4072
4073 #define CURSIZE(w) \
4074   *(widthflag ? (int *) &WINDOW_WIDTH (w) : (int *) &WINDOW_HEIGHT (w))
4075
4076 #define CURCHARSIZE(w) \
4077   (widthflag ? window_char_width (w, 0) : window_char_height (w, 1))
4078
4079 #define MINCHARSIZE(window) \
4080   (widthflag ? window_min_width : MINI_WINDOW_P (XWINDOW (window)) \
4081    ? 1 : window_min_height)
4082
4083 static int
4084 window_pixheight (Lisp_Object w)
4085 {
4086   return window_pixel_height (XWINDOW (w));
4087 }
4088
4089 /* Unlike set_window_pixheight, this function
4090    also changes the heights of the siblings so as to
4091    keep everything consistent. */
4092
4093 static void
4094 change_window_height (Lisp_Object window, int delta, Lisp_Object horizontalp,
4095                       int inpixels)
4096 {
4097   struct window *win = decode_window (window);
4098   int widthflag = !NILP (horizontalp);
4099   Lisp_Object parent;
4100   struct window *w;
4101   struct frame *f;
4102   int *sizep;
4103   int (*sizefun) (Lisp_Object) = (widthflag
4104                                   ? window_pixel_width
4105                                   : window_pixheight);
4106   void (*setsizefun) (Lisp_Object, int, int) = (widthflag
4107                                                 ? set_window_pixwidth
4108                                                 : set_window_pixheight);
4109   int dim;
4110   int defheight, defwidth;
4111
4112   if (delta == 0)
4113     return;
4114
4115   check_min_window_sizes ();
4116
4117   XSETWINDOW (window, win);
4118   f = XFRAME (win->frame);
4119   if (EQ (window, FRAME_ROOT_WINDOW (f)))
4120     error ("Won't change only window");
4121
4122   /* #### This is very likely incorrect and instead the char_to_pixel_
4123      functions should be called. */
4124   default_face_height_and_width (window, &defheight, &defwidth);
4125
4126   while (1)
4127     {
4128       w = XWINDOW (window);
4129       parent = w->parent;
4130       if (NILP (parent))
4131         {
4132           if (widthflag)
4133             error ("No other window to side of this one");
4134           break;
4135         }
4136       if (widthflag
4137           ? !NILP (XWINDOW (parent)->hchild)
4138           : !NILP (XWINDOW (parent)->vchild))
4139         break;
4140       window = parent;
4141     }
4142
4143   sizep = &CURSIZE (w);
4144   dim = CURCHARSIZE (w);
4145
4146   if ((inpixels  && (*sizep + delta) < MINSIZE (window)) ||
4147       (!inpixels && (dim + delta) < MINCHARSIZE (window)))
4148     {
4149       if (MINI_WINDOW_P (XWINDOW (window)))
4150         return;
4151       else if (!NILP (parent))
4152         {
4153           Fdelete_window (window, Qnil);
4154           return;
4155         }
4156     }
4157
4158   if (!inpixels)
4159     delta *= (widthflag ? defwidth : defheight);
4160
4161   {
4162     int maxdelta;
4163
4164     maxdelta = ((!NILP (parent))
4165                 ? (*sizefun) (parent) - *sizep
4166                 : ((!NILP (w->next))
4167                    ? (*sizefun) (w->next) - MINSIZE (w->next)
4168                    : ((!NILP (w->prev))
4169                       ? (*sizefun) (w->prev) - MINSIZE (w->prev)
4170                       /* This is a frame with only one window,
4171                          a minibuffer-only or a minibufferless frame.  */
4172                       : (delta = 0))));
4173
4174     if (delta > maxdelta)
4175       /* This case traps trying to make the minibuffer
4176          the full frame, or make the only window aside from the
4177          minibuffer the full frame.  */
4178       delta = maxdelta;
4179
4180     if (delta == 0)
4181       return;
4182
4183 #if 0 /* FSFmacs */
4184     /* #### Chuck: is this correct? */
4185     if (*sizep + delta < MINSIZE (window))
4186       {
4187         Fdelete_window (window);
4188         return;
4189       }
4190 #endif
4191   }
4192
4193   if (!NILP (w->next) &&
4194       (*sizefun) (w->next) - delta >= (int) MINSIZE (w->next))
4195     {
4196       CURBEG (XWINDOW (w->next)) += delta;
4197       (*setsizefun) (w->next, (*sizefun) (w->next) - delta, 0);
4198       (*setsizefun) (window, *sizep + delta, 0);
4199     }
4200   else if (!NILP (w->prev) &&
4201            (*sizefun) (w->prev) - delta >= (int) MINSIZE (w->prev))
4202     {
4203       (*setsizefun) (w->prev, (*sizefun) (w->prev) - delta, 0);
4204       CURBEG (w) -= delta;
4205       (*setsizefun) (window, *sizep + delta, 0);
4206     }
4207   else
4208     {
4209       int delta1;
4210       int opht = (*sizefun) (parent);
4211
4212       /* If trying to grow this window to or beyond size of the parent,
4213          make delta1 so big that, on shrinking back down,
4214          all the siblings end up with less than one line and are deleted.  */
4215       if (opht <= *sizep + delta)
4216         delta1 = opht * opht * 2;
4217       /* Otherwise, make delta1 just right so that if we add delta1
4218          lines to this window and to the parent, and then shrink
4219          the parent back to its original size, the new proportional
4220          size of this window will increase by delta.  */
4221       else
4222         delta1 = (delta * opht * 100) / ((opht - *sizep - delta) * 100);
4223
4224       /* Add delta1 lines or columns to this window, and to the parent,
4225          keeping things consistent while not affecting siblings.  */
4226       CURSIZE (XWINDOW (parent)) = opht + delta1;
4227       (*setsizefun) (window, *sizep + delta1, 0);
4228
4229       /* Squeeze out delta1 lines or columns from our parent,
4230          shrinking this window and siblings proportionately.
4231          This brings parent back to correct size.
4232          Delta1 was calculated so this makes this window the desired size,
4233          taking it all out of the siblings.  */
4234       (*setsizefun) (parent, opht, 0);
4235     }
4236
4237   SET_LAST_MODIFIED (w, 0);
4238   SET_LAST_FACECHANGE (w);
4239   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
4240   /* overkill maybe, but better to be correct */
4241   MARK_FRAME_GUTTERS_CHANGED (f);
4242 }
4243 #undef MINSIZE
4244 #undef CURBEG
4245 #undef CURSIZE
4246 #undef CURCHARSIZE
4247 #undef MINCHARSIZE
4248
4249 \f
4250
4251 /* Scroll contents of window WINDOW up COUNT lines.
4252    If COUNT < (top line height / average line height) then we just adjust
4253    the top clip.  */
4254 void
4255 window_scroll (Lisp_Object window, Lisp_Object count, int direction,
4256                Error_behavior errb)
4257 {
4258   struct window *w = XWINDOW (window);
4259   struct buffer *b = XBUFFER (w->buffer);
4260   int selected = EQ (window, Fselected_window (Qnil));
4261   int value = 0;
4262   Lisp_Object point, tem;
4263   display_line_dynarr *dla;
4264   int fheight, fwidth, modeline = 0;
4265   struct display_line* dl;
4266
4267   if (selected)
4268     point = make_int (BUF_PT (b));
4269   else
4270     {
4271       Bufpos pos = marker_position (w->pointm[CURRENT_DISP]);
4272
4273       if (pos < BUF_BEGV (b))
4274         pos = BUF_BEGV (b);
4275       else if (pos > BUF_ZV (b))
4276         pos = BUF_ZV (b);
4277
4278       point = make_int (pos);
4279     }
4280
4281   /* Always set force_start so that redisplay_window will run
4282      the window-scroll-functions.  */
4283   w->force_start = 1;
4284
4285   /* #### When the fuck does this happen?  I'm so glad that history has
4286      completely documented the behavior of the scrolling functions under
4287      all circumstances. */
4288   tem = Fpos_visible_in_window_p (point, window);
4289   if (NILP (tem))
4290     {
4291       Fvertical_motion (make_int (-window_char_height (w, 0) / 2),
4292                         window, Qnil);
4293       Fset_marker (w->start[CURRENT_DISP], point, w->buffer);
4294       w->start_at_line_beg = beginning_of_line_p (b, XINT (point));
4295       WINDOW_TEXT_TOP_CLIP (w) = 0;
4296       MARK_WINDOWS_CHANGED (w);
4297     }
4298
4299   if (!NILP (count))
4300     {
4301       if (EQ (count, Qminus))
4302         direction *= -1;
4303       else
4304         {
4305           count = Fprefix_numeric_value (count);
4306           value = XINT (count) * direction;
4307
4308           if (!value)
4309             return;     /* someone just made a pointless call */
4310         }
4311     }
4312
4313   /* If the user didn't specify how far to scroll then we have to figure it
4314      out by ourselves. */
4315   if (NILP (count) || EQ (count, Qminus))
4316     {
4317       /* Going forwards is easy.  If that is what we are doing then just
4318          set value and the section which handles the user specifying a
4319          positive value will work. */
4320       if (direction == 1)
4321         {
4322           value = window_displayed_height (w) - next_screen_context_lines;
4323           value = (value < 1 ? 1 : value);
4324         }
4325
4326       /* Going backwards is hard.  We can't use the same loop used if the
4327          user specified a negative value because we care about
4328          next_screen_context_lines.  In a variable height world you don't
4329          know how many lines above you can actually be displayed and still
4330          have the context lines appear.  So we leave value set to 0 and add
4331          a separate section to deal with this. */
4332
4333     }
4334
4335   if (direction == 1 && !value)
4336     {
4337       return;
4338     }
4339
4340   /* Determine parameters to test for partial line scrolling with. */
4341   dla = window_display_lines (w, CURRENT_DISP);
4342
4343   if (INTP (Vwindow_pixel_scroll_increment))
4344     fheight = XINT (Vwindow_pixel_scroll_increment);
4345   else if (!NILP (Vwindow_pixel_scroll_increment))
4346     default_face_height_and_width (window, &fheight, &fwidth);
4347
4348   if (Dynarr_length (dla) >= 1)
4349     modeline = Dynarr_atp (dla, 0)->modeline;
4350
4351   dl = Dynarr_atp (dla, modeline);
4352
4353   if (value > 0)
4354     {
4355       /* Go for partial display line scrolling. This just means bumping
4356          the clip by a reasonable amount and redisplaying, everything else
4357          remains unchanged. */
4358       if (!NILP (Vwindow_pixel_scroll_increment)
4359           &&
4360           Dynarr_length (dla) >= (1 + modeline)
4361           &&
4362           (dl->ascent - dl->top_clip) > fheight * value)
4363         {
4364           WINDOW_TEXT_TOP_CLIP (w) += value * fheight;
4365           MARK_WINDOWS_CHANGED (w);
4366         }
4367       else
4368         {
4369           int vtarget;
4370           Bufpos startp, old_start;
4371
4372           if (WINDOW_TEXT_TOP_CLIP (w))
4373             {
4374               WINDOW_TEXT_TOP_CLIP (w) = 0;
4375               MARK_WINDOWS_CHANGED (w);
4376             }
4377
4378           old_start = marker_position (w->start[CURRENT_DISP]);
4379           startp = vmotion (w, old_start, value, &vtarget);
4380
4381           if (vtarget < value &&
4382               (w->window_end_pos[CURRENT_DISP] == -1
4383                || (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b))))
4384             {
4385               maybe_signal_error (Qend_of_buffer, Qnil, Qwindow, errb);
4386               return;
4387             }
4388           else
4389             {
4390               set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4391                                      w->buffer);
4392               w->force_start = 1;
4393               w->start_at_line_beg = beginning_of_line_p (b, startp);
4394               MARK_WINDOWS_CHANGED (w);
4395
4396               if (!point_would_be_visible (w, startp, XINT (point)))
4397                 {
4398                   if (selected)
4399                     BUF_SET_PT (b, startp);
4400                   else
4401                     set_marker_restricted (w->pointm[CURRENT_DISP],
4402                                            make_int (startp),
4403                                            w->buffer);
4404                 }
4405             }
4406         }
4407     }
4408   else if (value < 0)
4409     {
4410       /* Go for partial display line scrolling. This just means bumping
4411          the clip by a reasonable amount and redisplaying, everything else
4412          remains unchanged. */
4413       if (!NILP (Vwindow_pixel_scroll_increment)
4414           &&
4415           Dynarr_length (dla) >= (1 + modeline)
4416           &&
4417           (dl->ascent - dl->top_clip) - fheight * value <
4418           (dl->ascent + dl->descent - dl->clip)
4419           &&
4420           WINDOW_TEXT_TOP_CLIP (w) + value * fheight > 0)
4421         {
4422           WINDOW_TEXT_TOP_CLIP (w) += value * fheight;
4423           MARK_WINDOWS_CHANGED (w);
4424         }
4425       else
4426         {
4427           int vtarget;
4428           Bufpos startp, old_start;
4429
4430           if (WINDOW_TEXT_TOP_CLIP (w))
4431             {
4432               WINDOW_TEXT_TOP_CLIP (w) = 0;
4433               MARK_WINDOWS_CHANGED (w);
4434             }
4435
4436           old_start = marker_position (w->start[CURRENT_DISP]);
4437           startp = vmotion (w, old_start, value, &vtarget);
4438
4439           if (vtarget > value
4440               && marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b))
4441             {
4442               maybe_signal_error (Qbeginning_of_buffer, Qnil, Qwindow, errb);
4443               return;
4444             }
4445           else
4446             {
4447               set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4448                                      w->buffer);
4449               w->force_start = 1;
4450               w->start_at_line_beg = beginning_of_line_p (b, startp);
4451               MARK_WINDOWS_CHANGED (w);
4452
4453               /* #### Scroll back by less than a line. This code was
4454                  originally for scrolling over large pixmaps and it
4455                  loses when a line being *exposed* at the top of the
4456                  window is bigger than the current one. However, for
4457                  pixel based scrolling in general we can guess that
4458                  the line we are going to display is probably the same
4459                  size as the one we are on. In that instance we can
4460                  have a reasonable stab at a suitable top clip. Fixing
4461                  this properly is hard (and probably slow) as we would
4462                  have to call redisplay to figure out the exposed line
4463                  size. */
4464               if (!NILP (Vwindow_pixel_scroll_increment)
4465                   && Dynarr_length (dla) >= (1 + modeline)
4466                   && dl->ascent + fheight * value > 0)
4467                 {
4468                   WINDOW_TEXT_TOP_CLIP (w) = (dl->ascent + fheight * value);
4469                 }
4470
4471               if (!point_would_be_visible (w, startp, XINT (point)))
4472                 {
4473                   Bufpos new_point;
4474
4475                   if (MINI_WINDOW_P (w))
4476                     new_point = startp;
4477                   else
4478                     new_point = start_of_last_line (w, startp);
4479
4480                   if (selected)
4481                     BUF_SET_PT (b, new_point);
4482                   else
4483                     set_marker_restricted (w->pointm[CURRENT_DISP],
4484                                            make_int (new_point),
4485                                            w->buffer);
4486                 }
4487             }
4488         }
4489     }
4490   else  /* value == 0 && direction == -1 */
4491     {
4492       if (WINDOW_TEXT_TOP_CLIP (w))
4493         {
4494           WINDOW_TEXT_TOP_CLIP (w) = 0;
4495           MARK_WINDOWS_CHANGED (w);
4496         }
4497       if (marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b))
4498         {
4499           maybe_signal_error (Qbeginning_of_buffer, Qnil, Qwindow, errb);
4500           return;
4501         }
4502       else
4503         {
4504           int vtarget;
4505           int movement = next_screen_context_lines - 1;
4506           Bufpos old_startp = marker_position (w->start[CURRENT_DISP]);
4507           Bufpos bottom = vmotion (w, old_startp, movement, &vtarget);
4508           Bufpos startp =
4509             start_with_point_on_display_line (w, bottom,
4510                                               -1 - (movement - vtarget));
4511
4512           if (startp >= old_startp)
4513             startp = vmotion (w, old_startp, -1, NULL);
4514
4515           set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4516                                  w->buffer);
4517           w->force_start = 1;
4518           w->start_at_line_beg = beginning_of_line_p (b, startp);
4519           MARK_WINDOWS_CHANGED (w);
4520
4521           if (!point_would_be_visible (w, startp, XINT (point)))
4522             {
4523               Bufpos new_point = start_of_last_line (w, startp);
4524
4525               if (selected)
4526                 BUF_SET_PT (b, new_point);
4527               else
4528                 set_marker_restricted (w->pointm[CURRENT_DISP],
4529                                        make_int (new_point),
4530                                        w->buffer);
4531             }
4532         }
4533     }
4534 }
4535 \f
4536 DEFUN ("scroll-up", Fscroll_up, 0, 1, "_P", /*
4537 Scroll text of current window up COUNT lines; or near full screen if no arg.
4538 A near full screen is `next-screen-context-lines' less than a full screen.
4539 Negative COUNT means scroll downward.
4540 When calling from a program, supply an integer as argument or nil.
4541 On attempt to scroll past end of buffer, `end-of-buffer' is signaled.
4542 On attempt to scroll past beginning of buffer, `beginning-of-buffer' is
4543 signaled.
4544
4545 The characters that are moved over may be added to the current selection
4546 \(i.e. active region) if the Shift key is held down, a motion key is used
4547 to invoke this command, and `shifted-motion-keys-select-region' is t; see
4548 the documentation for this variable for more details.
4549 */
4550        (count))
4551 {
4552   window_scroll (Fselected_window (Qnil), count, 1, ERROR_ME);
4553   return Qnil;
4554 }
4555
4556 DEFUN ("scroll-down", Fscroll_down, 0, 1, "_P", /*
4557 Scroll text of current window down COUNT lines; or near full screen if no arg.
4558 A near full screen is `next-screen-context-lines' less than a full screen.
4559 Negative COUNT means scroll upward.
4560 When calling from a program, supply a number as argument or nil.
4561 On attempt to scroll past end of buffer, `end-of-buffer' is signaled.
4562 On attempt to scroll past beginning of buffer, `beginning-of-buffer' is
4563 signaled.
4564
4565 The characters that are moved over may be added to the current selection
4566 \(i.e. active region) if the Shift key is held down, a motion key is used
4567 to invoke this command, and `shifted-motion-keys-select-region' is t; see
4568 the documentation for this variable for more details.
4569 */
4570        (count))
4571 {
4572   window_scroll (Fselected_window (Qnil), count, -1, ERROR_ME);
4573   return Qnil;
4574 }
4575 \f
4576 DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, 0, 0, 0, /*
4577 Return the other window for "other window scroll" commands.
4578 If in the minibuffer, `minibuffer-scroll-window' if non-nil
4579 specifies the window.
4580 If `other-window-scroll-buffer' is non-nil, a window
4581 showing that buffer is used.
4582 */
4583        ())
4584 {
4585   Lisp_Object window;
4586   Lisp_Object selected_window = Fselected_window (Qnil);
4587
4588   if (MINI_WINDOW_P (XWINDOW (selected_window))
4589       && !NILP (Vminibuffer_scroll_window))
4590     window = Vminibuffer_scroll_window;
4591   /* If buffer is specified, scroll that buffer.  */
4592   else if (!NILP (Vother_window_scroll_buffer))
4593     {
4594       window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil, Qnil);
4595       if (NILP (window))
4596         window = display_buffer (Vother_window_scroll_buffer, Qt, Qnil);
4597     }
4598   else
4599     {
4600       /* Nothing specified; look for a neighboring window on the same
4601          frame.  */
4602       window = Fnext_window (selected_window, Qnil, Qnil, Qnil);
4603
4604       if (EQ (window, selected_window))
4605         /* That didn't get us anywhere; look for a window on another
4606            visible frame.  */
4607         do
4608           window = Fnext_window (window, Qnil, Qt, Qnil);
4609         while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
4610                && ! EQ (window, selected_window));
4611     }
4612
4613   CHECK_LIVE_WINDOW (window);
4614
4615   if (EQ (window, selected_window))
4616     error ("There is no other window");
4617
4618   return window;
4619  }
4620
4621 DEFUN ("scroll-other-window", Fscroll_other_window, 0, 1, "_P", /*
4622 Scroll next window upward COUNT lines; or near full frame if no arg.
4623 The next window is the one below the current one; or the one at the top
4624 if the current one is at the bottom.  Negative COUNT means scroll downward.
4625 When calling from a program, supply a number as argument or nil.
4626
4627 If in the minibuffer, `minibuffer-scroll-window' if non-nil
4628 specifies the window to scroll.
4629 If `other-window-scroll-buffer' is non-nil, scroll the window
4630 showing that buffer, popping the buffer up if necessary.
4631 */
4632        (count))
4633 {
4634   window_scroll (Fother_window_for_scrolling (), count, 1, ERROR_ME);
4635   return Qnil;
4636 }
4637 \f
4638 DEFUN ("scroll-left", Fscroll_left, 0, 1, "_P", /*
4639 Scroll selected window display COUNT columns left.
4640 Default for COUNT is window width minus 2.
4641
4642 The characters that are moved over may be added to the current selection
4643 \(i.e. active region) if the Shift key is held down, a motion key is used
4644 to invoke this command, and `shifted-motion-keys-select-region' is t; see
4645 the documentation for this variable for more details.
4646 */
4647        (count))
4648 {
4649   Lisp_Object window = Fselected_window (Qnil);
4650   struct window *w = XWINDOW (window);
4651   int n = (NILP (count) ?
4652            window_char_width (w, 0) - 2 :
4653            XINT (Fprefix_numeric_value (count)));
4654
4655   return Fset_window_hscroll (window, make_int (w->hscroll + n));
4656 }
4657
4658 DEFUN ("scroll-right", Fscroll_right, 0, 1, "_P", /*
4659 Scroll selected window display COUNT columns right.
4660 Default for COUNT is window width minus 2.
4661
4662 The characters that are moved over may be added to the current selection
4663 \(i.e. active region) if the Shift key is held down, a motion key is used
4664 to invoke this command, and `shifted-motion-keys-select-region' is t; see
4665 the documentation for this variable for more details.
4666 */
4667        (count))
4668 {
4669   Lisp_Object window = Fselected_window (Qnil);
4670   struct window *w = XWINDOW (window);
4671   int n = (NILP (count) ?
4672            window_char_width (w, 0) - 2 :
4673            XINT (Fprefix_numeric_value (count)));
4674
4675   return Fset_window_hscroll (window, make_int (w->hscroll - n));
4676 }
4677 \f
4678 DEFUN ("center-to-window-line", Fcenter_to_window_line, 0, 2, "_P", /*
4679 Center point in WINDOW.  With N, put point on line N.
4680 The desired position of point is always relative to the window.
4681 If WINDOW is nil, the selected window is used.
4682 */
4683        (n, window))
4684 {
4685   struct window *w = decode_window (window);
4686   struct buffer *b = XBUFFER (w->buffer);
4687   Bufpos opoint = BUF_PT (b);
4688   Bufpos startp;
4689
4690   if (NILP (n))
4691     startp = start_with_line_at_pixpos (w, opoint, window_half_pixpos (w));
4692   else
4693     {
4694       n = Fprefix_numeric_value (n);
4695       CHECK_INT (n);
4696       startp = start_with_point_on_display_line (w, opoint, XINT (n));
4697     }
4698
4699   Fset_marker (w->start[CURRENT_DISP], make_int (startp), w->buffer);
4700
4701   w->start_at_line_beg = beginning_of_line_p (b, startp);
4702   w->force_start = 1;
4703   MARK_WINDOWS_CHANGED (w);
4704   return Qnil;
4705 }
4706
4707 DEFUN ("move-to-window-line", Fmove_to_window_line, 1, 2, "_P", /*
4708 Position point relative to WINDOW.
4709 With no argument, position text at center of window.
4710 An argument specifies window line; zero means top of window,
4711 negative means relative to bottom of window.
4712 If WINDOW is nil, the selected window is used.
4713 */
4714        (arg, window))
4715 {
4716   struct window *w;
4717   struct buffer *b;
4718   int height;
4719   Bufpos start, new_point;
4720   int selected;
4721
4722   /* Don't use decode_window() because we need the new value of
4723      WINDOW.  */
4724   if (NILP (window))
4725     window = Fselected_window (Qnil);
4726   else
4727     CHECK_LIVE_WINDOW (window);
4728   w = XWINDOW (window);
4729   b = XBUFFER (w->buffer);
4730
4731   height = window_displayed_height (w);
4732   selected = EQ (window, Fselected_window (w->frame));
4733
4734   if (NILP (arg))
4735     {
4736       int retval;
4737
4738       if (XINT (w->last_modified[CURRENT_DISP]) >= BUF_MODIFF (b)
4739           && XINT (w->last_facechange[CURRENT_DISP]) >= BUF_FACECHANGE (b))
4740         {
4741           new_point = point_at_center (w, CURRENT_DISP, 0, 0);
4742
4743           if (selected)
4744             BUF_SET_PT (b, new_point);
4745           else
4746             Fset_window_point (window, make_int (new_point));
4747
4748           retval = line_at_center (w, CURRENT_DISP, 0, 0);
4749         }
4750       else
4751         {
4752           start = marker_position (w->start[CURRENT_DISP]);
4753           if (start < BUF_BEGV (b))
4754             start = BUF_BEGV (b);
4755           else if (start > BUF_ZV (b))
4756             start = BUF_ZV (b);
4757
4758           if (selected)
4759             new_point = BUF_PT (b);
4760           else
4761             new_point = marker_position (w->pointm[CURRENT_DISP]);
4762
4763           new_point = point_at_center (w, CMOTION_DISP, start, BUF_PT (b));
4764
4765           if (selected)
4766             BUF_SET_PT (b, new_point);
4767           else
4768             Fset_window_point (window, make_int (new_point));
4769
4770           retval = line_at_center (w, CMOTION_DISP, start, BUF_PT (b));
4771         }
4772
4773       return make_int (retval);
4774     }
4775   else
4776     {
4777       /* #### Is this going to work right when at eob? */
4778       arg = Fprefix_numeric_value (arg);
4779       if (XINT (arg) < 0)
4780         XSETINT (arg, XINT (arg) + height);
4781     }
4782
4783   start = marker_position (w->start[CURRENT_DISP]);
4784   if (start < BUF_BEGV (b) || start > BUF_ZV (b))
4785     {
4786       if (selected)
4787         new_point = BUF_PT (b);
4788       else
4789         new_point = marker_position (w->pointm[CURRENT_DISP]);
4790
4791       new_point = vmotion (XWINDOW (window), new_point, -height / 2, 0);
4792
4793       if (selected)
4794         BUF_SET_PT (b, new_point);
4795       else
4796         Fset_window_point (window, make_int (new_point));
4797
4798       Fset_marker (w->start[CURRENT_DISP], make_int (new_point),
4799                    w->buffer);
4800       w->start_at_line_beg = beginning_of_line_p (b, new_point);
4801       w->force_start = 1;
4802     }
4803   else
4804     {
4805       if (selected)
4806         BUF_SET_PT (b, start);
4807       else
4808         Fset_window_point (window, make_int (start));
4809     }
4810
4811   if (selected)
4812     return Fvertical_motion (arg, window, Qnil);
4813   else
4814     {
4815       int vpos;
4816       new_point = vmotion (XWINDOW (window),
4817                            marker_position (w->pointm[CURRENT_DISP]),
4818                            XINT (arg), &vpos);
4819       Fset_window_point (window, make_int (new_point));
4820       return make_int (vpos);
4821     }
4822 }
4823
4824 \f
4825 static int
4826 map_windows_1 (Lisp_Object window,
4827                int (*mapfun) (struct window *w, void *closure),
4828                void *closure)
4829 {
4830   for (; !NILP (window); window = XWINDOW (window)->next)
4831     {
4832       int retval;
4833       struct window *w = XWINDOW (window);
4834
4835       if (!NILP (w->vchild))
4836         retval = map_windows_1 (w->vchild, mapfun, closure);
4837       else if (!NILP (w->hchild))
4838         retval = map_windows_1 (w->hchild, mapfun, closure);
4839       else
4840         retval = (mapfun) (w, closure);
4841
4842       if (retval)
4843         return retval;
4844     }
4845
4846   return 0;
4847 }
4848
4849 /* Map MAPFUN over the windows in F.  CLOSURE is passed to each
4850    invocation of MAPFUN.  If any invocation of MAPFUN returns
4851    non-zero, the mapping is halted.  Otherwise, map_windows() maps
4852    over all windows in F.
4853
4854    If MAPFUN creates or deletes windows, the behavior is undefined.  */
4855
4856 int
4857 map_windows (struct frame *f, int (*mapfun) (struct window *w, void *closure),
4858              void *closure)
4859 {
4860   if (f)
4861     return map_windows_1 (FRAME_ROOT_WINDOW (f), mapfun, closure);
4862   else
4863     {
4864       Lisp_Object frmcons, devcons, concons;
4865
4866       FRAME_LOOP_NO_BREAK(frmcons, devcons, concons)
4867         {
4868           int v = map_windows_1 (FRAME_ROOT_WINDOW (XFRAME (XCAR (frmcons))),
4869                                  mapfun, closure);
4870           if (v)
4871             return v;
4872         }
4873     }
4874
4875   return 0;
4876 }
4877
4878 \f
4879 static void
4880 modeline_shadow_thickness_changed (Lisp_Object specifier, struct window *w,
4881                                    Lisp_Object oldval)
4882 {
4883   w->shadow_thickness_changed = 1;
4884   MARK_WINDOWS_CHANGED (w);
4885 }
4886
4887 static void
4888 vertical_divider_changed_in_window (Lisp_Object specifier,
4889                                     struct window *w,
4890                                     Lisp_Object oldval)
4891 {
4892   MARK_WINDOWS_CHANGED (w);
4893   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (XFRAME (WINDOW_FRAME (w)));
4894 }
4895
4896 /* also used in scrollbar.c */
4897 void
4898 some_window_value_changed (Lisp_Object specifier, struct window *w,
4899                            Lisp_Object oldval)
4900 {
4901   MARK_WINDOWS_CHANGED (w);
4902 }
4903
4904 #ifdef MEMORY_USAGE_STATS
4905
4906 struct window_stats
4907 {
4908   int face;
4909   int glyph;
4910 #ifdef HAVE_SCROLLBARS
4911   int scrollbar;
4912 #endif
4913   int line_start;
4914   int other_redisplay;
4915   int other;
4916 };
4917
4918 static void
4919 compute_window_mirror_usage (struct window_mirror *mir,
4920                              struct window_stats *stats,
4921                              struct overhead_stats *ovstats)
4922 {
4923   if (!mir)
4924     return;
4925   stats->other += malloced_storage_size (mir, sizeof (struct window_mirror),
4926                                          ovstats);
4927 #ifdef HAVE_SCROLLBARS
4928   {
4929     struct device *d = XDEVICE (FRAME_DEVICE (mir->frame));
4930
4931     stats->scrollbar +=
4932       compute_scrollbar_instance_usage (d, mir->scrollbar_vertical_instance,
4933                                         ovstats);
4934     stats->scrollbar +=
4935       compute_scrollbar_instance_usage (d, mir->scrollbar_horizontal_instance,
4936                                         ovstats);
4937   }
4938 #endif /* HAVE_SCROLLBARS */
4939   stats->other_redisplay +=
4940     compute_display_line_dynarr_usage (mir->current_display_lines, ovstats);
4941   stats->other_redisplay +=
4942     compute_display_line_dynarr_usage (mir->desired_display_lines, ovstats);
4943 }
4944
4945 static void
4946 compute_window_usage (struct window *w, struct window_stats *stats,
4947                       struct overhead_stats *ovstats)
4948 {
4949   xzero (*stats);
4950   stats->other += malloced_storage_size (w, sizeof (struct window), ovstats);
4951   stats->face += compute_face_cachel_usage (w->face_cachels, ovstats);
4952   stats->glyph += compute_glyph_cachel_usage (w->glyph_cachels, ovstats);
4953   stats->line_start +=
4954     compute_line_start_cache_dynarr_usage (w->line_start_cache, ovstats);
4955   compute_window_mirror_usage (find_window_mirror (w), stats, ovstats);
4956 }
4957
4958 DEFUN ("window-memory-usage", Fwindow_memory_usage, 1, 1, 0, /*
4959 Return stats about the memory usage of window WINDOW.
4960 The values returned are in the form of an alist of usage types and byte
4961 counts.  The byte counts attempt to encompass all the memory used
4962 by the window (separate from the memory logically associated with a
4963 buffer or frame), including internal structures and any malloc()
4964 overhead associated with them.  In practice, the byte counts are
4965 underestimated because certain memory usage is very hard to determine
4966 \(e.g. the amount of memory used inside the Xt library or inside the
4967 X server) and because there is other stuff that might logically
4968 be associated with a window, buffer, or frame (e.g. window configurations,
4969 glyphs) but should not obviously be included in the usage counts.
4970
4971 Multiple slices of the total memory usage may be returned, separated
4972 by a nil.  Each slice represents a particular view of the memory, a
4973 particular way of partitioning it into groups.  Within a slice, there
4974 is no overlap between the groups of memory, and each slice collectively
4975 represents all the memory concerned.
4976 */
4977        (window))
4978 {
4979   struct window_stats stats;
4980   struct overhead_stats ovstats;
4981   Lisp_Object val = Qnil;
4982
4983   CHECK_WINDOW (window); /* dead windows should be allowed, no? */
4984   xzero (ovstats);
4985   compute_window_usage (XWINDOW (window), &stats, &ovstats);
4986
4987   val = acons (Qface_cache,          make_int (stats.face),              val);
4988   val = acons (Qglyph_cache,         make_int (stats.glyph),             val);
4989 #ifdef HAVE_SCROLLBARS
4990   val = acons (Qscrollbar_instances, make_int (stats.scrollbar),         val);
4991 #endif
4992   val = acons (Qline_start_cache,    make_int (stats.line_start),        val);
4993   val = acons (Qother_redisplay,     make_int (stats.other_redisplay),   val);
4994   val = acons (Qother,               make_int (stats.other),             val);
4995   val = Fcons (Qnil, val);
4996   val = acons (Qactually_requested,  make_int (ovstats.was_requested),   val);
4997   val = acons (Qmalloc_overhead,     make_int (ovstats.malloc_overhead), val);
4998   val = acons (Qdynarr_overhead,     make_int (ovstats.dynarr_overhead), val);
4999
5000   return Fnreverse (val);
5001 }
5002
5003 #endif /* MEMORY_USAGE_STATS */
5004
5005 \f
5006 /************************************************************************/
5007 /*                         Window configurations                        */
5008 /************************************************************************/
5009
5010 /* #### This window configuration stuff has had serious bugs lurking in it
5011    for years; it would be a -huge- win if this was reimplemented in lisp.
5012  */
5013
5014 /* If you add anything to this structure make sure saved_window_equal
5015    knows about it. */
5016 struct saved_window
5017 {
5018   Lisp_Object window;         /* window */
5019   Lisp_Object buffer;         /* buffer */
5020   Lisp_Object start;          /* copied marker */
5021   Lisp_Object pointm;         /* copied marker */
5022   Lisp_Object sb_point;       /* copied marker */
5023   Lisp_Object mark;           /* copied marker */
5024   int pixel_left;
5025   int pixel_top;
5026   int pixel_width;
5027   int pixel_height;
5028   int hscroll;
5029   Charcount modeline_hscroll;
5030   int parent_index;           /* index into saved_windows */
5031   int prev_index;             /* index into saved_windows */
5032   char start_at_line_beg; /* boolean */
5033
5034 #define WINDOW_SLOT_DECLARATION
5035 #define WINDOW_SLOT(slot, compare) Lisp_Object slot
5036 #include "winslots.h"
5037 };
5038
5039 /* If you add anything to this structure make sure window_config_equal
5040    knows about it. */
5041 struct window_config
5042 {
5043   struct lcrecord_header header;
5044   /*  int frame_width; No longer needed, JV
5045       int frame_height; */
5046 #if 0 /* FSFmacs */
5047   Lisp_Object selected_frame;
5048 #endif
5049   Lisp_Object current_window;
5050   Lisp_Object current_buffer;
5051   Lisp_Object minibuffer_scroll_window;
5052   Lisp_Object root_window;
5053   int minibuf_height; /* 0 = no minibuffer, <0, size in lines, >0 in pixels */
5054   /* Record the values of window-min-width and window-min-height
5055      so that window sizes remain consistent with them.  */
5056   int min_width, min_height;
5057   unsigned int saved_windows_count;
5058   /* Zero-sized arrays aren't ANSI C */
5059   struct saved_window saved_windows[1];
5060 };
5061
5062 #define SAVED_WINDOW_N(conf, n) (&((conf)->saved_windows[(n)]))
5063 #define XWINDOW_CONFIGURATION(x) XRECORD (x, window_configuration, struct window_config)
5064 #define XSETWINDOW_CONFIGURATION(x, p) XSETRECORD (x, p, window_configuration)
5065 #define WINDOW_CONFIGURATIONP(x) RECORDP (x, window_configuration)
5066 #define CHECK_WINDOW_CONFIGURATION(x) CHECK_RECORD (x, window_configuration)
5067
5068 static Lisp_Object
5069 mark_window_config (Lisp_Object obj)
5070 {
5071   struct window_config *config = XWINDOW_CONFIGURATION (obj);
5072   unsigned int i;
5073   mark_object (config->current_window);
5074   mark_object (config->current_buffer);
5075   mark_object (config->minibuffer_scroll_window);
5076   mark_object (config->root_window);
5077
5078   for (i = 0; i < config->saved_windows_count; i++)
5079     {
5080       struct saved_window *s = SAVED_WINDOW_N (config, i);
5081       mark_object (s->window);
5082       mark_object (s->buffer);
5083       mark_object (s->start);
5084       mark_object (s->pointm);
5085       mark_object (s->sb_point);
5086       mark_object (s->mark);
5087 #if 0
5088       /* #### This looked like this. I do not see why specifier cached
5089          values should not be marked, as such specifiers as toolbars
5090          might have GC-able instances. Freed configs are not marked,
5091          aren't they?  -- kkm */
5092       mark_object (s->dedicated);
5093 #else
5094 #define WINDOW_SLOT(slot, compare) mark_object (s->slot)
5095 #include "winslots.h"
5096 #endif
5097     }
5098   return Qnil;
5099 }
5100
5101 inline static size_t
5102 sizeof_window_config_for_n_windows (unsigned int n)
5103 {
5104   return FLEXIBLE_ARRAY_STRUCT_SIZEOF (struct window_config,
5105                                        struct saved_window, saved_windows, n);
5106 }
5107
5108 static size_t
5109 sizeof_window_config (const void *h)
5110 {
5111   const struct window_config *c = (const struct window_config *) h;
5112   return sizeof_window_config_for_n_windows (c->saved_windows_count);
5113 }
5114
5115 static void
5116 print_window_config (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
5117 {
5118   struct window_config *config = XWINDOW_CONFIGURATION (obj);
5119   char buf[200];
5120   if (print_readably)
5121     error ("printing unreadable object #<window-configuration 0x%x>",
5122            config->header.uid);
5123   write_c_string ("#<window-configuration ", printcharfun);
5124   sprintf (buf, "0x%x>", config->header.uid);
5125   write_c_string (buf, printcharfun);
5126 }
5127
5128 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION ("window-configuration",
5129                                         window_configuration,
5130                                         mark_window_config,
5131                                         print_window_config,
5132                                         0, 0, 0, 0, sizeof_window_config,
5133                                         struct window_config);
5134
5135
5136 /* Returns a boolean indicating whether the two saved windows are
5137    identical. */
5138 static int
5139 saved_window_equal (struct saved_window *win1, struct saved_window *win2)
5140 {
5141 #define WINDOW_SLOT(slot, compare)              \
5142   if (!compare (win1->slot, win2->slot))        \
5143     return 0;
5144 #include "winslots.h"
5145
5146   return
5147     EQ (win1->window, win2->window) &&
5148     EQ (win1->buffer, win2->buffer) &&
5149     internal_equal (win1->start,    win2->start, 0) &&
5150     internal_equal (win1->pointm,   win2->pointm, 0) &&
5151     internal_equal (win1->sb_point, win2->sb_point, 0) &&
5152     internal_equal (win1->mark,     win2->mark, 0) &&
5153     win1->pixel_left   == win2->pixel_left &&
5154     win1->pixel_top    == win2->pixel_top &&
5155     win1->pixel_width  == win2->pixel_width &&
5156     win1->pixel_height == win2->pixel_height &&
5157     win1->hscroll      == win2->hscroll &&
5158     win1->modeline_hscroll == win2->modeline_hscroll &&
5159     win1->parent_index == win2->parent_index &&
5160     win1->prev_index   == win2->prev_index &&
5161     win1->start_at_line_beg == win2->start_at_line_beg;
5162 }
5163
5164 /* Returns a boolean indicating whether the two given configurations
5165    are identical. */
5166 static int
5167 window_config_equal (Lisp_Object conf1, Lisp_Object conf2)
5168 {
5169   struct window_config *fig1, *fig2;
5170   unsigned int i;
5171
5172   /* First check if they are truly the same. */
5173   if (EQ (conf1, conf2))
5174     return 1;
5175
5176   fig1 = XWINDOW_CONFIGURATION (conf1);
5177   fig2 = XWINDOW_CONFIGURATION (conf2);
5178
5179   if (!((fig1->saved_windows_count == fig2->saved_windows_count) &&
5180         EQ (fig1->current_window,           fig2->current_window) &&
5181         EQ (fig1->current_buffer,           fig2->current_buffer) &&
5182         EQ (fig1->root_window,              fig2->root_window) &&
5183         EQ (fig1->minibuffer_scroll_window, fig2->minibuffer_scroll_window)))
5184         /* &&
5185         fig1->frame_width  == fig2->frame_width &&
5186         fig1->frame_height == fig2->frame_height)) */
5187     return 0;
5188
5189   for (i = 0; i < fig1->saved_windows_count; i++)
5190     {
5191       if (!saved_window_equal (SAVED_WINDOW_N (fig1, i),
5192                                SAVED_WINDOW_N (fig2, i)))
5193         return 0;
5194     }
5195
5196   return 1;
5197 }
5198
5199 DEFUN ("window-configuration-p", Fwindow_configuration_p, 1, 1, 0, /*
5200 Return t if OBJECT is a window-configuration object.
5201 */
5202        (object))
5203 {
5204   return WINDOW_CONFIGURATIONP (object) ? Qt : Qnil;
5205 }
5206
5207 static int
5208 mark_windows_in_use_closure (struct window *w, void *closure)
5209 {
5210   int mark = *(int *)closure;
5211   w->config_mark = mark;
5212   return 0;
5213 }
5214
5215 static void
5216 mark_windows_in_use (struct frame *f, int mark)
5217 {
5218   map_windows (f, mark_windows_in_use_closure, &mark);
5219 }
5220
5221 /* Lisp_Object return value so it can be used in record_unwind_protect() */
5222 static Lisp_Object
5223 free_window_configuration (Lisp_Object window_config)
5224 {
5225   unsigned int i;
5226   struct window_config *config = XWINDOW_CONFIGURATION (window_config);
5227
5228   /* Free all the markers.  It's not completely necessary that
5229      we do this (window configs sitting in a free list aren't
5230      marked normally so the markers wouldn't be marked anyway)
5231      but it's more efficient. */
5232   for (i = 0; i < config->saved_windows_count; i++)
5233     {
5234       struct saved_window *p = SAVED_WINDOW_N (config, i);
5235
5236       if (!NILP (p->pointm))
5237         {
5238           free_marker (XMARKER (p->pointm));
5239           p->pointm = Qnil;
5240         }
5241       if (!NILP (p->start))
5242         {
5243           free_marker (XMARKER (p->start));
5244           p->start = Qnil;
5245         }
5246       if (!NILP (p->sb_point))
5247         {
5248           free_marker (XMARKER (p->sb_point));
5249           p->sb_point = Qnil;
5250         }
5251       if (!NILP (p->mark))
5252         {
5253           free_marker (XMARKER (p->mark));
5254           p->mark = Qnil;
5255         }
5256     }
5257
5258   if (config->saved_windows_count <= countof (Vwindow_configuration_free_list))
5259     free_managed_lcrecord (Vwindow_configuration_free_list
5260                            [config->saved_windows_count - 1],
5261                            window_config);
5262
5263   return Qnil;
5264 }
5265
5266 DEFUN ("set-window-configuration", Fset_window_configuration, 1, 1, 0, /*
5267 Set the configuration of windows and buffers as specified by CONFIGURATION.
5268 CONFIGURATION must be a value previously returned
5269 by `current-window-configuration' (which see).
5270 */
5271        (configuration))
5272 {
5273   struct window *w;
5274   struct window_config *config;
5275   struct saved_window *p;
5276   Lisp_Object new_current_buffer;
5277   unsigned int k;
5278   Lisp_Object frame;
5279   struct frame *f;
5280   struct gcpro gcpro1;
5281   Lisp_Object old_window_config;
5282   /*  int previous_frame_height;
5283       int previous_frame_width;*/
5284   int previous_pixel_top;
5285   int previous_pixel_height;
5286   int previous_pixel_left;
5287   int previous_pixel_width;
5288   int previous_minibuf_height, previous_minibuf_top,previous_minibuf_width;
5289   int real_font_height;
5290   int converted_minibuf_height,target_minibuf_height;
5291   int specpdl_count = specpdl_depth ();
5292
5293   GCPRO1 (configuration);
5294
5295   CHECK_WINDOW_CONFIGURATION (configuration);
5296   config = XWINDOW_CONFIGURATION (configuration);
5297
5298   frame = XWINDOW (SAVED_WINDOW_N (config, 0)->window)->frame;
5299   f = XFRAME (frame);
5300
5301   /* Do not signal an error here if the frame was deleted.  There are
5302      reasonable cases where we could get here with a deleted frame and
5303      just want to do close to nothing instead. */
5304
5305   if (FRAME_LIVE_P (f))
5306     {
5307       /* restore the frame characteristics */
5308
5309       new_current_buffer = config->current_buffer;
5310       if (!BUFFER_LIVE_P (XBUFFER (new_current_buffer)))
5311         new_current_buffer = Qnil;
5312
5313       /*
5314        * Assumed precondition:  w->config_mark = 0 for all w
5315        * This procedure should ensure this is true by the time it exits
5316        * to ensure the precondition for future calls.
5317        *
5318        * We use w->config_mark to know whether we're modifying a
5319        * window that is currently visible on the frame (#### we
5320        * should just be able to check whether the window is dead
5321        * or not, but this way is safer?).  As we process each
5322        * window, we set its config_mark to 0.  At the end, we
5323        * go through all the windows that used to be on the frame,
5324        * set each one's config_mark to 0 (to maintain the
5325        * assumed precondition) and delete each one that's no
5326        * longer in use.
5327        *
5328        * #### Using a window-configuration to keep track of
5329        * the current windows is wasteful.  All we need is the
5330        * list of windows, so we could just use a dynarr.
5331        */
5332       old_window_config = Fcurrent_window_configuration (frame);
5333
5334       /* If the new configuration is already equal to the old, then stop
5335          right here.  This saves the work below and it also saves
5336          triggering a full redisplay of this window.  This is a huge win
5337          when using the mouse since the mode motion code uses
5338          save-window-excursion extensively but will rarely cause the
5339          configuration to actually change. */
5340       if (window_config_equal (configuration, old_window_config))
5341         {
5342           free_window_configuration (old_window_config);
5343           UNGCPRO;
5344           return Qnil;
5345         }
5346
5347       /* We can't quit or even check for quit because that may cause
5348          investigation of the frame state, which may crash if the frame is
5349          in an inconsistent state. */
5350       begin_dont_check_for_quit ();
5351       record_unwind_protect (free_window_configuration, old_window_config);
5352
5353       mark_windows_in_use (f, 1);
5354 #ifdef BROKEN_SUBWINDOW_REDISPLAY
5355       /* Force subwindows to be remapped. This is overkill but saves
5356         us having to rely on the redisplay code to unmap any extant
5357         subwindows.
5358
5359         #### It does cause some extra flashing though which we could
5360         possibly avoid. So consider trying to get redisplay to work
5361         correctly.
5362
5363         Removing the instances from the frame cache is wrong because
5364         an instance is only put in the frame cache when it is
5365         instantiated. So if we do this there is a chance that stuff
5366         will never get put back in the frame cache. */
5367       reset_frame_subwindow_instance_cache (f);
5368 #endif
5369 #if 0
5370       /* JV: This is bogus,
5371          First of all, the units are inconsistent. The frame sizes are measured
5372          in characters but the window sizes are stored in pixels. So if a
5373          font size change happened between saving and restoring, the
5374          frame "sizes" maybe equal but the windows still should be
5375          resized. This is tickled a lot by the new "character size
5376          stays constant" policy in 21.0. It leads to very weird
5377          glitches (and possibly crashes when asserts are tickled).
5378
5379          Just changing the units doesn't help because changing the
5380          toolbar configuration can also change the pixel positions.
5381          Luckily there is a much simpler way of doing this, see below.
5382        */
5383       previous_frame_width = FRAME_WIDTH (f);
5384       previous_frame_height = FRAME_HEIGHT (f);
5385       /* If the frame has been resized since this window configuration was
5386          made, we change the frame to the size specified in the
5387          configuration, restore the configuration, and then resize it
5388          back.  We keep track of the prevailing height in these variables.  */
5389       if (config->frame_height != FRAME_HEIGHT (f)
5390           || config->frame_width != FRAME_WIDTH (f))
5391         change_frame_size (f, config->frame_height, config->frame_width, 0);
5392 #endif
5393
5394       previous_pixel_top = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_top;
5395       previous_pixel_height = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_height;
5396       previous_pixel_left = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_left;
5397       previous_pixel_width = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_width;
5398
5399       /* remember some properties of the minibuffer */
5400
5401       default_face_height_and_width (frame, &real_font_height, 0);
5402       assert(real_font_height > 0);
5403
5404       if (FRAME_HAS_MINIBUF_P (f) && ! FRAME_MINIBUF_ONLY_P (f))
5405         {
5406           previous_minibuf_height
5407             = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_height;
5408           previous_minibuf_top
5409             = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_top;
5410           previous_minibuf_width
5411             = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_width;
5412         }
5413       else
5414         {
5415           previous_minibuf_height = 0;
5416           previous_minibuf_top = 0;
5417           previous_minibuf_width = 0;
5418         }
5419       converted_minibuf_height =
5420         (previous_minibuf_height % real_font_height) == 0 ?
5421         - (previous_minibuf_height / real_font_height ) :    /* lines */
5422             previous_minibuf_height;   /* pixels */
5423
5424       /* Temporarily avoid any problems with windows that are smaller
5425          than they are supposed to be.  */
5426       window_min_height = 1;
5427       window_min_width = 1;
5428
5429       /* OK, now restore all the windows in the window config.
5430          This may involve "undeleting" windows, since the
5431          windows in the window config may be deleted.
5432          */
5433       for (k = 0; k < config->saved_windows_count; k++)
5434         {
5435           p = SAVED_WINDOW_N (config, k);
5436           w = XWINDOW (p->window);
5437           w->next = Qnil;
5438
5439           /* The window might be dead.  In this case, its redisplay
5440              structures were freed, so we need to reallocate them. */
5441           if (!w->face_cachels)
5442             {
5443               w->face_cachels = Dynarr_new (face_cachel);
5444               reset_face_cachels (w);
5445             }
5446           if (!w->glyph_cachels)
5447             w->glyph_cachels = Dynarr_new (glyph_cachel);
5448           if (!w->line_start_cache)
5449             w->line_start_cache = Dynarr_new (line_start_cache);
5450           w->gutter_extent_modiff[0] = 0;
5451           w->gutter_extent_modiff[1] = 0;
5452           w->gutter_extent_modiff[2] = 0;
5453           w->gutter_extent_modiff[3] = 0;
5454           w->dead = 0;
5455
5456           if (p->parent_index >= 0)
5457             w->parent = SAVED_WINDOW_N (config, p->parent_index)->window;
5458           else
5459             w->parent = Qnil;
5460
5461           if (p->prev_index >= 0)
5462             {
5463               w->prev = SAVED_WINDOW_N (config, p->prev_index)->window;
5464
5465               /* This is true for a minibuffer-only frame. */
5466               if (!NILP (w->mini_p) && EQ (w->prev, p->window))
5467                 w->next = Qnil;
5468               else
5469                 XWINDOW (w->prev)->next = p->window;
5470             }
5471           else
5472             {
5473               w->prev = Qnil;
5474               if (!NILP (w->parent))
5475                 {
5476                   if (WINDOW_WIDTH (p) == WINDOW_WIDTH (XWINDOW (w->parent)))
5477                     {
5478                       XWINDOW (w->parent)->vchild = p->window;
5479                       XWINDOW (w->parent)->hchild = Qnil;
5480                     }
5481                   else
5482                     {
5483                       XWINDOW (w->parent)->hchild = p->window;
5484                       XWINDOW (w->parent)->vchild = Qnil;
5485                     }
5486                 }
5487             }
5488           if (!w->config_mark)
5489             {
5490               /* #### This should be equivalent to the window previously
5491                  having been dead.  If we're brave, we'll put in an
5492                  assertion to this effect. */
5493               MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
5494             }
5495           else /* if (!EQ (w->buffer, p->buffer)) */
5496             {
5497               /* With the new redisplay we let it know that a change has
5498                  been made and it will take care of the rest.  If we don't
5499                  tell it something has possibly changed it could lead to
5500                  incorrect display. */
5501               MARK_WINDOWS_CHANGED (w);
5502             }
5503
5504           WINDOW_LEFT (w) = WINDOW_LEFT (p);
5505           WINDOW_TOP (w) = WINDOW_TOP (p);
5506           WINDOW_WIDTH (w) = WINDOW_WIDTH (p);
5507           WINDOW_HEIGHT (w) = WINDOW_HEIGHT (p);
5508           w->hscroll = p->hscroll;
5509           w->modeline_hscroll = p->modeline_hscroll;
5510           w->line_cache_last_updated = Qzero;
5511           /* When we restore a window's configuration, the identity of
5512              the window hasn't actually changed - so there is no
5513              reason why we shouldn't preserve the instance cache for
5514              it - unless it was originally deleted. This will often
5515              buy us something as we will not have to re-instantiate
5516              all the instances. This is because this is an instance
5517              cache - not a display cache. Preserving the display cache
5518              would definitely be wrong.
5519
5520              We specifically want to do this for tabs, since for some
5521              reason finding a file will cause the configuration to be
5522              set. */
5523           if (NILP (w->subwindow_instance_cache))
5524             w->subwindow_instance_cache =
5525               make_image_instance_cache_hash_table ();
5526
5527           SET_LAST_MODIFIED (w, 1);
5528           SET_LAST_FACECHANGE (w);
5529           w->config_mark = 0;
5530
5531           /* #### Consider making the instance cache a winslot. */
5532 #define WINDOW_SLOT(slot, compare) w->slot = p->slot
5533 #include "winslots.h"
5534
5535           /* Reinstall the saved buffer and pointers into it.  */
5536           if (NILP (p->buffer))
5537             w->buffer = p->buffer;
5538           else
5539             {
5540               if (BUFFER_LIVE_P (XBUFFER (p->buffer)))
5541                 /* If saved buffer is alive, install it.  */
5542                 {
5543                   w->buffer = p->buffer;
5544                   w->start_at_line_beg = p->start_at_line_beg;
5545                   set_marker_restricted (w->start[CURRENT_DISP],
5546                                          Fmarker_position (p->start),
5547                                          w->buffer);
5548                   set_marker_restricted (w->pointm[CURRENT_DISP],
5549                                          Fmarker_position (p->pointm),
5550                                          w->buffer);
5551                   set_marker_restricted (w->sb_point,
5552                                          Fmarker_position (p->sb_point),
5553                                          w->buffer);
5554                   Fset_marker (XBUFFER (w->buffer)->mark,
5555                                Fmarker_position (p->mark), w->buffer);
5556
5557                   /* As documented in Fcurrent_window_configuration, don't
5558                      save the location of point in the buffer which was current
5559                      when the window configuration was recorded.  */
5560                   if (!EQ (p->buffer, new_current_buffer) &&
5561                       XBUFFER (p->buffer) == current_buffer)
5562                     Fgoto_char (w->pointm[CURRENT_DISP], Qnil);
5563                 }
5564               else if (NILP (w->buffer) ||
5565                        !BUFFER_LIVE_P (XBUFFER (w->buffer)))
5566                 /* Else if window's old buffer is dead too, get a live one.  */
5567                 {
5568                   /* #### The following line makes me nervous... */
5569                   /* w->buffer = Fcdr (Fcar (XFRAME (w->frame)->buffer_alist));*/
5570                   w->buffer = Fget_buffer_create (QSscratch);
5571                   /* w->buffer = Fother_buffer (Qnil, w->frame, Qnil); */
5572                   /* This will set the markers to beginning of visible
5573                      range.  */
5574                   set_marker_restricted (w->start[CURRENT_DISP], Qzero, w->buffer);
5575                   set_marker_restricted (w->pointm[CURRENT_DISP], Qzero,
5576                                          w->buffer);
5577                   set_marker_restricted (w->sb_point, Qzero, w->buffer);
5578                   w->start_at_line_beg = 1;
5579                 }
5580               else
5581                 /* Keeping window's old buffer; make sure the markers
5582                    are real.  */
5583                 {
5584                   /* Set window markers at start of visible range.  */
5585                   if (XMARKER (w->start[CURRENT_DISP])->buffer == 0)
5586                     set_marker_restricted (w->start[CURRENT_DISP], Qzero,
5587                                            w->buffer);
5588                   if (XMARKER (w->sb_point)->buffer == 0)
5589                     set_marker_restricted (w->sb_point, Qzero, w->buffer);
5590                   if (XMARKER (w->pointm[CURRENT_DISP])->buffer == 0)
5591                     set_marker_restricted (w->pointm[CURRENT_DISP],
5592                                            make_int
5593                                            (BUF_PT (XBUFFER (w->buffer))),
5594                                            w->buffer);
5595                   w->start_at_line_beg = 1;
5596                 }
5597             }
5598         }
5599
5600       FRAME_ROOT_WINDOW (f) = config->root_window;
5601       /* Note that FSFmacs unilaterally calls Fselect_window() here, and
5602          then calls do_switch_frame() below to select the frame that was
5603          recorded in the window config as being selected.
5604
5605          Instead, we don't ever change the selected frame, and either
5606          call Fselect_window() below if the window config's frame is
5607          currently selected, or just set the selected window of the
5608          window config's frame. */
5609
5610 #if 0
5611       /* Set the frame height to the value it had before this function.  */
5612       if (previous_frame_height != FRAME_HEIGHT (f)
5613           || previous_frame_width != FRAME_WIDTH (f))
5614         change_frame_size (f, previous_frame_height, previous_frame_width, 0);
5615 #endif
5616       /* We just reset the size and position of the minibuffer, to its old
5617          value, which needn't be valid. So we do some magic to see which value
5618          to actually take. Then we set it.
5619
5620          The magic:
5621          We take the old value if is in the same units but differs from the
5622          current value.
5623
5624          #### Now we get more cases correct then ever before, but
5625          are we treating all? For instance what if the frames minibuf window
5626          is no longer the same one?
5627       */
5628       target_minibuf_height = previous_minibuf_height;
5629       if (converted_minibuf_height &&
5630           (converted_minibuf_height * config->minibuf_height) > 0 &&
5631           (converted_minibuf_height !=  config->minibuf_height))
5632         {
5633           target_minibuf_height = config->minibuf_height < 0 ?
5634             - (config->minibuf_height * real_font_height) :
5635             config->minibuf_height;
5636           target_minibuf_height =
5637             max(target_minibuf_height,real_font_height);
5638         }
5639       if (previous_minibuf_height)
5640         {
5641           XWINDOW (FRAME_MINIBUF_WINDOW (f))->pixel_top
5642             = previous_minibuf_top -
5643                   (target_minibuf_height - previous_minibuf_height);
5644           set_window_pixheight (FRAME_MINIBUF_WINDOW (f),
5645                                 target_minibuf_height, 0);
5646           set_window_pixwidth  (FRAME_MINIBUF_WINDOW (f),
5647                             previous_minibuf_width, 0);
5648         }
5649
5650       /* This is a better way to deal with frame resizing, etc.
5651          What we _actually_ want is for the old (just restored)
5652          root window to fit
5653          into the place of the new one. So we just do that. Simple! */
5654       XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_top = previous_pixel_top;
5655       /* Note that this function also updates the subwindow
5656          "pixel_top"s */
5657       set_window_pixheight (FRAME_ROOT_WINDOW (f),
5658           previous_pixel_height -
5659                   (target_minibuf_height - previous_minibuf_height), 0);
5660       XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_left = previous_pixel_left;
5661       /* Note that this function also updates the subwindow
5662          "pixel_left"s */
5663       set_window_pixwidth (FRAME_ROOT_WINDOW (f), previous_pixel_width, 0);
5664
5665       /* If restoring in the current frame make the window current,
5666          otherwise just update the frame selected_window slot to be
5667          the restored current_window. */
5668       if (f == selected_frame ())
5669         {
5670 #if 0
5671           /* When using `pop-window-configuration', often the minibuffer
5672              ends up as the selected window even though it's not active ...
5673              I really don't know the cause of this, but it should never
5674              happen.  This kludge should fix it.
5675
5676              #### Find out why this is really going wrong. */
5677           if (!minibuf_level &&
5678               MINI_WINDOW_P (XWINDOW (config->current_window)))
5679             window_to_select = Fnext_window (config->current_window,
5680                                              Qnil, Qnil, Qnil);
5681           else
5682             window_to_select = config->current_window;
5683 #endif
5684           /* Do this last so that buffer stacking is calculated
5685              correctly. */
5686           Fselect_window (config->current_window, Qnil);
5687
5688           if (!NILP (new_current_buffer))
5689             {
5690               Fset_buffer (new_current_buffer);
5691               Frecord_buffer (new_current_buffer);
5692             }
5693           else
5694             {
5695               Fset_buffer (XWINDOW (config->current_window)->buffer);
5696               Frecord_buffer (XWINDOW (config->current_window)->buffer);
5697             }
5698         }
5699       else
5700         set_frame_selected_window (f, config->current_window);
5701     }
5702   else
5703     old_window_config = Qnil; /* Warning suppression */
5704
5705   /* Restore the minimum heights recorded in the configuration.  */
5706   window_min_height = config->min_height;
5707   window_min_width = config->min_width;
5708
5709 #if 0 /* FSFmacs */
5710   /* see above comment */
5711   /* Fselect_window will have made f the selected frame, so we
5712      reselect the proper frame here.  Fhandle_switch_frame will change the
5713      selected window too, but that doesn't make the call to
5714      Fselect_window above totally superfluous; it still sets f's
5715      selected window.  */
5716   if (FRAME_LIVE_P (XFRAME (config->selected_frame)))
5717     do_switch_frame (config->selected_frame, Qnil, 0);
5718 #endif
5719
5720   Vminibuffer_scroll_window = config->minibuffer_scroll_window;
5721
5722   if (FRAME_LIVE_P (f))
5723     {
5724       /* Do this before calling recompute_all_cached_specifiers_in_window()
5725          so that things like redisplay_redraw_cursor() won't abort due
5726          to no window mirror present. */
5727       f->mirror_dirty = 1;
5728
5729       config = XWINDOW_CONFIGURATION (old_window_config);
5730       for (k = 0; k < config->saved_windows_count; k++)
5731         {
5732           p = SAVED_WINDOW_N (config, k);
5733           w = XWINDOW (p->window);
5734           /* Remember, we set w->config_mark on all currently visible
5735              windows, and reset it on all newly visible windows.
5736              Any windows still marked need to be deleted. */
5737           if (w->config_mark)
5738             {
5739               mark_window_as_deleted (w);
5740               w->config_mark = 0;
5741             }
5742           else
5743             {
5744               /* We just potentially changed the window's buffer and
5745                  potentially turned a dead window into a live one,
5746                  so we need to recompute the cached specifier values. */
5747               recompute_all_cached_specifiers_in_window (w);
5748             }
5749         }
5750     }
5751
5752   /* Now restore things, when everything else if OK. */
5753
5754   unbind_to (specpdl_count, Qnil);
5755
5756   UNGCPRO;
5757
5758   return Qnil;
5759 }
5760
5761 /* Mark all subwindows of a window as deleted.  The argument
5762    W is actually the subwindow tree of the window in question. */
5763
5764 void
5765 delete_all_subwindows (struct window *w)
5766 {
5767   if (!NILP (w->next))   delete_all_subwindows (XWINDOW (w->next));
5768   if (!NILP (w->vchild)) delete_all_subwindows (XWINDOW (w->vchild));
5769   if (!NILP (w->hchild)) delete_all_subwindows (XWINDOW (w->hchild));
5770
5771   mark_window_as_deleted (w);
5772 }
5773
5774 \f
5775 static unsigned int
5776 count_windows (struct window *window)
5777 {
5778   return 1 +
5779     (!NILP (window->next)   ? count_windows (XWINDOW (window->next))   : 0) +
5780     (!NILP (window->vchild) ? count_windows (XWINDOW (window->vchild)) : 0) +
5781     (!NILP (window->hchild) ? count_windows (XWINDOW (window->hchild)) : 0);
5782 }
5783
5784 static int
5785 saved_window_index (Lisp_Object window, struct window_config *config, int lim)
5786 {
5787   int j;
5788   for (j = 0; j < lim; j++)
5789     {
5790       if (EQ (SAVED_WINDOW_N (config, j)->window, window))
5791         return j;
5792     }
5793   abort ();
5794   return 0;     /* suppress compiler warning */
5795 }
5796
5797 static int
5798 save_window_save (Lisp_Object window, struct window_config *config, int i)
5799 {
5800   struct window *w;
5801
5802   for (; !NILP (window); window = w->next)
5803     {
5804       struct saved_window *p = SAVED_WINDOW_N (config, i);
5805
5806       w = XWINDOW (window);
5807       i++;
5808       p->window = window;
5809       p->buffer = w->buffer;
5810       WINDOW_LEFT (p) = WINDOW_LEFT (w);
5811       WINDOW_TOP (p) = WINDOW_TOP (w);
5812       WINDOW_WIDTH (p) = WINDOW_WIDTH (w);
5813       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (w);
5814       p->hscroll = w->hscroll;
5815       p->modeline_hscroll = w->modeline_hscroll;
5816
5817 #define WINDOW_SLOT(slot, compare) p->slot = w->slot
5818 #include "winslots.h"
5819
5820       if (!NILP (w->buffer))
5821         {
5822           /* Save w's value of point in the window configuration.
5823              If w is the selected window, then get the value of point
5824              from the buffer; pointm is garbage in the selected window.  */
5825           if (EQ (window, Fselected_window (Qnil)))
5826             {
5827               p->pointm = noseeum_make_marker ();
5828               Fset_marker (p->pointm,
5829                            make_int (BUF_PT (XBUFFER (w->buffer))),
5830                            w->buffer);
5831             }
5832           else
5833             p->pointm = noseeum_copy_marker (w->pointm[CURRENT_DISP], Qnil);
5834
5835           p->start = noseeum_copy_marker (w->start[CURRENT_DISP], Qnil);
5836           p->sb_point = noseeum_copy_marker (w->sb_point, Qnil);
5837           p->start_at_line_beg = w->start_at_line_beg;
5838
5839           p->mark = noseeum_copy_marker (XBUFFER (w->buffer)->mark, Qnil);
5840         }
5841       else
5842         {
5843           p->pointm = Qnil;
5844           p->start = Qnil;
5845           p->sb_point = Qnil;
5846           p->mark = Qnil;
5847           p->start_at_line_beg = 0;
5848         }
5849
5850       if (NILP (w->parent))
5851         p->parent_index = -1;
5852       else
5853         p->parent_index = saved_window_index (w->parent, config, i);
5854       if (NILP (w->prev))
5855         p->prev_index = -1;
5856       else
5857         p->prev_index = saved_window_index (w->prev, config, i);
5858       if (!NILP (w->vchild))
5859         i = save_window_save (w->vchild, config, i);
5860       if (!NILP (w->hchild))
5861         i = save_window_save (w->hchild, config, i);
5862     }
5863
5864   return i;
5865 }
5866
5867 #if 0 /* FSFmacs */
5868 /* Added to doc string:
5869
5870 This also records the currently selected frame, and FRAME's focus
5871 redirection (see `redirect-frame-focus').
5872
5873 */
5874 #endif
5875
5876 DEFUN ("current-window-configuration", Fcurrent_window_configuration, 0, 1, 0, /*
5877 Return an object representing the current window configuration of FRAME.
5878 If FRAME is nil or omitted, use the selected frame.
5879 This describes the number of windows, their sizes and current buffers,
5880 and for each window on FRAME the displayed buffer, where display
5881 starts, and the positions of point and mark.
5882 An exception is made for point in the current buffer:
5883 its value is -not- saved.
5884 */
5885        (frame))
5886 {
5887   Lisp_Object result;
5888   struct frame *f = decode_frame (frame);
5889   struct window_config *config;
5890   unsigned int n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
5891   int minibuf_height;
5892   int real_font_height;
5893
5894   if (n_windows <= countof (Vwindow_configuration_free_list))
5895     config = XWINDOW_CONFIGURATION (allocate_managed_lcrecord
5896                                     (Vwindow_configuration_free_list
5897                                      [n_windows - 1]));
5898   else
5899     /* More than ten windows; just allocate directly */
5900     config = (struct window_config *)
5901       alloc_lcrecord (sizeof_window_config_for_n_windows (n_windows),
5902                       &lrecord_window_configuration);
5903   XSETWINDOW_CONFIGURATION (result, config);
5904   /*
5905   config->frame_width = FRAME_WIDTH (f);
5906   config->frame_height = FRAME_HEIGHT (f); */
5907   /* #### When using `push-window-configuration', often the minibuffer ends
5908      up as the selected window because functions run as the result of
5909      user interaction e.g. hyper-apropos. It seems to me the sensible
5910      thing to do is not record the minibuffer here. 
5911
5912      #### Unfortunately this is a change to previous behaviour, however logical
5913      it may be, so revert for the moment. */
5914 #if 0
5915   if (FRAME_MINIBUF_ONLY_P (f) || minibuf_level)
5916     config->current_window = FRAME_SELECTED_WINDOW (f);
5917   else
5918     config->current_window = FRAME_LAST_NONMINIBUF_WINDOW (f);
5919 #endif
5920   config->current_window = FRAME_SELECTED_WINDOW (f);
5921   XSETBUFFER (config->current_buffer, current_buffer);
5922   config->minibuffer_scroll_window = Vminibuffer_scroll_window;
5923   config->root_window = FRAME_ROOT_WINDOW (f);
5924   config->min_height = window_min_height;
5925   config->min_width = window_min_width;
5926   config->saved_windows_count = n_windows;
5927   save_window_save (FRAME_ROOT_WINDOW (f), config, 0);
5928
5929   /* save the minibuffer height using the heuristics from
5930      change_frame_size_1 */
5931
5932   XSETFRAME (frame, f); /* frame could have been nil ! */
5933   default_face_height_and_width (frame, &real_font_height, 0);
5934   assert(real_font_height > 0);
5935
5936   if (FRAME_HAS_MINIBUF_P (f) && ! FRAME_MINIBUF_ONLY_P (f))
5937     minibuf_height = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_height;
5938   else
5939     minibuf_height = 0;
5940   config->minibuf_height = (minibuf_height % real_font_height) == 0 ?
5941     - (minibuf_height / real_font_height ) :    /* lines */
5942     minibuf_height;   /* pixels */
5943
5944   return result;
5945 }
5946
5947 Lisp_Object
5948 save_window_excursion_unwind (Lisp_Object window_config)
5949 {
5950   Lisp_Object val = Fset_window_configuration (window_config);
5951   free_window_configuration (window_config);
5952   return val;
5953 }
5954
5955 DEFUN ("save-window-excursion", Fsave_window_excursion, 0, UNEVALLED, 0, /*
5956 Execute body, preserving window sizes and contents.
5957 Restores which buffer appears in which window, where display starts,
5958 as well as the current buffer.
5959 Does not restore the value of point in current buffer.
5960 */
5961        (args))
5962 {
5963   /* This function can GC */
5964   Lisp_Object val;
5965   int speccount = specpdl_depth ();
5966
5967   record_unwind_protect (save_window_excursion_unwind,
5968                          Fcurrent_window_configuration (Qnil));
5969   val = Fprogn (args);
5970   return unbind_to (speccount, val);
5971 }
5972
5973 DEFUN ("current-pixel-column", Fcurrent_pixel_column, 0, 2, 0, /*
5974 Return the horizontal pixel position of POS in window.
5975 Beginning of line is column 0. This is calculated using the redisplay
5976 display tables.  If WINDOW is nil, the current window is assumed.
5977 If POS is nil, point is assumed. Note that POS must be visible for
5978 a non-nil result to be returned.
5979 */
5980        (window, pos))
5981 {
5982   struct window* w = decode_window (window);
5983   display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
5984
5985   struct display_line *dl = 0;
5986   struct display_block *db = 0;
5987   struct rune* rb = 0;
5988   int y = w->last_point_y[CURRENT_DISP];
5989   int x = w->last_point_x[CURRENT_DISP];
5990
5991   if (MINI_WINDOW_P (w))
5992     return Qnil;
5993
5994   if (y<0 || x<0 || y >= Dynarr_length (dla) || !NILP (pos))
5995     {
5996       int first_line, i;
5997       Bufpos point;
5998
5999       if (NILP (pos))
6000         pos = Fwindow_point (window);
6001
6002       CHECK_INT (pos);
6003       point = XINT (pos);
6004
6005       if (Dynarr_length (dla) && Dynarr_atp (dla, 0)->modeline)
6006         first_line = 1;
6007       else
6008         first_line = 0;
6009
6010       for (i = first_line; i < Dynarr_length (dla); i++)
6011         {
6012           dl = Dynarr_atp (dla, i);
6013           /* find the vertical location first */
6014           if (point >= dl->bufpos && point <= dl->end_bufpos)
6015             {
6016               db = get_display_block_from_line (dl, TEXT);
6017               for (i = 0; i < Dynarr_length (db->runes); i++)
6018                 {
6019                   rb = Dynarr_atp (db->runes, i);
6020                   if (point <= rb->bufpos)
6021                     goto found_bufpos;
6022                 }
6023               return Qnil;
6024             }
6025         }
6026       return Qnil;
6027     found_bufpos:
6028       ;
6029     }
6030   else
6031     {
6032       /* optimized case */
6033       dl = Dynarr_atp (dla, y);
6034       db = get_display_block_from_line (dl, TEXT);
6035
6036       if (x >= Dynarr_length (db->runes))
6037         return Qnil;
6038
6039       rb = Dynarr_atp (db->runes, x);
6040     }
6041
6042   return make_int (rb->xpos - WINDOW_LEFT (w));
6043 }
6044
6045 \f
6046 #ifdef DEBUG_XEMACS
6047 /* This is short and simple in elisp, but... it was written to debug
6048    problems purely on the C side.  That is where we need to call it so
6049    here it is. */
6050 static void
6051 debug_print_window (Lisp_Object window, int level)
6052 {
6053   int i;
6054   Lisp_Object child = Fwindow_first_vchild (window);
6055
6056   if (NILP (child))
6057     child = Fwindow_first_hchild (window);
6058
6059   for (i = level; i > 0; i--)
6060     stderr_out ("\t");
6061
6062   stderr_out ("#<window");
6063   {
6064     Lisp_Object buffer = XWINDOW (window)->buffer;
6065     if (!NILP (buffer) && BUFFERP (buffer))
6066       stderr_out (" on %s", XSTRING_DATA (XBUFFER (buffer)->name));
6067   }
6068   stderr_out (" 0x%x>", XWINDOW (window)->header.uid);
6069
6070   while (!NILP (child))
6071     {
6072       debug_print_window (child, level + 1);
6073       child = Fwindow_next_child (child);
6074     }
6075 }
6076
6077 void debug_print_windows (struct frame *f);
6078 void
6079 debug_print_windows (struct frame *f)
6080 {
6081   debug_print_window (f->root_window, 0);
6082   putc ('\n', stderr);
6083 }
6084 #endif /* DEBUG_XEMACS */
6085
6086 \f
6087 /************************************************************************/
6088 /*                            initialization                            */
6089 /************************************************************************/
6090
6091 void
6092 syms_of_window (void)
6093 {
6094   INIT_LRECORD_IMPLEMENTATION (window);
6095   INIT_LRECORD_IMPLEMENTATION (window_configuration);
6096
6097   defsymbol (&Qwindowp, "windowp");
6098   defsymbol (&Qwindow_live_p, "window-live-p");
6099   defsymbol (&Qwindow_configurationp, "window-configuration-p");
6100   defsymbol (&Qtemp_buffer_show_hook, "temp-buffer-show-hook");
6101   defsymbol (&Qdisplay_buffer, "display-buffer");
6102
6103 #ifdef MEMORY_USAGE_STATS
6104   defsymbol (&Qface_cache, "face-cache");
6105   defsymbol (&Qglyph_cache, "glyph-cache");
6106   defsymbol (&Qline_start_cache, "line-start-cache");
6107 #ifdef HAVE_SCROLLBARS
6108   defsymbol (&Qscrollbar_instances, "scrollbar-instances");
6109 #endif
6110   defsymbol (&Qother_redisplay, "other-redisplay");
6111   /* Qother in general.c */
6112 #endif
6113
6114   DEFSYMBOL (Qtruncate_partial_width_windows);
6115   
6116   DEFSUBR (Fselected_window);
6117   DEFSUBR (Flast_nonminibuf_window);
6118   DEFSUBR (Fminibuffer_window);
6119   DEFSUBR (Fwindow_minibuffer_p);
6120   DEFSUBR (Fwindowp);
6121   DEFSUBR (Fwindow_live_p);
6122   DEFSUBR (Fwindow_first_hchild);
6123   DEFSUBR (Fwindow_first_vchild);
6124   DEFSUBR (Fwindow_next_child);
6125   DEFSUBR (Fwindow_previous_child);
6126   DEFSUBR (Fwindow_parent);
6127   DEFSUBR (Fwindow_lowest_p);
6128   DEFSUBR (Fwindow_truncated_p);
6129   DEFSUBR (Fwindow_highest_p);
6130   DEFSUBR (Fwindow_leftmost_p);
6131   DEFSUBR (Fwindow_rightmost_p);
6132   DEFSUBR (Fpos_visible_in_window_p);
6133   DEFSUBR (Fwindow_buffer);
6134   DEFSUBR (Fwindow_frame);
6135   DEFSUBR (Fwindow_height);
6136   DEFSUBR (Fwindow_displayed_height);
6137   DEFSUBR (Fwindow_width);
6138   DEFSUBR (Fwindow_full_width);
6139   DEFSUBR (Fwindow_pixel_height);
6140   DEFSUBR (Fwindow_pixel_width);
6141   DEFSUBR (Fwindow_text_area_height);
6142   DEFSUBR (Fwindow_text_area_pixel_height);
6143   DEFSUBR (Fwindow_displayed_text_pixel_height);
6144   DEFSUBR (Fwindow_text_area_pixel_width);
6145   DEFSUBR (Fwindow_hscroll);
6146   DEFSUBR (Fset_window_hscroll);
6147   DEFSUBR (Fmodeline_hscroll);
6148   DEFSUBR (Fset_modeline_hscroll);
6149 #if 0 /* bogus FSF crock */
6150   DEFSUBR (Fwindow_redisplay_end_trigger);
6151   DEFSUBR (Fset_window_redisplay_end_trigger);
6152 #endif
6153   DEFSUBR (Fwindow_pixel_edges);
6154   DEFSUBR (Fwindow_text_area_pixel_edges);
6155   DEFSUBR (Fwindow_point);
6156   DEFSUBR (Fwindow_start);
6157   DEFSUBR (Fwindow_end);
6158   DEFSUBR (Fwindow_last_line_visible_height);
6159   DEFSUBR (Fset_window_point);
6160   DEFSUBR (Fset_window_start);
6161   DEFSUBR (Fwindow_dedicated_p);
6162   DEFSUBR (Fset_window_dedicated_p);
6163   DEFSUBR (Fnext_window);
6164   DEFSUBR (Fprevious_window);
6165   DEFSUBR (Fnext_vertical_window);
6166   DEFSUBR (Fother_window);
6167   DEFSUBR (Fget_lru_window);
6168   DEFSUBR (Fget_largest_window);
6169   DEFSUBR (Fget_buffer_window);
6170   DEFSUBR (Fwindow_left_margin_pixel_width);
6171   DEFSUBR (Fwindow_right_margin_pixel_width);
6172   DEFSUBR (Fdelete_other_windows);
6173   DEFSUBR (Fdelete_windows_on);
6174   DEFSUBR (Freplace_buffer_in_windows);
6175   DEFSUBR (Fdelete_window);
6176   DEFSUBR (Fset_window_buffer);
6177   DEFSUBR (Fselect_window);
6178   DEFSUBR (Fsplit_window);
6179   DEFSUBR (Fenlarge_window);
6180   DEFSUBR (Fenlarge_window_pixels);
6181   DEFSUBR (Fshrink_window);
6182   DEFSUBR (Fshrink_window_pixels);
6183   DEFSUBR (Fscroll_up);
6184   DEFSUBR (Fscroll_down);
6185   DEFSUBR (Fscroll_left);
6186   DEFSUBR (Fscroll_right);
6187   DEFSUBR (Fother_window_for_scrolling);
6188   DEFSUBR (Fscroll_other_window);
6189   DEFSUBR (Fcenter_to_window_line);
6190   DEFSUBR (Fmove_to_window_line);
6191 #ifdef MEMORY_USAGE_STATS
6192   DEFSUBR (Fwindow_memory_usage);
6193 #endif
6194   DEFSUBR (Fwindow_configuration_p);
6195   DEFSUBR (Fset_window_configuration);
6196   DEFSUBR (Fcurrent_window_configuration);
6197   DEFSUBR (Fsave_window_excursion);
6198   DEFSUBR (Fcurrent_pixel_column);
6199 }
6200
6201 void
6202 reinit_vars_of_window (void)
6203 {
6204   unsigned int i;
6205   /* Make sure all windows get marked */
6206   minibuf_window = Qnil;
6207   staticpro_nodump (&minibuf_window);
6208
6209   for (i = 0; i < countof (Vwindow_configuration_free_list); i++)
6210     {
6211       Vwindow_configuration_free_list[i] =
6212         make_lcrecord_list (sizeof_window_config_for_n_windows (i + 1),
6213                             &lrecord_window_configuration);
6214       staticpro_nodump (&Vwindow_configuration_free_list[i]);
6215     }
6216 }
6217
6218 void
6219 vars_of_window (void)
6220 {
6221   reinit_vars_of_window ();
6222
6223   DEFVAR_BOOL ("scroll-on-clipped-lines", &scroll_on_clipped_lines /*
6224 *Non-nil means to scroll if point lands on a line which is clipped.
6225 */ );
6226   scroll_on_clipped_lines = 1;
6227
6228   DEFVAR_LISP ("temp-buffer-show-hook", &Vtemp_buffer_show_hook /*
6229 See `temp-buffer-show-function'.
6230 */ );
6231   Vtemp_buffer_show_hook = Qnil;
6232
6233   DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function /*
6234 Non-nil means call as function to display a help buffer.
6235 The function is called with one argument, the buffer to be displayed.
6236 Used by `with-output-to-temp-buffer'.
6237 If this function is used, then it must do the entire job of showing
6238 the buffer; `temp-buffer-show-hook' is not run unless this function runs it.
6239 \(`temp-buffer-show-hook' is obsolete.  Do not use in new code.)
6240 */ );
6241   Vtemp_buffer_show_function = Qnil;
6242
6243   DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuffer_scroll_window /*
6244 Non-nil means it is the window that \\<minibuffer-local-map>\\[scroll-other-window] in minibuffer should scroll.
6245 */ );
6246   Vminibuffer_scroll_window = Qnil;
6247
6248   DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer /*
6249 If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.
6250 */ );
6251   Vother_window_scroll_buffer = Qnil;
6252
6253   DEFVAR_LISP ("window-pixel-scroll-increment", &Vwindow_pixel_scroll_increment /*
6254 *Number of pixels to scroll by per requested line.
6255 If nil then normal line scrolling occurs regardless of line height.
6256 If t then scrolling is done in increments equal to the height of the default face.
6257 */ );
6258   Vwindow_pixel_scroll_increment = Qt;
6259
6260   DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines /*
6261 *Number of lines of continuity when scrolling by screenfuls.
6262 */ );
6263   next_screen_context_lines = 2;
6264
6265   DEFVAR_INT ("window-min-height", &window_min_height /*
6266 *Delete any window less than this tall (including its modeline).
6267 */ );
6268   window_min_height = 4;
6269
6270   DEFVAR_INT ("window-min-width", &window_min_width /*
6271 *Delete any window less than this wide.
6272 */ );
6273   window_min_width = 10;
6274 }
6275
6276 void
6277 specifier_vars_of_window (void)
6278 {
6279   DEFVAR_SPECIFIER ("modeline-shadow-thickness", &Vmodeline_shadow_thickness /*
6280 *How thick to draw 3D shadows around modelines.
6281 If this is set to 0, modelines will be the traditional 2D.  Sizes above
6282 10 will be accepted but the maximum thickness that will be drawn is 10.
6283 This is a specifier; use `set-specifier' to change it.
6284 */ );
6285   Vmodeline_shadow_thickness = Fmake_specifier (Qinteger);
6286   /* The initial value for modeline-shadow-thickness is 2, but if the
6287      user removes all specifications we provide a fallback value of 0,
6288      which is probably what was expected. */
6289   set_specifier_fallback (Vmodeline_shadow_thickness,
6290                           list1 (Fcons (Qnil, Qzero)));
6291   Fadd_spec_to_specifier (Vmodeline_shadow_thickness, make_int (2),
6292                           Qnil, Qnil, Qnil);
6293   set_specifier_caching (Vmodeline_shadow_thickness,
6294                          offsetof (struct window, modeline_shadow_thickness),
6295                          modeline_shadow_thickness_changed,
6296                          0, 0, 0);
6297
6298   DEFVAR_SPECIFIER ("has-modeline-p", &Vhas_modeline_p /*
6299 *Whether the modeline should be displayed.
6300 This is a specifier; use `set-specifier' to change it.
6301 */ );
6302   Vhas_modeline_p = Fmake_specifier (Qboolean);
6303   set_specifier_fallback (Vhas_modeline_p,
6304                           list1 (Fcons (Qnil, Qt)));
6305   set_specifier_caching (Vhas_modeline_p,
6306                          offsetof (struct window, has_modeline_p),
6307                          /* #### It's strange that we need a special
6308                             flag to indicate that the shadow-thickness
6309                             has changed, but not one to indicate that
6310                             the modeline has been turned off or on. */
6311                          some_window_value_changed,
6312                          0, 0, 0);
6313
6314   DEFVAR_SPECIFIER ("vertical-divider-always-visible-p",
6315                     &Vvertical_divider_always_visible_p /*
6316 *Should XEmacs always display vertical dividers between windows.
6317
6318 When this is non-nil, vertical dividers are always shown, and are
6319 draggable.  When it is nil, vertical dividers are shown only when
6320 there are no scrollbars in between windows, and are not draggable.
6321
6322 This is a specifier; use `set-specifier' to change it.
6323 */ );
6324   Vvertical_divider_always_visible_p = Fmake_specifier (Qboolean);
6325   set_specifier_fallback (Vvertical_divider_always_visible_p,
6326                           list1 (Fcons (Qnil, Qt)));
6327   set_specifier_caching (Vvertical_divider_always_visible_p,
6328                          offsetof (struct window,
6329                                    vertical_divider_always_visible_p),
6330                          vertical_divider_changed_in_window,
6331                          0, 0, 0);
6332
6333   DEFVAR_SPECIFIER ("vertical-divider-shadow-thickness", &Vvertical_divider_shadow_thickness /*
6334 *How thick to draw 3D shadows around vertical dividers.
6335 This is a specifier; use `set-specifier' to change it.
6336 */ );
6337   Vvertical_divider_shadow_thickness = Fmake_specifier (Qinteger);
6338   set_specifier_fallback (Vvertical_divider_shadow_thickness,
6339                           list1 (Fcons (Qnil, Qzero)));
6340   Fadd_spec_to_specifier (Vvertical_divider_shadow_thickness, make_int (2),
6341                           Qnil, Qnil, Qnil);
6342   set_specifier_caching (Vvertical_divider_shadow_thickness,
6343                          offsetof (struct window,
6344                                    vertical_divider_shadow_thickness),
6345                          vertical_divider_changed_in_window,
6346                          0, 0, 0);
6347   DEFVAR_SPECIFIER ("vertical-divider-line-width", &Vvertical_divider_line_width /*
6348 *The width of the vertical dividers, not including shadows.
6349
6350 For TTY windows, divider line is always one character wide.  When
6351 instance of this specifier is zero in a TTY window, no divider is
6352 drawn at all between windows.  When non-zero, a one character wide
6353 divider is displayed.
6354
6355 This is a specifier; use `set-specifier' to change it.
6356 */ );
6357
6358   Vvertical_divider_line_width = Fmake_specifier (Qnatnum);
6359   {
6360     Lisp_Object fb = Qnil;
6361 #ifdef HAVE_TTY
6362     fb = Fcons (Fcons (list1 (Qtty), make_int (1)), fb);
6363 #endif
6364 #ifdef HAVE_GTK
6365     fb = Fcons (Fcons (list1 (Qgtk), make_int (3)), fb);
6366 #endif
6367 #ifdef HAVE_X_WINDOWS
6368     fb = Fcons (Fcons (list1 (Qx), make_int (3)), fb);
6369 #endif
6370 #ifdef HAVE_MS_WINDOWS
6371     /* #### This should be made magic and made to obey system settings */
6372     fb = Fcons (Fcons (list1 (Qmswindows), make_int (3)), fb);
6373 #endif
6374     set_specifier_fallback (Vvertical_divider_line_width, fb);
6375   }
6376   set_specifier_caching (Vvertical_divider_line_width,
6377                          offsetof (struct window,
6378                                    vertical_divider_line_width),
6379                          vertical_divider_changed_in_window,
6380                          0, 0, 0);
6381
6382   DEFVAR_SPECIFIER ("vertical-divider-spacing", &Vvertical_divider_spacing /*
6383 *How much space to leave around the vertical dividers.
6384
6385 In TTY windows, spacing is always zero, and the value of this
6386 specifier is ignored.
6387
6388 This is a specifier; use `set-specifier' to change it.
6389 */ );
6390   Vvertical_divider_spacing = Fmake_specifier (Qnatnum);
6391   {
6392     Lisp_Object fb = Qnil;
6393 #ifdef HAVE_TTY
6394     fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
6395 #endif
6396 #ifdef HAVE_X_WINDOWS
6397     /* #### 3D dividers look great on MS Windows with spacing = 0.
6398        Should not the same value be the fallback under X? - kkm */
6399     fb = Fcons (Fcons (list1 (Qx), make_int (2)), fb);
6400 #endif
6401 #ifdef HAVE_GTK
6402     fb = Fcons (Fcons (list1 (Qgtk), Qzero), fb);
6403 #endif
6404 #ifdef HAVE_MS_WINDOWS
6405     fb = Fcons (Fcons (list1 (Qmswindows), Qzero), fb);
6406 #endif
6407     set_specifier_fallback (Vvertical_divider_spacing, fb);
6408   }
6409   set_specifier_caching (Vvertical_divider_spacing,
6410                          offsetof (struct window, vertical_divider_spacing),
6411                          vertical_divider_changed_in_window,
6412                          0, 0, 0);
6413 }