XEmacs 21.2.7
[chise/xemacs-chise.git.1] / src / redisplay-output.c
1 /* Synchronize redisplay structures and output changes.
2    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3    Copyright (C) 1995, 1996 Ben Wing.
4    Copyright (C) 1996 Chuck Thompson.
5
6 This file is part of XEmacs.
7
8 XEmacs is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
11 later version.
12
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with XEmacs; see the file COPYING.  If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.  */
22
23 /* Synched up with: Not in FSF. */
24
25 /* This file has been Mule-ized. */
26
27 /* Author: Chuck Thompson */
28
29 #include <config.h>
30 #include "lisp.h"
31
32 #include "buffer.h"
33 #include "window.h"
34 #include "frame.h"
35 #include "device.h"
36 #include "glyphs.h"
37 #include "redisplay.h"
38 #include "faces.h"
39
40 static int compare_runes (struct window *w, struct rune *crb,
41                           struct rune *drb);
42 static void redraw_cursor_in_window (struct window *w,
43                                      int run_end_begin_glyphs);
44
45 /*****************************************************************************
46  sync_rune_structs
47
48  Synchronize the given rune blocks.
49  ****************************************************************************/
50 static void
51 sync_rune_structs (struct window *w, rune_dynarr *cra, rune_dynarr *dra)
52 {
53   int rune_elt;
54   int max_move = ((Dynarr_length (dra) > Dynarr_largest (cra))
55                   ? Dynarr_largest (cra)
56                   : Dynarr_length (dra));
57
58   if (max_move)
59     {
60       /* #### Doing this directly breaks the encapsulation.  But, the
61          running time of this function has a measurable impact on
62          redisplay performance so avoiding all excess overhead is a
63          good thing.  Is all of this true? */
64       memcpy (cra->base, dra->base, sizeof (struct rune) * max_move);
65       Dynarr_set_size (cra, max_move);
66     }
67   else
68     Dynarr_reset (cra);
69
70   for (rune_elt = max_move; rune_elt < Dynarr_length (dra); rune_elt++)
71     {
72       struct rune rb, *crb;
73       struct rune *drb = Dynarr_atp (dra, rune_elt);
74
75       crb = &rb;
76       memcpy (crb, drb, sizeof (struct rune));
77       Dynarr_add (cra, *crb);
78     }
79 }
80
81 /*****************************************************************************
82  sync_display_line_structs
83
84  For the given LINE in window W, make the current display line equal
85  the desired display line.
86  ****************************************************************************/
87 static void
88 sync_display_line_structs (struct window *w, int line, int do_blocks,
89                            display_line_dynarr *cdla,
90                            display_line_dynarr *ddla)
91 {
92   int cdla_len = Dynarr_length (cdla);
93
94   struct display_line dl, *clp, *dlp;
95   int db_elt;
96
97   dlp = Dynarr_atp (ddla, line);
98   if (line >= Dynarr_largest (cdla))
99     {
100       clp = &dl;
101       clp->display_blocks = Dynarr_new (display_block);
102     }
103   else
104     {
105       clp = Dynarr_atp (cdla, line);
106       if (clp->display_blocks)
107         Dynarr_reset (clp->display_blocks);
108       if (clp->left_glyphs)
109         {
110           Dynarr_free (clp->left_glyphs);
111           clp->left_glyphs = 0;
112         }
113       if (clp->right_glyphs)
114         {
115           Dynarr_free (clp->right_glyphs);
116           clp->right_glyphs = 0;
117         }
118     }
119   {
120     display_block_dynarr *tdb = clp->display_blocks;
121
122     memcpy (clp, dlp, sizeof (struct display_line));
123     clp->display_blocks = tdb;
124     clp->left_glyphs = 0;
125     clp->right_glyphs = 0;
126   }
127
128   if (!do_blocks && line >= cdla_len)
129     {
130       Dynarr_add (cdla, *clp);
131       return;
132     }
133
134   for (db_elt = 0; db_elt < Dynarr_length (dlp->display_blocks); db_elt++)
135     {
136       struct display_block db, *cdb;
137       struct display_block *ddb = Dynarr_atp (dlp->display_blocks, db_elt);
138
139       if (db_elt >= Dynarr_largest (clp->display_blocks))
140         {
141           cdb = &db;
142           memcpy (cdb, ddb, sizeof (struct display_block));
143           cdb->runes = Dynarr_new (rune);
144           Dynarr_add (clp->display_blocks, *cdb);
145         }
146       else
147         {
148           rune_dynarr *tr;
149
150           cdb = Dynarr_atp (clp->display_blocks, db_elt);
151           tr = cdb->runes;
152           memcpy (cdb, ddb, sizeof (struct display_block));
153           cdb->runes = tr;
154           Dynarr_increment (clp->display_blocks);
155         }
156
157       sync_rune_structs (w, cdb->runes, ddb->runes);
158     }
159
160   if (line >= cdla_len)
161     Dynarr_add (cdla, *clp);
162 }
163
164 /*****************************************************************************
165  compare_runes
166
167  Compare to runes to see if each of their fields is equal.  If so,
168  return true otherwise return false.
169  ****************************************************************************/
170 static int
171 compare_runes (struct window *w, struct rune *crb, struct rune *drb)
172 {
173   /* Do not compare the values of bufpos and endpos.  They do not
174      affect the display characteristics. */
175
176   if ((crb->findex != drb->findex) ||
177       (WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)))
178     return 0;
179   else if (crb->xpos != drb->xpos)
180     return 0;
181   else if (crb->width != drb->width)
182     return 0;
183   else if (crb->cursor_type != drb->cursor_type)
184     return 0;
185   else if (crb->type != drb->type)
186     return 0;
187   else if (crb->type == RUNE_CHAR &&
188            (crb->object.chr.ch != drb->object.chr.ch))
189     return 0;
190   else if (crb->type == RUNE_DGLYPH &&
191            (!EQ (crb->object.dglyph.glyph, drb->object.dglyph.glyph) ||
192             !EQ (crb->object.dglyph.extent, drb->object.dglyph.extent) ||
193             crb->object.dglyph.xoffset != drb->object.dglyph.xoffset))
194     return 0;
195   else if (crb->type == RUNE_HLINE &&
196            (crb->object.hline.thickness != drb->object.hline.thickness ||
197             crb->object.hline.yoffset != drb->object.hline.yoffset))
198     return 0;
199   else
200     return 1;
201 }
202
203 /*****************************************************************************
204  get_next_display_block
205
206  Return the next display starting at or overlapping START_POS.  Return
207  the start of the next region in NEXT_START.
208  ****************************************************************************/
209 int
210 get_next_display_block (layout_bounds bounds, display_block_dynarr *dba,
211                         int start_pos, int *next_start)
212 {
213   int next_display_block = NO_BLOCK;
214   int priority = -1;
215   int block;
216
217   /* If we don't find a display block covering or starting at
218      start_pos, then we return the starting point of the next display
219      block or the next division boundary, whichever is closer to
220      start_pos. */
221   if (next_start)
222     {
223       if (start_pos >= bounds.left_out && start_pos < bounds.left_in)
224         *next_start = bounds.left_in;
225       else if (start_pos < bounds.left_white)
226         *next_start = bounds.left_white;
227       else if (start_pos < bounds.right_white)
228         *next_start = bounds.right_white;
229       else if (start_pos < bounds.right_in)
230         *next_start = bounds.right_in;
231       else if (start_pos <= bounds.right_out)
232         *next_start = bounds.right_out;
233       else
234         abort ();
235     }
236
237   for (block = 0; block < Dynarr_length (dba); block++)
238     {
239       struct display_block *db = Dynarr_atp (dba, block);
240
241       if (db->start_pos <= start_pos && db->end_pos > start_pos)
242         {
243           if ((int) db->type > priority)
244             {
245               priority = db->type;
246               next_display_block = block;
247               if (next_start)
248                 *next_start = db->end_pos;
249             }
250         }
251       else if (next_start && db->start_pos > start_pos)
252         {
253           if (db->start_pos < *next_start)
254             *next_start = db->start_pos;
255         }
256     }
257
258   return next_display_block;
259 }
260
261 /*****************************************************************************
262  get_cursor_size_and_location
263
264  Return the information defining the pixel location of the cursor.
265  ****************************************************************************/
266 static void
267 get_cursor_size_and_location (struct window *w, struct display_block *db,
268                               int cursor_location,
269                               int *cursor_start, int *cursor_width,
270                               int *cursor_height)
271 {
272   struct rune *rb;
273   Lisp_Object window;
274   int defheight, defwidth;
275
276   if (Dynarr_length (db->runes) <= cursor_location)
277     abort ();
278
279   XSETWINDOW (window, w);
280
281   rb = Dynarr_atp (db->runes, cursor_location);
282   *cursor_start = rb->xpos;
283
284   default_face_height_and_width (window, &defheight, &defwidth);
285   *cursor_height = defheight;
286
287   if (rb->type == RUNE_BLANK)
288     *cursor_width = defwidth;
289   else
290     *cursor_width = rb->width;
291 }
292
293 /*****************************************************************************
294  compare_display_blocks
295
296  Given two display blocks, output only those areas where they differ.
297  ****************************************************************************/
298 static int
299 compare_display_blocks (struct window *w, struct display_line *cdl,
300                         struct display_line *ddl, int c_block, int d_block,
301                         int start_pixpos, int cursor_start, int cursor_width,
302                         int cursor_height)
303 {
304   struct frame *f = XFRAME (w->frame);
305   struct device *d = XDEVICE (f->device);
306
307   struct display_block *cdb, *ddb;
308   int start_pos;
309   int stop_pos;
310   int force = 0;
311   int block_end;
312
313   cdb = Dynarr_atp (cdl->display_blocks, c_block);
314   ddb = Dynarr_atp (ddl->display_blocks, d_block);
315
316   assert (cdb->type == ddb->type);
317
318   start_pos = -1;
319   stop_pos = min (Dynarr_length (cdb->runes), Dynarr_length (ddb->runes));
320
321   block_end =
322     (!Dynarr_length (ddb->runes)
323      ? 0
324      : (Dynarr_atp (ddb->runes, Dynarr_length (ddb->runes) - 1)->xpos +
325         Dynarr_atp (ddb->runes, Dynarr_length (ddb->runes) - 1)->width));
326
327   /* If the new block type is not text and the cursor status is
328      changing and it overlaps the position of this block then force a
329      full redraw of the block in order to make sure that the cursor is
330      updated properly. */
331   if (ddb->type != TEXT
332 #if 0
333       /* I'm not sure exactly what this code wants to do, but it's
334        * not right--it doesn't update when cursor_elt changes from, e.g.,
335        * 0 to 8, and the new or old cursor loc overlaps this block.
336        * I've replaced it with the more conservative test below.
337        * -dkindred@cs.cmu.edu 23-Mar-1997 */
338       && ((cdl->cursor_elt == -1 && ddl->cursor_elt != -1)
339           || (cdl->cursor_elt != -1 && ddl->cursor_elt == -1))
340       && (ddl->cursor_elt == -1 ||
341           (cursor_start
342            && cursor_width
343            && (cursor_start + cursor_width) >= start_pixpos
344            && cursor_start <= block_end))
345 #else
346       && (cdl->cursor_elt != ddl->cursor_elt)
347 #endif
348       )
349     force = 1;
350
351   if (f->windows_structure_changed ||
352       f->faces_changed ||
353       f->glyphs_changed ||
354       cdl->ypos != ddl->ypos ||
355       cdl->ascent != ddl->ascent ||
356       cdl->descent != ddl->descent ||
357       cdl->clip != ddl->clip ||
358       force)
359     {
360       start_pos = 0;
361       force = 1;
362     }
363   else
364     {
365       int elt = 0;
366
367       while (start_pos < 0 && elt < stop_pos)
368         {
369           if (!compare_runes (w, Dynarr_atp (cdb->runes, elt),
370                               Dynarr_atp (ddb->runes, elt)))
371             {
372               start_pos = elt;
373             }
374           else
375             {
376               elt++;
377             }
378         }
379
380       /* If nothing has changed in the area where the blocks overlap, but
381          there are new blocks in the desired block, then adjust the start
382          point accordingly. */
383       if (elt == stop_pos && stop_pos < Dynarr_length (ddb->runes))
384         start_pos = stop_pos;
385     }
386
387   if (start_pos >= 0)
388     {
389       if ((Dynarr_length (ddb->runes) != Dynarr_length (cdb->runes))
390           || force)
391         {
392           stop_pos = Dynarr_length (ddb->runes);
393         }
394       else
395         {
396           /* If the lines have the same number of runes and we are not
397              forcing a full redraw because the display line has
398              changed position then we try and optimize how much of the
399              line we actually redraw by scanning backwards from the
400              end for the first changed rune.  This optimization is
401              almost always triggered by face changes. */
402
403           int elt = Dynarr_length (ddb->runes) - 1;
404
405           while (elt > start_pos)
406             {
407               if (!compare_runes (w, Dynarr_atp (cdb->runes, elt),
408                                   Dynarr_atp (ddb->runes, elt)))
409                 break;
410               else
411                 elt--;
412             }
413           stop_pos = elt + 1;
414         }
415
416       DEVMETH (d, output_display_block, (w, ddl, d_block, start_pos,
417                                          stop_pos, start_pixpos,
418                                          cursor_start, cursor_width,
419                                          cursor_height));
420       return 1;
421     }
422
423   return 0;
424 }
425
426 /*****************************************************************************
427  clear_left_border
428
429  Clear the lefthand outside border.
430  ****************************************************************************/
431 static void
432 clear_left_border (struct window *w, int y, int height)
433 {
434   struct frame *f = XFRAME (w->frame);
435   Lisp_Object window;
436
437   XSETWINDOW (window, w);
438   redisplay_clear_region (window, DEFAULT_INDEX,
439                 FRAME_LEFT_BORDER_START (f), y,
440                 FRAME_BORDER_WIDTH (f), height);
441 }
442
443 /*****************************************************************************
444  clear_right_border
445
446  Clear the righthand outside border.
447  ****************************************************************************/
448 static void
449 clear_right_border (struct window *w, int y, int height)
450 {
451   struct frame *f = XFRAME (w->frame);
452   Lisp_Object window;
453
454   XSETWINDOW (window, w);
455   redisplay_clear_region (window, DEFAULT_INDEX,
456                 FRAME_RIGHT_BORDER_START (f),
457                 y, FRAME_BORDER_WIDTH (f), height);
458 }
459
460 /*****************************************************************************
461  output_display_line
462
463  Ensure that the contents of the given display line is correct
464  on-screen.  The force_ parameters are used by redisplay_move_cursor
465  to correctly update cursor locations and only cursor locations.
466  ****************************************************************************/
467 void
468 output_display_line (struct window *w, display_line_dynarr *cdla,
469                      display_line_dynarr *ddla, int line, int force_start,
470                      int force_end)
471
472 {
473   struct frame *f = XFRAME (w->frame);
474   struct device *d = XDEVICE (f->device);
475   struct buffer *b = XBUFFER (w->buffer);
476   struct buffer *old_b = window_display_buffer (w);
477   struct display_line *cdl, *ddl;
478   display_block_dynarr *cdba, *ddba;
479   int start_pixpos, end_pixpos;
480   int cursor_start, cursor_width, cursor_height;
481
482   int force = (force_start >= 0 || force_end >= 0);
483   int clear_border = 0;
484   int must_sync = 0;
485
486   if (cdla && line < Dynarr_length (cdla))
487     {
488       cdl = Dynarr_atp (cdla, line);
489       cdba = cdl->display_blocks;
490     }
491   else
492     {
493       cdl = NULL;
494       cdba = NULL;
495     }
496
497   ddl = Dynarr_atp (ddla, line);      /* assert line < Dynarr_length (ddla) */
498   ddba = ddl->display_blocks;
499
500   if (force_start >= 0 && force_start >= ddl->bounds.left_out)
501     start_pixpos = force_start;
502   else
503     start_pixpos = ddl->bounds.left_out;
504
505   if (force_end >= 0 && force_end < ddl->bounds.right_out)
506     end_pixpos = force_end;
507   else
508     end_pixpos = ddl->bounds.right_out;
509
510   /* Get the cursor parameters. */
511   if (ddl->cursor_elt != -1)
512     {
513       struct display_block *db;
514
515       /* If the lines cursor parameter is not -1 then it indicates
516          which rune in the TEXT block contains the cursor.  This means
517          that there must be at least one display block.  The TEXT
518          block, if present, must always be the first display block. */
519       assert (Dynarr_length (ddba) != 0);
520
521       db = Dynarr_atp (ddba, 0);
522       assert (db->type == TEXT);
523
524       get_cursor_size_and_location (w, db, ddl->cursor_elt, &cursor_start,
525                                     &cursor_width, &cursor_height);
526     }
527   else
528     {
529       cursor_start = cursor_width = cursor_height = 0;
530     }
531
532   /* The modeline should only have a single block and it had better be
533      a TEXT block. */
534   if (ddl->modeline)
535     {
536       /* The shadow thickness check is necessary if only the sign of
537          the size changed. */
538       if (cdba && !w->shadow_thickness_changed)
539         {
540           must_sync |= compare_display_blocks (w, cdl, ddl, 0, 0,
541                                                start_pixpos, 0, 0, 0);
542         }
543       else
544         {
545           DEVMETH (d, output_display_block, (w, ddl, 0, 0, -1, start_pixpos,
546                                              0, 0, 0));
547           must_sync = 1;
548         }
549
550       if (must_sync)
551         clear_border = 1;
552     }
553
554   while (!ddl->modeline && start_pixpos < end_pixpos)
555     {
556       int block;
557       int next_start_pixpos;
558
559       block = get_next_display_block (ddl->bounds, ddba, start_pixpos,
560                                       &next_start_pixpos);
561
562       /* If we didn't find a block then we should blank the area
563          between start_pos and next_start if necessary. */
564       if (block == NO_BLOCK)
565         {
566           /* We only erase those areas which were actually previously
567              covered by a display block unless the window structure
568              changed.  In that case we clear all areas since the current
569              structures may actually represent a different buffer. */
570           while (start_pixpos < next_start_pixpos)
571             {
572               int block_end;
573               int old_block;
574
575               if (cdba)
576                 old_block = get_next_display_block (ddl->bounds, cdba,
577                                                     start_pixpos, &block_end);
578               else
579                 {
580                   old_block = NO_BLOCK;
581                   block_end = next_start_pixpos;
582                 }
583
584               if (!cdba || old_block != NO_BLOCK || b != old_b ||
585                   f->windows_structure_changed ||
586                   f->faces_changed ||
587                   force ||
588                   (cdl && (cdl->ypos != ddl->ypos ||
589                            cdl->ascent != ddl->ascent ||
590                            cdl->descent != ddl->descent ||
591                            cdl->clip != ddl->clip)))
592                 {
593                   int x, y, width, height;
594                   Lisp_Object face;
595
596                   must_sync = 1;
597                   x = start_pixpos;
598                   y = ddl->ypos - ddl->ascent;
599                   width = min (next_start_pixpos, block_end) - x;
600                   height = ddl->ascent + ddl->descent - ddl->clip;
601
602                   if (x < ddl->bounds.left_in)
603                     face = Vleft_margin_face;
604                   else if (x < ddl->bounds.right_in)
605                     face = Vdefault_face;
606                   else if (x < ddl->bounds.right_out)
607                     face = Vright_margin_face;
608                   else
609                     face = Qnil;
610
611                   if (!NILP (face))
612                     {
613                       Lisp_Object window;
614
615                       XSETWINDOW (window, w);
616
617                       /* Clear the empty area. */
618                       redisplay_clear_region (window, get_builtin_face_cache_index (w, face),
619                                     x, y, width, height);
620
621                       /* Mark that we should clear the border.  This is
622                          necessary because italic fonts may leave
623                          droppings in the border. */
624                       clear_border = 1;
625                     }
626                 }
627
628               start_pixpos = min (next_start_pixpos, block_end);
629             }
630         }
631       else
632         {
633           struct display_block *cdb, *ddb;
634           int block_end;
635           int old_block;
636
637           if (cdba)
638             old_block = get_next_display_block (ddl->bounds, cdba,
639                                                 start_pixpos, &block_end);
640           else
641             old_block = NO_BLOCK;
642
643           ddb = Dynarr_atp (ddba, block);
644           cdb = (old_block != NO_BLOCK ? Dynarr_atp (cdba, old_block) : 0);
645
646           /* If there was formerly no block over the current
647              region or if it was a block of a different type, then
648              output the entire ddb.  Otherwise, compare cdb and
649              ddb and output only the changed region. */
650           if (!force && cdb && ddb->type == cdb->type && b == old_b)
651             {
652               must_sync |= compare_display_blocks (w, cdl, ddl, old_block,
653                                                    block, start_pixpos,
654                                                    cursor_start, cursor_width,
655                                                    cursor_height);
656             }
657           else
658             {
659               int elt;
660               int first_elt = 0;
661               int last_elt = -1;
662
663               for (elt = 0; elt < Dynarr_length (ddb->runes); elt++)
664                 {
665                   struct rune *rb = Dynarr_atp (ddb->runes, elt);
666
667                   if (start_pixpos >= rb->xpos
668                       && start_pixpos < rb->xpos + rb->width)
669                     first_elt = elt;
670
671                   if (end_pixpos > rb->xpos
672                       && end_pixpos <= rb->xpos + rb->width)
673                     {
674                       last_elt = elt + 1;
675                       if (last_elt > Dynarr_length (ddb->runes))
676                         last_elt = Dynarr_length (ddb->runes);
677                       break;
678                     }
679                 }
680
681               must_sync = 1;
682               DEVMETH (d, output_display_block, (w, ddl, block, first_elt,
683                                                  last_elt,
684                                                  start_pixpos,
685                                                  cursor_start, cursor_width,
686                                                  cursor_height));
687             }
688
689           start_pixpos = next_start_pixpos;
690         }
691     }
692
693   /* Clear the internal border if we are next to it and the window
694      structure or frame size has changed or if something caused
695      clear_border to be tripped.  */
696   /* #### Doing this on f->clear sucks but is necessary because of
697      window-local background values. */
698   if (f->windows_structure_changed || f->faces_changed || clear_border
699       || f->clear)
700     {
701       int y = ddl->ypos - ddl->ascent;
702       int height = ddl->ascent + ddl->descent - ddl->clip;
703
704       if (ddl->modeline)
705         {
706           y -= MODELINE_SHADOW_THICKNESS (w);
707           height += (2 * MODELINE_SHADOW_THICKNESS (w));
708         }
709
710       if (window_is_leftmost (w))
711         clear_left_border (w, y, height);
712       if (window_is_rightmost (w))
713         clear_right_border (w, y, height);
714     }
715
716   if (cdla)
717     sync_display_line_structs (w, line, must_sync, cdla, ddla);
718 }
719
720 /*****************************************************************************
721  redisplay_move_cursor
722
723  For the given window W, move the cursor to NEW_POINT.  Returns a
724  boolean indicating success or failure.
725  ****************************************************************************/
726
727 #define ADJ_BUFPOS (rb->bufpos + dl->offset)
728 #define ADJ_ENDPOS (rb->endpos + dl->offset)
729
730 int
731 redisplay_move_cursor (struct window *w, Bufpos new_point, int no_output_end)
732 {
733   struct frame *f = XFRAME (w->frame);
734   struct device *d = XDEVICE (f->device);
735
736   display_line_dynarr *cla = window_display_lines (w, CURRENT_DISP);
737   struct display_line *dl;
738   struct display_block *db;
739   struct rune *rb;
740   int x = w->last_point_x[CURRENT_DISP];
741   int y = w->last_point_y[CURRENT_DISP];
742
743   /*
744    * Bail if cursor_in_echo_area is non-zero and we're fiddling with
745    * the cursor in a non-active minibuffer window, since that is a
746    * special case that is handled elsewhere and this function need
747    * not handle it.  Return 1 so the caller will assume we
748    * succeeded.
749    */
750   if (cursor_in_echo_area && MINI_WINDOW_P (w) &&
751       w != XWINDOW (FRAME_SELECTED_WINDOW (f)))
752     return 1;
753
754   if (y < 0 || y >= Dynarr_length (cla))
755     return 0;
756
757   dl = Dynarr_atp (cla, y);
758   db = get_display_block_from_line (dl, TEXT);
759
760   if (x < 0 || x >= Dynarr_length (db->runes))
761     return 0;
762
763   rb = Dynarr_atp (db->runes, x);
764
765   if (rb->cursor_type == CURSOR_OFF)
766     return 0;
767   else if (ADJ_BUFPOS == new_point
768            || (ADJ_ENDPOS && (new_point >= ADJ_BUFPOS)
769                && (new_point <= ADJ_ENDPOS)))
770     {
771       w->last_point_x[CURRENT_DISP] = x;
772       w->last_point_y[CURRENT_DISP] = y;
773       Fset_marker (w->last_point[CURRENT_DISP], make_int (ADJ_BUFPOS),
774                    w->buffer);
775       dl->cursor_elt = x;
776       return 1;
777     }
778   else
779     {
780       DEVMETH (d, output_begin, (d));
781
782       /* #### This is a gross kludge.  Cursor handling is such a royal
783          pain in the ass. */
784       if (rb->type == RUNE_DGLYPH &&
785           (EQ (rb->object.dglyph.glyph, Vtruncation_glyph) ||
786            EQ (rb->object.dglyph.glyph, Vcontinuation_glyph)))
787         rb->cursor_type = NO_CURSOR;
788       else
789         rb->cursor_type = CURSOR_OFF;
790       dl->cursor_elt = -1;
791       output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width);
792     }
793
794   w->last_point_x[CURRENT_DISP] = -1;
795   w->last_point_y[CURRENT_DISP] = -1;
796   Fset_marker (w->last_point[CURRENT_DISP], Qnil, w->buffer);
797
798   /* If this isn't the selected frame, then erasing the old cursor is
799      all we actually had to do. */
800   if (w != XWINDOW (FRAME_SELECTED_WINDOW (device_selected_frame (d))))
801     {
802       if (!no_output_end)
803         DEVMETH (d, output_end, (d));
804
805       return 1;
806     }
807
808   /* This should only occur in the minibuffer. */
809   if (new_point == 0)
810     {
811       w->last_point_x[CURRENT_DISP] = 0;
812       w->last_point_y[CURRENT_DISP] = y;
813       Fset_marker (w->last_point[CURRENT_DISP], Qzero, w->buffer);
814
815       rb = Dynarr_atp (db->runes, 0);
816       rb->cursor_type = CURSOR_ON;
817       dl->cursor_elt = 0;
818
819       output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width);
820
821       if (!no_output_end)
822         DEVMETH (d, output_end, (d));
823       return 1;
824     }
825   else
826     {
827       int cur_rb = 0;
828       int first = 0;
829       int cur_dl, up;
830
831       if (ADJ_BUFPOS < new_point)
832         {
833           up = 1;
834           cur_rb = x + 1;
835           cur_dl = y;
836         }
837       else /* (rb->bufpos + dl->offset) > new_point */
838         {
839           up = 0;
840
841           if (!x)
842             {
843               cur_dl = y - 1;
844               first = 0;
845             }
846           else
847             {
848               cur_rb = x - 1;
849               cur_dl = y;
850               first = 1;
851             }
852         }
853
854       while ((up ? (cur_dl < Dynarr_length (cla)) : (cur_dl >= 0)))
855         {
856           dl = Dynarr_atp (cla, cur_dl);
857           db = get_display_block_from_line (dl, TEXT);
858
859           if (!up && !first)
860             cur_rb = Dynarr_length (db->runes) - 1;
861
862           while ((!scroll_on_clipped_lines || !dl->clip) &&
863                  (up ? (cur_rb < Dynarr_length (db->runes)) : (cur_rb >= 0)))
864             {
865               rb = Dynarr_atp (db->runes, cur_rb);
866
867               if (rb->cursor_type != IGNORE_CURSOR
868                   && rb->cursor_type != NO_CURSOR &&
869                   (ADJ_BUFPOS == new_point
870                    || (ADJ_ENDPOS && (new_point >= ADJ_BUFPOS)
871                        && (new_point <= ADJ_BUFPOS))))
872                 {
873                   rb->cursor_type = CURSOR_ON;
874                   dl->cursor_elt = cur_rb;
875
876
877                   output_display_line (w, 0, cla, cur_dl, rb->xpos,
878                                        rb->xpos + rb->width);
879
880                   w->last_point_x[CURRENT_DISP] = cur_rb;
881                   w->last_point_y[CURRENT_DISP] = cur_dl;
882                   Fset_marker (w->last_point[CURRENT_DISP],
883                                make_int (ADJ_BUFPOS), w->buffer);
884
885                   if (!no_output_end)
886                     DEVMETH (d, output_end, (d));
887                   return 1;
888                 }
889
890               (up ? cur_rb++ : cur_rb--);
891             }
892
893           (up ? (cur_rb = 0) : (first = 0));
894           (up ? cur_dl++ : cur_dl--);
895         }
896     }
897
898   if (!no_output_end)
899     DEVMETH (d, output_end, (d));
900   return 0;
901 }
902 #undef ADJ_BUFPOS
903 #undef ADJ_ENDPOS
904
905 /*****************************************************************************
906  redraw_cursor_in_window
907
908  For the given window W, redraw the cursor if it is contained within
909  the window.
910  ****************************************************************************/
911 static void
912 redraw_cursor_in_window (struct window *w, int run_end_begin_meths)
913 {
914   struct frame *f = XFRAME (w->frame);
915   struct device *d = XDEVICE (f->device);
916
917   display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
918   struct display_line *dl;
919   struct display_block *db;
920   struct rune *rb;
921
922   int x = w->last_point_x[CURRENT_DISP];
923   int y = w->last_point_y[CURRENT_DISP];
924
925   if (cursor_in_echo_area && MINI_WINDOW_P (w) &&
926       !echo_area_active (f) && minibuf_level == 0)
927     {
928       MAYBE_DEVMETH (d, set_final_cursor_coords, (f, w->pixel_top, 0));
929     }
930
931   if (y < 0 || y >= Dynarr_length (dla))
932     return;
933
934   if (MINI_WINDOW_P (w) && f != device_selected_frame (d) &&
935       !is_surrogate_for_selected_frame (f))
936     return;
937
938   dl = Dynarr_atp (dla, y);
939   db = get_display_block_from_line (dl, TEXT);
940
941   if (x < 0 || x >= Dynarr_length (db->runes))
942     return;
943
944   rb = Dynarr_atp (db->runes, x);
945
946   /* Don't call the output routine if the block isn't actually the
947      cursor. */
948   if (rb->cursor_type == CURSOR_ON)
949     {
950       MAYBE_DEVMETH (d, set_final_cursor_coords,
951                      (f, dl->ypos - 1, rb->xpos));
952
953       if (run_end_begin_meths)
954         DEVMETH (d, output_begin, (d));
955
956       output_display_line (w, 0, dla, y, rb->xpos, rb->xpos + rb->width);
957
958       if (run_end_begin_meths)
959         DEVMETH (d, output_end, (d));
960     }
961 }
962
963 /*****************************************************************************
964  redisplay_redraw_cursor
965
966  For the given frame F, redraw the cursor on the selected window.
967  This is used to update the cursor after focus changes.
968  ****************************************************************************/
969 void
970 redisplay_redraw_cursor (struct frame *f, int run_end_begin_meths)
971 {
972   Lisp_Object window;
973
974   if (!cursor_in_echo_area)
975     window = FRAME_SELECTED_WINDOW (f);
976   else if (FRAME_HAS_MINIBUF_P (f))
977     window = FRAME_MINIBUF_WINDOW (f);
978   else
979     return;
980
981   redraw_cursor_in_window (XWINDOW (window), run_end_begin_meths);
982 }
983
984 /****************************************************************************
985  redisplay_unmap_subwindows
986
987  Remove subwindows from the area in the box defined by the given
988  parameters.
989  ****************************************************************************/
990 static void redisplay_unmap_subwindows (struct frame* f, int x, int y, int width, int height)
991 {
992   int elt;
993
994   for (elt = 0; elt < Dynarr_length (f->subwindow_cachels); elt++)
995     {
996       struct subwindow_cachel *cachel =
997         Dynarr_atp (f->subwindow_cachels, elt);
998
999       if (cachel->being_displayed
1000           &&
1001           cachel->x + cachel->width > x && cachel->x < x + width
1002           &&
1003           cachel->y + cachel->height > y && cachel->y < y + height)
1004         {
1005           unmap_subwindow (cachel->subwindow);
1006         }
1007     }
1008 }
1009
1010 /****************************************************************************
1011  redisplay_output_subwindow
1012
1013
1014  output a subwindow.  This code borrows heavily from the pixmap stuff,
1015  although is much simpler not needing to account for partial
1016  pixmaps, backgrounds etc.
1017  ****************************************************************************/
1018 void
1019 redisplay_output_subwindow (struct window *w, struct display_line *dl,
1020                             Lisp_Object image_instance, int xpos, int xoffset,
1021                             int start_pixpos, int width, face_index findex,
1022                             int cursor_start, int cursor_width, int cursor_height)
1023 {
1024   struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1025   Lisp_Object window;
1026
1027   int lheight = dl->ascent + dl->descent - dl->clip;
1028   int pheight = ((int) IMAGE_INSTANCE_SUBWINDOW_HEIGHT (p) > lheight ? lheight :
1029                  IMAGE_INSTANCE_SUBWINDOW_HEIGHT (p));
1030
1031   XSETWINDOW (window, w);
1032
1033   /* Clear the area the subwindow is going into.  The subwindow itself
1034      will always take care of the full width.  We don't want to clear
1035      where it is going to go in order to avoid flicker.  So, all we
1036      have to take care of is any area above or below the subwindow. Of
1037      course this is rubbish if the subwindow has transparent areas
1038      (for instance with frames). */
1039   /* #### We take a shortcut for now.  We know that since we have
1040      subwindow_offset hardwired to 0 that the subwindow is against the top
1041      edge so all we have to worry about is below it. */
1042   if ((int) (dl->ypos - dl->ascent + pheight) <
1043       (int) (dl->ypos + dl->descent - dl->clip))
1044     {
1045       int clear_x, clear_width;
1046
1047       int clear_y = dl->ypos - dl->ascent + pheight;
1048       int clear_height = lheight - pheight;
1049
1050       if (start_pixpos >= 0 && start_pixpos > xpos)
1051         {
1052           clear_x = start_pixpos;
1053           clear_width = xpos + width - start_pixpos;
1054         }
1055       else
1056         {
1057           clear_x = xpos;
1058           clear_width = width;
1059         }
1060
1061       redisplay_clear_region (window, findex, clear_x, clear_y,
1062                               clear_width, clear_height);
1063     }
1064 #if 0
1065   redisplay_clear_region (window, findex, xpos - xoffset, dl->ypos - dl->ascent,
1066                           width, lheight);
1067 #endif
1068   /* if we can't view the whole window we can't view any of it */
1069   if (IMAGE_INSTANCE_SUBWINDOW_HEIGHT (p) > lheight
1070       ||
1071       IMAGE_INSTANCE_SUBWINDOW_WIDTH (p) > width)
1072     {
1073       redisplay_clear_region (window, findex, xpos - xoffset, dl->ypos - dl->ascent,
1074                               width, lheight);
1075       unmap_subwindow (image_instance);
1076     }
1077   else
1078     map_subwindow (image_instance, xpos - xoffset, dl->ypos - dl->ascent);
1079 }
1080
1081 /****************************************************************************
1082  redisplay_clear_region
1083
1084  Clear the area in the box defined by the given parameters using the
1085  given face. This has been generalised so that subwindows can be
1086  coped with effectively.
1087  ****************************************************************************/
1088 void
1089 redisplay_clear_region (Lisp_Object locale, face_index findex, int x, int y,
1090                         int width, int height)
1091 {
1092   struct window *w = NULL;
1093   struct frame *f = NULL;
1094   struct device *d;
1095   Lisp_Object background_pixmap = Qunbound;
1096   Lisp_Object fcolor = Qnil, bcolor = Qnil;
1097
1098   if (!width || !height)
1099      return;
1100
1101   if (WINDOWP (locale))
1102     {
1103       w = XWINDOW (locale);
1104       f = XFRAME (w->frame);
1105     }
1106   else if (FRAMEP (locale))
1107     {
1108       w = NULL;
1109       f = XFRAME (locale);
1110     }
1111   else
1112     abort ();
1113
1114   d = XDEVICE (f->device);
1115
1116   /* if we have subwindows in the region we have to unmap them */
1117   if (Dynarr_length (FRAME_SUBWINDOW_CACHE (f)))
1118     {
1119       redisplay_unmap_subwindows (f, x, y, width, height);
1120     }
1121
1122   /* #### This isn't quite right for when this function is called
1123      from the toolbar code. */
1124   
1125   /* Don't use a backing pixmap in the border area */
1126   if (x >= FRAME_LEFT_BORDER_END (f)
1127       && x < FRAME_RIGHT_BORDER_START (f)
1128       && y >= FRAME_TOP_BORDER_END (f)
1129       && y < FRAME_BOTTOM_BORDER_START (f))
1130     {
1131       Lisp_Object temp;
1132       
1133       if (w)
1134         {
1135           temp = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, findex);
1136           
1137           if (IMAGE_INSTANCEP (temp)
1138               && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
1139             {
1140               /* #### maybe we could implement such that a string
1141                  can be a background pixmap? */
1142               background_pixmap = temp;
1143             }
1144         }
1145       else
1146         {
1147           temp = FACE_BACKGROUND_PIXMAP (Vdefault_face, locale);
1148           
1149           if (IMAGE_INSTANCEP (temp)
1150               && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
1151             {
1152               background_pixmap = temp;
1153             }
1154         }
1155     }      
1156
1157   if (!UNBOUNDP (background_pixmap) &&
1158       XIMAGE_INSTANCE_PIXMAP_DEPTH (background_pixmap) == 0)
1159     {
1160       if (w)
1161         {
1162           fcolor = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1163           bcolor = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1164         }
1165       else
1166         {
1167           fcolor = FACE_FOREGROUND (Vdefault_face, locale);
1168           bcolor = FACE_BACKGROUND (Vdefault_face, locale);
1169         }
1170     }
1171   else
1172     {
1173       fcolor = (w ?
1174                 WINDOW_FACE_CACHEL_BACKGROUND (w, findex) :
1175                 FACE_BACKGROUND (Vdefault_face, locale));
1176       
1177     }
1178   
1179   if (UNBOUNDP (background_pixmap))
1180     background_pixmap = Qnil;
1181   
1182   DEVMETH (d, clear_region, 
1183            (locale, d, f, findex, x, y, width, height, fcolor, bcolor, background_pixmap));
1184 }
1185
1186 /*****************************************************************************
1187  redisplay_clear_top_of_window
1188
1189  If window is topmost, clear the internal border above it.
1190  ****************************************************************************/
1191 static void
1192 redisplay_clear_top_of_window (struct window *w)
1193 {
1194   Lisp_Object window;
1195   XSETWINDOW (window, w);
1196
1197   if (!NILP (Fwindow_highest_p (window)))
1198     {
1199       struct frame *f = XFRAME (w->frame);
1200       int x, y, width, height;
1201
1202       x = w->pixel_left;
1203       width = w->pixel_width;
1204
1205       if (window_is_leftmost (w))
1206         {
1207           x -= FRAME_BORDER_WIDTH (f);
1208           width += FRAME_BORDER_WIDTH (f);
1209         }
1210       if (window_is_rightmost (w))
1211         width += FRAME_BORDER_WIDTH (f);
1212
1213       y = FRAME_TOP_BORDER_START (f) - 1;
1214       height = FRAME_BORDER_HEIGHT (f) + 1;
1215
1216       redisplay_clear_region (window, DEFAULT_INDEX, x, y, width, height);
1217     }
1218 }
1219
1220 /*****************************************************************************
1221  redisplay_clear_bottom_of_window
1222
1223  Clear window from right below the last display line to right above
1224  the modeline.  The calling function can limit the area actually
1225  erased by setting min_start and/or max_end to positive values.
1226  ****************************************************************************/
1227 void
1228 redisplay_clear_bottom_of_window (struct window *w, display_line_dynarr *ddla,
1229                                   int min_start, int max_end)
1230 {
1231   struct frame *f = XFRAME (w->frame);
1232   struct device *d = XDEVICE (f->device);
1233   int ypos1, ypos2;
1234   int ddla_len = Dynarr_length (ddla);
1235
1236   ypos2 = WINDOW_TEXT_BOTTOM (w);
1237 #ifdef HAVE_SCROLLBARS
1238   /* This adjustment is to catch the intersection of any scrollbars. */
1239   if (f->windows_structure_changed && NILP (w->scrollbar_on_top_p))
1240     ypos2 += window_scrollbar_height (w);
1241 #endif
1242
1243   if (ddla_len)
1244     {
1245       if (ddla_len == 1 && Dynarr_atp (ddla, 0)->modeline)
1246         {
1247           ypos1 = WINDOW_TEXT_TOP (w);
1248 #ifdef HAVE_SCROLLBARS
1249           /* This adjustment is to catch the intersection of any scrollbars. */
1250           if (f->windows_structure_changed && !NILP (w->scrollbar_on_top_p))
1251             ypos1 -= window_scrollbar_height (w);
1252 #endif
1253         }
1254       else
1255         {
1256           struct display_line *dl = Dynarr_atp (ddla, ddla_len - 1);
1257           ypos1 = dl->ypos + dl->descent - dl->clip;
1258         }
1259     }
1260   else
1261     ypos1 = WINDOW_TEXT_TOP (w);
1262
1263   /* #### See if this can be made conditional on the frame
1264      changing size. */
1265   if (MINI_WINDOW_P (w))
1266     ypos2 += FRAME_BORDER_HEIGHT (f);
1267
1268   if (min_start >= 0 && ypos1 < min_start)
1269     ypos1 = min_start;
1270   if (max_end >= 0 && ypos2 > max_end)
1271     ypos2 = max_end;
1272
1273   if (ypos2 <= ypos1)
1274     return;
1275
1276   DEVMETH (d, clear_to_window_end, (w, ypos1, ypos2));
1277 }
1278
1279 /*****************************************************************************
1280  redisplay_update_line
1281
1282  This is used during incremental updates to update a single line and
1283  correct the offsets on all lines below it.  At the moment
1284  update_values is false if we are only updating the modeline.
1285  ****************************************************************************/
1286 void
1287 redisplay_update_line (struct window *w, int first_line, int last_line,
1288                        int update_values)
1289 {
1290   struct frame *f = XFRAME (w->frame);
1291   struct device *d = XDEVICE (f->device);
1292
1293   display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1294   display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
1295
1296   DEVMETH (d, output_begin, (d));
1297
1298   while (first_line <= last_line)
1299     {
1300       Charcount old_len = (Dynarr_atp (cdla, first_line)->end_bufpos -
1301                            Dynarr_atp (cdla, first_line)->bufpos);
1302       Charcount new_len = (Dynarr_atp (ddla, first_line)->end_bufpos -
1303                            Dynarr_atp (ddla, first_line)->bufpos);
1304
1305       assert (Dynarr_length (cdla) == Dynarr_length (ddla));
1306
1307       /* Output the changes. */
1308       output_display_line (w, cdla, ddla, first_line, -1, -1);
1309
1310       /* Update the offsets. */
1311       if (update_values)
1312         {
1313           int cur_line = first_line + 1;
1314           while (cur_line < Dynarr_length (cdla))
1315             {
1316               Dynarr_atp (cdla, cur_line)->offset += (new_len - old_len);
1317               Dynarr_atp (ddla, cur_line)->offset += (new_len - old_len);
1318               cur_line++;
1319             }
1320         }
1321
1322       /* Update the window_end_pos and other settings. */
1323       if (update_values)
1324         {
1325           w->window_end_pos[CURRENT_DISP] -= (new_len - old_len);
1326
1327           if (Dynarr_atp (ddla, first_line)->cursor_elt != -1)
1328             {
1329               w->last_point_x[CURRENT_DISP] = w->last_point_x[DESIRED_DISP];
1330               w->last_point_y[CURRENT_DISP] = w->last_point_y[DESIRED_DISP];
1331             }
1332         }
1333
1334       first_line++;
1335     }
1336
1337   /* Update the window max line length.  We have to scan the entire
1338      set of display lines otherwise we might not detect if the max is
1339      supposed to shrink. */
1340   if (update_values)
1341     {
1342       int line = 0;
1343
1344       w->max_line_len = 0;
1345       while (line < Dynarr_length (ddla))
1346         {
1347           struct display_line *dl = Dynarr_atp (ddla, line);
1348
1349           if (!dl->modeline)
1350             w->max_line_len = max (dl->num_chars, w->max_line_len);
1351
1352           line++;
1353         }
1354     }
1355
1356   w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP];
1357   w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP];
1358   Fset_marker (w->last_point[CURRENT_DISP],
1359                Fmarker_position (w->last_point[DESIRED_DISP]), w->buffer);
1360   Fset_marker (w->last_start[CURRENT_DISP],
1361                Fmarker_position (w->last_start[DESIRED_DISP]), w->buffer);
1362
1363   /* We don't bother updating the vertical scrollbars here.  This
1364      gives us a performance increase while having minimal loss of
1365      quality to the scrollbar slider size and position since when this
1366      function is called we know that the changes to the buffer were
1367      very localized.  We have to update the horizontal scrollbars,
1368      though, because this routine could cause a change which has a
1369      larger impact on their sizing. */
1370   /* #### See if we can get away with only calling this if
1371      max_line_len is greater than the window_char_width. */
1372 #if defined(HAVE_SCROLLBARS) && defined(HAVE_X_WINDOWS)
1373   {
1374     extern int stupid_vertical_scrollbar_drag_hack;
1375
1376     update_window_scrollbars (w, NULL, 1, stupid_vertical_scrollbar_drag_hack);
1377     stupid_vertical_scrollbar_drag_hack = 1;
1378   }
1379 #endif
1380
1381   /* This has to be done after we've updated the values.  We don't
1382      call output_end for tty frames.  Redisplay will do this after all
1383      tty windows have been updated.  This cuts down on cursor
1384      flicker. */
1385   if (FRAME_TTY_P (f))
1386     redisplay_redraw_cursor (f, 0);
1387   else
1388     DEVMETH (d, output_end, (d));
1389 }
1390
1391 /*****************************************************************************
1392  redisplay_output_window
1393
1394  For the given window W, ensure that the current display lines are
1395  equal to the desired display lines, outputing changes as necessary.
1396
1397  #### Fuck me.  This just isn't going to cut it for tty's.  The output
1398  decisions for them must be based on the contents of the entire frame
1399  because that is how the available output capabilities think.  The
1400  solution is relatively simple.  Create redisplay_output_frame.  This
1401  will basically merge all of the separate window display structs into
1402  a single one for the frame.  This combination structure will be able
1403  to be passed to the same output_display_line which works for windows
1404  on X frames and the right things will happen.  It just takes time to
1405  do.
1406  ****************************************************************************/
1407 void
1408 redisplay_output_window (struct window *w)
1409 {
1410   struct frame *f = XFRAME (w->frame);
1411   struct device *d = XDEVICE (f->device);
1412
1413   display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1414   display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
1415
1416   int cdla_len = Dynarr_length (cdla);
1417   int ddla_len = Dynarr_length (ddla);
1418
1419   int line;
1420   int need_to_clear_bottom = 0;
1421   int need_to_clear_start = -1;
1422   int need_to_clear_end = -1;
1423
1424   /* Backgrounds may have changed or windows may have gone away
1425      leaving dividers lying around. */
1426   if (f->faces_changed
1427       || f->windows_structure_changed
1428       || w->shadow_thickness_changed)
1429     need_to_clear_bottom = 1;
1430
1431   /* The first thing we do is determine if we are going to need to
1432      clear the bottom of the window.  We only need to do this if the
1433      bottom of the current display lines is below the bottom of the
1434      desired display lines.  Note that the number of lines is
1435      irrelevant.  Only the position matters.  We also clear to the
1436      bottom of the window if the modeline has shifted position. */
1437   /* #### We can't blindly not clear the bottom if f->clear is true
1438      since there might be a window-local background.  However, for
1439      those cases where there isn't, clearing the end of the window in
1440      this case sucks. */
1441   if (!need_to_clear_bottom)
1442     {
1443       struct display_line *cdl, *ddl;
1444
1445       /* If the modeline has changed position or size, clear the bottom
1446          of the window. */
1447       if (!need_to_clear_bottom)
1448         {
1449           cdl = ddl = 0;
1450
1451           if (cdla_len)
1452             cdl = Dynarr_atp (cdla, 0);
1453           if (ddla_len)
1454             ddl = Dynarr_atp (ddla, 0);
1455
1456           if (!cdl || !ddl)
1457             need_to_clear_bottom = 1;
1458           else if ((!cdl->modeline && ddl->modeline)
1459                    || (cdl->modeline && !ddl->modeline))
1460             need_to_clear_bottom = 1;
1461           else if (cdl->ypos != ddl->ypos ||
1462                    cdl->ascent != ddl->ascent ||
1463                    cdl->descent != ddl->descent ||
1464                    cdl->clip != ddl->clip)
1465             need_to_clear_bottom = 1;
1466
1467           /* #### This kludge is to make sure the modeline shadows get
1468              redrawn if the modeline position shifts. */
1469           if (need_to_clear_bottom)
1470             w->shadow_thickness_changed = 1;
1471         }
1472
1473       if (!need_to_clear_bottom)
1474         {
1475           cdl = ddl = 0;
1476
1477           if (cdla_len)
1478             cdl = Dynarr_atp (cdla, cdla_len - 1);
1479           if (ddla_len)
1480             ddl = Dynarr_atp (ddla, ddla_len - 1);
1481
1482           if (!cdl || !ddl)
1483             need_to_clear_bottom = 1;
1484           else
1485             {
1486               int cdl_bottom, ddl_bottom;
1487
1488               cdl_bottom = cdl->ypos + cdl->descent;
1489               ddl_bottom = ddl->ypos + ddl->descent;
1490
1491               if (cdl_bottom > ddl_bottom)
1492                 {
1493                   need_to_clear_bottom = 1;
1494                   need_to_clear_start = ddl_bottom;
1495                   need_to_clear_end = cdl_bottom;
1496                 }
1497             }
1498         }
1499     }
1500
1501   /* Perform any output initialization. */
1502   DEVMETH (d, output_begin, (d));
1503
1504   /* If the window's structure has changed clear the internal border
1505      above it if it is topmost (the function will check). */
1506   if (f->windows_structure_changed)
1507     redisplay_clear_top_of_window (w);
1508
1509   /* Output each line. */
1510   for (line = 0; line < Dynarr_length (ddla); line++)
1511     {
1512       output_display_line (w, cdla, ddla, line, -1, -1);
1513     }
1514
1515   /* If the number of display lines has shrunk, adjust. */
1516   if (cdla_len > ddla_len)
1517     {
1518       Dynarr_length (cdla) = ddla_len;
1519     }
1520
1521   /* Output a vertical divider between windows, if necessary. */
1522   if (window_needs_vertical_divider (w)
1523       && (f->windows_structure_changed || f->clear))
1524     {
1525       DEVMETH (d, output_vertical_divider, (w, f->windows_structure_changed));
1526     }
1527
1528   /* Clear the rest of the window, if necessary. */
1529   if (need_to_clear_bottom)
1530     {
1531       redisplay_clear_bottom_of_window (w, ddla, need_to_clear_start,
1532                                         need_to_clear_end);
1533     }
1534
1535   w->window_end_pos[CURRENT_DISP] = w->window_end_pos[DESIRED_DISP];
1536   Fset_marker (w->start[CURRENT_DISP],
1537                make_int (marker_position (w->start[DESIRED_DISP])),
1538                w->buffer);
1539   Fset_marker (w->pointm[CURRENT_DISP],
1540                make_int (marker_position (w->pointm[DESIRED_DISP])),
1541                w->buffer);
1542   w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP];
1543   w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP];
1544   Fset_marker (w->last_start[CURRENT_DISP],
1545                Fmarker_position (w->last_start[DESIRED_DISP]), w->buffer);
1546   Fset_marker (w->last_point[CURRENT_DISP],
1547                Fmarker_position (w->last_point[DESIRED_DISP]), w->buffer);
1548   w->last_point_x[CURRENT_DISP] = w->last_point_x[DESIRED_DISP];
1549   w->last_point_y[CURRENT_DISP] = w->last_point_y[DESIRED_DISP];
1550   w->shadow_thickness_changed = 0;
1551
1552   set_window_display_buffer (w, XBUFFER (w->buffer));
1553   find_window_mirror (w)->truncate_win = window_truncation_on (w);
1554
1555   /* Overkill on invalidating the cache.  It is very bad for it to not
1556      get invalidated when it should be. */
1557   INVALIDATE_DEVICE_PIXEL_TO_GLYPH_CACHE (d);
1558
1559   /* We don't call output_end for tty frames.  Redisplay will do this
1560      after all tty windows have been updated.  This cuts down on
1561      cursor flicker. */
1562   if (FRAME_TTY_P (f))
1563     redisplay_redraw_cursor (f, 0);
1564   else
1565     DEVMETH (d, output_end, (d));
1566
1567 #ifdef HAVE_SCROLLBARS
1568   update_window_scrollbars (w, NULL, !MINI_WINDOW_P (w), 0);
1569 #endif
1570 }