Coverity fixes
[sxemacs] / src / ui / window.c
1 /* Window creation, deletion and examination for SXEmacs.
2    Copyright (C) 1985-1987, 1992-1995 Free Software Foundation, Inc.
3    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
4    Copyright (C) 1995, 1996 Ben Wing.
5    Copyright (C) 1996 Chuck Thompson.
6    Copyright (C) 2004 Johann "Myrkraverk" Oskarsson.
7
8 This file is part of SXEmacs
9
10 SXEmacs is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 SXEmacs is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
22
23
24 /* Synched up with: FSF 19.30. */
25 /* Beginning to diverge significantly. */
26
27 /*  window-configuraion-hook, by Johann "Myrkraverk" Oskarsson, Jun 2004. */
28
29 /* This file has been Mule-ized. */
30
31 #include <config.h>
32 #include "lisp.h"
33
34 #include "buffer.h"
35 #include "faces.h"
36 #include "frame.h"
37 #include "objects.h"
38 #include "glyphs.h"
39 #include "redisplay.h"
40 #include "window.h"
41 #include "elhash.h"
42 #include "commands.h"
43 #include "gutter.h"
44
45 Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configurationp;
46 Lisp_Object Qdisplay_buffer;
47
48 #if defined MEMORY_USAGE_STATS && !(defined HAVE_BDWGC && defined EF_USE_BDWGC)
49 Lisp_Object Qface_cache, Qglyph_cache, Qline_start_cache, Qother_redisplay;
50 #ifdef HAVE_SCROLLBARS
51 Lisp_Object Qscrollbar_instances;
52 #endif
53 #endif
54
55 extern int allow_deletion_of_last_visible_frame;
56
57 EXFUN(Fnext_window, 4);
58
59 static int window_pixel_width_to_char_width(struct window *w,
60                                             int pixel_width,
61                                             int include_margins_p);
62 static int window_char_width_to_pixel_width(struct window *w,
63                                             int char_width,
64                                             int include_margins_p);
65 static int window_pixel_height_to_char_height(struct window *w,
66                                               int pixel_height,
67                                               int include_gutters_p);
68 static int window_char_height_to_pixel_height(struct window *w,
69                                               int char_height,
70                                               int include_gutters_p);
71 static void change_window_height(Lisp_Object window, int delta,
72                                  Lisp_Object horizontalp, int inpixels);
73
74 /* Thickness of shadow border around 3d modelines. */
75 Lisp_Object Vmodeline_shadow_thickness;
76
77 /* Whether vertical dividers are draggable and displayed */
78 Lisp_Object Vvertical_divider_always_visible_p;
79
80 /* Whether a modeline should be displayed. */
81 Lisp_Object Vhas_modeline_p;
82
83 /* Thickness of shadow border around vertical dividers. */
84 Lisp_Object Vvertical_divider_shadow_thickness;
85
86 /* Divider surface width (not counting 3-d borders) */
87 Lisp_Object Vvertical_divider_line_width;
88
89 /* Spacing between outer edge of divider border and window edge */
90 Lisp_Object Vvertical_divider_spacing;
91
92 /* How much to scroll by per-line. */
93 Lisp_Object Vwindow_pixel_scroll_increment;
94
95 /* Scroll if point lands on the bottom line and that line is partially
96    clipped. */
97 int scroll_on_clipped_lines;
98
99 /* The minibuffer window of the selected frame.
100    Note that you cannot test for minibufferness of an arbitrary window
101    by comparing against this; but you can test for minibufferness of
102    the selected window.  */
103 Lisp_Object minibuf_window;
104
105 /* Non-nil means it is the window for C-M-v to scroll
106    when the minibuffer is selected.  */
107 Lisp_Object Vminibuffer_scroll_window;
108
109 /* Non-nil means this is the buffer whose window C-M-v should scroll.  */
110 Lisp_Object Vother_window_scroll_buffer;
111
112 /* Non-nil means it's the function to call to display temp buffers.  */
113 Lisp_Object Vtemp_buffer_show_function;
114
115 Lisp_Object Vtemp_buffer_show_hook;
116
117 /* If a window gets smaller than either of these, it is removed. */
118 Fixnum window_min_height;
119 Fixnum window_min_width;
120
121 /* Hook run at end of temp_output_buffer_show.  */
122 Lisp_Object Qtemp_buffer_show_hook;
123
124 /* Number of lines of continuity in scrolling by screenfuls.  */
125 Fixnum next_screen_context_lines;
126
127 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
128 /* List of freed window configurations with 1 - 10 windows. */
129 static Lisp_Object Vwindow_configuration_free_list[10];
130 #endif  /* !BDWGC */
131
132 Lisp_Object Qtruncate_partial_width_windows;
133
134 Lisp_Object Qwindow_configuration_hook, Vwindow_configuration_hook;
135
136 #define SET_LAST_MODIFIED(w, cache_too)                         \
137         do {                                                    \
138                 (w)->last_modified[CURRENT_DISP] = Qzero;       \
139                 (w)->last_modified[DESIRED_DISP] = Qzero;       \
140                 (w)->last_modified[CMOTION_DISP] = Qzero;       \
141                 if (cache_too)                                  \
142                         (w)->line_cache_last_updated = Qzero;   \
143         } while (0)
144
145 #define SET_LAST_FACECHANGE(w)                                  \
146         do {                                                    \
147                 (w)->last_facechange[CURRENT_DISP] = Qzero;     \
148                 (w)->last_facechange[DESIRED_DISP] = Qzero;     \
149                 (w)->last_facechange[CMOTION_DISP] = Qzero;     \
150         } while (0)
151 \f
152 #define MARK_DISP_VARIABLE(field)               \
153         mark_object (window->field[CURRENT_DISP]);      \
154         mark_object (window->field[DESIRED_DISP]);      \
155         mark_object (window->field[CMOTION_DISP]);
156
157 static Lisp_Object mark_window(Lisp_Object obj)
158 {
159         struct window *window = XWINDOW(obj);
160         mark_object(window->frame);
161         mark_object(window->mini_p);
162         mark_object(window->next);
163         mark_object(window->prev);
164         mark_object(window->hchild);
165         mark_object(window->vchild);
166         mark_object(window->parent);
167         mark_object(window->buffer);
168         MARK_DISP_VARIABLE(start);
169         MARK_DISP_VARIABLE(pointm);
170         mark_object(window->sb_point);  /* #### move to scrollbar.c? */
171         mark_object(window->use_time);
172         MARK_DISP_VARIABLE(last_modified);
173         MARK_DISP_VARIABLE(last_point);
174         MARK_DISP_VARIABLE(last_start);
175         MARK_DISP_VARIABLE(last_facechange);
176         mark_object(window->line_cache_last_updated);
177         mark_object(window->redisplay_end_trigger);
178         mark_object(window->subwindow_instance_cache);
179
180         mark_face_cachels(window->face_cachels);
181         mark_glyph_cachels(window->glyph_cachels);
182
183 #define WINDOW_SLOT(slot, compare) mark_object (window->slot)
184 #include "winslots.h"
185
186         return Qnil;
187 }
188
189 static void
190 run_window_configuration_hook ( Lisp_Object win )
191 {
192         struct window *w;
193         Lisp_Object frame;
194         struct frame *f;
195
196         if (NILP(win))
197                 win = Fselected_window(Qnil);
198
199         CHECK_WINDOW(win);
200    
201         w = XWINDOW (win);
202         frame = WINDOW_FRAME (w);
203         f = XFRAME (frame);
204  
205         if ( ! f->window_configuration_hook ) {
206                 f->window_configuration_hook = 1;
207                 va_run_hook_with_args(Qwindow_configuration_hook, 1, win);
208                 f->window_configuration_hook = 0;
209         }
210 }
211
212 static void
213 print_window(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
214 {
215         if (print_readably)
216                 error("printing unreadable object #<window 0x%x>",
217                       XWINDOW(obj)->header.uid);
218
219         write_c_string("#<window", printcharfun);
220         if (!NILP(XWINDOW(obj)->buffer)) {
221                 Lisp_Object name = XBUFFER(XWINDOW(obj)->buffer)->name;
222                 write_c_string(" on ", printcharfun);
223                 print_internal(name, printcharfun, 1);
224         }
225         write_fmt_str(printcharfun, " 0x%x>", XWINDOW(obj)->header.uid);
226 }
227
228 static void finalize_window(void *header, int for_disksave)
229 {
230         struct window *w = (struct window *)header;
231
232         if (w->line_start_cache) {
233                 Dynarr_free(w->line_start_cache);
234                 w->line_start_cache = 0;
235         }
236
237         if (w->face_cachels) {
238                 int i;
239
240                 for (i = 0; i < Dynarr_length(w->face_cachels); i++) {
241                         struct face_cachel *cachel =
242                             Dynarr_atp(w->face_cachels, i);
243                         if (cachel->merged_faces) {
244                                 Dynarr_free(cachel->merged_faces);
245                                 cachel->merged_faces = 0;
246                         }
247                 }
248                 Dynarr_free(w->face_cachels);
249                 w->face_cachels = 0;
250         }
251
252         if (w->glyph_cachels) {
253                 Dynarr_free(w->glyph_cachels);
254                 w->glyph_cachels = 0;
255         }
256 }
257
258 DEFINE_LRECORD_IMPLEMENTATION("window", window,
259                               mark_window, print_window, finalize_window,
260                               0, 0, 0, struct window);
261
262 #define INIT_DISP_VARIABLE(field, initialization)       \
263         p->field[CURRENT_DISP] = initialization;        \
264         p->field[DESIRED_DISP] = initialization;        \
265         p->field[CMOTION_DISP] = initialization;
266
267 /* We have an implicit assertion that the first two elements (default
268    and modeline faces) are always present in the face_element_cache.
269    Normally redisplay ensures this.  However, it is possible for a
270    window to get created and functions which reference these values
271    called before redisplay works with the window for the first time.
272    All callers of allocate_window should therefore call
273    reset_face_cachels on the created window.  We can't do it
274    here because the window must have its frame pointer set or
275    reset_face_cachels will fail. */
276 Lisp_Object allocate_window(void)
277 {
278         Lisp_Object val;
279         struct window *p = alloc_lcrecord_type(struct window, &lrecord_window);
280
281         zero_lcrecord(p);
282         XSETWINDOW(val, p);
283
284         p->dead = 0;
285         p->frame = Qnil;
286         p->mini_p = Qnil;
287         p->next = Qnil;
288         p->prev = Qnil;
289         p->hchild = Qnil;
290         p->vchild = Qnil;
291         p->parent = Qnil;
292         p->buffer = Qnil;
293         INIT_DISP_VARIABLE(start, Fmake_marker());
294         INIT_DISP_VARIABLE(pointm, Fmake_marker());
295         p->sb_point = Fmake_marker();
296         p->use_time = Qzero;
297         INIT_DISP_VARIABLE(last_modified, Qzero);
298         INIT_DISP_VARIABLE(last_point, Fmake_marker());
299         INIT_DISP_VARIABLE(last_start, Fmake_marker());
300         INIT_DISP_VARIABLE(last_facechange, Qzero);
301         p->face_cachels = Dynarr_new(face_cachel);
302         p->glyph_cachels = Dynarr_new(glyph_cachel);
303         p->line_start_cache = Dynarr_new(line_start_cache);
304         p->subwindow_instance_cache = make_image_instance_cache_hash_table();
305
306         p->line_cache_last_updated = Qzero;
307         INIT_DISP_VARIABLE(last_point_x, 0);
308         INIT_DISP_VARIABLE(last_point_y, 0);
309         INIT_DISP_VARIABLE(window_end_pos, 0);
310         p->redisplay_end_trigger = Qnil;
311
312         p->gutter_extent_modiff[0] = 0;
313         p->gutter_extent_modiff[1] = 0;
314         p->gutter_extent_modiff[2] = 0;
315         p->gutter_extent_modiff[3] = 0;
316
317 #define WINDOW_SLOT(slot, compare) p->slot = Qnil
318 #include "winslots.h"
319
320         p->windows_changed = 1;
321         p->shadow_thickness_changed = 1;
322
323         return val;
324 }
325
326 #undef INIT_DISP_VARIABLE
327 \f
328 /*
329  * The redisplay structures used to be stored with each window.  While
330  * they are logically something associated with frames they can't be
331  * stored there with a redisplay which handles variable height lines.
332  * Lines in horizontally split windows might not line up.  So they get
333  * stored with the windows.
334  *
335  * The problem with this is window configurations.  When restoring a
336  * window configuration it now becomes problematic to do an
337  * incremental redisplay.  The solution is to store the redisplay
338  * structures with the frame as they should be but laid out in the
339  * same manner as the window structure.  Thus is born the window
340  * mirror.
341  *
342  * It also becomes a convenient place to stick scrollbar instances
343  * since they extrapolate out to having the same problem described for
344  * the display structures.
345  */
346
347 /* Create a new window mirror structure and associated redisplay
348    structs. */
349 static struct window_mirror *new_window_mirror(struct frame *f)
350 {
351         struct window_mirror *t = xnew_and_zero(struct window_mirror);
352
353         t->frame = f;
354
355         t->current_display_lines = Dynarr_new(display_line);
356         t->desired_display_lines = Dynarr_new(display_line);
357         t->buffer = NULL;
358
359 #ifdef HAVE_SCROLLBARS
360         t->scrollbar_vertical_instance = NULL;
361         t->scrollbar_horizontal_instance = NULL;
362 #endif
363
364         return t;
365 }
366
367 /* Synchronize the mirror structure with a given window structure.
368    This is normally called from update_frame_window_mirror with a
369    starting window of f->root_window. */
370 static struct window_mirror *update_mirror_internal(Lisp_Object win,
371                                                     struct window_mirror *mir)
372 {
373         if (NILP(win)) {
374                 if (mir) {
375                         free_window_mirror(mir);
376                         mir = NULL;
377                 }
378                 return mir;
379         } else if (!mir)
380                 mir = new_window_mirror(XFRAME(XWINDOW(win)->frame));
381
382         mir->next = update_mirror_internal(XWINDOW(win)->next, mir->next);
383         mir->hchild = update_mirror_internal(XWINDOW(win)->hchild, mir->hchild);
384         mir->vchild = update_mirror_internal(XWINDOW(win)->vchild, mir->vchild);
385
386         /*
387          * If the redisplay structs are not empty and the mirror has
388          * children, then this mirror structure was formerly being used for
389          * display but is no longer.  Reset its current display structs so
390          * that redisplay doesn't accidentally think they are accurate if it
391          * is later used for display purposes once again.  Also, mark the
392          * scrollbar instance as not active.
393          */
394         if (mir->vchild || mir->hchild) {
395                 /* The redisplay structures are big.  Leaving them around in
396                    non-leaf windows can add up to a lot of wasted space.  So
397                    don't do it. */
398                 free_display_structs(mir);
399                 mir->current_display_lines = Dynarr_new(display_line);
400                 mir->desired_display_lines = Dynarr_new(display_line);
401
402 #ifdef HAVE_SCROLLBARS
403                 update_window_scrollbars(XWINDOW(win), mir, 0, 0);
404 #endif
405                 mir->buffer = NULL;
406         }
407
408         return mir;
409 }
410
411 /* Given a window mirror, determine which real window it contains the
412    redisplay structures for. */
413 static Lisp_Object
414 real_window_internal(Lisp_Object win, struct window_mirror *rmir,
415                      struct window_mirror *mir)
416 {
417         for (; !NILP(win) && rmir; win = XWINDOW(win)->next, rmir = rmir->next) {
418                 if (mir == rmir)
419                         return win;
420                 if (!NILP(XWINDOW(win)->vchild)) {
421                         Lisp_Object retval =
422                             real_window_internal(XWINDOW(win)->vchild,
423                                                  rmir->vchild, mir);
424                         if (!NILP(retval))
425                                 return retval;
426                 }
427                 if (!NILP(XWINDOW(win)->hchild)) {
428                         Lisp_Object retval =
429                             real_window_internal(XWINDOW(win)->hchild,
430                                                  rmir->hchild, mir);
431                         if (!NILP(retval))
432                                 return retval;
433                 }
434         }
435
436         return Qnil;
437 }
438
439 /* Given a real window, find the mirror structure which contains its
440    redisplay structures. */
441 static struct window_mirror *find_window_mirror_internal(Lisp_Object win,
442                                                          struct window_mirror
443                                                          *rmir,
444                                                          struct window *w)
445 {
446         for (; !NILP(win); win = XWINDOW(win)->next, rmir = rmir->next) {
447                 if (w == XWINDOW(win))
448                         return rmir;
449
450                 if (!NILP(XWINDOW(win)->vchild)) {
451                         struct window_mirror *retval =
452                             find_window_mirror_internal(XWINDOW(win)->vchild,
453                                                         rmir->vchild, w);
454                         if (retval)
455                                 return retval;
456                 }
457
458                 if (!NILP(XWINDOW(win)->hchild)) {
459                         struct window_mirror *retval =
460                             find_window_mirror_internal(XWINDOW(win)->hchild,
461                                                         rmir->hchild, w);
462                         if (retval)
463                                 return retval;
464                 }
465         }
466
467         return 0;
468 }
469
470 /* Update the mirror structure for the given frame. */
471 void update_frame_window_mirror(struct frame *f)
472 {
473         f->root_mirror = update_mirror_internal(f->root_window, f->root_mirror);
474         f->mirror_dirty = 0;
475 }
476
477 /* Free a given mirror structure along with all of its children as
478    well as their associated display structures. */
479 void free_window_mirror(struct window_mirror *mir)
480 {
481         while (mir) {
482                 struct window_mirror *free_me = mir;
483                 if (mir->hchild)
484                         free_window_mirror(mir->hchild);
485                 if (mir->vchild)
486                         free_window_mirror(mir->vchild);
487 #ifdef HAVE_SCROLLBARS
488                 release_window_mirror_scrollbars(mir);
489 #endif
490                 free_display_structs(mir);
491                 mir = mir->next;
492                 xfree(free_me);
493         }
494 }
495
496 /* Given a mirror structure, return the window it mirrors.  Calls
497    real_window_internal to do most of the work. */
498 Lisp_Object real_window(struct window_mirror *mir, int no_abort)
499 {
500         Lisp_Object retval = real_window_internal(mir->frame->root_window,
501                                                   mir->frame->root_mirror, mir);
502         if (NILP(retval) && !no_abort)
503                 abort();
504
505         return retval;
506 }
507
508 /* Given a real window, return its mirror structure.  Calls
509    find_window_mirror_internal to do all of the work. */
510 struct window_mirror *find_window_mirror(struct window *w)
511 {
512         struct frame *f = XFRAME(w->frame);
513         if (f->mirror_dirty)
514                 update_frame_window_mirror(f);
515         return find_window_mirror_internal(f->root_window, f->root_mirror, w);
516 }
517
518 /*****************************************************************************
519  find_window_by_pixel_pos
520
521  Given a pixel position relative to a frame, find the window at that
522  position.
523  ****************************************************************************/
524 struct window *find_window_by_pixel_pos(int pix_x, int pix_y, Lisp_Object win)
525 {
526         if (NILP(win))
527                 return 0;
528
529         for (; !NILP(win); win = XWINDOW(win)->next) {
530                 struct window *w;
531
532                 if (!NILP(XWINDOW(win)->vchild)) {
533                         w = find_window_by_pixel_pos(pix_x, pix_y,
534                                                      XWINDOW(win)->vchild);
535                         if (w)
536                                 return w;
537                 }
538                 if (!NILP(XWINDOW(win)->hchild)) {
539                         w = find_window_by_pixel_pos(pix_x, pix_y,
540                                                      XWINDOW(win)->hchild);
541                         if (w)
542                                 return w;
543                 }
544                 w = XWINDOW(win);
545                 if (pix_x >= WINDOW_LEFT(w)
546                     && pix_x <= WINDOW_RIGHT(w)
547                     && pix_y >= WINDOW_TOP(w)
548                     && pix_y <= WINDOW_BOTTOM(w))
549                         return w;
550         }
551         return NULL;
552 }
553
554 /* Return a pointer to the display structures for the given window. */
555 display_line_dynarr *window_display_lines(struct window * w, int which)
556 {
557         struct window_mirror *t;
558
559         if (XFRAME(w->frame)->mirror_dirty)
560                 update_frame_window_mirror(XFRAME(w->frame));
561         t = find_window_mirror(w);
562         if (!t)
563                 abort();
564
565         if (which == CURRENT_DISP)
566                 return t->current_display_lines;
567         else if (which == DESIRED_DISP)
568                 return t->desired_display_lines;
569         else if (which == CMOTION_DISP)
570                 /* The CMOTION_DISP display lines are global. */
571                 return cmotion_display_lines;
572         else
573                 abort();
574
575         return 0;               /* shut up compiler */
576 }
577
578 struct buffer *window_display_buffer(struct window *w)
579 {
580         struct window_mirror *t;
581
582         if (XFRAME(w->frame)->mirror_dirty)
583                 update_frame_window_mirror(XFRAME(w->frame));
584         t = find_window_mirror(w);
585         if (!t)
586                 abort();
587
588         return t->buffer;
589 }
590
591 void set_window_display_buffer(struct window *w, struct buffer *b)
592 {
593         struct window_mirror *t;
594
595         if (XFRAME(w->frame)->mirror_dirty)
596                 update_frame_window_mirror(XFRAME(w->frame));
597         t = find_window_mirror(w);
598         if (!t)
599                 abort();
600
601         t->buffer = b;
602 }
603 \f
604 /* Determining a window's position based solely on its pixel
605    positioning doesn't work.  Instead, we do it the intelligent way,
606    by checking its positioning in the window hierarchy. */
607 int window_is_leftmost(struct window *w)
608 {
609         Lisp_Object parent, current_ancestor, window;
610
611         XSETWINDOW(window, w);
612
613         parent = XWINDOW(window)->parent;
614         current_ancestor = window;
615
616         while (!NILP(parent)) {
617                 if (!NILP(XWINDOW(parent)->hchild) &&
618                     !EQ(XWINDOW(parent)->hchild, current_ancestor))
619                         return 0;
620
621                 current_ancestor = parent;
622                 parent = XWINDOW(parent)->parent;
623         }
624
625         return 1;
626 }
627
628 int window_is_rightmost(struct window *w)
629 {
630         Lisp_Object parent, current_ancestor, window;
631
632         XSETWINDOW(window, w);
633
634         parent = XWINDOW(window)->parent;
635         current_ancestor = window;
636
637         while (!NILP(parent)) {
638                 if (!NILP(XWINDOW(parent)->hchild)
639                     && !NILP(XWINDOW(current_ancestor)->next))
640                         return 0;
641
642                 current_ancestor = parent;
643                 parent = XWINDOW(parent)->parent;
644         }
645
646         return 1;
647 }
648
649 static int window_full_width_p(struct window *w)
650 {
651         return window_is_leftmost(w) && window_is_rightmost(w);
652 }
653
654 int window_is_highest(struct window *w)
655 {
656         Lisp_Object parent, current_ancestor, window;
657
658         XSETWINDOW(window, w);
659
660         parent = XWINDOW(window)->parent;
661         current_ancestor = window;
662
663         while (!NILP(parent)) {
664                 if (!NILP(XWINDOW(parent)->vchild) &&
665                     !EQ(XWINDOW(parent)->vchild, current_ancestor))
666                         return 0;
667
668                 current_ancestor = parent;
669                 parent = XWINDOW(parent)->parent;
670         }
671
672         /* This is really to catch the minibuffer but we make it generic in
673            case we ever change things around to let the minibuffer be on top. */
674         if (NILP(XWINDOW(current_ancestor)->prev))
675                 return 1;
676         else
677                 return 0;
678 }
679
680 int window_is_lowest(struct window *w)
681 {
682         Lisp_Object parent, current_ancestor, window;
683
684         XSETWINDOW(window, w);
685
686         parent = XWINDOW(window)->parent;
687         current_ancestor = window;
688
689         while (!NILP(parent)) {
690                 if (!NILP(XWINDOW(parent)->vchild)
691                     && !NILP(XWINDOW(current_ancestor)->next))
692                         return 0;
693
694                 current_ancestor = parent;
695                 parent = XWINDOW(parent)->parent;
696         }
697
698         return 1;
699 }
700
701 #if 0                           /* not currently used */
702
703 static int window_full_height_p(struct window *w)
704 {
705         return window_is_highest(w) && window_is_lowest(w);
706 }
707
708 #endif
709
710 int window_truncation_on(struct window *w)
711 {
712         /* Minibuffer windows are never truncated.
713            #### is this the right way ? */
714         if (MINI_WINDOW_P(w))
715                 return 0;
716
717         /* Horizontally scrolled windows are truncated. */
718         if (w->hscroll)
719                 return 1;
720
721         /* If truncate_partial_width_windows is true and the window is not
722            the full width of the frame it is truncated. */
723         if (!NILP(symbol_value_in_buffer(Qtruncate_partial_width_windows,
724                                          w->buffer))
725             && !(window_is_leftmost(w) && window_is_rightmost(w)))
726                 return 1;
727
728         /* If the window's buffer's value of truncate_lines is non-nil, then
729            the window is truncated. */
730         if (!NILP(XBUFFER(w->buffer)->truncate_lines))
731                 return 1;
732
733         return 0;
734 }
735
736 DEFUN("window-truncated-p", Fwindow_truncated_p, 0, 1, 0,       /*
737 Returns non-nil if text in the window is truncated.
738 */
739       (window))
740 {
741         struct window *w = decode_window(window);
742
743         return window_truncation_on(w) ? Qt : Qnil;
744 }
745
746 static int have_undivided_common_edge(struct window *w_right, void *closure)
747 {
748         struct window *w_left = (struct window *)closure;
749         return (WINDOW_RIGHT(w_left) == WINDOW_LEFT(w_right)
750                 && WINDOW_TOP(w_left) < WINDOW_BOTTOM(w_right)
751                 && WINDOW_TOP(w_right) < WINDOW_BOTTOM(w_left)
752 #ifdef HAVE_SCROLLBARS
753                 && (NILP(w_right->scrollbar_on_left_p)
754                     || NILP(w_right->vertical_scrollbar_visible_p)
755                     || ZEROP(w_right->scrollbar_width))
756 #endif
757             );
758 }
759
760 static int window_needs_vertical_divider_1(struct window *w)
761 {
762         /* Never if we're on the right */
763         if (window_is_rightmost(w))
764                 return 0;
765
766         /* Always if draggable */
767         if (!NILP(w->vertical_divider_always_visible_p))
768                 return 1;
769
770 #ifdef HAVE_SCROLLBARS
771         /* Our right scrollbar is enough to separate us at the right */
772         if (NILP(w->scrollbar_on_left_p)
773             && !NILP(w->vertical_scrollbar_visible_p)
774             && !ZEROP(w->scrollbar_width))
775                 return 0;
776 #endif
777
778         /* Ok. to determine whether we need a divider on the left, we must
779            check that our right neighbor windows ha