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