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