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