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