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