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