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