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