XEmacs 21.2-b1
[chise/xemacs-chise.git.1] / src / window.c
1 /* Window creation, deletion and examination for XEmacs.
2    Copyright (C) 1985-1987, 1992-1995 Free Software Foundation, Inc.
3    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
4    Copyright (C) 1995, 1996 Ben Wing.
5    Copyright (C) 1996 Chuck Thompson.
6
7 This file is part of XEmacs.
8
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
12 later version.
13
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING.  If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 /* Synched up with: FSF 19.30. */
25 /* Beginning to diverge significantly. */
26
27 /* This file has been Mule-ized. */
28
29 #include <config.h>
30 #include "lisp.h"
31
32 #include "buffer.h"
33 #include "faces.h"
34 #include "frame.h"
35 #include "objects.h"
36 #include "glyphs.h"
37 #include "redisplay.h"
38 #include "window.h"
39 #include "commands.h"
40
41 Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configurationp;
42 Lisp_Object Qscroll_up, Qscroll_down, Qdisplay_buffer;
43
44 #ifdef MEMORY_USAGE_STATS
45 Lisp_Object Qface_cache, Qglyph_cache, Qline_start_cache, Qother_redisplay;
46 #ifdef HAVE_SCROLLBARS
47 Lisp_Object Qscrollbar_instances;
48 #endif
49 #endif
50
51 EXFUN (Fnext_window, 4);
52
53 static int window_pixel_width_to_char_width (struct window *w,
54                                              int pixel_width,
55                                              int include_margins_p);
56 static int window_char_width_to_pixel_width (struct window *w,
57                                              int char_width,
58                                              int include_margins_p);
59 static int window_pixel_height_to_char_height (struct window *w,
60                                                int pixel_height,
61                                                int include_gutters_p);
62 static int window_char_height_to_pixel_height (struct window *w,
63                                                int char_height,
64                                                int include_gutters_p);
65 static void change_window_height (struct window *w, int delta, int widthflag,
66                                   int inpixels);
67
68 /* Thickness of shadow border around 3d modelines. */
69 Lisp_Object Vmodeline_shadow_thickness;
70
71 /* Whether vertical dividers are draggable and displayed */
72 Lisp_Object Vvertical_divider_always_visible_p;
73
74 /* Whether a modeline should be displayed. */
75 Lisp_Object Vhas_modeline_p;
76
77 /* Thickness of shadow border around vertical dividers. */
78 Lisp_Object Vvertical_divider_shadow_thickness;
79
80 /* Divider surface width (not counting 3-d borders) */
81 Lisp_Object Vvertical_divider_line_width;
82
83 /* Spacing between outer egde of divider border and window edge */
84 Lisp_Object Vvertical_divider_spacing;
85
86 /* Scroll if point lands on the bottom line and that line is partially
87    clipped. */
88 int scroll_on_clipped_lines;
89
90 /* The minibuffer window of the selected frame.
91    Note that you cannot test for minibufferness of an arbitrary window
92    by comparing against this; but you can test for minibufferness of
93    the selected window.  */
94 Lisp_Object minibuf_window;
95
96 /* Non-nil means it is the window for C-M-v to scroll
97    when the minibuffer is selected.  */
98 Lisp_Object Vminibuffer_scroll_window;
99
100 /* Non-nil means this is the buffer whose window C-M-v should scroll.  */
101 Lisp_Object Vother_window_scroll_buffer;
102
103 /* Non-nil means it's the function to call to display temp buffers.  */
104 Lisp_Object Vtemp_buffer_show_function;
105
106 Lisp_Object Vtemp_buffer_show_hook;
107
108 /* If a window gets smaller than either of these, it is removed. */
109 int window_min_height;
110 int window_min_width;
111
112 /* Hook run at end of temp_output_buffer_show.  */
113 Lisp_Object Qtemp_buffer_show_hook;
114
115 /* Number of lines of continuity in scrolling by screenfuls.  */
116 int next_screen_context_lines;
117
118 /* List of freed window configurations with 1 - 10 windows. */
119 Lisp_Object Vwindow_configuration_free_list[10];
120
121 #define SET_LAST_MODIFIED(w, cache_too)         \
122 do {                                            \
123   (w)->last_modified[CURRENT_DISP] = Qzero;     \
124   (w)->last_modified[DESIRED_DISP] = Qzero;     \
125   (w)->last_modified[CMOTION_DISP] = Qzero;     \
126   if (cache_too)                                \
127     (w)->line_cache_last_updated = Qzero;       \
128 } while (0)
129
130 #define SET_LAST_FACECHANGE(w)                  \
131 do {                                            \
132   (w)->last_facechange[CURRENT_DISP] = Qzero;   \
133   (w)->last_facechange[DESIRED_DISP] = Qzero;   \
134   (w)->last_facechange[CMOTION_DISP] = Qzero;   \
135 } while (0)
136
137 \f
138 #define MARK_DISP_VARIABLE(field)               \
139   ((markobj) (window->field[CURRENT_DISP]));    \
140   ((markobj) (window->field[DESIRED_DISP]));    \
141   ((markobj) (window->field[CMOTION_DISP]));
142
143 static Lisp_Object
144 mark_window (Lisp_Object obj, void (*markobj) (Lisp_Object))
145 {
146   struct window *window = XWINDOW (obj);
147   ((markobj) (window->frame));
148   ((markobj) (window->mini_p));
149   ((markobj) (window->next));
150   ((markobj) (window->prev));
151   ((markobj) (window->hchild));
152   ((markobj) (window->vchild));
153   ((markobj) (window->parent));
154   ((markobj) (window->buffer));
155   MARK_DISP_VARIABLE (start);
156   MARK_DISP_VARIABLE (pointm);
157   ((markobj) (window->sb_point));       /* #### move to scrollbar.c? */
158   ((markobj) (window->use_time));
159   MARK_DISP_VARIABLE (last_modified);
160   MARK_DISP_VARIABLE (last_point);
161   MARK_DISP_VARIABLE (last_start);
162   MARK_DISP_VARIABLE (last_facechange);
163   ((markobj) (window->line_cache_last_updated));
164   ((markobj) (window->redisplay_end_trigger));
165   mark_face_cachels (window->face_cachels, markobj);
166   mark_glyph_cachels (window->glyph_cachels, markobj);
167
168 #define WINDOW_SLOT(slot, compare) ((markobj) (window->slot))
169 #include "winslots.h"
170
171   return Qnil;
172 }
173
174 static void
175 print_window (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
176 {
177   char buf[200];
178
179   if (print_readably)
180     error ("printing unreadable object #<window 0x%x>",
181            XWINDOW (obj)->header.uid);
182
183   write_c_string ("#<window", printcharfun);
184   if (!NILP (XWINDOW (obj)->buffer))
185     {
186       Lisp_Object name = XBUFFER (XWINDOW (obj)->buffer)->name;
187       write_c_string (" on ", printcharfun);
188       print_internal (name, printcharfun, 1);
189     }
190   sprintf (buf, " 0x%x>", XWINDOW (obj)->header.uid);
191   write_c_string (buf, printcharfun);
192 }
193
194 static void
195 finalize_window (void *header, int for_disksave)
196 {
197   struct window *w = (struct window *) header;
198
199   if (w->line_start_cache)
200     {
201       Dynarr_free (w->line_start_cache);
202       w->line_start_cache = 0;
203     }
204
205   if (w->face_cachels)
206     {
207       int i;
208
209       for (i = 0; i < Dynarr_length (w->face_cachels); i++)
210         {
211           struct face_cachel *cachel = Dynarr_atp (w->face_cachels, i);
212           if (cachel->merged_faces)
213             {
214               Dynarr_free (cachel->merged_faces);
215               cachel->merged_faces = 0;
216             }
217         }
218       Dynarr_free (w->face_cachels);
219       w->face_cachels = 0;
220     }
221
222   if (w->glyph_cachels)
223     {
224       Dynarr_free (w->glyph_cachels);
225       w->glyph_cachels = 0;
226     }
227 }
228
229 DEFINE_LRECORD_IMPLEMENTATION ("window", window,
230                                mark_window, print_window, finalize_window,
231                                0, 0, struct window);
232
233
234 #define INIT_DISP_VARIABLE(field, initialization)       \
235   p->field[CURRENT_DISP] = initialization;              \
236   p->field[DESIRED_DISP] = initialization;              \
237   p->field[CMOTION_DISP] = initialization;
238
239 /* We have an implicit assertion that the first two elements (default
240    and modeline faces) are always present in the face_element_cache.
241    Normally redisplay ensures this.  However, it is possible for a
242    window to get created and functions which reference these values
243    called before redisplay works with the window for the first time.
244    All callers of allocate_window should therefore call
245    reset_face_cachels on the created window.  We can't do it
246    here because the window must have its frame pointer set or
247    reset_face_cachels will fail. */
248 Lisp_Object
249 allocate_window (void)
250 {
251   Lisp_Object val;
252   struct window *p = alloc_lcrecord_type (struct window, lrecord_window);
253
254   zero_lcrecord (p);
255   XSETWINDOW (val, p);
256
257   p->dead = 0;
258   p->frame = Qnil;
259   p->mini_p = Qnil;
260   p->next = Qnil;
261   p->prev = Qnil;
262   p->hchild = Qnil;
263   p->vchild = Qnil;
264   p->parent = Qnil;
265   p->buffer = Qnil;
266   INIT_DISP_VARIABLE (start, Fmake_marker ());
267   INIT_DISP_VARIABLE (pointm, Fmake_marker ());
268   p->sb_point = Fmake_marker ();
269   p->use_time = Qzero;
270   INIT_DISP_VARIABLE (last_modified, Qzero);
271   INIT_DISP_VARIABLE (last_point, Fmake_marker ());
272   INIT_DISP_VARIABLE (last_start, Fmake_marker ());
273   INIT_DISP_VARIABLE (last_facechange, Qzero);
274   p->face_cachels     = Dynarr_new (face_cachel);
275   p->glyph_cachels    = Dynarr_new (glyph_cachel);
276   p->line_start_cache = Dynarr_new (line_start_cache);
277   p->line_cache_last_updated = Qzero;
278   INIT_DISP_VARIABLE (last_point_x, 0);
279   INIT_DISP_VARIABLE (last_point_y, 0);
280   INIT_DISP_VARIABLE (window_end_pos, 0);
281   p->redisplay_end_trigger = Qnil;
282
283 #define WINDOW_SLOT(slot, compare) p->slot = Qnil
284 #include "winslots.h"
285
286   p->windows_changed = 1;
287   p->shadow_thickness_changed = 1;
288
289   return val;
290 }
291 #undef INIT_DISP_VARIABLE
292 \f
293 /*
294  * The redisplay structures used to be stored with each window.  While
295  * they are logically something associated with frames they can't be
296  * stored there with a redisplay which handles variable height lines.
297  * Lines in horizontally split windows might not line up.  So they get
298  * stored with the windows.
299  *
300  * The problem with this is window configurations.  When restoring a
301  * window configuration it now becomes problematic to do an
302  * incremental redisplay.  The solution is to store the redisplay
303  * structures with the frame as they should be but laid out in the
304  * same manner as the window structure.  Thus is born the window
305  * mirror.
306  *
307  * It also becomes a convenient place to stick scrollbar instances
308  * since they extrapolate out to having the same problem described for
309  * the display structures.
310  */
311
312 /* Create a new window mirror structure and associated redisplay
313    structs. */
314 static struct window_mirror *
315 new_window_mirror (struct frame *f)
316 {
317   struct window_mirror *t = xnew_and_zero (struct window_mirror);
318
319   t->frame = f;
320
321   t->current_display_lines = Dynarr_new (display_line);
322   t->desired_display_lines = Dynarr_new (display_line);
323   t->buffer = NULL;
324
325 #ifdef HAVE_SCROLLBARS
326   t->scrollbar_vertical_instance = NULL;
327   t->scrollbar_horizontal_instance = NULL;
328 #endif
329
330   return t;
331 }
332
333 /* Synchronize the mirror structure with a given window structure.
334    This is normally called from update_frame_window_mirror with a
335    starting window of f->root_window. */
336 static struct window_mirror *
337 update_mirror_internal (Lisp_Object win, struct window_mirror *mir)
338 {
339   if (NILP (win))
340     {
341       if (mir)
342         {
343           free_window_mirror (mir);
344           mir = NULL;
345         }
346       return mir;
347     }
348   else
349     if (!mir)
350       mir = new_window_mirror (XFRAME (XWINDOW (win)->frame));
351
352   mir->next   = update_mirror_internal (XWINDOW (win)->next,   mir->next);
353   mir->hchild = update_mirror_internal (XWINDOW (win)->hchild, mir->hchild);
354   mir->vchild = update_mirror_internal (XWINDOW (win)->vchild, mir->vchild);
355
356   /*
357    * If the redisplay structs are not empty and the mirror has
358    * children, then this mirror structure was formerly being used for
359    * display but is no longer.  Reset its current display structs so
360    * that redisplay doesn't accidentally think they are accurate if it
361    * is later used for display purposes once again.  Also, mark the
362    * scrollbar instance as not active.
363    */
364   if (mir->vchild || mir->hchild)
365     {
366       /* The redisplay structures are big.  Leaving them around in
367          non-leaf windows can add up to a lot of wasted space.  So
368          don't do it. */
369       free_display_structs (mir);
370       mir->current_display_lines = Dynarr_new (display_line);
371       mir->desired_display_lines = Dynarr_new (display_line);
372
373 #ifdef HAVE_SCROLLBARS
374       update_window_scrollbars (XWINDOW (win), mir, 0, 0);
375 #endif
376       mir->buffer = NULL;
377     }
378
379   return mir;
380 }
381
382 /* Given a window mirror, determine which real window it contains the
383    redisplay structures for. */
384 static Lisp_Object
385 real_window_internal (Lisp_Object win, struct window_mirror *rmir,
386                       struct window_mirror *mir)
387 {
388   Lisp_Object retval;
389
390   for (; !NILP (win) && rmir ; win = XWINDOW (win)->next, rmir = rmir->next)
391     {
392       if (mir == rmir)
393         return win;
394       if (!NILP (XWINDOW (win)->vchild))
395         {
396           retval = real_window_internal (XWINDOW (win)->vchild, rmir->vchild,
397                                          mir);
398           if (!NILP (retval))
399             return retval;
400         }
401       if (!NILP (XWINDOW (win)->hchild))
402         {
403           retval = real_window_internal (XWINDOW (win)->hchild, rmir->hchild,
404                                          mir);
405           if (!NILP (retval))
406             return retval;
407         }
408     }
409
410   return Qnil;
411 }
412
413 /* Given a real window, find the mirror structure which contains its
414    redisplay structures. */
415 static struct window_mirror *
416 find_window_mirror_internal (Lisp_Object win, struct window_mirror *rmir,
417                             struct window *w)
418 {
419   for (; !NILP (win); win = XWINDOW (win)->next, rmir = rmir->next)
420     {
421       if (w == XWINDOW (win))
422         return rmir;
423
424       if (!NILP (XWINDOW (win)->vchild))
425         {
426           struct window_mirror *retval =
427             find_window_mirror_internal (XWINDOW (win)->vchild,
428                                          rmir->vchild, w);
429           if (retval) return retval;
430         }
431
432       if (!NILP (XWINDOW (win)->hchild))
433         {
434           struct window_mirror *retval =
435             find_window_mirror_internal (XWINDOW (win)->hchild,
436                                          rmir->hchild, w);
437           if (retval) return retval;
438         }
439     }
440
441   return 0;
442 }
443
444 /* Update the mirror structure for the given frame. */
445 void
446 update_frame_window_mirror (struct frame *f)
447 {
448   f->root_mirror = update_mirror_internal (f->root_window, f->root_mirror);
449   f->mirror_dirty = 0;
450 }
451
452 /* Free a given mirror structure along with all of its children as
453    well as their associated display structures. */
454 void
455 free_window_mirror (struct window_mirror *mir)
456 {
457   while (mir)
458     {
459       struct window_mirror *prev = mir;
460       if (mir->hchild) free_window_mirror (mir->hchild);
461       if (mir->vchild) free_window_mirror (mir->vchild);
462 #ifdef HAVE_SCROLLBARS
463       release_window_mirror_scrollbars (mir);
464 #endif
465       free_display_structs (mir);
466       mir = mir->next;
467       xfree (prev);
468     }
469 }
470
471 /* Given a mirror structure, return the window it mirrors.  Calls
472    real_window_internal to do most of the work. */
473 Lisp_Object
474 real_window (struct window_mirror *mir, int no_abort)
475 {
476   Lisp_Object retval = real_window_internal (mir->frame->root_window,
477                                              mir->frame->root_mirror, mir);
478   if (NILP (retval) && !no_abort)
479     abort ();
480
481   return retval;
482 }
483
484 /* Given a real window, return its mirror structure.  Calls
485    find_window_mirror_internal to do all of the work. */
486 struct window_mirror *
487 find_window_mirror (struct window *w)
488 {
489   struct frame *f = XFRAME (w->frame);
490   if (f->mirror_dirty)
491     update_frame_window_mirror (f);
492   return find_window_mirror_internal (f->root_window, f->root_mirror, w);
493 }
494
495 /*****************************************************************************
496  find_window_by_pixel_pos
497
498  Given a pixel position relative to a frame, find the window at that
499  position.
500  ****************************************************************************/
501 struct window *
502 find_window_by_pixel_pos (int pix_x, int pix_y, Lisp_Object win)
503 {
504   if (NILP (win))
505     return 0;
506
507   for (; !NILP (win); win = XWINDOW (win)->next)
508     {
509       struct window *w;
510
511       if (!NILP (XWINDOW (win)->vchild))
512         {
513           w = find_window_by_pixel_pos (pix_x, pix_y, XWINDOW (win)->vchild);
514           if (w) return w;
515         }
516       if (!NILP (XWINDOW (win)->hchild))
517         {
518           w = find_window_by_pixel_pos (pix_x, pix_y, XWINDOW (win)->hchild);
519           if (w) return w;
520         }
521       w = XWINDOW (win);
522       if (pix_x >= WINDOW_LEFT (w)
523           && pix_x <= WINDOW_RIGHT (w)
524           && pix_y >= WINDOW_TOP (w)
525           && pix_y <= WINDOW_BOTTOM (w))
526         return w;
527     }
528   return NULL;
529 }
530
531 /* Return a pointer to the display structures for the given window. */
532 display_line_dynarr *
533 window_display_lines (struct window *w, int which)
534 {
535   struct window_mirror *t;
536
537   if (XFRAME (w->frame)->mirror_dirty)
538     update_frame_window_mirror (XFRAME (w->frame));
539   t = find_window_mirror (w);
540   if (!t)
541     abort ();
542
543   if (which == CURRENT_DISP)
544     return t->current_display_lines;
545   else if (which == DESIRED_DISP)
546     return t->desired_display_lines;
547   else if (which == CMOTION_DISP)
548     /* The CMOTION_DISP display lines are global. */
549     return cmotion_display_lines;
550   else
551     abort ();
552
553   return 0;     /* shut up compiler */
554 }
555
556 struct buffer *
557 window_display_buffer (struct window *w)
558 {
559   struct window_mirror *t;
560
561   if (XFRAME (w->frame)->mirror_dirty)
562     update_frame_window_mirror (XFRAME (w->frame));
563   t = find_window_mirror (w);
564   if (!t)
565     abort ();
566
567   return t->buffer;
568 }
569
570 void
571 set_window_display_buffer (struct window *w, struct buffer *b)
572 {
573   struct window_mirror *t;
574
575   if (XFRAME (w->frame)->mirror_dirty)
576     update_frame_window_mirror (XFRAME (w->frame));
577   t = find_window_mirror (w);
578   if (!t)
579     abort ();
580
581   t->buffer = b;
582 }
583
584 \f
585 /* Determining a window's position based solely on its pixel
586    positioning doesn't work.  Instead, we do it the intelligent way,
587    by checking its positioning in the window hierarchy. */
588 int
589 window_is_leftmost (struct window *w)
590 {
591   Lisp_Object parent, current_ancestor, window;
592
593   XSETWINDOW (window, w);
594
595   parent = XWINDOW (window)->parent;
596   current_ancestor = window;
597
598   while (!NILP (parent))
599     {
600       if (!NILP (XWINDOW (parent)->hchild) &&
601           !EQ (XWINDOW (parent)->hchild, current_ancestor))
602         return 0;
603
604       current_ancestor = parent;
605       parent = XWINDOW (parent)->parent;
606     }
607
608   return 1;
609 }
610
611 int
612 window_is_rightmost (struct window *w)
613 {
614   Lisp_Object parent, current_ancestor, window;
615
616   XSETWINDOW (window, w);
617
618   parent = XWINDOW (window)->parent;
619   current_ancestor = window;
620
621   while (!NILP (parent))
622     {
623       if (!NILP (XWINDOW (parent)->hchild)
624           && !NILP (XWINDOW (current_ancestor)->next))
625         return 0;
626
627       current_ancestor = parent;
628       parent = XWINDOW (parent)->parent;
629     }
630
631   return 1;
632 }
633
634 static int
635 window_full_width_p (struct window *w)
636 {
637   return window_is_leftmost (w) && window_is_rightmost (w);
638 }
639
640 static int
641 window_is_highest (struct window *w)
642 {
643   Lisp_Object parent, current_ancestor, window;
644
645   XSETWINDOW (window, w);
646
647   parent = XWINDOW (window)->parent;
648   current_ancestor = window;
649
650   while (!NILP (parent))
651     {
652       if (!NILP (XWINDOW (parent)->vchild) &&
653           !EQ (XWINDOW (parent)->vchild, current_ancestor))
654         return 0;
655
656       current_ancestor = parent;
657       parent = XWINDOW (parent)->parent;
658     }
659
660   /* This is really to catch the minibuffer but we make it generic in
661      case we ever change things around to let the minibuffer be on top. */
662   if (NILP (XWINDOW (current_ancestor)->prev))
663     return 1;
664   else
665     return 0;
666 }
667
668 static int
669 window_is_lowest (struct window *w)
670 {
671   Lisp_Object parent, current_ancestor, window;
672
673   XSETWINDOW (window, w);
674
675   parent = XWINDOW (window)->parent;
676   current_ancestor = window;
677
678   while (!NILP (parent))
679     {
680       if (!NILP (XWINDOW (parent)->vchild)
681           && !NILP (XWINDOW (current_ancestor)->next))
682         return 0;
683
684       current_ancestor = parent;
685       parent = XWINDOW (parent)->parent;
686     }
687
688   return 1;
689 }
690
691 #if 0 /* not currently used */
692
693 static int
694 window_full_height_p (struct window *w)
695 {
696   return window_is_highest (w) && window_is_lowest (w);
697 }
698
699 #endif
700
701 int
702 window_truncation_on (struct window *w)
703 {
704   /* Horizontally scrolled windows are truncated. */
705   if (w->hscroll)
706     return 1;
707
708   /* If truncate_partial_width_windows is true and the window is not
709      the full width of the frame it is truncated. */
710   if (truncate_partial_width_windows
711       && !(window_is_leftmost (w) && window_is_rightmost (w)))
712     return 1;
713
714   /* If the window's buffer's value of truncate_lines is non-nil, then
715      the window is truncated. */
716   if (!NILP (XBUFFER (w->buffer)->truncate_lines))
717     return 1;
718
719   return 0;
720 }
721
722 static int
723 have_undivided_common_edge (struct window *w_right, void *closure)
724 {
725   struct window *w_left = (struct window *) closure;
726   return (WINDOW_RIGHT (w_left) == WINDOW_LEFT (w_right)
727           && WINDOW_TOP (w_left) < WINDOW_BOTTOM (w_right)
728           && WINDOW_TOP (w_right) < WINDOW_BOTTOM (w_left)
729 #ifdef HAVE_SCROLLBARS
730           && (NILP (w_right->scrollbar_on_left_p)
731               || NILP (w_right->vertical_scrollbar_visible_p)
732               || ZEROP (w_right->scrollbar_width))
733 #endif
734           );
735 }
736
737 static int
738 window_needs_vertical_divider_1 (struct window *w)
739 {
740   /* Never if we're on the right */
741   if (window_is_rightmost (w))
742     return 0;
743
744   /* Always if draggable */
745   if (!NILP (w->vertical_divider_always_visible_p))
746     return 1;
747
748 #ifdef HAVE_SCROLLBARS
749   /* Our right scrollabr is enough to separate us at the right */
750   if (NILP (w->scrollbar_on_left_p)
751       && !NILP (w->vertical_scrollbar_visible_p)
752       && !ZEROP (w->scrollbar_width))
753     return 0;
754 #endif
755
756   /* Ok. to determine whether we need a divider on the left, we must
757      check that our right neighbor windows have scrollbars on their
758      left sides. We must check all such windows which have common
759      left edge with our window's right edge. */
760   return map_windows (XFRAME (WINDOW_FRAME (w)),
761                       have_undivided_common_edge, (void*)w);
762 }
763
764 int
765 window_needs_vertical_divider (struct window *w)
766 {
767   if (!w->need_vertical_divider_valid_p)
768     {
769       w->need_vertical_divider_p =
770         window_needs_vertical_divider_1 (w);
771       w->need_vertical_divider_valid_p = 1;
772     }
773   return w->need_vertical_divider_p;
774 }
775
776 /* Called from invalidate_vertical_divider_cache_in_frame */
777 int
778 invalidate_vertical_divider_cache_in_window (struct window *w,
779                                              void *u_n_u_s_e_d)
780 {
781   w->need_vertical_divider_valid_p = 0;
782   return 0;
783 }
784
785 /* Calculate width of vertical divider, including its shadows
786    and spacing. The returned value is effectively the distance
787    between adjacent window edges. This function does not check
788    whether a windows needs vertival divider, so the returned 
789    value is a "theoretical" one */
790 int
791 window_divider_width (struct window *w)
792 {
793   /* the shadow thickness can be negative. This means that the divider
794      will have a depressed look */
795
796   if (FRAME_WIN_P (XFRAME (WINDOW_FRAME (w))))
797     return 
798       XINT (w->vertical_divider_line_width)
799       + 2 * XINT (w->vertical_divider_spacing)
800       + 2 * abs (XINT (w->vertical_divider_shadow_thickness));
801   else
802     return XINT (w->vertical_divider_line_width) == 0 ? 0 : 1;
803 }
804
805 int
806 window_scrollbar_width (struct window *w)
807 {
808 #ifdef HAVE_SCROLLBARS
809   if (!WINDOW_WIN_P (w)
810       || MINI_WINDOW_P (w)
811       || NILP (w->buffer)
812       || NILP (w->vertical_scrollbar_visible_p))
813     /* #### when does NILP (w->buffer) happen? */
814     return 0;
815
816   return XINT (w->scrollbar_width);
817 #else
818   return 0;
819 #endif /* HAVE_SCROLLBARS */
820 }
821
822 /* Horizontal scrollbars are only active on windows with truncation
823    turned on. */
824 int
825 window_scrollbar_height (struct window *w)
826 {
827 #ifdef HAVE_SCROLLBARS
828   if (!WINDOW_WIN_P (w)
829       || MINI_WINDOW_P (w)
830       || NILP (w->buffer)
831       || NILP (w->horizontal_scrollbar_visible_p)
832       || !window_truncation_on (w))
833     return 0;
834
835   return XINT (w->scrollbar_height);
836 #else
837   return 0;
838 #endif /* HAVE_SCROLLBARS */
839 }
840
841 int
842 window_modeline_height (struct window *w)
843 {
844   struct frame *f = XFRAME (w->frame);
845   int modeline_height;
846
847   if (MINI_WINDOW_P (w) || NILP (w->buffer))
848     {
849       modeline_height = 0;
850     }
851   else if (!WINDOW_HAS_MODELINE_P (w))
852     {
853       if (window_scrollbar_height (w))
854         modeline_height = 0;
855       else
856         {
857           modeline_height = FRAMEMETH (f, divider_height, ());
858
859           if (!EQ (Qzero, w->modeline_shadow_thickness) && FRAME_WIN_P (f))
860             modeline_height += (2 * MODELINE_SHADOW_THICKNESS (w));
861         }
862     }
863   else
864     {
865       if (noninteractive)
866         modeline_height = 0;
867       else
868         {
869           display_line_dynarr *dla;
870
871           /* We don't force a regeneration of the modeline here.
872              Instead it is now a precondition that any function calling
873              this should make sure that one of these structures is
874              up-to-date.  In practice this only affects two internal
875              redisplay functions, regenerate_window and
876              regenerate_window_point_center. */
877           /* We check DESIRED_DISP because if it is valid it is more
878              up-to-date than CURRENT_DISP.  For calls to this outside
879              of redisplay it doesn't matter which structure we check
880              since there is a redisplay condition that these
881              structures be identical outside of redisplay. */
882           dla = window_display_lines (w, DESIRED_DISP);
883           if (dla && Dynarr_length (dla) && Dynarr_atp (dla, 0)->modeline)
884             modeline_height = (Dynarr_atp (dla, 0)->ascent +
885                                Dynarr_atp (dla, 0)->descent);
886           else
887             {
888               dla = window_display_lines (w, CURRENT_DISP);
889               if (dla && Dynarr_length (dla) && Dynarr_atp (dla, 0)->modeline)
890                 modeline_height = (Dynarr_atp (dla, 0)->ascent +
891                                    Dynarr_atp (dla, 0)->descent);
892               else
893                 /* This should be an abort except I'm not yet 100%
894                    confident that it won't ever get hit (though I
895                    haven't been able to trigger it).  It is extremely
896                    unlikely to cause any noticable problem and even if
897                    it does it will be a minor display glitch. */
898                 /* #### Bullshit alert.  It does get hit and it causes
899                    noticeable glitches.  real_current_modeline_height
900                    is a kludge to fix this for 19.14. */
901                 modeline_height = real_current_modeline_height (w);
902             }
903
904           if (!EQ (Qzero, w->modeline_shadow_thickness) && FRAME_WIN_P (f))
905             modeline_height += (2 * MODELINE_SHADOW_THICKNESS (w));
906         }
907     }
908
909   return modeline_height;
910 }
911
912 /*****************************************************************************
913  margin_width_internal
914
915  For a given window, return the width in pixels of the specified margin.
916  ****************************************************************************/
917 static int
918 margin_width_internal (struct window *w, int left_margin)
919 {
920   struct buffer *b;
921   int window_cwidth = window_char_width (w, 1);
922   int margin_cwidth;
923   int font_width;
924   Lisp_Object window;
925
926   /* We might be getting called on a non-leaf. */
927   if (NILP (w->buffer))
928     return 0;
929
930   /* The minibuffer never has margins. */
931   if (MINI_WINDOW_P (w))
932     return 0;
933
934   XSETWINDOW (window, w);
935   b = XBUFFER (w->buffer);
936   margin_cwidth = (left_margin ? XINT (w->left_margin_width) :
937                    XINT (w->right_margin_width));
938
939   default_face_height_and_width (window, 0, &font_width);
940
941   /* The left margin takes precedence over the right margin so we
942      subtract its width from the space available for the right
943      margin. */
944   if (!left_margin)
945     window_cwidth -= XINT (w->left_margin_width);
946
947   /* The margin cannot be wider than the window is.  We allow the
948      value to be bigger since it is possible for the user to enlarge
949      the window such that the left margin value would no longer be too
950      big, but we won't return a value that is larger. */
951   if (margin_cwidth > window_cwidth)
952     margin_cwidth = window_cwidth;
953
954   /* At the user level the margin is always specified in characters.
955      Internally however it is manipulated in terms of pixels. */
956   return margin_cwidth * font_width;
957 }
958
959 int
960 window_left_margin_width (struct window *w)
961 {
962   return margin_width_internal (w, 1);
963 }
964
965 int
966 window_right_margin_width (struct window *w)
967 {
968   return margin_width_internal (w, 0);
969 }
970
971 static int
972 window_top_toolbar_height (struct window *w)
973 {
974   /* #### implement this shit. */
975   return 0;
976 }
977
978 /* #### Currently used in scrollbar.c.  Does it actually need to be? */
979 int
980 window_bottom_toolbar_height (struct window *w)
981 {
982   return 0;
983 }
984
985 static int
986 window_left_toolbar_width (struct window *w)
987 {
988   return 0;
989 }
990
991 static int
992 window_right_toolbar_width (struct window *w)
993 {
994   return 0;
995 }
996
997 /*****************************************************************************
998  Window Gutters
999
1000  The gutters of a window are those areas in the boundary defined by
1001  w->pixel_top, w->pixel_left, w->pixel_height and w->pixel_width which
1002  do not contain text.  Items which may be in the gutters include
1003  scrollbars, toolbars and modelines.  The margin areas are not
1004  included.  This is an exception made because redisplay special cases
1005  the handling of those areas in many places in such a way that
1006  including them in the gutter area would make life difficult.
1007
1008  The size functions refer to height for the bottom and top gutters and
1009  width for the left and right gutters.  The starting position
1010  functions refer to the Y coord for bottom and top gutters and the X
1011  coord for left and right gutters.  All starting positions are
1012  relative to the frame, not the window.
1013  ****************************************************************************/
1014
1015 int
1016 window_top_gutter_height (struct window *w)
1017 {
1018   int toolbar_height = window_top_toolbar_height (w);
1019
1020   if (!NILP (w->hchild) || !NILP (w->vchild))
1021     return 0;
1022
1023 #ifdef HAVE_SCROLLBARS
1024   if (!NILP (w->scrollbar_on_top_p))
1025     return window_scrollbar_height (w) + toolbar_height;
1026   else
1027 #endif
1028     return toolbar_height;
1029 }
1030
1031 int
1032 window_bottom_gutter_height (struct window *w)
1033 {
1034   int other_height;
1035
1036   if (!NILP (w->hchild) || !NILP (w->vchild))
1037     return 0;
1038   else
1039     other_height =
1040       window_modeline_height (w) + window_bottom_toolbar_height (w);
1041
1042 #ifdef HAVE_SCROLLBARS
1043   if (NILP (w->scrollbar_on_top_p))
1044     return window_scrollbar_height (w) + other_height;
1045   else
1046 #endif
1047     return other_height;
1048 }
1049
1050 int
1051 window_left_gutter_width (struct window *w, int modeline)
1052 {
1053   int gutter = window_left_toolbar_width (w);
1054   
1055   if (!NILP (w->hchild) || !NILP (w->vchild))
1056     return 0;
1057
1058
1059 #ifdef HAVE_SCROLLBARS
1060   if (!modeline && !NILP (w->scrollbar_on_left_p))
1061     gutter += window_scrollbar_width (w);
1062 #endif
1063
1064   return gutter;
1065 }
1066
1067 int
1068 window_right_gutter_width (struct window *w, int modeline)
1069 {
1070   int gutter = window_left_toolbar_width (w);
1071   
1072   if (!NILP (w->hchild) || !NILP (w->vchild))
1073     return 0;
1074
1075 #ifdef HAVE_SCROLLBARS
1076   if (!modeline && NILP (w->scrollbar_on_left_p))
1077     gutter += window_scrollbar_width (w);
1078 #endif
1079
1080   if (window_needs_vertical_divider (w))
1081     gutter += window_divider_width (w);
1082
1083   return gutter;
1084 }
1085
1086 \f
1087 DEFUN ("windowp", Fwindowp, 1, 1, 0, /*
1088 Return t if OBJ is a window.
1089 */
1090        (obj))
1091 {
1092   return WINDOWP (obj) ? Qt : Qnil;
1093 }
1094
1095 DEFUN ("window-live-p", Fwindow_live_p, 1, 1, 0, /*
1096 Return t if OBJ is a window which is currently visible.
1097 */
1098        (obj))
1099 {
1100   return WINDOWP (obj) && WINDOW_LIVE_P (XWINDOW (obj)) ? Qt : Qnil;
1101 }
1102
1103 DEFUN ("selected-window", Fselected_window, 0, 1, 0, /*
1104 Return the window that the cursor now appears in and commands apply to.
1105 If the optional argument CON-DEV-OR-FRAME is specified and is a frame, return
1106 the selected window used by that frame.  If CON-DEV-OR-FRAME is a device,
1107 then the selected frame on that device will be used.  If CON-DEV-OR-FRAME
1108 is a console, the selected frame on that console's selected device will
1109 be used.  Otherwise, the selected frame is used.
1110 */
1111        (con_dev_or_frame))
1112 {
1113   if (NILP (con_dev_or_frame) && NILP (Fselected_device (Qnil)))
1114     return Qnil; /* happens at startup */
1115
1116   {
1117     struct frame *f = decode_frame_or_selected (con_dev_or_frame);
1118     return FRAME_SELECTED_WINDOW (f);
1119   }
1120 }
1121
1122 DEFUN ("minibuffer-window", Fminibuffer_window, 0, 1, 0, /*
1123 Return the window used now for minibuffers.
1124 If the optional argument CON-DEV-OR-FRAME is specified and is a frame, return
1125 the minibuffer window used by that frame.  If CON-DEV-OR-FRAME is a device,
1126 then the selected frame on that device will be used.  If CON-DEV-OR-FRAME
1127 is a console, the selected frame on that console's selected device will
1128 be used.  Otherwise, the selected frame is used.
1129 */
1130        (con_dev_or_frame))
1131 {
1132   return FRAME_MINIBUF_WINDOW (decode_frame_or_selected (con_dev_or_frame));
1133 }
1134
1135 DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, 1, 1, 0, /*
1136 Return non-nil if WINDOW is a minibuffer window.
1137 */
1138        (window))
1139 {
1140   return MINI_WINDOW_P (decode_window (window)) ? Qt : Qnil;
1141 }
1142
1143 DEFUN ("window-first-hchild", Fwindow_first_hchild, 1, 1, 0, /*
1144 Return the first horizontal child of WINDOW, or nil.
1145 */
1146        (window))
1147 {
1148   return decode_window (window)->hchild;
1149 }
1150
1151 DEFUN ("window-first-vchild", Fwindow_first_vchild, 1, 1, 0, /*
1152 Return the first vertical child of WINDOW, or nil.
1153 */
1154        (window))
1155 {
1156   return decode_window (window)->vchild;
1157 }
1158
1159 DEFUN ("window-next-child", Fwindow_next_child, 1, 1, 0, /*
1160 Return the next window on the same level as WINDOW, or nil.
1161 */
1162        (window))
1163 {
1164   return decode_window (window)->next;
1165 }
1166
1167 DEFUN ("window-previous-child", Fwindow_previous_child, 1, 1, 0, /*
1168 Return the previous window on the same level as WINDOW, or nil.
1169 */
1170        (window))
1171 {
1172   return decode_window (window)->prev;
1173 }
1174
1175 DEFUN ("window-parent", Fwindow_parent, 1, 1, 0, /*
1176 Return the parent of WINDOW, or nil.
1177 */
1178        (window))
1179 {
1180   return decode_window (window)->parent;
1181 }
1182
1183 DEFUN ("window-lowest-p", Fwindow_lowest_p, 1, 1, 0, /*
1184 Return non-nil if WINDOW is along the bottom of its frame.
1185 */
1186        (window))
1187 {
1188   return window_is_lowest (decode_window (window)) ? Qt : Qnil;
1189 }
1190
1191 DEFUN ("window-highest-p", Fwindow_highest_p, 1, 1, 0, /*
1192 Return non-nil if WINDOW is along the top of its frame.
1193 */
1194        (window))
1195 {
1196   return window_is_highest (decode_window (window)) ? Qt : Qnil;
1197 }
1198
1199 DEFUN ("window-leftmost-p", Fwindow_leftmost_p, 1, 1, 0, /*
1200 Return non-nil if WINDOW is along the left edge of its frame.
1201 */
1202        (window))
1203 {
1204   return window_is_leftmost (decode_window (window)) ? Qt : Qnil;
1205 }
1206
1207 DEFUN ("window-rightmost-p", Fwindow_rightmost_p, 1, 1, 0, /*
1208 Return non-nil if WINDOW is along the right edge of its frame.
1209 */
1210        (window))
1211 {
1212   return window_is_rightmost (decode_window (window)) ? Qt : Qnil;
1213 }
1214
1215 DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p, 0, 2, 0, /*
1216 Return t if position POS is currently on the frame in WINDOW.
1217 Returns nil if that position is scrolled vertically out of view.
1218 POS defaults to point in WINDOW's buffer; WINDOW, to the selected window.
1219 */
1220        (pos, window))
1221 {
1222   struct window *w = decode_window (window);
1223   Bufpos top = marker_position (w->start[CURRENT_DISP]);
1224   Bufpos posint;
1225   struct buffer *buf = XBUFFER (w->buffer);
1226
1227   if (NILP (pos))
1228     posint = BUF_PT (buf);
1229   else
1230     {
1231       CHECK_INT_COERCE_MARKER (pos);
1232       posint = XINT (pos);
1233     }
1234
1235   if (posint < top || posint > BUF_ZV (buf))
1236     return Qnil;
1237
1238   /* w->start can be out of range.  If it is, do something reasonable.  */
1239   if (top < BUF_BEGV (buf) || top > BUF_ZV (buf))
1240     return Qnil;
1241
1242   return point_would_be_visible (w, top, posint) ? Qt : Qnil;
1243 }
1244
1245 \f
1246 struct window *
1247 decode_window (Lisp_Object window)
1248 {
1249   if (NILP (window))
1250     return XWINDOW (Fselected_window (Qnil));
1251
1252   CHECK_LIVE_WINDOW (window);
1253   return XWINDOW (window);
1254 }
1255
1256 DEFUN ("window-buffer", Fwindow_buffer, 0, 1, 0, /*
1257 Return the buffer that WINDOW is displaying.
1258 */
1259        (window))
1260 {
1261   return decode_window (window)->buffer;
1262 }
1263
1264 DEFUN ("window-frame", Fwindow_frame, 0, 1, 0, /*
1265 Return the frame that window WINDOW is on.
1266 */
1267        (window))
1268 {
1269   return decode_window (window)->frame;
1270 }
1271
1272 DEFUN ("window-height", Fwindow_height, 0, 1, 0, /*
1273 Return the number of default lines in WINDOW.
1274 This actually works by dividing the window's pixel height (including
1275 the modeline and horizontal scrollbar, if any) by the height of the
1276 default font; therefore, the number of displayed lines will probably
1277 be different.
1278 Use `window-height' to get consistent results in geometry calculations.
1279 Use `window-displayed-height' to get the actual number of lines
1280 currently displayed in a window.
1281 */
1282        (window))
1283 {
1284   return make_int (window_char_height (decode_window (window), 1));
1285 }
1286
1287 DEFUN ("window-displayed-height", Fwindow_displayed_height, 0, 1, 0, /*
1288 Return the number of lines currently displayed in WINDOW.
1289 This counts the actual number of lines displayed in WINDOW
1290 \(as opposed to `window-height').  The modeline and horizontal
1291 scrollbar do not count as lines.  If there is some blank space
1292 between the end of the buffer and the end of the window, this
1293 function pretends that there are lines of text in the default
1294 font there.
1295 */
1296      (window))
1297 {
1298   return make_int (window_displayed_height (decode_window (window)));
1299 }
1300
1301 DEFUN ("window-pixel-height", Fwindow_pixel_height, 0, 1, 0, /*
1302 Return the height of WINDOW in pixels.  Defaults to current window.
1303 This includes the window's modeline and horizontal scrollbar (if any).
1304 */
1305        (window))
1306 {
1307   return make_int (decode_window (window)->pixel_height);
1308 }
1309
1310 DEFUN ("window-text-area-pixel-height",
1311        Fwindow_text_area_pixel_height, 0, 1, 0, /*
1312 Return the height in pixels of the text-displaying portion of WINDOW.
1313 Unlike `window-pixel-height', the space occupied by the modeline and
1314 horizontal scrollbar, if any, is not counted.
1315 */
1316      (window))
1317 {
1318   struct window *w = decode_window (window);
1319
1320   return make_int (WINDOW_TEXT_HEIGHT (w));
1321 }
1322
1323 DEFUN ("window-displayed-text-pixel-height",
1324        Fwindow_displayed_text_pixel_height, 0, 2, 0, /*
1325 Return the height in pixels of the text displayed in WINDOW.
1326 Unlike `window-text-area-pixel-height', any blank space below the
1327 end of the buffer is not included.  If optional argument NOCLIPPED
1328 is non-nil, do not include space occupied by clipped lines.
1329 */
1330      (window, noclipped))
1331 {
1332   struct window *w;
1333   Bufpos start, eobuf;
1334   int defheight;
1335   int hlimit, height, prev_height = -1;
1336   int line;
1337   int elt, nelt, i;
1338   int needed;
1339   line_start_cache_dynarr *cache;
1340
1341   if (NILP (window))
1342     window = Fselected_window (Qnil);
1343
1344   CHECK_WINDOW (window);
1345   w = XWINDOW (window);
1346
1347   start  = marker_position (w->start[CURRENT_DISP]);
1348   hlimit = WINDOW_TEXT_HEIGHT (w);
1349   eobuf  = BUF_ZV (XBUFFER (w->buffer));
1350
1351   default_face_height_and_width (window, &defheight, NULL);
1352
1353   /* guess lines needed in line start cache + a few extra */
1354   needed = (hlimit + defheight-1) / defheight + 3;
1355
1356   while (1) {
1357     elt = point_in_line_start_cache (w, start, needed);
1358     assert (elt >= 0); /* in the cache */
1359
1360     cache = w->line_start_cache;
1361     nelt  = Dynarr_length (cache);
1362
1363     height = 0;
1364     for (i = elt; i < nelt; i++) {
1365       line = Dynarr_atp (cache, i)->height;
1366
1367       if (height + line > hlimit)
1368         return make_int (!NILP (noclipped) ? height : hlimit);
1369
1370       height += line;
1371
1372       if (height == hlimit || Dynarr_atp (cache, i)->end >= eobuf)
1373         return make_int (height);
1374     }
1375
1376     /* get here => need more cache lines.  try again. */
1377     assert(height > prev_height); /* progress? */
1378     prev_height = height;
1379
1380     needed += ((hlimit - height)*(nelt - elt) + height-1)/height + 3;
1381   }
1382
1383   RETURN_NOT_REACHED(make_int (0))        /* shut up compiler */
1384 }
1385
1386 DEFUN ("window-width", Fwindow_width, 0, 1, 0, /*
1387 Return the number of display columns in WINDOW.
1388 This is the width that is usable columns available for text in WINDOW.
1389 */
1390        (window))
1391 {
1392   return make_int (window_char_width (decode_window (window), 0));
1393 }
1394
1395 DEFUN ("window-pixel-width", Fwindow_pixel_width, 0, 1, 0, /*
1396 Return the width of WINDOW in pixels.  Defaults to current window.
1397 */
1398        (window))
1399 {
1400   return make_int (decode_window (window)->pixel_width);
1401 }
1402
1403 DEFUN ("window-text-area-pixel-width",
1404        Fwindow_text_area_pixel_width, 0, 1, 0, /*
1405 Return the width in pixels of the text-displaying portion of WINDOW.
1406 Unlike `window-pixel-width', the space occupied by the vertical
1407 scrollbar or divider, if any, is not counted.  
1408 */
1409      (window))
1410 {
1411   struct window *w = decode_window (window);
1412
1413   return make_int (WINDOW_TEXT_WIDTH (w));
1414 }
1415
1416 DEFUN ("window-hscroll", Fwindow_hscroll, 0, 1, 0, /*
1417 Return the number of columns by which WINDOW is scrolled from left margin.
1418 */
1419        (window))
1420 {
1421   return make_int (decode_window (window)->hscroll);
1422 }
1423
1424 #ifdef MODELINE_IS_SCROLLABLE
1425 DEFUN ("modeline-hscroll", Fmodeline_hscroll, 0, 1, 0, /*
1426 Return the number of columns by which WINDOW's modeline is scrolled from
1427 left margin. If the window has no modeline, return nil.
1428 */
1429        (window))
1430 {
1431   struct window *w = decode_window (window);
1432
1433   return (WINDOW_HAS_MODELINE_P (w)) ? make_int (w->modeline_hscroll) : Qnil;
1434 }
1435
1436 DEFUN ("set-modeline-hscroll", Fset_modeline_hscroll, 2, 2, 0, /*
1437 Set number of columns WINDOW's modeline is scrolled from left margin to NCOL.
1438 NCOL should be zero or positive. If NCOL is negative, it will be forced to 0.
1439 If the window has no modeline, do nothing and return nil.
1440 */
1441        (window, ncol))
1442 {
1443   struct window *w = decode_window (window);
1444
1445   if (WINDOW_HAS_MODELINE_P (w))
1446     {
1447       int ncols;
1448       CHECK_INT (ncol);
1449       ncols = XINT (ncol);
1450       if (ncols < 0) ncols = 0;
1451       if (w->modeline_hscroll != ncols)
1452         MARK_MODELINE_CHANGED;
1453       w->modeline_hscroll = ncols;
1454       return ncol;
1455     }
1456   return Qnil;
1457 }
1458 #endif /* MODELINE_IS_SCROLLABLE */
1459
1460 DEFUN ("set-window-hscroll", Fset_window_hscroll, 2, 2, 0, /*
1461 Set number of columns WINDOW is scrolled from left margin to NCOL.
1462 NCOL should be zero or positive.
1463 */
1464        (window, ncol))
1465 {
1466   struct window *w;
1467   int ncols;
1468
1469   CHECK_INT (ncol);
1470   ncols = XINT (ncol);
1471   if (ncols < 0) ncols = 0;
1472   w = decode_window (window);
1473   if (w->hscroll != ncols)
1474     MARK_CLIP_CHANGED;  /* FSF marks differently but we aren't FSF. */
1475   w->hscroll = ncols;
1476   return ncol;
1477 }
1478
1479 #if 0 /* bogus FSF crock */
1480
1481 xxDEFUN ("window-redisplay-end-trigger",
1482          Fwindow_redisplay_end_trigger, 0, 1, 0, /*
1483 Return WINDOW's redisplay end trigger value.
1484 See `set-window-redisplay-end-trigger' for more information.
1485 */
1486          (window))
1487 {
1488   return decode_window (window)->redisplay_end_trigger;
1489 }
1490
1491 xxDEFUN ("set-window-redisplay-end-trigger",
1492          Fset_window_redisplay_end_trigger, 2, 2, 0, /*
1493 Set WINDOW's redisplay end trigger value to VALUE.
1494 VALUE should be a buffer position (typically a marker) or nil.
1495 If it is a buffer position, then if redisplay in WINDOW reaches a position
1496 beyond VALUE, the functions in `redisplay-end-trigger-functions' are called
1497 with two arguments: WINDOW, and the end trigger value.
1498 Afterwards the end-trigger value is reset to nil.
1499 */
1500          (window, value))
1501 {
1502   return (decode_window (window)->redisplay_end_trigger = value);
1503 }
1504
1505 #endif /* 0 */
1506
1507 DEFUN ("window-pixel-edges", Fwindow_pixel_edges, 0, 1, 0, /*
1508 Return a list of the pixel edge coordinates of WINDOW.
1509 \(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.
1510 The frame toolbars and menubars are considered to be outside of this area.
1511 */
1512        (window))
1513 {
1514   struct window *w = decode_window (window);
1515   struct frame *f = XFRAME (w->frame);
1516
1517   int left = w->pixel_left - FRAME_LEFT_BORDER_END (f);
1518   int top  = w->pixel_top  - FRAME_TOP_BORDER_END  (f);
1519
1520   return list4 (make_int (left),
1521                 make_int (top),
1522                 make_int (left + w->pixel_width),
1523                 make_int (top + w->pixel_height));
1524 }
1525
1526 DEFUN ("window-text-area-pixel-edges",
1527        Fwindow_text_area_pixel_edges, 0, 1, 0, /*
1528 Return a list of the pixel edge coordinates of the text area of WINDOW.
1529 Returns the list \(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at the
1530 top left corner of the window.
1531 */
1532        (window))
1533 {
1534   struct window *w = decode_window (window);
1535
1536   int left   = window_left_gutter_width (w, /* modeline = */ 0);
1537   int top    = window_top_gutter_height (w);
1538   int right  = WINDOW_WIDTH (w) - window_right_gutter_width (w, 0);
1539   int bottom = WINDOW_HEIGHT (w) - window_bottom_gutter_height (w);
1540
1541   return list4 (make_int (left),
1542                 make_int (top),
1543                 make_int (right),
1544                 make_int (bottom));
1545 }
1546
1547 DEFUN ("window-point", Fwindow_point, 0, 1, 0, /*
1548 Return current value of point in WINDOW.
1549 For a nonselected window, this is the value point would have
1550 if that window were selected.
1551
1552 Note that, when WINDOW is the selected window and its buffer
1553 is also currently selected, the value returned is the same as (point).
1554 It would be more strictly correct to return the `top-level' value
1555 of point, outside of any save-excursion forms.
1556 But that is hard to define.
1557 */
1558        (window))
1559 {
1560   struct window *w = decode_window (window);
1561
1562   /* The special check for current buffer is necessary for this
1563      function to work as defined when called within an excursion. */
1564   if (w == XWINDOW (Fselected_window (XFRAME (w->frame)->device))
1565       && current_buffer == XBUFFER (w->buffer))
1566     return Fpoint (Qnil);
1567   return Fmarker_position (w->pointm[CURRENT_DISP]);
1568 }
1569
1570 DEFUN ("window-start", Fwindow_start, 0, 1, 0, /*
1571 Return position at which display currently starts in WINDOW.
1572 This is updated by redisplay or by calling `set-window-start'.
1573 */
1574        (window))
1575 {
1576   return Fmarker_position (decode_window (window)->start[CURRENT_DISP]);
1577 }
1578
1579 DEFUN ("window-end", Fwindow_end, 0, 2, 0, /*
1580 Return position at which display currently ends in WINDOW.
1581 This is updated by redisplay, when it runs to completion.
1582 Simply changing the buffer text or setting `window-start'
1583 does not update this value.
1584 If GUARANTEE is non-nil, then the return value is guaranteed to be
1585 the value of window-end at the end of the next full redisplay assuming
1586 nothing else changes in the meantime.  This function is potentially much
1587 slower with this flag set.
1588 */
1589        (window, guarantee))
1590 {
1591   struct window *w = decode_window (window);
1592
1593   if (NILP (guarantee))
1594     {
1595       Lisp_Object buf;
1596       buf = w->buffer;
1597       CHECK_BUFFER (buf);
1598       return make_int (BUF_Z (XBUFFER (buf)) - w->window_end_pos[CURRENT_DISP]);
1599     }
1600   else
1601     {
1602       Bufpos startp = marker_position (w->start[CURRENT_DISP]);
1603       return make_int (end_of_last_line (w, startp));
1604     }
1605 }
1606
1607 DEFUN ("set-window-point", Fset_window_point, 2, 2, 0, /*
1608 Make point value in WINDOW be at position POS in WINDOW's buffer.
1609 */
1610        (window, pos))
1611 {
1612   struct window *w = decode_window (window);
1613
1614   CHECK_INT_COERCE_MARKER (pos);
1615   if (w == XWINDOW (Fselected_window (Qnil)))
1616     Fgoto_char (pos, Qnil);
1617   else
1618     set_marker_restricted (w->pointm[CURRENT_DISP], pos, w->buffer);
1619
1620   MARK_POINT_CHANGED;
1621   return pos;
1622 }
1623
1624 DEFUN ("set-window-start", Fset_window_start, 2, 3, 0, /*
1625 Make display in WINDOW start at position POS in WINDOW's buffer.
1626 Optional third arg NOFORCE non-nil inhibits next redisplay
1627 from overriding motion of point in order to display at this exact start.
1628 */
1629        (window, pos, noforce))
1630 {
1631   struct window *w = decode_window (window);
1632
1633   CHECK_INT_COERCE_MARKER (pos);
1634   set_marker_restricted (w->start[CURRENT_DISP], pos, w->buffer);
1635   /* this is not right, but much easier than doing what is right. */
1636   w->start_at_line_beg = 0;
1637   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   w->start_at_line_beg = 0;
3167   w->force_start = 0;           /* Lucid fix */
3168   SET_LAST_MODIFIED (w, 1);
3169   SET_LAST_FACECHANGE (w);
3170   MARK_WINDOWS_CHANGED (w);
3171   recompute_all_cached_specifiers_in_window (w);
3172   if (EQ (window, Fselected_window (Qnil)))
3173     {
3174       Fset_buffer (buffer);
3175     }
3176   return Qnil;
3177 }
3178
3179 DEFUN ("select-window", Fselect_window, 1, 2, 0, /*
3180 Select WINDOW.  Most editing will apply to WINDOW's buffer.
3181 The main editor command loop selects the buffer of the selected window
3182 before each command.
3183
3184 With non-nil optional argument `norecord', do not modify the
3185 global or per-frame buffer ordering.
3186 */
3187        (window, norecord))
3188 {
3189   struct window *w;
3190   Lisp_Object old_selected_window = Fselected_window (Qnil);
3191
3192   CHECK_LIVE_WINDOW (window);
3193   w = XWINDOW (window);
3194
3195   /* we have already caught dead-window errors */
3196   if (!NILP (w->hchild) || !NILP (w->vchild))
3197     error ("Trying to select non-leaf window");
3198
3199   w->use_time = make_int (++window_select_count);
3200   if (EQ (window, old_selected_window))
3201     return window;
3202
3203   /* deselect the old window, if it exists (it might not exist if
3204      the selected device has no frames, which occurs at startup) */
3205   if (!NILP (old_selected_window))
3206     {
3207       struct window *ow = XWINDOW (old_selected_window);
3208
3209       Fset_marker (ow->pointm[CURRENT_DISP],
3210                    make_int (BUF_PT (XBUFFER (ow->buffer))),
3211                    ow->buffer);
3212
3213       MARK_WINDOWS_CHANGED (ow);
3214     }
3215
3216   /* now select the window's frame */
3217   set_frame_selected_window (XFRAME (WINDOW_FRAME (w)), window);
3218
3219   select_frame_1 (WINDOW_FRAME (w));
3220
3221   /* also select the window's buffer */
3222   if (NILP (norecord))
3223     Frecord_buffer (w->buffer);
3224   Fset_buffer (w->buffer);
3225
3226   /* Go to the point recorded in the window.
3227      This is important when the buffer is in more
3228      than one window.  It also matters when
3229      redisplay_window has altered point after scrolling,
3230      because it makes the change only in the window.  */
3231   {
3232     Bufpos new_point = marker_position (w->pointm[CURRENT_DISP]);
3233     if (new_point < BUF_BEGV (current_buffer))
3234       new_point = BUF_BEGV (current_buffer);
3235     else if (new_point > BUF_ZV (current_buffer))
3236       new_point = BUF_ZV (current_buffer);
3237
3238     BUF_SET_PT (current_buffer, new_point);
3239   }
3240
3241   MARK_WINDOWS_CHANGED (w);
3242
3243   return window;
3244 }
3245
3246 Lisp_Object
3247 display_buffer (Lisp_Object buffer, Lisp_Object not_this_window_p,
3248                 Lisp_Object override_frame)
3249 {
3250   return call3 (Qdisplay_buffer, buffer, not_this_window_p, override_frame);
3251 }
3252
3253 void
3254 temp_output_buffer_show (Lisp_Object buf, Lisp_Object same_frame)
3255 {
3256   /* This function can GC */
3257   Lisp_Object window;
3258   struct window *w;
3259   struct buffer *b = XBUFFER (buf);
3260
3261   BUF_SAVE_MODIFF (XBUFFER (buf)) = BUF_MODIFF (b);
3262   widen_buffer (b, 0);
3263   BUF_SET_PT (b, BUF_BEG (b));
3264
3265   if (!NILP (Vtemp_buffer_show_function))
3266     call1 (Vtemp_buffer_show_function, buf);
3267   else
3268     {
3269       window = display_buffer (buf, Qnil, same_frame);
3270
3271       if (!EQ (XWINDOW (window)->frame, Fselected_frame (Qnil)))
3272         Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
3273
3274       Vminibuffer_scroll_window = window;
3275       w = XWINDOW (window);
3276       w->hscroll = 0;
3277       w->modeline_hscroll = 0;
3278       set_marker_restricted (w->start[CURRENT_DISP], make_int (1), buf);
3279       set_marker_restricted (w->pointm[CURRENT_DISP], make_int (1), buf);
3280       set_marker_restricted (w->sb_point, make_int (1), buf);
3281
3282       /* Run temp-buffer-show-hook, with the chosen window selected.  */
3283       if (!preparing_for_armageddon)
3284         {
3285           Lisp_Object tem;
3286           tem = Fboundp (Qtemp_buffer_show_hook);
3287           if (!NILP (tem))
3288             {
3289               tem = Fsymbol_value (Qtemp_buffer_show_hook);
3290               if (!NILP (tem))
3291                 {
3292                   int count = specpdl_depth ();
3293
3294                   /* Select the window that was chosen, for running
3295                      the hook.  */
3296                   record_unwind_protect (save_window_excursion_unwind,
3297                                          Fcurrent_window_configuration (Qnil));
3298
3299                   Fselect_window (window, Qnil);
3300                   run_hook (Qtemp_buffer_show_hook);
3301                   unbind_to (count, Qnil);
3302                 }
3303             }
3304         }
3305     }
3306 }
3307 \f
3308 static void
3309 make_dummy_parent (Lisp_Object window)
3310 {
3311   Lisp_Object new;
3312   struct window *o = XWINDOW (window);
3313   struct window *p = alloc_lcrecord_type (struct window, lrecord_window);
3314
3315   XSETWINDOW (new, p);
3316   copy_lcrecord (p, o);
3317
3318   /* Don't copy the pointers to the line start cache or the face
3319      instances. */
3320   p->line_start_cache = Dynarr_new (line_start_cache);
3321   p->face_cachels     = Dynarr_new (face_cachel);
3322   p->glyph_cachels    = Dynarr_new (glyph_cachel);
3323
3324   /* Put new into window structure in place of window */
3325   replace_window (window, new);
3326
3327   o->next = Qnil;
3328   o->prev = Qnil;
3329   o->vchild = Qnil;
3330   o->hchild = Qnil;
3331   o->parent = new;
3332
3333   p->start[CURRENT_DISP] = Qnil;
3334   p->start[DESIRED_DISP] = Qnil;
3335   p->start[CMOTION_DISP] = Qnil;
3336   p->pointm[CURRENT_DISP] = Qnil;
3337   p->pointm[DESIRED_DISP] = Qnil;
3338   p->pointm[CMOTION_DISP] = Qnil;
3339   p->sb_point = Qnil;
3340   p->buffer = Qnil;
3341 }
3342
3343 DEFUN ("split-window", Fsplit_window, 0, 3, "", /*
3344 Split WINDOW, putting SIZE lines in the first of the pair.
3345 WINDOW defaults to selected one and SIZE to half its size.
3346 If optional third arg HOR-FLAG is non-nil, split side by side
3347 and put SIZE columns in the first of the pair.
3348 */
3349        (window, chsize, horflag))
3350 {
3351   Lisp_Object new;
3352   struct window *o, *p;
3353   struct frame *f;
3354   int size;
3355   int psize;
3356
3357   if (NILP (window))
3358     window = Fselected_window (Qnil);
3359   else
3360     CHECK_WINDOW (window);
3361
3362   o = XWINDOW (window);
3363   f = XFRAME (WINDOW_FRAME (o));
3364
3365   if (NILP (chsize))
3366     {
3367       if (!NILP (horflag))
3368         /* In the new scheme, we are symmetric with respect to separators
3369            so there is no need to do weird things here. */
3370         {
3371           psize = WINDOW_WIDTH (o) >> 1;
3372           size = window_pixel_width_to_char_width (o, psize, 0);
3373         }
3374       else
3375         {
3376           psize = WINDOW_HEIGHT (o) >> 1;
3377           size = window_pixel_height_to_char_height (o, psize, 1);
3378         }
3379     }
3380   else
3381     {
3382       CHECK_INT (chsize);
3383       size = XINT (chsize);
3384       if (!NILP (horflag))
3385         psize = window_char_width_to_pixel_width (o, size, 0);
3386       else
3387         psize = window_char_height_to_pixel_height (o, size, 1);
3388     }
3389
3390   if (MINI_WINDOW_P (o))
3391     error ("Attempt to split minibuffer window");
3392   else if (FRAME_NO_SPLIT_P (XFRAME (WINDOW_FRAME (o))))
3393     error ("Attempt to split unsplittable frame");
3394
3395   check_min_window_sizes ();
3396
3397   if (NILP (horflag))
3398     {
3399       if (size < window_min_height)
3400         error ("Window height %d too small (after splitting)", size);
3401       if (size + window_min_height > window_char_height (o, 1))
3402         error ("Window height %d too small (after splitting)",
3403                window_char_height (o, 1) - size);
3404       if (NILP (o->parent)
3405           || NILP (XWINDOW (o->parent)->vchild))
3406         {
3407           make_dummy_parent (window);
3408           reset_face_cachels (XWINDOW (window));
3409           new = o->parent;
3410           XWINDOW (new)->vchild = window;
3411           XFRAME (o->frame)->mirror_dirty = 1;
3412         }
3413     }
3414   else
3415     {
3416       if (size < window_min_width)
3417         error ("Window width %d too small (after splitting)", size);
3418       if (size + window_min_width > window_char_width (o, 0))
3419         error ("Window width %d too small (after splitting)",
3420                window_char_width (o, 0) - size);
3421       if (NILP (o->parent)
3422           || NILP (XWINDOW (o->parent)->hchild))
3423         {
3424           make_dummy_parent (window);
3425           reset_face_cachels (XWINDOW (window));
3426           new = o->parent;
3427           XWINDOW (new)->hchild = window;
3428           XFRAME (o->frame)->mirror_dirty = 1;
3429         }
3430     }
3431
3432   /* Now we know that window's parent is a vertical combination
3433      if we are dividing vertically, or a horizontal combination
3434      if we are making side-by-side windows */
3435
3436   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
3437   new = allocate_window ();
3438   p = XWINDOW (new);
3439
3440   p->frame = o->frame;
3441   p->next = o->next;
3442   if (!NILP (p->next))
3443     XWINDOW (p->next)->prev = new;
3444   p->prev = window;
3445   o->next = new;
3446   p->parent = o->parent;
3447   p->buffer = Qt;
3448
3449   reset_face_cachels (p);
3450   reset_glyph_cachels (p);
3451
3452
3453   /* Apportion the available frame space among the two new windows */
3454
3455   if (!NILP (horflag))
3456     {
3457       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o);
3458       WINDOW_TOP (p) = WINDOW_TOP (o);
3459       WINDOW_WIDTH (p) = WINDOW_WIDTH (o) - psize;
3460       WINDOW_WIDTH (o) = psize;
3461       WINDOW_LEFT (p) = WINDOW_LEFT (o) + psize;
3462     }
3463   else
3464     {
3465       WINDOW_LEFT (p) = WINDOW_LEFT (o);
3466       WINDOW_WIDTH (p) = WINDOW_WIDTH (o);
3467       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o) - psize;
3468       WINDOW_HEIGHT (o) = psize;
3469       WINDOW_TOP (p) = WINDOW_TOP (o) + psize;
3470     }
3471
3472   XFRAME (p->frame)->mirror_dirty = 1;
3473   /* do this last (after the window is completely initialized and
3474      the mirror-dirty flag is set) so that specifier recomputation
3475      caused as a result of this will work properly and not abort. */
3476   Fset_window_buffer (new, o->buffer);
3477   return new;
3478 }
3479 \f
3480
3481 DEFUN ("enlarge-window", Fenlarge_window, 1, 3, "_p", /*
3482 Make the selected window ARG lines bigger.
3483 From program, optional second arg non-nil means grow sideways ARG columns,
3484 and optional third ARG specifies the window to change instead of the
3485 selected window.
3486 */
3487        (n, side, window))
3488 {
3489   struct window *w = decode_window (window);
3490   CHECK_INT (n);
3491   change_window_height (w, XINT (n), !NILP (side), /* inpixels */ 0);
3492   return Qnil;
3493 }
3494
3495 DEFUN ("enlarge-window-pixels", Fenlarge_window_pixels, 1, 3, "_p", /*
3496 Make the selected window ARG pixels bigger.
3497 From program, optional second arg non-nil means grow sideways ARG pixels,
3498 and optional third ARG specifies the window to change instead of the
3499 selected window.
3500 */
3501        (n, side, window))
3502 {
3503   struct window *w = decode_window (window);
3504   CHECK_INT (n);
3505   change_window_height (w, XINT (n), !NILP (side), /* inpixels */ 1);
3506   return Qnil;
3507 }
3508
3509 DEFUN ("shrink-window", Fshrink_window, 1, 3, "_p", /*
3510 Make the selected window ARG lines smaller.
3511 From program, optional second arg non-nil means shrink sideways ARG columns,
3512 and optional third ARG specifies the window to change instead of the
3513 selected window.
3514 */
3515        (n, side, window))
3516 {
3517   CHECK_INT (n);
3518   change_window_height (decode_window (window), -XINT (n), !NILP (side),
3519                         /* inpixels */ 0);
3520   return Qnil;
3521 }
3522
3523 DEFUN ("shrink-window-pixels", Fshrink_window_pixels, 1, 3, "_p", /*
3524 Make the selected window ARG pixels smaller.
3525 From program, optional second arg non-nil means shrink sideways ARG pixels,
3526 and optional third ARG specifies the window to change instead of the
3527 selected window.
3528 */
3529        (n, side, window))
3530 {
3531   CHECK_INT (n);
3532   change_window_height (decode_window (window), -XINT (n), !NILP (side),
3533                         /* inpixels */ 1);
3534   return Qnil;
3535 }
3536
3537 static int
3538 window_pixel_height (Lisp_Object window)
3539 {
3540   return WINDOW_HEIGHT (XWINDOW (window));
3541 }
3542
3543 static int
3544 window_pixel_height_to_char_height (struct window *w, int pixel_height,
3545                                     int include_gutters_p)
3546 {
3547   int avail_height;
3548   int defheight, defwidth;
3549   int char_height;
3550   Lisp_Object window;
3551
3552   XSETWINDOW (window, w);
3553
3554   avail_height = (pixel_height -
3555                   (include_gutters_p ? 0 :
3556                    window_top_gutter_height (w) +
3557                    window_bottom_gutter_height (w)));
3558
3559   default_face_height_and_width (window, &defheight, &defwidth);
3560
3561   char_height = avail_height / defheight;
3562
3563   /* It's the calling function's responsibility to check these values
3564      and make sure they're not out of range.
3565
3566      #### We need to go through the calling functions and actually
3567      do this. */
3568   return max (0, char_height);
3569 }
3570
3571 static int
3572 window_char_height_to_pixel_height (struct window *w, int char_height,
3573                                     int include_gutters_p)
3574 {
3575   int avail_height;
3576   int defheight, defwidth;
3577   int pixel_height;
3578
3579   Lisp_Object window;
3580
3581   XSETWINDOW (window, w);
3582
3583   default_face_height_and_width (window, &defheight, &defwidth);
3584
3585   avail_height = char_height * defheight;
3586   pixel_height = (avail_height +
3587                   (include_gutters_p ? 0 :
3588                    window_top_gutter_height (w) +
3589                    window_bottom_gutter_height (w)));
3590
3591   /* It's the calling function's responsibility to check these values
3592      and make sure they're not out of range.
3593
3594      #### We need to go through the calling functions and actually
3595      do this. */
3596   return max (0, pixel_height);
3597 }
3598
3599 /* Return number of default lines of text can fit in the window W.
3600    If INCLUDE_GUTTERS_P is 1, include "gutter" space (modeline plus
3601    horizontal scrollbar) in the space that is used for the calculation.
3602    */
3603 int
3604 window_char_height (struct window *w, int include_gutters_p)
3605 {
3606   return window_pixel_height_to_char_height (w, WINDOW_HEIGHT (w),
3607                                              include_gutters_p);
3608 }
3609
3610 /*
3611  * Return number of lines currently displayed in window w.  If
3612  * end-of-buffer is displayed then the area below end-of-buffer is assume
3613  * to be blank lines of default height.
3614  * Does not include the modeline.
3615  */
3616 int
3617 window_displayed_height (struct window *w)
3618 {
3619   struct buffer *b = XBUFFER (w->buffer);
3620   display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
3621   int num_lines;
3622   Charcount end_pos = (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b)
3623                        ? -1
3624                        : w->window_end_pos[CURRENT_DISP]);
3625
3626   if (!Dynarr_length (dla))
3627     return window_char_height (w, 0);
3628
3629   num_lines = Dynarr_length (dla);
3630
3631   /* #### Document and assert somewhere that w->window_end_pos == -1
3632      indicates that end-of-buffer is being displayed. */
3633   if (end_pos == -1)
3634     {
3635       struct display_line *dl = Dynarr_atp (dla, 0);
3636       int ypos1 = dl->ypos + dl->descent;
3637       int ypos2 = WINDOW_TEXT_BOTTOM (w);
3638       Lisp_Object window;
3639       int defheight, defwidth;
3640
3641       XSETWINDOW (window, w);
3642
3643       if (dl->modeline)
3644         {
3645           num_lines--;
3646
3647           if (Dynarr_length (dla) == 1)
3648             ypos1 = WINDOW_TEXT_TOP (w);
3649           else
3650             {
3651               dl = Dynarr_atp (dla, Dynarr_length (dla) - 1);
3652               /* If this line is clipped then we know that there is no
3653                  blank room between eob and the modeline.  If we are
3654                  scrolling on clipped lines just know off the clipped
3655                  line and return .*/
3656               if (scroll_on_clipped_lines && dl->clip)
3657                 return num_lines - 1;
3658               ypos1 = dl->ypos + dl->descent - dl->clip;
3659             }
3660         }
3661
3662       default_face_height_and_width (window, &defheight, &defwidth);
3663       /* #### This probably needs to know about the clipping area once a
3664          final definition is decided on. */
3665       num_lines += ((ypos2 - ypos1) / defheight);
3666     }
3667   else
3668     {
3669       if (num_lines > 1 && Dynarr_atp (dla, 0)->modeline)
3670         num_lines--;
3671
3672       if (scroll_on_clipped_lines
3673           && Dynarr_atp (dla, Dynarr_length (dla) - 1)->clip)
3674         num_lines--;
3675     }
3676
3677   return num_lines;
3678 }
3679
3680 static int
3681 window_pixel_width (Lisp_Object window)
3682 {
3683   return WINDOW_WIDTH (XWINDOW (window));
3684 }
3685
3686 static int
3687 window_pixel_width_to_char_width (struct window *w, int pixel_width,
3688                                   int include_margins_p)
3689 {
3690   int avail_width;
3691   int char_width;
3692   int defheight, defwidth;
3693   Lisp_Object window;
3694
3695   XSETWINDOW (window, w);
3696
3697   avail_width = (pixel_width -
3698                  window_left_gutter_width (w, 0) -
3699                  window_right_gutter_width (w, 0) -
3700                  (include_margins_p ? 0 : window_left_margin_width (w)) -
3701                  (include_margins_p ? 0 : window_right_margin_width (w)));
3702
3703   default_face_height_and_width (window, &defheight, &defwidth);
3704
3705   char_width = (avail_width / defwidth);
3706
3707   /* It's the calling function's responsibility to check these values
3708      and make sure they're not out of range.
3709
3710      #### We need to go through the calling functions and actually
3711      do this. */
3712   return max (0, char_width);
3713 }
3714
3715 static int
3716 window_char_width_to_pixel_width (struct window *w, int char_width,
3717                                   int include_margins_p)
3718 {
3719   int avail_width;
3720   int pixel_width;
3721   int defheight, defwidth;
3722   Lisp_Object window;
3723
3724   XSETWINDOW (window, w);
3725
3726   default_face_height_and_width (window, &defheight, &defwidth);
3727
3728   avail_width = char_width * defwidth;
3729   pixel_width = (avail_width +
3730                  window_left_gutter_width (w, 0) +
3731                  window_right_gutter_width (w, 0) +
3732                  (include_margins_p ? 0 : window_left_margin_width (w)) +
3733                  (include_margins_p ? 0 : window_right_margin_width (w)));
3734
3735   /* It's the calling function's responsibility to check these values
3736      and make sure they're not out of range.
3737
3738      #### We need to go through the calling functions and actually
3739      do this. */
3740   return max (0, pixel_width);
3741 }
3742
3743 /* This returns the usable space which doesn't include space needed by
3744    scrollbars or divider lines. */
3745 int
3746 window_char_width (struct window *w, int include_margins_p)
3747 {
3748   return window_pixel_width_to_char_width (w, WINDOW_WIDTH (w),
3749                                            include_margins_p);
3750 }
3751
3752 #define MINSIZE(w)                                              \
3753   (widthflag                                                    \
3754    ? window_min_width * defwidth                                \
3755    : (defheight * (MINI_WINDOW_P (XWINDOW (w)) ? 1 : window_min_height)))
3756
3757 #define CURBEG(w) \
3758   *(widthflag ? (int *) &WINDOW_LEFT (w) : (int *) &WINDOW_TOP (w))
3759
3760 #define CURSIZE(w) \
3761   *(widthflag ? (int *) &WINDOW_WIDTH (w) : (int *) &WINDOW_HEIGHT (w))
3762
3763 #define CURCHARSIZE(w) \
3764   (widthflag ? window_char_width (w, 0) : window_char_height (w, 1))
3765
3766 #define MINCHARSIZE(window) \
3767   (widthflag ? window_min_width : MINI_WINDOW_P (XWINDOW (window)) \
3768    ? 1 : window_min_height)
3769
3770 /* Unlike set_window_pixheight, this function
3771    also changes the heights of the siblings so as to
3772    keep everything consistent. */
3773
3774 static void
3775 change_window_height (struct window *win, int delta, int widthflag,
3776                       int inpixels)
3777 {
3778   Lisp_Object parent;
3779   Lisp_Object window;
3780   struct window *w;
3781   struct frame *f;
3782   int *sizep;
3783   int (*sizefun) (Lisp_Object) = (widthflag
3784                                   ? window_pixel_width
3785                                   : window_pixel_height);
3786   void (*setsizefun) (Lisp_Object, int, int) = (widthflag
3787                                                 ? set_window_pixwidth
3788                                                 : set_window_pixheight);
3789   int dim;
3790   int defheight, defwidth;
3791
3792   if (delta == 0)
3793     return;
3794
3795   check_min_window_sizes ();
3796
3797   XSETWINDOW (window, win);
3798   f = XFRAME (win->frame);
3799   if (EQ (window, FRAME_ROOT_WINDOW (f)))
3800     error ("Won't change only window");
3801
3802   /* #### This is very likely incorrect and instead the char_to_pixel_
3803      functions should be called. */
3804   default_face_height_and_width (window, &defheight, &defwidth);
3805
3806   while (1)
3807     {
3808       w = XWINDOW (window);
3809       parent = w->parent;
3810       if (NILP (parent))
3811         {
3812           if (widthflag)
3813             error ("No other window to side of this one");
3814           break;
3815         }
3816       if (widthflag
3817           ? !NILP (XWINDOW (parent)->hchild)
3818           : !NILP (XWINDOW (parent)->vchild))
3819         break;
3820       window = parent;
3821     }
3822
3823   sizep = &CURSIZE (w);
3824   dim = CURCHARSIZE (w);
3825
3826   if ((inpixels  && (*sizep + delta) < MINSIZE (window)) ||
3827       (!inpixels && (dim + delta) < MINCHARSIZE (window)))
3828     {
3829       if (MINI_WINDOW_P (XWINDOW (window)))
3830         return;
3831       else if (!NILP (parent))
3832         {
3833           Fdelete_window (window, Qnil);
3834           return;
3835         }
3836     }
3837
3838   if (!inpixels)
3839     delta *= (widthflag ? defwidth : defheight);
3840
3841   {
3842     int maxdelta;
3843
3844     maxdelta = ((!NILP (parent))
3845                 ? (*sizefun) (parent) - *sizep
3846                 : ((!NILP (w->next))
3847                    ? (*sizefun) (w->next) - MINSIZE (w->next)
3848                    : ((!NILP (w->prev))
3849                       ? (*sizefun) (w->prev) - MINSIZE (w->prev)
3850                       /* This is a frame with only one window,
3851                          a minibuffer-only or a minibufferless frame.  */
3852                       : (delta = 0))));
3853
3854     if (delta > maxdelta)
3855       /* This case traps trying to make the minibuffer
3856          the full frame, or make the only window aside from the
3857          minibuffer the full frame.  */
3858       delta = maxdelta;
3859
3860     if (delta == 0)
3861       return;
3862
3863 #if 0 /* FSFmacs */
3864     /* #### Chuck: is this correct? */
3865     if (*sizep + delta < MINSIZE (window))
3866       {
3867         Fdelete_window (window);
3868         return;
3869       }
3870 #endif
3871   }
3872
3873   if (!NILP (w->next) &&
3874       (*sizefun) (w->next) - delta >= (int) MINSIZE (w->next))
3875     {
3876       CURBEG (XWINDOW (w->next)) += delta;
3877       (*setsizefun) (w->next, (*sizefun) (w->next) - delta, 0);
3878       (*setsizefun) (window, *sizep + delta, 0);
3879     }
3880   else if (!NILP (w->prev) &&
3881            (*sizefun) (w->prev) - delta >= (int) MINSIZE (w->prev))
3882     {
3883       (*setsizefun) (w->prev, (*sizefun) (w->prev) - delta, 0);
3884       CURBEG (w) -= delta;
3885       (*setsizefun) (window, *sizep + delta, 0);
3886     }
3887   else
3888     {
3889       int delta1;
3890       int opht = (*sizefun) (parent);
3891
3892       /* If trying to grow this window to or beyond size of the parent,
3893          make delta1 so big that, on shrinking back down,
3894          all the siblings end up with less than one line and are deleted.  */
3895       if (opht <= *sizep + delta)
3896         delta1 = opht * opht * 2;
3897       /* Otherwise, make delta1 just right so that if we add delta1
3898          lines to this window and to the parent, and then shrink
3899          the parent back to its original size, the new proportional
3900          size of this window will increase by delta.  */
3901       else
3902         delta1 = (delta * opht * 100) / ((opht - *sizep - delta) * 100);
3903
3904       /* Add delta1 lines or columns to this window, and to the parent,
3905          keeping things consistent while not affecting siblings.  */
3906       CURSIZE (XWINDOW (parent)) = opht + delta1;
3907       (*setsizefun) (window, *sizep + delta1, 0);
3908
3909       /* Squeeze out delta1 lines or columns from our parent,
3910          shriking this window and siblings proportionately.
3911          This brings parent back to correct size.
3912          Delta1 was calculated so this makes this window the desired size,
3913          taking it all out of the siblings.  */
3914       (*setsizefun) (parent, opht, 0);
3915     }
3916
3917   SET_LAST_MODIFIED (w, 0);
3918   SET_LAST_FACECHANGE (w);
3919   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
3920 }
3921 #undef MINSIZE
3922 #undef CURBEG
3923 #undef CURSIZE
3924 #undef CURCHARSIZE
3925 #undef MINCHARSIZE
3926
3927 \f
3928
3929 /* Scroll contents of window WINDOW up N lines.  */
3930 void
3931 window_scroll (Lisp_Object window, Lisp_Object n, int direction,
3932                Error_behavior errb)
3933 {
3934   struct window *w = XWINDOW (window);
3935   struct buffer *b = XBUFFER (w->buffer);
3936   int selected = EQ (window, Fselected_window (Qnil));
3937   int value = 0;
3938   Lisp_Object point, tem;
3939
3940   if (selected)
3941     point = make_int (BUF_PT (b));
3942   else
3943     {
3944       Bufpos pos = marker_position (w->pointm[CURRENT_DISP]);
3945
3946       if (pos < BUF_BEGV (b))
3947         pos = BUF_BEGV (b);
3948       else if (pos > BUF_ZV (b))
3949         pos = BUF_ZV (b);
3950
3951       point = make_int (pos);
3952     }
3953
3954   /* Always set force_start so that redisplay_window will run
3955      thw window-scroll-functions.  */
3956   w->force_start = 1;
3957
3958   /* #### When the fuck does this happen?  I'm so glad that history has
3959      completely documented the behavior of the scrolling functions under
3960      all circumstances. */
3961   tem = Fpos_visible_in_window_p (point, window);
3962   if (NILP (tem))
3963     {
3964       Fvertical_motion (make_int (-window_char_height (w, 0) / 2),
3965                         window, Qnil);
3966       Fset_marker (w->start[CURRENT_DISP], point, w->buffer);
3967       w->start_at_line_beg = beginning_of_line_p (b, XINT (point));
3968       MARK_WINDOWS_CHANGED (w);
3969     }
3970
3971   if (!NILP (n))
3972     {
3973       if (EQ (n, Qminus))
3974         direction *= -1;
3975       else
3976         {
3977           n = Fprefix_numeric_value (n);
3978           value = XINT (n) * direction;
3979
3980           if (!value)
3981             return;     /* someone just made a pointless call */
3982         }
3983     }
3984
3985   /* If the user didn't specify how far to scroll then we have to figure it
3986      out by ourselves. */
3987   if (NILP (n) || EQ (n, Qminus))
3988     {
3989       /* Going forwards is easy.  If that is what we are doing then just
3990          set value and the section which handles the user specifying a
3991          positive value will work. */
3992       if (direction == 1)
3993         {
3994           value = window_displayed_height (w) - next_screen_context_lines;
3995           value = (value < 1 ? 1 : value);
3996         }
3997
3998       /* Going backwards is hard.  We can't use the same loop used if the
3999          user specified a negative value because we care about
4000          next_screen_context_lines.  In a variable height world you don't
4001          know how many lines above you can actually be displayed and still
4002          have the context lines appear.  So we leave value set to 0 and add
4003          a separate section to deal with this. */
4004
4005     }
4006
4007   if (direction == 1 && !value)
4008     {
4009       return;
4010     }
4011   else if (value > 0)
4012     {
4013       int vtarget;
4014       Bufpos startp, old_start;
4015
4016       old_start = marker_position (w->start[CURRENT_DISP]);
4017       startp = vmotion (w, old_start, value, &vtarget);
4018
4019       if (vtarget < value &&
4020           (w->window_end_pos[CURRENT_DISP] == -1
4021            || (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b))))
4022         {
4023           maybe_signal_error (Qend_of_buffer, Qnil, Qwindow, errb);
4024           return;
4025         }
4026       else
4027         {
4028           set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4029                                  w->buffer);
4030           w->force_start = 1;
4031           w->start_at_line_beg = beginning_of_line_p (b, startp);
4032           MARK_WINDOWS_CHANGED (w);
4033
4034           if (!point_would_be_visible (w, startp, XINT (point)))
4035             {
4036               if (selected)
4037                 BUF_SET_PT (b, startp);
4038               else
4039                 set_marker_restricted (w->pointm[CURRENT_DISP],
4040                                        make_int (startp),
4041                                        w->buffer);
4042             }
4043         }
4044     }
4045   else if (value < 0)
4046     {
4047       int vtarget;
4048       Bufpos startp, old_start;
4049
4050       old_start = marker_position (w->start[CURRENT_DISP]);
4051       startp = vmotion (w, old_start, value, &vtarget);
4052
4053       if (vtarget > value
4054           && marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b))
4055         {
4056           maybe_signal_error (Qbeginning_of_buffer, Qnil, Qwindow, errb);
4057           return;
4058         }
4059       else
4060         {
4061           set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4062                                  w->buffer);
4063           w->force_start = 1;
4064           w->start_at_line_beg = beginning_of_line_p (b, startp);
4065           MARK_WINDOWS_CHANGED (w);
4066
4067           if (!point_would_be_visible (w, startp, XINT (point)))
4068             {
4069               Bufpos new_point;
4070
4071               if (MINI_WINDOW_P (w))
4072                 new_point = startp;
4073               else
4074                 new_point = start_of_last_line (w, startp);
4075
4076               if (selected)
4077                 BUF_SET_PT (b, new_point);
4078               else
4079                 set_marker_restricted (w->pointm[CURRENT_DISP],
4080                                        make_int (new_point),
4081                                        w->buffer);
4082             }
4083         }
4084     }
4085   else  /* value == 0 && direction == -1 */
4086     {
4087       if (marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b))
4088         {
4089           maybe_signal_error (Qbeginning_of_buffer, Qnil, Qwindow, errb);
4090           return;
4091         }
4092       else
4093         {
4094           int vtarget;
4095           int movement = next_screen_context_lines - 1;
4096           Bufpos old_startp = marker_position (w->start[CURRENT_DISP]);
4097           Bufpos bottom = vmotion (w, old_startp, movement, &vtarget);
4098           Bufpos startp =
4099             start_with_point_on_display_line (w, bottom,
4100                                               -1 - (movement - vtarget));
4101
4102           if (startp >= old_startp)
4103             startp = vmotion (w, old_startp, -1, NULL);
4104
4105           set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4106                                  w->buffer);
4107           w->force_start = 1;
4108           w->start_at_line_beg = beginning_of_line_p (b, startp);
4109           MARK_WINDOWS_CHANGED (w);
4110
4111           if (!point_would_be_visible (w, startp, XINT (point)))
4112             {
4113               Bufpos new_point = start_of_last_line (w, startp);
4114
4115               if (selected)
4116                 BUF_SET_PT (b, new_point);
4117               else
4118                 set_marker_restricted (w->pointm[CURRENT_DISP],
4119                                        make_int (new_point),
4120                                        w->buffer);
4121             }
4122         }
4123     }
4124
4125 }
4126 \f
4127 DEFUN ("scroll-up", Fscroll_up, 0, 1, "_P", /*
4128 Scroll text of current window upward ARG lines; or near full screen if no ARG.
4129 A near full screen is `next-screen-context-lines' less than a full screen.
4130 Negative ARG means scroll downward.
4131 When calling from a program, supply a number as argument or nil.
4132 On attempt to scroll past end of buffer, `end-of-buffer' is signaled.
4133 On attempt to scroll past beginning of buffer, `beginning-of-buffer' is
4134 signaled.
4135 */
4136        (n))
4137 {
4138   window_scroll (Fselected_window (Qnil), n, 1, ERROR_ME);
4139   return Qnil;
4140 }
4141
4142 DEFUN ("scroll-down", Fscroll_down, 0, 1, "_P", /*
4143 Scroll text of current window downward ARG lines; or near full screen if no ARG.
4144 A near full screen is `next-screen-context-lines' less than a full screen.
4145 Negative ARG means scroll upward.
4146 When calling from a program, supply a number as argument or nil.
4147 On attempt to scroll past end of buffer, `end-of-buffer' is signaled.
4148 On attempt to scroll past beginning of buffer, `beginning-of-buffer' is
4149 signaled.
4150 */
4151        (n))
4152 {
4153   window_scroll (Fselected_window (Qnil), n, -1, ERROR_ME);
4154   return Qnil;
4155 }
4156 \f
4157 DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, 0, 0, 0, /*
4158 Return the other window for "other window scroll" commands.
4159 If in the minibuffer, `minibuffer-scroll-window' if non-nil
4160 specifies the window.
4161 If `other-window-scroll-buffer' is non-nil, a window
4162 showing that buffer is used.
4163 */
4164        ())
4165 {
4166   Lisp_Object window;
4167   Lisp_Object selected_window = Fselected_window (Qnil);
4168
4169   if (MINI_WINDOW_P (XWINDOW (selected_window))
4170       && !NILP (Vminibuffer_scroll_window))
4171     window = Vminibuffer_scroll_window;
4172   /* If buffer is specified, scroll that buffer.  */
4173   else if (!NILP (Vother_window_scroll_buffer))
4174     {
4175       window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil, Qnil);
4176       if (NILP (window))
4177         window = display_buffer (Vother_window_scroll_buffer, Qt, Qnil);
4178     }
4179   else
4180     {
4181       /* Nothing specified; look for a neighboring window on the same
4182          frame.  */
4183       window = Fnext_window (selected_window, Qnil, Qnil, Qnil);
4184
4185       if (EQ (window, selected_window))
4186         /* That didn't get us anywhere; look for a window on another
4187            visible frame.  */
4188         do
4189           window = Fnext_window (window, Qnil, Qt, Qnil);
4190         while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
4191                && ! EQ (window, selected_window));
4192     }
4193
4194   CHECK_LIVE_WINDOW (window);
4195
4196   if (EQ (window, selected_window))
4197     error ("There is no other window");
4198
4199   return window;
4200  }
4201
4202 DEFUN ("scroll-other-window", Fscroll_other_window, 0, 1, "_P", /*
4203 Scroll next window upward ARG lines; or near full frame if no ARG.
4204 The next window is the one below the current one; or the one at the top
4205 if the current one is at the bottom.  Negative ARG means scroll downward.
4206 When calling from a program, supply a number as argument or nil.
4207
4208 If in the minibuffer, `minibuffer-scroll-window' if non-nil
4209 specifies the window to scroll.
4210 If `other-window-scroll-buffer' is non-nil, scroll the window
4211 showing that buffer, popping the buffer up if necessary.
4212 */
4213        (n))
4214 {
4215   window_scroll (Fother_window_for_scrolling (), n, 1, ERROR_ME);
4216   return Qnil;
4217 }
4218 \f
4219 DEFUN ("scroll-left", Fscroll_left, 0, 1, "_P", /*
4220 Scroll selected window display ARG columns left.
4221 Default for ARG is window width minus 2.
4222 */
4223        (arg))
4224 {
4225   Lisp_Object window = Fselected_window (Qnil);
4226   struct window *w = XWINDOW (window);
4227
4228   if (NILP (arg))
4229     arg = make_int (window_char_width (w, 0) - 2);
4230   else
4231     arg = Fprefix_numeric_value (arg);
4232
4233   return Fset_window_hscroll (window, make_int (w->hscroll + XINT (arg)));
4234 }
4235
4236 DEFUN ("scroll-right", Fscroll_right, 0, 1, "_P", /*
4237 Scroll selected window display ARG columns right.
4238 Default for ARG is window width minus 2.
4239 */
4240        (arg))
4241 {
4242   Lisp_Object window = Fselected_window (Qnil);
4243   struct window *w = XWINDOW (window);
4244
4245   if (NILP (arg))
4246     arg = make_int (window_char_width (w, 0) - 2);
4247   else
4248     arg = Fprefix_numeric_value (arg);
4249
4250   return Fset_window_hscroll (window, make_int (w->hscroll - XINT (arg)));
4251 }
4252 \f
4253 DEFUN ("center-to-window-line", Fcenter_to_window_line, 0, 2, "_P", /*
4254 Center point in WINDOW.  With N, put point on line N.
4255 The desired position of point is always relative to the window.
4256 If WINDOW is nil, the selected window is used.
4257 */
4258        (n, window))
4259 {
4260   struct window *w = decode_window (window);
4261   struct buffer *b = XBUFFER (w->buffer);
4262   Bufpos opoint = BUF_PT (b);
4263   Bufpos startp;
4264
4265   if (NILP (n))
4266     startp = start_with_line_at_pixpos (w, opoint, window_half_pixpos (w));
4267   else
4268     {
4269       n = Fprefix_numeric_value (n);
4270       CHECK_INT (n);
4271       startp = start_with_point_on_display_line (w, opoint, XINT (n));
4272     }
4273
4274   Fset_marker (w->start[CURRENT_DISP], make_int (startp), w->buffer);
4275
4276   w->start_at_line_beg = beginning_of_line_p (b, startp);
4277   w->force_start = 1;
4278   MARK_WINDOWS_CHANGED (w);
4279   return Qnil;
4280 }
4281
4282 DEFUN ("move-to-window-line", Fmove_to_window_line, 1, 2, "_P", /*
4283 Position point relative to WINDOW.
4284 With no argument, position text at center of window.
4285 An argument specifies window line; zero means top of window,
4286 negative means relative to bottom of window.
4287 If WINDOW is nil, the selected window is used.
4288 */
4289        (arg, window))
4290 {
4291   struct window *w;
4292   struct buffer *b;
4293   int height;
4294   Bufpos start, new_point;
4295   int selected;
4296
4297   /* Don't use decode_window() because we need the new value of
4298      WINDOW.  */
4299   if (NILP (window))
4300     window = Fselected_window (Qnil);
4301   else
4302     CHECK_WINDOW (window);
4303   w = XWINDOW (window);
4304   b = XBUFFER (w->buffer);
4305
4306   height = window_displayed_height (w);
4307   selected = EQ (window, Fselected_window (w->frame));
4308
4309   if (NILP (arg))
4310     {
4311       int retval;
4312
4313       if (XINT (w->last_modified[CURRENT_DISP]) >= BUF_MODIFF (b)
4314           && XINT (w->last_facechange[CURRENT_DISP]) >= BUF_FACECHANGE (b))
4315         {
4316           new_point = point_at_center (w, CURRENT_DISP, 0, 0);
4317
4318           if (selected)
4319             BUF_SET_PT (b, new_point);
4320           else
4321             Fset_window_point (window, make_int (new_point));
4322
4323           retval = line_at_center (w, CURRENT_DISP, 0, 0);
4324         }
4325       else
4326         {
4327           start = marker_position (w->start[CURRENT_DISP]);
4328           if (start < BUF_BEGV (b))
4329             start = BUF_BEGV (b);
4330           else if (start > BUF_ZV (b))
4331             start = BUF_ZV (b);
4332
4333           if (selected)
4334             new_point = BUF_PT (b);
4335           else
4336             new_point = marker_position (w->pointm[CURRENT_DISP]);
4337
4338           new_point = point_at_center (w, CMOTION_DISP, start, BUF_PT (b));
4339
4340           if (selected)
4341             BUF_SET_PT (b, new_point);
4342           else
4343             Fset_window_point (window, make_int (new_point));
4344
4345           retval = line_at_center (w, CMOTION_DISP, start, BUF_PT (b));
4346         }
4347
4348       return make_int (retval);
4349     }
4350   else
4351     {
4352       /* #### Is this going to work right when at eob? */
4353       arg = Fprefix_numeric_value (arg);
4354       if (XINT (arg) < 0)
4355         XSETINT (arg, XINT (arg) + height);
4356     }
4357
4358   start = marker_position (w->start[CURRENT_DISP]);
4359   if (start < BUF_BEGV (b) || start > BUF_ZV (b))
4360     {
4361       if (selected)
4362         new_point = BUF_PT (b);
4363       else
4364         new_point = marker_position (w->pointm[CURRENT_DISP]);
4365
4366       new_point = vmotion (XWINDOW (window), new_point, -height / 2, 0);
4367
4368       if (selected)
4369         BUF_SET_PT (b, new_point);
4370       else
4371         Fset_window_point (window, make_int (new_point));
4372
4373       Fset_marker (w->start[CURRENT_DISP], make_int (new_point),
4374                    w->buffer);
4375       w->start_at_line_beg = beginning_of_line_p (b, new_point);
4376       w->force_start = 1;
4377     }
4378   else
4379     {
4380       if (selected)
4381         BUF_SET_PT (b, start);
4382       else
4383         Fset_window_point (window, make_int (start));
4384     }
4385
4386   if (selected)
4387     return Fvertical_motion (arg, window, Qnil);
4388   else
4389     {
4390       int vpos;
4391       new_point = vmotion (XWINDOW (window),
4392                            marker_position (w->pointm[CURRENT_DISP]),
4393                            XINT (arg), &vpos);
4394       Fset_window_point (window, make_int (new_point));
4395       return make_int (vpos);
4396     }
4397 }
4398
4399 \f
4400 static int
4401 map_windows_1 (Lisp_Object window,
4402                int (*mapfun) (struct window *w, void *closure),
4403                void *closure)
4404 {
4405   for (; !NILP (window); window = XWINDOW (window)->next)
4406     {
4407       int retval;
4408       struct window *w = XWINDOW (window);
4409
4410       if (!NILP (w->vchild))
4411         retval = map_windows_1 (w->vchild, mapfun, closure);
4412       else if (!NILP (w->hchild))
4413         retval = map_windows_1 (w->hchild, mapfun, closure);
4414       else
4415         retval = (mapfun) (w, closure);
4416
4417       if (retval)
4418         return retval;
4419     }
4420
4421   return 0;
4422 }
4423
4424 /* Map MAPFUN over the windows in F.  CLOSURE is passed to each
4425    invocation of MAPFUN.  If any invocation of MAPFUN returns
4426    non-zero, the mapping is halted.  Otherwise, map_windows() maps
4427    over all windows in F.
4428
4429    If MAPFUN creates or deletes windows, the behaviour is undefined.  */
4430
4431 int
4432 map_windows (struct frame *f, int (*mapfun) (struct window *w, void *closure),
4433              void *closure)
4434 {
4435   if (f)
4436     return map_windows_1 (FRAME_ROOT_WINDOW (f), mapfun, closure);
4437   else
4438     {
4439       Lisp_Object frmcons, devcons, concons;
4440
4441       FRAME_LOOP_NO_BREAK(frmcons, devcons, concons)
4442         {
4443           int v = map_windows_1 (FRAME_ROOT_WINDOW (XFRAME (XCAR (frmcons))),
4444                                  mapfun, closure);
4445           if (v)     
4446             return v;
4447         }
4448     }
4449
4450   return 0;
4451 }
4452
4453 \f
4454 static void
4455 modeline_shadow_thickness_changed (Lisp_Object specifier, struct window *w,
4456                                    Lisp_Object oldval)
4457 {
4458   w->shadow_thickness_changed = 1;
4459   MARK_WINDOWS_CHANGED (w);
4460 }
4461
4462 static void
4463 vertical_divider_changed_in_window (Lisp_Object specifier, 
4464                                     struct window *w, 
4465                                     Lisp_Object oldval)
4466 {
4467   MARK_WINDOWS_CHANGED (w);
4468   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (XFRAME (WINDOW_FRAME (w)));
4469 }
4470
4471 /* also used in scrollbar.c */
4472 void
4473 some_window_value_changed (Lisp_Object specifier, struct window *w,
4474                            Lisp_Object oldval)
4475 {
4476   MARK_WINDOWS_CHANGED (w);
4477 }
4478
4479 #ifdef MEMORY_USAGE_STATS
4480
4481 struct window_stats
4482 {
4483   int face;
4484   int glyph;
4485 #ifdef HAVE_SCROLLBARS
4486   int scrollbar;
4487 #endif
4488   int line_start;
4489   int other_redisplay;
4490   int other;
4491 };
4492
4493 static void
4494 compute_window_mirror_usage (struct window_mirror *mir,
4495                              struct window_stats *stats,
4496                              struct overhead_stats *ovstats)
4497 {
4498   if (!mir)
4499     return;
4500   stats->other += malloced_storage_size (mir, sizeof (struct window_mirror),
4501                                          ovstats);
4502 #ifdef HAVE_SCROLLBARS
4503   {
4504     struct device *d = XDEVICE (FRAME_DEVICE (mir->frame));
4505
4506     stats->scrollbar +=
4507       compute_scrollbar_instance_usage (d, mir->scrollbar_vertical_instance,
4508                                         ovstats);
4509     stats->scrollbar +=
4510       compute_scrollbar_instance_usage (d, mir->scrollbar_horizontal_instance,
4511                                         ovstats);
4512   }
4513 #endif /* HAVE_SCROLLBARS */
4514   stats->other_redisplay +=
4515     compute_display_line_dynarr_usage (mir->current_display_lines, ovstats);
4516   stats->other_redisplay +=
4517     compute_display_line_dynarr_usage (mir->desired_display_lines, ovstats);
4518 }
4519
4520 static void
4521 compute_window_usage (struct window *w, struct window_stats *stats,
4522                       struct overhead_stats *ovstats)
4523 {
4524   xzero (*stats);
4525   stats->other += malloced_storage_size (w, sizeof (struct window), ovstats);
4526   stats->face += compute_face_cachel_usage (w->face_cachels, ovstats);
4527   stats->glyph += compute_glyph_cachel_usage (w->glyph_cachels, ovstats);
4528   stats->line_start +=
4529     compute_line_start_cache_dynarr_usage (w->line_start_cache, ovstats);
4530   compute_window_mirror_usage (find_window_mirror (w), stats, ovstats);
4531 }
4532
4533 DEFUN ("window-memory-usage", Fwindow_memory_usage, 1, 1, 0, /*
4534 Return stats about the memory usage of window WINDOW.
4535 The values returned are in the form of an alist of usage types and byte
4536 counts.  The byte counts attempt to encompass all the memory used
4537 by the window (separate from the memory logically associated with a
4538 buffer or frame), including internal structures and any malloc()
4539 overhead associated with them.  In practice, the byte counts are
4540 underestimated because certain memory usage is very hard to determine
4541 \(e.g. the amount of memory used inside the Xt library or inside the
4542 X server) and because there is other stuff that might logically
4543 be associated with a window, buffer, or frame (e.g. window configurations,
4544 glyphs) but should not obviously be included in the usage counts.
4545
4546 Multiple slices of the total memory usage may be returned, separated
4547 by a nil.  Each slice represents a particular view of the memory, a
4548 particular way of partitioning it into groups.  Within a slice, there
4549 is no overlap between the groups of memory, and each slice collectively
4550 represents all the memory concerned.
4551 */
4552        (window))
4553 {
4554   struct window_stats stats;
4555   struct overhead_stats ovstats;
4556   Lisp_Object val = Qnil;
4557
4558   CHECK_WINDOW (window); /* dead windows should be allowed, no? */
4559   xzero (ovstats);
4560   compute_window_usage (XWINDOW (window), &stats, &ovstats);
4561
4562   val = acons (Qface_cache,          make_int (stats.face),              val);
4563   val = acons (Qglyph_cache,         make_int (stats.glyph),             val);
4564 #ifdef HAVE_SCROLLBARS
4565   val = acons (Qscrollbar_instances, make_int (stats.scrollbar),         val);
4566 #endif
4567   val = acons (Qline_start_cache,    make_int (stats.line_start),        val);
4568   val = acons (Qother_redisplay,     make_int (stats.other_redisplay),   val);
4569   val = acons (Qother,               make_int (stats.other),             val);
4570   val = Fcons (Qnil, val);
4571   val = acons (Qactually_requested,  make_int (ovstats.was_requested),   val);
4572   val = acons (Qmalloc_overhead,     make_int (ovstats.malloc_overhead), val);
4573   val = acons (Qdynarr_overhead,     make_int (ovstats.dynarr_overhead), val);
4574
4575   return Fnreverse (val);
4576 }
4577
4578 #endif /* MEMORY_USAGE_STATS */
4579
4580 \f
4581 /************************************************************************/
4582 /*                         Window configurations                        */
4583 /************************************************************************/
4584
4585 /* #### This window configuration stuff has had serious bugs lurking in it
4586    for years; it would be a -huge- win if this was reimplemented in lisp.
4587  */
4588
4589 /* If you add anything to this structure make sure saved_window_equal
4590    knows about it. */
4591 struct saved_window
4592 {
4593   Lisp_Object window;         /* window */
4594   Lisp_Object buffer;         /* buffer */
4595   Lisp_Object start;          /* copied marker */
4596   Lisp_Object pointm;         /* copied marker */
4597   Lisp_Object sb_point;       /* copied marker */
4598   Lisp_Object mark;           /* copied marker */
4599   int pixel_left;
4600   int pixel_top;
4601   int pixel_width;
4602   int pixel_height;
4603   int hscroll;
4604   int modeline_hscroll;
4605   int parent_index;           /* index into saved_windows */
4606   int prev_index;             /* index into saved_windows */
4607   char start_at_line_beg; /* boolean */
4608
4609 #define WINDOW_SLOT_DECLARATION
4610 #define WINDOW_SLOT(slot, compare) Lisp_Object slot
4611 #include "winslots.h"
4612 };
4613
4614 /* If you add anything to this structure make sure window_config_equal
4615    knows about it. */
4616 struct window_config
4617 {
4618   struct lcrecord_header header;
4619   int frame_width;
4620   int frame_height;
4621 #if 0 /* FSFmacs */
4622   Lisp_Object selected_frame;
4623 #endif
4624   Lisp_Object current_window;
4625   Lisp_Object current_buffer;
4626   Lisp_Object minibuffer_scroll_window;
4627   Lisp_Object root_window;
4628   /* Record the values of window-min-width and window-min-height
4629      so that window sizes remain consistent with them.  */
4630   int min_width, min_height;
4631   int saved_windows_count;
4632   /* Zero-sized arrays aren't ANSI C */
4633   struct saved_window saved_windows[1];
4634 };
4635
4636 #define SAVED_WINDOW_N(conf, n) (&((conf)->saved_windows[(n)]))
4637 #define XWINDOW_CONFIGURATION(x) XRECORD (x, window_configuration, struct window_config)
4638 #define XSETWINDOW_CONFIGURATION(x, p) XSETRECORD (x, p, window_configuration)
4639 #define WINDOW_CONFIGURATIONP(x) RECORDP (x, window_configuration)
4640 #define GC_WINDOW_CONFIGURATIONP(x) GC_RECORDP (x, window_configuration)
4641 #define CHECK_WINDOW_CONFIGURATION(x) CHECK_RECORD (x, window_configuration)
4642
4643 static Lisp_Object
4644 mark_window_config (Lisp_Object obj, void (*markobj) (Lisp_Object))
4645 {
4646   struct window_config *config = XWINDOW_CONFIGURATION (obj);
4647   int i;
4648   ((markobj) (config->current_window));
4649   ((markobj) (config->current_buffer));
4650   ((markobj) (config->minibuffer_scroll_window));
4651   ((markobj) (config->root_window));
4652
4653   for (i = 0; i < config->saved_windows_count; i++)
4654     {
4655       struct saved_window *s = SAVED_WINDOW_N (config, i);
4656       ((markobj) (s->window));
4657       ((markobj) (s->buffer));
4658       ((markobj) (s->start));
4659       ((markobj) (s->pointm));
4660       ((markobj) (s->sb_point));
4661       ((markobj) (s->mark));
4662 #if 0
4663       /* #### This looked like this. I do not see why specifier cached
4664          values should not be marked, as such specifiers as toolbars
4665          might have GC-able instances. Freed configs are not marked,
4666          aren't they?  -- kkm */
4667       ((markobj) (s->dedicated));
4668 #else
4669 #define WINDOW_SLOT(slot, compare) ((markobj) (s->slot))
4670 #include "winslots.h"
4671 #endif
4672     }
4673   return Qnil;
4674 }
4675
4676 static size_t
4677 sizeof_window_config_for_n_windows (int n)
4678 {
4679   return (sizeof (struct window_config) +
4680           /* n - 1 because zero-sized arrays aren't ANSI C */
4681           (n - 1) *sizeof (struct saved_window));
4682 }
4683
4684 static size_t
4685 sizeof_window_config (CONST void *h)
4686 {
4687   CONST struct window_config *c = (CONST struct window_config *) h;
4688   return sizeof_window_config_for_n_windows (c->saved_windows_count);
4689 }
4690
4691 static void
4692 print_window_config (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
4693 {
4694   struct window_config *config = XWINDOW_CONFIGURATION (obj);
4695   char buf[200];
4696   if (print_readably)
4697     error ("printing unreadable object #<window-configuration 0x%x>",
4698            config->header.uid);
4699   write_c_string ("#<window-configuration ", printcharfun);
4700   sprintf (buf, "0x%x>", config->header.uid);
4701   write_c_string (buf, printcharfun);
4702 }
4703
4704 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION ("window-configuration",
4705                                         window_configuration,
4706                                         mark_window_config,
4707                                         print_window_config,
4708                                         0, 0, 0, sizeof_window_config,
4709                                         struct window_config);
4710
4711
4712 /* Returns a boolean indicating whether the two saved windows are
4713    identical. */
4714 static int
4715 saved_window_equal (struct saved_window *win1, struct saved_window *win2)
4716 {
4717 #define WINDOW_SLOT(slot, compare)              \
4718   if (!compare (win1->slot, win2->slot))        \
4719     return 0;
4720 #include "winslots.h"
4721
4722   return
4723     EQ (win1->window, win2->window) &&
4724     EQ (win1->buffer, win2->buffer) &&
4725     internal_equal (win1->start,    win2->start, 0) &&
4726     internal_equal (win1->pointm,   win2->pointm, 0) &&
4727     internal_equal (win1->sb_point, win2->sb_point, 0) &&
4728     internal_equal (win1->mark,     win2->mark, 0) &&
4729     win1->pixel_left   == win2->pixel_left &&
4730     win1->pixel_top    == win2->pixel_top &&
4731     win1->pixel_width  == win2->pixel_width &&
4732     win1->pixel_height == win2->pixel_height &&
4733     win1->hscroll      == win2->hscroll &&
4734     win1->modeline_hscroll == win2->modeline_hscroll &&
4735     win1->parent_index == win2->parent_index &&
4736     win1->prev_index   == win2->prev_index &&
4737     win1->start_at_line_beg == win2->start_at_line_beg;
4738 }
4739
4740 /* Returns a boolean indicating whether the two given configurations
4741    are identical. */
4742 static int
4743 window_config_equal (Lisp_Object conf1, Lisp_Object conf2)
4744 {
4745   struct window_config *fig1, *fig2;
4746   int i;
4747
4748   /* First check if they are truly the same. */
4749   if (EQ (conf1, conf2))
4750     return 1;
4751
4752   fig1 = XWINDOW_CONFIGURATION (conf1);
4753   fig2 = XWINDOW_CONFIGURATION (conf2);
4754
4755   if (!((fig1->saved_windows_count == fig2->saved_windows_count) &&
4756         EQ (fig1->current_window,           fig2->current_window) &&
4757         EQ (fig1->current_buffer,           fig2->current_buffer) &&
4758         EQ (fig1->root_window,              fig2->root_window) &&
4759         EQ (fig1->minibuffer_scroll_window, fig2->minibuffer_scroll_window) &&
4760         fig1->frame_width  == fig2->frame_width &&
4761         fig1->frame_height == fig2->frame_height))
4762     return 0;
4763
4764   for (i = 0; i < fig1->saved_windows_count; i++)
4765     {
4766       if (!saved_window_equal (SAVED_WINDOW_N (fig1, i),
4767                                SAVED_WINDOW_N (fig2, i)))
4768         return 0;
4769     }
4770
4771   return 1;
4772 }
4773
4774 DEFUN ("window-configuration-p", Fwindow_configuration_p, 1, 1, 0, /*
4775 Return t if OBJECT is a window-configuration object.
4776 */
4777        (obj))
4778 {
4779   return WINDOW_CONFIGURATIONP (obj) ? Qt : Qnil;
4780 }
4781
4782 static int
4783 mark_windows_in_use_closure (struct window *w, void *closure)
4784 {
4785   int mark = *(int *)closure;
4786   w->config_mark = mark;
4787   return 0;
4788 }
4789
4790 static void
4791 mark_windows_in_use (struct frame *f, int mark)
4792 {
4793   map_windows (f, mark_windows_in_use_closure, &mark);
4794 }
4795
4796 /* Lisp_Object return value so it can be used in record_unwind_protect() */
4797 static Lisp_Object
4798 free_window_configuration (Lisp_Object window_config)
4799 {
4800   int i;
4801   struct window_config *config = XWINDOW_CONFIGURATION (window_config);
4802
4803   /* Free all the markers.  It's not completely necessary that
4804      we do this (window configs sitting in a free list aren't
4805      marked normally so the markers wouldn't be marked anyway)
4806      but it's more efficient. */
4807   for (i = 0; i < config->saved_windows_count; i++)
4808     {
4809       struct saved_window *p = SAVED_WINDOW_N (config, i);
4810
4811       if (!NILP (p->pointm))
4812         {
4813           free_marker (XMARKER (p->pointm));
4814           p->pointm = Qnil;
4815         }
4816       if (!NILP (p->start))
4817         {
4818           free_marker (XMARKER (p->start));
4819           p->start = Qnil;
4820         }
4821       if (!NILP (p->sb_point))
4822         {
4823           free_marker (XMARKER (p->sb_point));
4824           p->sb_point = Qnil;
4825         }
4826       if (!NILP (p->mark))
4827         {
4828           free_marker (XMARKER (p->mark));
4829           p->mark = Qnil;
4830         }
4831     }
4832
4833   if (config->saved_windows_count <= countof (Vwindow_configuration_free_list))
4834     free_managed_lcrecord (Vwindow_configuration_free_list
4835                            [config->saved_windows_count - 1],
4836                            window_config);
4837
4838   return Qnil;
4839 }
4840
4841 DEFUN ("set-window-configuration", Fset_window_configuration, 1, 1, 0, /*
4842 Set the configuration of windows and buffers as specified by CONFIGURATION.
4843 CONFIGURATION must be a value previously returned
4844 by `current-window-configuration' (which see).
4845 */
4846        (configuration))
4847 {
4848   struct window *w;
4849   struct window_config *config;
4850   struct saved_window *p;
4851   Lisp_Object new_current_buffer;
4852   int k;
4853   Lisp_Object frame;
4854   struct frame *f;
4855   struct gcpro gcpro1;
4856   Lisp_Object old_window_config;
4857   int previous_frame_height;
4858   int previous_frame_width;
4859   int specpdl_count = specpdl_depth ();
4860
4861   GCPRO1 (configuration);
4862
4863   CHECK_WINDOW_CONFIGURATION (configuration);
4864   config = XWINDOW_CONFIGURATION (configuration);
4865
4866   frame = XWINDOW (SAVED_WINDOW_N (config, 0)->window)->frame;
4867   f = XFRAME (frame);
4868
4869   /* Do not signal an error here if the frame was deleted.  There are
4870      reasonable cases where we could get here with a deleted frame and
4871      just want to do close to nothing instead. */
4872
4873   if (FRAME_LIVE_P (f))
4874     {
4875       /* restore the frame characteristics */
4876
4877       new_current_buffer = config->current_buffer;
4878       if (!BUFFER_LIVE_P (XBUFFER (new_current_buffer)))
4879         new_current_buffer = Qnil;
4880
4881       /*
4882        * Assumed precondition:  w->config_mark = 0 for all w
4883        * This procedure should ensure this is true by the time it exits
4884        * to ensure the precondition for future calls.
4885        *
4886        * We use w->config_mark to know whether we're modifying a
4887        * window that is currently visible on the frame (#### we
4888        * should just be able to check whether the window is dead
4889        * or not, but this way is safer?).  As we process each
4890        * window, we set its config_mark to 0.  At the end, we
4891        * go through all the windows that used to be on the frame,
4892        * set each one's config_mark to 0 (to maintain the
4893        * assumed precondition) and delete each one that's no
4894        * longer in use.
4895        *
4896        * #### Using a window-configuration to keep track of
4897        * the current windows is wasteful.  All we need is the
4898        * list of windows, so we could just use a dynarr.
4899        */
4900       old_window_config = Fcurrent_window_configuration (frame);
4901
4902       /* If the new configuration is already equal to the old, then stop
4903          right here.  This saves the work below and it also saves
4904          triggering a full redisplay of this window.  This is a huge win
4905          when using the mouse since the mode motion code uses
4906          save-window-excursion extensively but will rarely cause the
4907          configuration to actually change. */
4908       if (window_config_equal (configuration, old_window_config))
4909         {
4910           free_window_configuration (old_window_config);
4911           UNGCPRO;
4912           return Qnil;
4913         }
4914
4915       /* We can't quit or even check for quit because that may cause
4916          investigation of the frame state, which may crash if the frame is
4917          in an inconsistent state. */
4918       begin_dont_check_for_quit ();
4919       record_unwind_protect (free_window_configuration, old_window_config);
4920
4921       mark_windows_in_use (f, 1);
4922
4923       previous_frame_width = FRAME_WIDTH (f);
4924       previous_frame_height = FRAME_HEIGHT (f);
4925       /* If the frame has been resized since this window configuration was
4926          made, we change the frame to the size specified in the
4927          configuration, restore the configuration, and then resize it
4928          back.  We keep track of the prevailing height in these variables.  */
4929       if (config->frame_height != FRAME_HEIGHT (f)
4930           || config->frame_width != FRAME_WIDTH (f))
4931         change_frame_size (f, config->frame_height, config->frame_width, 0);
4932
4933       /* Temporarily avoid any problems with windows that are smaller
4934          than they are supposed to be.  */
4935       window_min_height = 1;
4936       window_min_width = 1;
4937
4938       /* OK, now restore all the windows in the window config.
4939          This may involve "undeleting" windows, since the
4940          windows in the window config may be deleted.
4941          */
4942       for (k = 0; k < config->saved_windows_count; k++)
4943         {
4944           p = SAVED_WINDOW_N (config, k);
4945           w = XWINDOW (p->window);
4946           w->next = Qnil;
4947
4948           /* The window might be dead.  In this case, its redisplay
4949              structures were freed, so we need to reallocate them. */
4950           if (!w->face_cachels)
4951             {
4952               w->face_cachels = Dynarr_new (face_cachel);
4953               reset_face_cachels (w);
4954             }
4955           if (!w->glyph_cachels)
4956             w->glyph_cachels = Dynarr_new (glyph_cachel);
4957           if (!w->line_start_cache)
4958             w->line_start_cache = Dynarr_new (line_start_cache);
4959           w->dead = 0;
4960
4961           if (p->parent_index >= 0)
4962             w->parent = SAVED_WINDOW_N (config, p->parent_index)->window;
4963           else
4964             w->parent = Qnil;
4965
4966           if (p->prev_index >= 0)
4967             {
4968               w->prev = SAVED_WINDOW_N (config, p->prev_index)->window;
4969
4970               /* This is true for a minibuffer-only frame. */
4971               if (!NILP (w->mini_p) && EQ (w->prev, p->window))
4972                 w->next = Qnil;
4973               else
4974                 XWINDOW (w->prev)->next = p->window;
4975             }
4976           else
4977             {
4978               w->prev = Qnil;
4979               if (!NILP (w->parent))
4980                 {
4981                   if (WINDOW_WIDTH (p) == WINDOW_WIDTH (XWINDOW (w->parent)))
4982                     {
4983                       XWINDOW (w->parent)->vchild = p->window;
4984                       XWINDOW (w->parent)->hchild = Qnil;
4985                     }
4986                   else
4987                     {
4988                       XWINDOW (w->parent)->hchild = p->window;
4989                       XWINDOW (w->parent)->vchild = Qnil;
4990                     }
4991                 }
4992             }
4993           if (!w->config_mark)
4994             {
4995               /* #### This should be equivalent to the window previously
4996                  having been dead.  If we're brave, we'll put in an
4997                  assertion to this effect. */
4998               MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
4999             }
5000           else /* if (!EQ (w->buffer, p->buffer)) */
5001             {
5002               /* With the new redisplay we let it know that a change has
5003                  been made and it will take care of the rest.  If we don't
5004                  tell it something has possibly changed it could lead to
5005                  incorrect display. */
5006               MARK_WINDOWS_CHANGED (w);
5007             }
5008
5009           WINDOW_LEFT (w) = WINDOW_LEFT (p);
5010           WINDOW_TOP (w) = WINDOW_TOP (p);
5011           WINDOW_WIDTH (w) = WINDOW_WIDTH (p);
5012           WINDOW_HEIGHT (w) = WINDOW_HEIGHT (p);
5013           w->hscroll = p->hscroll;
5014           w->modeline_hscroll = p->modeline_hscroll;
5015           w->line_cache_last_updated = Qzero;
5016           SET_LAST_MODIFIED (w, 1);
5017           SET_LAST_FACECHANGE (w);
5018           w->config_mark = 0;
5019
5020 #define WINDOW_SLOT(slot, compare) w->slot = p->slot;
5021 #include "winslots.h"
5022
5023           /* Reinstall the saved buffer and pointers into it.  */
5024           if (NILP (p->buffer))
5025             w->buffer = p->buffer;
5026           else
5027             {
5028               if (BUFFER_LIVE_P (XBUFFER (p->buffer)))
5029                 /* If saved buffer is alive, install it.  */
5030                 {
5031                   w->buffer = p->buffer;
5032                   w->start_at_line_beg = p->start_at_line_beg;
5033                   set_marker_restricted (w->start[CURRENT_DISP],
5034                                          Fmarker_position (p->start),
5035                                          w->buffer);
5036                   set_marker_restricted (w->pointm[CURRENT_DISP],
5037                                          Fmarker_position (p->pointm),
5038                                          w->buffer);
5039                   set_marker_restricted (w->sb_point,
5040                                          Fmarker_position (p->sb_point),
5041                                          w->buffer);
5042                   Fset_marker (XBUFFER (w->buffer)->mark,
5043                                Fmarker_position (p->mark), w->buffer);
5044
5045                   /* As documented in Fcurrent_window_configuration, don't
5046                      save the location of point in the buffer which was current
5047                      when the window configuration was recorded.  */
5048                   if (!EQ (p->buffer, new_current_buffer) &&
5049                       XBUFFER (p->buffer) == current_buffer)
5050                     Fgoto_char (w->pointm[CURRENT_DISP], Qnil);
5051                 }
5052               else if (NILP (w->buffer) ||
5053                        !BUFFER_LIVE_P (XBUFFER (w->buffer)))
5054                 /* Else if window's old buffer is dead too, get a live one.  */
5055                 {
5056                   /* #### The following line makes me nervous... */
5057                   /* w->buffer = Fcdr (Fcar (XFRAME (w->frame)->buffer_alist));*/
5058                   w->buffer = Fget_buffer_create (QSscratch);
5059                   /* w->buffer = Fother_buffer (Qnil, w->frame, Qnil); */
5060                   /* This will set the markers to beginning of visible
5061                      range.  */
5062                   set_marker_restricted (w->start[CURRENT_DISP], Qzero, w->buffer);
5063                   set_marker_restricted (w->pointm[CURRENT_DISP], Qzero,
5064                                          w->buffer);
5065                   set_marker_restricted (w->sb_point, Qzero, w->buffer);
5066                   w->start_at_line_beg = 1;
5067                 }
5068               else
5069                 /* Keeping window's old buffer; make sure the markers
5070                    are real.  */
5071                 {
5072                   /* Set window markers at start of visible range.  */
5073                   if (XMARKER (w->start[CURRENT_DISP])->buffer == 0)
5074                     set_marker_restricted (w->start[CURRENT_DISP], Qzero,
5075                                            w->buffer);
5076                   if (XMARKER (w->sb_point)->buffer == 0)
5077                     set_marker_restricted (w->sb_point, Qzero, w->buffer);
5078                   if (XMARKER (w->pointm[CURRENT_DISP])->buffer == 0)
5079                     set_marker_restricted (w->pointm[CURRENT_DISP],
5080                                            make_int
5081                                            (BUF_PT (XBUFFER (w->buffer))),
5082                                            w->buffer);
5083                   w->start_at_line_beg = 1;
5084                 }
5085             }
5086         }
5087
5088       FRAME_ROOT_WINDOW (f) = config->root_window;
5089       /* Note that FSFmacs unilaterally calls Fselect_window() here, and
5090          then calls do_switch_frame() below to select the frame that was
5091          recorded in the window config as being selected.
5092
5093          Instead, we don't ever change the selected frame, and either
5094          call Fselect_window() below if the window config's frame is
5095          currently selected, or just set the selected window of the
5096          window config's frame. */
5097
5098       /* Set the frame height to the value it had before this function.  */
5099       if (previous_frame_height != FRAME_HEIGHT (f)
5100           || previous_frame_width != FRAME_WIDTH (f))
5101         change_frame_size (f, previous_frame_height, previous_frame_width, 0);
5102
5103       /* If restoring in the current frame make the window current,
5104          otherwise just update the frame selected_window slot to be
5105          the restored current_window. */
5106       if (f == selected_frame ())
5107         {
5108           /* When using `pop-window-configuration', often the minibuffer
5109              ends up as the selected window even though it's not active ...
5110              I really don't know the cause of this, but it should never
5111              happen.  This kludge should fix it.
5112
5113              #### Find out why this is really going wrong. */
5114           if (!minibuf_level &&
5115               MINI_WINDOW_P (XWINDOW (config->current_window)))
5116             Fselect_window (Fnext_window (config->current_window,
5117                                           Qnil, Qnil, Qnil),
5118                             Qnil);
5119           else
5120             Fselect_window (config->current_window, Qnil);
5121           if (!NILP (new_current_buffer))
5122             Fset_buffer (new_current_buffer);
5123           else
5124             Fset_buffer (XWINDOW (Fselected_window (Qnil))->buffer);
5125         }
5126       else
5127         set_frame_selected_window (f, config->current_window);
5128     }
5129   else
5130     old_window_config = Qnil; /* Warning suppression */
5131
5132   /* Restore the minimum heights recorded in the configuration.  */
5133   window_min_height = config->min_height;
5134   window_min_width = config->min_width;
5135
5136 #if 0 /* FSFmacs */
5137   /* see above comment */
5138   /* Fselect_window will have made f the selected frame, so we
5139      reselect the proper frame here.  Fhandle_switch_frame will change the
5140      selected window too, but that doesn't make the call to
5141      Fselect_window above totally superfluous; it still sets f's
5142      selected window.  */
5143   if (FRAME_LIVE_P (XFRAME (config->selected_frame)))
5144     do_switch_frame (config->selected_frame, Qnil, 0);
5145 #endif
5146
5147   Vminibuffer_scroll_window = config->minibuffer_scroll_window;
5148
5149   if (FRAME_LIVE_P (f))
5150     {
5151       /* Do this before calling recompute_all_cached_specifiers_in_window()
5152          so that things like redisplay_redraw_cursor() won't abort due
5153          to no window mirror present. */
5154       f->mirror_dirty = 1;
5155
5156       config = XWINDOW_CONFIGURATION (old_window_config);
5157       for (k = 0; k < config->saved_windows_count; k++)
5158         {
5159           p = SAVED_WINDOW_N (config, k);
5160           w = XWINDOW (p->window);
5161           /* Remember, we set w->config_mark on all currently visible
5162              windows, and reset it on all newly visible windows.
5163              Any windows still marked need to be deleted. */
5164           if (w->config_mark)
5165             {
5166               mark_window_as_deleted (w);
5167               w->config_mark = 0;
5168             }
5169           else
5170             {
5171               /* We just potentially changed the window's buffer and
5172                  potentially turned a dead window into a live one,
5173                  so we need to recompute the cached specifier values. */
5174               recompute_all_cached_specifiers_in_window (w);
5175             }
5176         }
5177     }
5178
5179   /* Now restore things, when everything else if OK. */
5180
5181   unbind_to (specpdl_count, Qnil);
5182
5183   UNGCPRO;
5184
5185   return Qnil;
5186 }
5187
5188 /* Mark all subwindows of a window as deleted.  The argument
5189    W is actually the subwindow tree of the window in question. */
5190
5191 void
5192 delete_all_subwindows (struct window *w)
5193 {
5194   if (!NILP (w->next))   delete_all_subwindows (XWINDOW (w->next));
5195   if (!NILP (w->vchild)) delete_all_subwindows (XWINDOW (w->vchild));
5196   if (!NILP (w->hchild)) delete_all_subwindows (XWINDOW (w->hchild));
5197
5198   mark_window_as_deleted (w);
5199 }
5200
5201 \f
5202 static int
5203 count_windows (struct window *window)
5204 {
5205   return 1 +
5206     (!NILP (window->next)   ? count_windows (XWINDOW (window->next))   : 0) +
5207     (!NILP (window->vchild) ? count_windows (XWINDOW (window->vchild)) : 0) +
5208     (!NILP (window->hchild) ? count_windows (XWINDOW (window->hchild)) : 0);
5209 }
5210
5211 static int
5212 saved_window_index (Lisp_Object window, struct window_config *config, int lim)
5213 {
5214   int j;
5215   for (j = 0; j < lim; j++)
5216     {
5217       if (EQ (SAVED_WINDOW_N (config, j)->window, window))
5218         return j;
5219     }
5220   abort ();
5221   return 0;     /* suppress compiler warning */
5222 }
5223
5224 static int
5225 save_window_save (Lisp_Object window, struct window_config *config, int i)
5226 {
5227   struct window *w;
5228
5229   for (; !NILP (window); window = w->next)
5230     {
5231       struct saved_window *p = SAVED_WINDOW_N (config, i);
5232
5233       w = XWINDOW (window);
5234       i++;
5235       p->window = window;
5236       p->buffer = w->buffer;
5237       WINDOW_LEFT (p) = WINDOW_LEFT (w);
5238       WINDOW_TOP (p) = WINDOW_TOP (w);
5239       WINDOW_WIDTH (p) = WINDOW_WIDTH (w);
5240       WINDOW_HEIGHT (p) = WINDOW_HEIGHT (w);
5241       p->hscroll = w->hscroll;
5242       p->modeline_hscroll = w->modeline_hscroll;
5243
5244 #define WINDOW_SLOT(slot, compare) p->slot = w->slot;
5245 #include "winslots.h"
5246
5247       if (!NILP (w->buffer))
5248         {
5249           /* Save w's value of point in the window configuration.
5250              If w is the selected window, then get the value of point
5251              from the buffer; pointm is garbage in the selected window.  */
5252           if (EQ (window, Fselected_window (Qnil)))
5253             {
5254               p->pointm = noseeum_make_marker ();
5255               Fset_marker (p->pointm,
5256                            make_int (BUF_PT (XBUFFER (w->buffer))),
5257                            w->buffer);
5258             }
5259           else
5260             p->pointm = noseeum_copy_marker (w->pointm[CURRENT_DISP], Qnil);
5261
5262           p->start = noseeum_copy_marker (w->start[CURRENT_DISP], Qnil);
5263           p->sb_point = noseeum_copy_marker (w->sb_point, Qnil);
5264           p->start_at_line_beg = w->start_at_line_beg;
5265
5266           p->mark = noseeum_copy_marker (XBUFFER (w->buffer)->mark, Qnil);
5267         }
5268       else
5269         {
5270           p->pointm = Qnil;
5271           p->start = Qnil;
5272           p->sb_point = Qnil;
5273           p->mark = Qnil;
5274           p->start_at_line_beg = 0;
5275         }
5276
5277       if (NILP (w->parent))
5278         p->parent_index = -1;
5279       else
5280         p->parent_index = saved_window_index (w->parent, config, i);
5281       if (NILP (w->prev))
5282         p->prev_index = -1;
5283       else
5284         p->prev_index = saved_window_index (w->prev, config, i);
5285       if (!NILP (w->vchild))
5286         i = save_window_save (w->vchild, config, i);
5287       if (!NILP (w->hchild))
5288         i = save_window_save (w->hchild, config, i);
5289     }
5290
5291   return i;
5292 }
5293
5294 #if 0 /* FSFmacs */
5295 /* Added to doc string:
5296
5297 This also records the currently selected frame, and FRAME's focus
5298 redirection (see `redirect-frame-focus').
5299
5300 */
5301 #endif
5302
5303 DEFUN ("current-window-configuration", Fcurrent_window_configuration, 0, 1, 0, /*
5304 Return an object representing the current window configuration of FRAME.
5305 If FRAME is nil or omitted, use the selected frame.
5306 This describes the number of windows, their sizes and current buffers,
5307 and for each displayed buffer, where display starts, and the positions of
5308 point and mark.  An exception is made for point in the current buffer:
5309 its value is -not- saved.
5310 */
5311        (frame))
5312 {
5313   Lisp_Object result;
5314   struct frame *f = decode_frame (frame);
5315   struct window_config *config;
5316   int n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
5317
5318   if (n_windows <= countof (Vwindow_configuration_free_list))
5319     config = XWINDOW_CONFIGURATION (allocate_managed_lcrecord
5320                                     (Vwindow_configuration_free_list
5321                                      [n_windows - 1]));
5322   else
5323     /* More than ten windows; just allocate directly */
5324     config = (struct window_config *)
5325       alloc_lcrecord (sizeof_window_config_for_n_windows (n_windows),
5326                       lrecord_window_configuration);
5327   XSETWINDOW_CONFIGURATION (result, config);
5328
5329   config->frame_width = FRAME_WIDTH (f);
5330   config->frame_height = FRAME_HEIGHT (f);
5331   config->current_window = FRAME_SELECTED_WINDOW (f);
5332   XSETBUFFER (config->current_buffer, current_buffer);
5333   config->minibuffer_scroll_window = Vminibuffer_scroll_window;
5334   config->root_window = FRAME_ROOT_WINDOW (f);
5335   config->min_height = window_min_height;
5336   config->min_width = window_min_width;
5337   config->saved_windows_count = n_windows;
5338   save_window_save (FRAME_ROOT_WINDOW (f), config, 0);
5339   return result;
5340 }
5341
5342 Lisp_Object
5343 save_window_excursion_unwind (Lisp_Object window_config)
5344 {
5345   Lisp_Object val = Fset_window_configuration (window_config);
5346   free_window_configuration (window_config);
5347   return val;
5348 }
5349
5350 DEFUN ("save-window-excursion", Fsave_window_excursion, 0, UNEVALLED, 0, /*
5351 Execute body, preserving window sizes and contents.
5352 Restores which buffer appears in which window, where display starts,
5353 as well as the current buffer.
5354 Does not restore the value of point in current buffer.
5355 */
5356        (args))
5357 {
5358   /* This function can GC */
5359   Lisp_Object val;
5360   int speccount = specpdl_depth ();
5361
5362   record_unwind_protect (save_window_excursion_unwind,
5363                          Fcurrent_window_configuration (Qnil));
5364   val = Fprogn (args);
5365   return unbind_to (speccount, val);
5366 }
5367
5368 \f
5369 #ifdef DEBUG_XEMACS
5370 /* This is short and simple in elisp, but... it was written to debug
5371    problems purely on the C side.  That is where we need to call it so
5372    here it is. */
5373 static void
5374 debug_print_window (Lisp_Object window, int level)
5375 {
5376   int i;
5377   Lisp_Object child = Fwindow_first_vchild (window);
5378
5379   if (NILP (child))
5380     child = Fwindow_first_hchild (window);
5381
5382   for (i = level; i > 0; i--)
5383     putc ('\t', stderr);
5384
5385   fputs ("#<window", stderr);
5386   {
5387     Lisp_Object buffer = XWINDOW (window)->buffer;
5388     if (!NILP (buffer) && BUFFERP (buffer))
5389       fprintf (stderr, " on %s", XSTRING_DATA (XBUFFER (buffer)->name));
5390   }
5391   fprintf (stderr, " 0x%x>", XWINDOW (window)->header.uid);
5392
5393   while (!NILP (child))
5394     {
5395       debug_print_window (child, level + 1);
5396       child = Fwindow_next_child (child);
5397     }
5398 }
5399
5400 void debug_print_windows (struct frame *f);
5401 void
5402 debug_print_windows (struct frame *f)
5403 {
5404   debug_print_window (f->root_window, 0);
5405   putc ('\n', stderr);
5406 }
5407 #endif /* DEBUG_XEMACS */
5408
5409 \f
5410 /************************************************************************/
5411 /*                            initialization                            */
5412 /************************************************************************/
5413
5414 void
5415 syms_of_window (void)
5416 {
5417   defsymbol (&Qwindowp, "windowp");
5418   defsymbol (&Qwindow_live_p, "window-live-p");
5419   defsymbol (&Qwindow_configurationp, "window-configuration-p");
5420   defsymbol (&Qscroll_up, "scroll-up");
5421   defsymbol (&Qscroll_down, "scroll-down");
5422   defsymbol (&Qtemp_buffer_show_hook, "temp-buffer-show-hook");
5423   defsymbol (&Qdisplay_buffer, "display-buffer");
5424
5425 #ifdef MEMORY_USAGE_STATS
5426   defsymbol (&Qface_cache, "face-cache");
5427   defsymbol (&Qglyph_cache, "glyph-cache");
5428   defsymbol (&Qline_start_cache, "line-start-cache");
5429 #ifdef HAVE_SCROLLBARS
5430   defsymbol (&Qscrollbar_instances, "scrollbar-instances");
5431 #endif
5432   defsymbol (&Qother_redisplay, "other-redisplay");
5433   /* Qother in general.c */
5434 #endif
5435
5436   DEFSUBR (Fselected_window);
5437   DEFSUBR (Fminibuffer_window);
5438   DEFSUBR (Fwindow_minibuffer_p);
5439   DEFSUBR (Fwindowp);
5440   DEFSUBR (Fwindow_live_p);
5441   DEFSUBR (Fwindow_first_hchild);
5442   DEFSUBR (Fwindow_first_vchild);
5443   DEFSUBR (Fwindow_next_child);
5444   DEFSUBR (Fwindow_previous_child);
5445   DEFSUBR (Fwindow_parent);
5446   DEFSUBR (Fwindow_lowest_p);
5447   DEFSUBR (Fwindow_highest_p);
5448   DEFSUBR (Fwindow_leftmost_p);
5449   DEFSUBR (Fwindow_rightmost_p);
5450   DEFSUBR (Fpos_visible_in_window_p);
5451   DEFSUBR (Fwindow_buffer);
5452   DEFSUBR (Fwindow_frame);
5453   DEFSUBR (Fwindow_height);
5454   DEFSUBR (Fwindow_displayed_height);
5455   DEFSUBR (Fwindow_width);
5456   DEFSUBR (Fwindow_pixel_height);
5457   DEFSUBR (Fwindow_pixel_width);
5458   DEFSUBR (Fwindow_text_area_pixel_height);
5459   DEFSUBR (Fwindow_displayed_text_pixel_height);
5460   DEFSUBR (Fwindow_text_area_pixel_width);
5461   DEFSUBR (Fwindow_hscroll);
5462 #ifdef MODELINE_IS_SCROLLABLE
5463   DEFSUBR (Fmodeline_hscroll);
5464   DEFSUBR (Fset_modeline_hscroll);
5465 #endif /* MODELINE_IS_SCROLLABLE */
5466 #if 0 /* bogus FSF crock */
5467   DEFSUBR (Fwindow_redisplay_end_trigger);
5468   DEFSUBR (Fset_window_redisplay_end_trigger);
5469 #endif
5470   DEFSUBR (Fset_window_hscroll);
5471   DEFSUBR (Fwindow_pixel_edges);
5472   DEFSUBR (Fwindow_text_area_pixel_edges);
5473   DEFSUBR (Fwindow_point);
5474   DEFSUBR (Fwindow_start);
5475   DEFSUBR (Fwindow_end);
5476   DEFSUBR (Fset_window_point);
5477   DEFSUBR (Fset_window_start);
5478   DEFSUBR (Fwindow_dedicated_p);
5479   DEFSUBR (Fset_window_dedicated_p);
5480   DEFSUBR (Fnext_window);
5481   DEFSUBR (Fprevious_window);
5482   DEFSUBR (Fnext_vertical_window);
5483   DEFSUBR (Fother_window);
5484   DEFSUBR (Fget_lru_window);
5485   DEFSUBR (Fget_largest_window);
5486   DEFSUBR (Fget_buffer_window);
5487   DEFSUBR (Fwindow_left_margin_pixel_width);
5488   DEFSUBR (Fwindow_right_margin_pixel_width);
5489   DEFSUBR (Fdelete_other_windows);
5490   DEFSUBR (Fdelete_windows_on);
5491   DEFSUBR (Freplace_buffer_in_windows);
5492   DEFSUBR (Fdelete_window);
5493   DEFSUBR (Fset_window_buffer);
5494   DEFSUBR (Fselect_window);
5495   DEFSUBR (Fsplit_window);
5496   DEFSUBR (Fenlarge_window);
5497   DEFSUBR (Fenlarge_window_pixels);
5498   DEFSUBR (Fshrink_window);
5499   DEFSUBR (Fshrink_window_pixels);
5500   DEFSUBR (Fscroll_up);
5501   DEFSUBR (Fscroll_down);
5502   DEFSUBR (Fscroll_left);
5503   DEFSUBR (Fscroll_right);
5504   DEFSUBR (Fother_window_for_scrolling);
5505   DEFSUBR (Fscroll_other_window);
5506   DEFSUBR (Fcenter_to_window_line);
5507   DEFSUBR (Fmove_to_window_line);
5508 #ifdef MEMORY_USAGE_STATS
5509   DEFSUBR (Fwindow_memory_usage);
5510 #endif
5511   DEFSUBR (Fwindow_configuration_p);
5512   DEFSUBR (Fset_window_configuration);
5513   DEFSUBR (Fcurrent_window_configuration);
5514   DEFSUBR (Fsave_window_excursion);
5515 }
5516
5517 void
5518 vars_of_window (void)
5519 {
5520   /* Make sure all windows get marked */
5521   minibuf_window = Qnil;
5522   staticpro (&minibuf_window);
5523
5524   DEFVAR_BOOL ("scroll-on-clipped-lines", &scroll_on_clipped_lines /*
5525 *Non-nil means to scroll if point lands on a line which is clipped.
5526 */ );
5527   scroll_on_clipped_lines = 1;
5528
5529   DEFVAR_LISP ("temp-buffer-show-hook", &Vtemp_buffer_show_hook /*
5530 See `temp-buffer-show-function'.
5531 */ );
5532   Vtemp_buffer_show_hook = Qnil;
5533
5534   DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function /*
5535 Non-nil means call as function to display a help buffer.
5536 The function is called with one argument, the buffer to be displayed.
5537 Used by `with-output-to-temp-buffer'.
5538 If this function is used, then it must do the entire job of showing
5539 the buffer; `temp-buffer-show-hook' is not run unless this function runs it.
5540 */ );
5541   Vtemp_buffer_show_function = Qnil;
5542
5543   DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuffer_scroll_window /*
5544 Non-nil means it is the window that \\<minibuffer-local-map>\\[scroll-other-window] in minibuffer should scroll.
5545 */ );
5546   Vminibuffer_scroll_window = Qnil;
5547
5548   DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer /*
5549 If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.
5550 */ );
5551   Vother_window_scroll_buffer = Qnil;
5552
5553   DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines /*
5554 *Number of lines of continuity when scrolling by screenfuls.
5555 */ );
5556   next_screen_context_lines = 2;
5557
5558   DEFVAR_INT ("window-min-height", &window_min_height /*
5559 *Delete any window less than this tall (including its modeline).
5560 */ );
5561   window_min_height = 4;
5562
5563   DEFVAR_INT ("window-min-width", &window_min_width /*
5564 *Delete any window less than this wide.
5565 */ );
5566   window_min_width = 10;
5567
5568   {
5569     int i;
5570
5571     for (i = 0; i < countof (Vwindow_configuration_free_list); i++)
5572       {
5573         Vwindow_configuration_free_list[i] =
5574           make_lcrecord_list (sizeof_window_config_for_n_windows (i + 1),
5575                               lrecord_window_configuration);
5576         staticpro (&Vwindow_configuration_free_list[i]);
5577       }
5578   }
5579 }
5580
5581 void
5582 specifier_vars_of_window (void)
5583 {
5584   DEFVAR_SPECIFIER ("modeline-shadow-thickness", &Vmodeline_shadow_thickness /*
5585 *How thick to draw 3D shadows around modelines.
5586 If this is set to 0, modelines will be the traditional 2D.  Sizes above
5587 10 will be accepted but the maximum thickness that will be drawn is 10.
5588 This is a specifier; use `set-specifier' to change it.
5589 */ );
5590   Vmodeline_shadow_thickness = Fmake_specifier (Qinteger);
5591   /* The initial value for modeline-shadow-thickness is 2, but if the
5592      user removes all specifications we provide a fallback value of 0,
5593      which is probably what was expected. */
5594   set_specifier_fallback (Vmodeline_shadow_thickness,
5595                           list1 (Fcons (Qnil, Qzero)));
5596   Fadd_spec_to_specifier (Vmodeline_shadow_thickness, make_int (2),
5597                           Qnil, Qnil, Qnil);
5598   set_specifier_caching (Vmodeline_shadow_thickness,
5599                          slot_offset (struct window,
5600                                       modeline_shadow_thickness),
5601                          modeline_shadow_thickness_changed,
5602                          0, 0);
5603   
5604   DEFVAR_SPECIFIER ("has-modeline-p", &Vhas_modeline_p /*
5605 *Whether the modeline should be displayed.
5606 This is a specifier; use `set-specifier' to change it.
5607 */ );
5608   Vhas_modeline_p = Fmake_specifier (Qboolean);
5609   set_specifier_fallback (Vhas_modeline_p,
5610                           list1 (Fcons (Qnil, Qt)));
5611   set_specifier_caching (Vhas_modeline_p,
5612                          slot_offset (struct window,
5613                                       has_modeline_p),
5614                          /* #### It's strange that we need a special
5615                             flag to indicate that the shadow-thickness
5616                             has changed, but not one to indicate that
5617                             the modeline has been turned off or on. */
5618                          some_window_value_changed,
5619                          0, 0);
5620
5621   DEFVAR_SPECIFIER ("vertical-divider-always-visible-p",
5622                     &Vvertical_divider_always_visible_p /*
5623 *Should XEmacs always display vertical dividers between windows.
5624
5625 When this is non-nil, vertical dividers are always shown, and are
5626 draggable.  When it is nil, vertical dividers are shown only when
5627 there are no scrollbars in between windows, and are not draggable.
5628
5629 This is a specifier; use `set-specifier' to change it.
5630 */ );
5631   Vvertical_divider_always_visible_p = Fmake_specifier (Qboolean);
5632   set_specifier_fallback (Vvertical_divider_always_visible_p,
5633                           list1 (Fcons (Qnil, Qt)));
5634   set_specifier_caching (Vvertical_divider_always_visible_p,
5635                          slot_offset (struct window,
5636                                       vertical_divider_always_visible_p),
5637                          vertical_divider_changed_in_window,
5638                          0, 0);
5639
5640   DEFVAR_SPECIFIER ("vertical-divider-shadow-thickness", &Vvertical_divider_shadow_thickness /*
5641 *How thick to draw 3D shadows around vertical dividers. 
5642 This is a specifier; use `set-specifier' to change it.
5643 */ );
5644   Vvertical_divider_shadow_thickness = Fmake_specifier (Qinteger);
5645   set_specifier_fallback (Vvertical_divider_shadow_thickness,
5646                           list1 (Fcons (Qnil, Qzero)));
5647   Fadd_spec_to_specifier (Vvertical_divider_shadow_thickness, make_int (2),
5648                           Qnil, Qnil, Qnil);
5649   set_specifier_caching (Vvertical_divider_shadow_thickness,
5650                          slot_offset (struct window,
5651                                       vertical_divider_shadow_thickness),
5652                          vertical_divider_changed_in_window,
5653                          0, 0);
5654   DEFVAR_SPECIFIER ("vertical-divider-line-width", &Vvertical_divider_line_width /*
5655 *The width of the vertical dividers, not including shadows.
5656
5657 For TTY windows, divider line is always one character wide.  When
5658 instance of this specifier is zero in a TTY window, no divider is
5659 drawn at all between windows.  When non-zero, a one character wide
5660 divider is displayed.
5661
5662 This is a specifier; use `set-specifier' to change it.
5663 */ );
5664
5665   Vvertical_divider_line_width = Fmake_specifier (Qnatnum);
5666   {
5667     Lisp_Object fb = Qnil;
5668 #ifdef HAVE_TTY
5669     fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
5670 #endif
5671 #ifdef HAVE_X_WINDOWS
5672     fb = Fcons (Fcons (list1 (Qx), make_int (3)), fb);
5673 #endif
5674 #ifdef HAVE_MS_WINDOWS
5675     /* #### This should be made magic and made to obey system settings */
5676     fb = Fcons (Fcons (list1 (Qmswindows), make_int (3)), fb);
5677 #endif
5678     set_specifier_fallback (Vvertical_divider_line_width, fb);
5679   }
5680   set_specifier_caching (Vvertical_divider_line_width,
5681                          slot_offset (struct window,
5682                                       vertical_divider_line_width),
5683                          vertical_divider_changed_in_window,
5684                          0, 0);
5685
5686   DEFVAR_SPECIFIER ("vertical-divider-spacing", &Vvertical_divider_spacing /*
5687 *How much space to leave around the vertical dividers.
5688
5689 In TTY windows, spacing is always zero, and the value of this
5690 specifier is ignored.
5691
5692 This is a specifier; use `set-specifier' to change it.
5693 */ );
5694   Vvertical_divider_spacing = Fmake_specifier (Qnatnum);
5695   {
5696     Lisp_Object fb = Qnil;
5697 #ifdef HAVE_TTY
5698     fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
5699 #endif
5700 #ifdef HAVE_X_WINDOWS
5701     /* #### 3D dividers look great on MS Windows with spacing = 0.
5702        Should not the same value be the fallback under X? - kkm */
5703     fb = Fcons (Fcons (list1 (Qx), make_int (2)), fb);
5704 #endif
5705 #ifdef HAVE_MS_WINDOWS
5706     fb = Fcons (Fcons (list1 (Qmswindows), Qzero), fb);
5707 #endif
5708     set_specifier_fallback (Vvertical_divider_spacing, fb);
5709   }
5710   set_specifier_caching (Vvertical_divider_spacing,
5711                          slot_offset (struct window,
5712                                       vertical_divider_spacing),
5713                          vertical_divider_changed_in_window,
5714                          0, 0);
5715 }