XEmacs 21.2.9
[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                   Lisp_Object face;
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                     face = Vleft_margin_face;
605                   else if (x < ddl->bounds.right_in)
606                     face = Vdefault_face;
607                   else if (x < ddl->bounds.right_out)
608                     face = Vright_margin_face;
609                   else
610                     face = Qnil;
611
612                   if (!NILP (face))
613                     {
614                       Lisp_Object window;
615
616                       XSETWINDOW (window, w);
617
618                       /* Clear the empty area. */
619                       redisplay_clear_region (window, get_builtin_face_cache_index (w, face),
620                                     x, y, width, height);
621
622                       /* Mark that we should clear the border.  This is
623                          necessary because italic fonts may leave
624                          droppings in the border. */
625                       clear_border = 1;
626                     }
627                 }
628
629               start_pixpos = min (next_start_pixpos, block_end);
630             }
631         }
632       else
633         {
634           struct display_block *cdb, *ddb;
635           int block_end;
636           int old_block;
637
638           if (cdba)
639             old_block = get_next_display_block (ddl->bounds, cdba,
640                                                 start_pixpos, &block_end);
641           else
642             old_block = NO_BLOCK;
643
644           ddb = Dynarr_atp (ddba, block);
645           cdb = (old_block != NO_BLOCK ? Dynarr_atp (cdba, old_block) : 0);
646
647           /* If there was formerly no block over the current
648              region or if it was a block of a different type, then
649              output the entire ddb.  Otherwise, compare cdb and
650              ddb and output only the changed region. */
651           if (!force && cdb && ddb->type == cdb->type && b == old_b)
652             {
653               must_sync |= compare_display_blocks (w, cdl, ddl, old_block,
654                                                    block, start_pixpos,
655                                                    cursor_start, cursor_width,
656                                                    cursor_height);
657             }
658           else
659             {
660               int elt;
661               int first_elt = 0;
662               int last_elt = -1;
663
664               for (elt = 0; elt < Dynarr_length (ddb->runes); elt++)
665                 {
666                   struct rune *rb = Dynarr_atp (ddb->runes, elt);
667
668                   if (start_pixpos >= rb->xpos
669                       && start_pixpos < rb->xpos + rb->width)
670                     first_elt = elt;
671
672                   if (end_pixpos > rb->xpos
673                       && end_pixpos <= rb->xpos + rb->width)
674                     {
675                       last_elt = elt + 1;
676                       if (last_elt > Dynarr_length (ddb->runes))
677                         last_elt = Dynarr_length (ddb->runes);
678                       break;
679                     }
680                 }
681
682               must_sync = 1;
683               redisplay_output_display_block (w, ddl, block, first_elt,
684                                               last_elt,
685                                               start_pixpos,
686                                               cursor_start, cursor_width,
687                                               cursor_height);
688             }
689           
690           start_pixpos = next_start_pixpos;
691         }
692     }
693
694   /* Clear the internal border if we are next to it and the window
695      structure or frame size has changed or if something caused
696      clear_border to be tripped.  */
697   /* #### Doing this on f->clear sucks but is necessary because of
698      window-local background values. */
699   if (f->windows_structure_changed || f->faces_changed || clear_border
700       || f->clear)
701     {
702       int y = ddl->ypos - ddl->ascent;
703       int height = ddl->ascent + ddl->descent - ddl->clip;
704
705       if (ddl->modeline)
706         {
707           y -= MODELINE_SHADOW_THICKNESS (w);
708           height += (2 * MODELINE_SHADOW_THICKNESS (w));
709         }
710
711       if (window_is_leftmost (w))
712         clear_left_border (w, y, height);
713       if (window_is_rightmost (w))
714         clear_right_border (w, y, height);
715     }
716
717   if (cdla)
718     sync_display_line_structs (w, line, must_sync, cdla, ddla);
719 }
720
721 /*****************************************************************************
722  redisplay_move_cursor
723
724  For the given window W, move the cursor to NEW_POINT.  Returns a
725  boolean indicating success or failure.
726  ****************************************************************************/
727
728 #define ADJ_BUFPOS (rb->bufpos + dl->offset)
729 #define ADJ_ENDPOS (rb->endpos + dl->offset)
730
731 int
732 redisplay_move_cursor (struct window *w, Bufpos new_point, int no_output_end)
733 {
734   struct frame *f = XFRAME (w->frame);
735   struct device *d = XDEVICE (f->device);
736
737   display_line_dynarr *cla = window_display_lines (w, CURRENT_DISP);
738   struct display_line *dl;
739   struct display_block *db;
740   struct rune *rb;
741   int x = w->last_point_x[CURRENT_DISP];
742   int y = w->last_point_y[CURRENT_DISP];
743
744   /*
745    * Bail if cursor_in_echo_area is non-zero and we're fiddling with
746    * the cursor in a non-active minibuffer window, since that is a
747    * special case that is handled elsewhere and this function need
748    * not handle it.  Return 1 so the caller will assume we
749    * succeeded.
750    */
751   if (cursor_in_echo_area && MINI_WINDOW_P (w) &&
752       w != XWINDOW (FRAME_SELECTED_WINDOW (f)))
753     return 1;
754
755   if (y < 0 || y >= Dynarr_length (cla))
756     return 0;
757
758   dl = Dynarr_atp (cla, y);
759   db = get_display_block_from_line (dl, TEXT);
760
761   if (x < 0 || x >= Dynarr_length (db->runes))
762     return 0;
763
764   rb = Dynarr_atp (db->runes, x);
765
766   if (rb->cursor_type == CURSOR_OFF)
767     return 0;
768   else if (ADJ_BUFPOS == new_point
769            || (ADJ_ENDPOS && (new_point >= ADJ_BUFPOS)
770                && (new_point <= ADJ_ENDPOS)))
771     {
772       w->last_point_x[CURRENT_DISP] = x;
773       w->last_point_y[CURRENT_DISP] = y;
774       Fset_marker (w->last_point[CURRENT_DISP], make_int (ADJ_BUFPOS),
775                    w->buffer);
776       dl->cursor_elt = x;
777       return 1;
778     }
779   else
780     {
781       DEVMETH (d, output_begin, (d));
782
783       /* #### This is a gross kludge.  Cursor handling is such a royal
784          pain in the ass. */
785       if (rb->type == RUNE_DGLYPH &&
786           (EQ (rb->object.dglyph.glyph, Vtruncation_glyph) ||
787            EQ (rb->object.dglyph.glyph, Vcontinuation_glyph)))
788         rb->cursor_type = NO_CURSOR;
789       else
790         rb->cursor_type = CURSOR_OFF;
791       dl->cursor_elt = -1;
792       output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width);
793     }
794
795   w->last_point_x[CURRENT_DISP] = -1;
796   w->last_point_y[CURRENT_DISP] = -1;
797   Fset_marker (w->last_point[CURRENT_DISP], Qnil, w->buffer);
798
799   /* If this isn't the selected frame, then erasing the old cursor is
800      all we actually had to do. */
801   if (w != XWINDOW (FRAME_SELECTED_WINDOW (device_selected_frame (d))))
802     {
803       if (!no_output_end)
804         DEVMETH (d, output_end, (d));
805
806       return 1;
807     }
808
809   /* This should only occur in the minibuffer. */
810   if (new_point == 0)
811     {
812       w->last_point_x[CURRENT_DISP] = 0;
813       w->last_point_y[CURRENT_DISP] = y;
814       Fset_marker (w->last_point[CURRENT_DISP], Qzero, w->buffer);
815
816       rb = Dynarr_atp (db->runes, 0);
817       rb->cursor_type = CURSOR_ON;
818       dl->cursor_elt = 0;
819
820       output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width);
821
822       if (!no_output_end)
823         DEVMETH (d, output_end, (d));
824       return 1;
825     }
826   else
827     {
828       int cur_rb = 0;
829       int first = 0;
830       int cur_dl, up;
831
832       if (ADJ_BUFPOS < new_point)
833         {
834           up = 1;
835           cur_rb = x + 1;
836           cur_dl = y;
837         }
838       else /* (rb->bufpos + dl->offset) > new_point */
839         {
840           up = 0;
841
842           if (!x)
843             {
844               cur_dl = y - 1;
845               first = 0;
846             }
847           else
848             {
849               cur_rb = x - 1;
850               cur_dl = y;
851               first = 1;
852             }
853         }
854
855       while ((up ? (cur_dl < Dynarr_length (cla)) : (cur_dl >= 0)))
856         {
857           dl = Dynarr_atp (cla, cur_dl);
858           db = get_display_block_from_line (dl, TEXT);
859
860           if (!up && !first)
861             cur_rb = Dynarr_length (db->runes) - 1;
862
863           while ((!scroll_on_clipped_lines || !dl->clip) &&
864                  (up ? (cur_rb < Dynarr_length (db->runes)) : (cur_rb >= 0)))
865             {
866               rb = Dynarr_atp (db->runes, cur_rb);
867
868               if (rb->cursor_type != IGNORE_CURSOR
869                   && rb->cursor_type != NO_CURSOR &&
870                   (ADJ_BUFPOS == new_point
871                    || (ADJ_ENDPOS && (new_point >= ADJ_BUFPOS)
872                        && (new_point <= ADJ_BUFPOS))))
873                 {
874                   rb->cursor_type = CURSOR_ON;
875                   dl->cursor_elt = cur_rb;
876
877
878                   output_display_line (w, 0, cla, cur_dl, rb->xpos,
879                                        rb->xpos + rb->width);
880
881                   w->last_point_x[CURRENT_DISP] = cur_rb;
882                   w->last_point_y[CURRENT_DISP] = cur_dl;
883                   Fset_marker (w->last_point[CURRENT_DISP],
884                                make_int (ADJ_BUFPOS), w->buffer);
885
886                   if (!no_output_end)
887                     DEVMETH (d, output_end, (d));
888                   return 1;
889                 }
890
891               (up ? cur_rb++ : cur_rb--);
892             }
893
894           (up ? (cur_rb = 0) : (first = 0));
895           (up ? cur_dl++ : cur_dl--);
896         }
897     }
898
899   if (!no_output_end)
900     DEVMETH (d, output_end, (d));
901   return 0;
902 }
903 #undef ADJ_BUFPOS
904 #undef ADJ_ENDPOS
905
906 /*****************************************************************************
907  redraw_cursor_in_window
908
909  For the given window W, redraw the cursor if it is contained within
910  the window.
911  ****************************************************************************/
912 static void
913 redraw_cursor_in_window (struct window *w, int run_end_begin_meths)
914 {
915   struct frame *f = XFRAME (w->frame);
916   struct device *d = XDEVICE (f->device);
917
918   display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
919   struct display_line *dl;
920   struct display_block *db;
921   struct rune *rb;
922
923   int x = w->last_point_x[CURRENT_DISP];
924   int y = w->last_point_y[CURRENT_DISP];
925
926   if (cursor_in_echo_area && MINI_WINDOW_P (w) &&
927       !echo_area_active (f) && minibuf_level == 0)
928     {
929       MAYBE_DEVMETH (d, set_final_cursor_coords, (f, w->pixel_top, 0));
930     }
931
932   if (y < 0 || y >= Dynarr_length (dla))
933     return;
934
935   if (MINI_WINDOW_P (w) && f != device_selected_frame (d) &&
936       !is_surrogate_for_selected_frame (f))
937     return;
938
939   dl = Dynarr_atp (dla, y);
940   db = get_display_block_from_line (dl, TEXT);
941
942   if (x < 0 || x >= Dynarr_length (db->runes))
943     return;
944
945   rb = Dynarr_atp (db->runes, x);
946
947   /* Don't call the output routine if the block isn't actually the
948      cursor. */
949   if (rb->cursor_type == CURSOR_ON)
950     {
951       MAYBE_DEVMETH (d, set_final_cursor_coords,
952                      (f, dl->ypos - 1, rb->xpos));
953
954       if (run_end_begin_meths)
955         DEVMETH (d, output_begin, (d));
956
957       output_display_line (w, 0, dla, y, rb->xpos, rb->xpos + rb->width);
958
959       if (run_end_begin_meths)
960         DEVMETH (d, output_end, (d));
961     }
962 }
963
964 /*****************************************************************************
965  redisplay_redraw_cursor
966
967  For the given frame F, redraw the cursor on the selected window.
968  This is used to update the cursor after focus changes.
969  ****************************************************************************/
970 void
971 redisplay_redraw_cursor (struct frame *f, int run_end_begin_meths)
972 {
973   Lisp_Object window;
974
975   if (!cursor_in_echo_area)
976     window = FRAME_SELECTED_WINDOW (f);
977   else if (FRAME_HAS_MINIBUF_P (f))
978     window = FRAME_MINIBUF_WINDOW (f);
979   else
980     return;
981
982   redraw_cursor_in_window (XWINDOW (window), run_end_begin_meths);
983 }
984
985 /****************************************************************************
986  redisplay_output_display_block
987
988  Given a display line, a block number for that start line, output all
989  runes between start and end in the specified display block.
990  ****************************************************************************/
991 static void
992 redisplay_output_display_block (struct window *w, struct display_line *dl, int block,
993                                 int start, int end, int start_pixpos, int cursor_start,
994                                 int cursor_width, int cursor_height)
995 {
996   struct frame *f = XFRAME (w->frame);
997   struct device *d = XDEVICE (f->device);
998
999   DEVMETH (d, output_display_block, (w, dl, block, start,
1000                                      end, start_pixpos,
1001                                      cursor_start, cursor_width,
1002                                      cursor_height));
1003 }
1004   
1005 /****************************************************************************
1006  redisplay_unmap_subwindows
1007
1008  Remove subwindows from the area in the box defined by the given
1009  parameters.
1010  ****************************************************************************/
1011 static void redisplay_unmap_subwindows (struct frame* f, int x, int y, int width, int height)
1012 {
1013   int elt;
1014
1015   for (elt = 0; elt < Dynarr_length (f->subwindow_cachels); elt++)
1016     {
1017       struct subwindow_cachel *cachel =
1018         Dynarr_atp (f->subwindow_cachels, elt);
1019
1020       if (cachel->being_displayed
1021           &&
1022           cachel->x + cachel->width > x && cachel->x < x + width
1023           &&
1024           cachel->y + cachel->height > y && cachel->y < y + height)
1025         {
1026           unmap_subwindow (cachel->subwindow);
1027         }
1028     }
1029 }
1030
1031 /****************************************************************************
1032  redisplay_unmap_subwindows_maybe
1033
1034  Potentially subwindows from the area in the box defined by the given
1035  parameters.
1036  ****************************************************************************/
1037 void redisplay_unmap_subwindows_maybe (struct frame* f, int x, int y, int width, int height)
1038 {
1039   if (Dynarr_length (FRAME_SUBWINDOW_CACHE (f)))
1040     {
1041       redisplay_unmap_subwindows (f, x, y, width, height);
1042     }
1043 }
1044
1045 /****************************************************************************
1046  redisplay_output_subwindow
1047
1048
1049  output a subwindow.  This code borrows heavily from the pixmap stuff,
1050  although is much simpler not needing to account for partial
1051  pixmaps, backgrounds etc.
1052  ****************************************************************************/
1053 void
1054 redisplay_output_subwindow (struct window *w, struct display_line *dl,
1055                             Lisp_Object image_instance, int xpos, int xoffset,
1056                             int start_pixpos, int width, face_index findex,
1057                             int cursor_start, int cursor_width, int cursor_height)
1058 {
1059   struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1060   Lisp_Object window;
1061
1062   int lheight = dl->ascent + dl->descent - dl->clip;
1063   int pheight = ((int) IMAGE_INSTANCE_SUBWINDOW_HEIGHT (p) > lheight ? lheight :
1064                  IMAGE_INSTANCE_SUBWINDOW_HEIGHT (p));
1065
1066   XSETWINDOW (window, w);
1067
1068   /* Clear the area the subwindow is going into.  The subwindow itself
1069      will always take care of the full width.  We don't want to clear
1070      where it is going to go in order to avoid flicker.  So, all we
1071      have to take care of is any area above or below the subwindow. Of
1072      course this is rubbish if the subwindow has transparent areas
1073      (for instance with frames). */
1074   /* #### We take a shortcut for now.  We know that since we have
1075      subwindow_offset hardwired to 0 that the subwindow is against the top
1076      edge so all we have to worry about is below it. */
1077   if ((int) (dl->ypos - dl->ascent + pheight) <
1078       (int) (dl->ypos + dl->descent - dl->clip))
1079     {
1080       int clear_x, clear_width;
1081
1082       int clear_y = dl->ypos - dl->ascent + pheight;
1083       int clear_height = lheight - pheight;
1084
1085       if (start_pixpos >= 0 && start_pixpos > xpos)
1086         {
1087           clear_x = start_pixpos;
1088           clear_width = xpos + width - start_pixpos;
1089         }
1090       else
1091         {
1092           clear_x = xpos;
1093           clear_width = width;
1094         }
1095
1096       redisplay_clear_region (window, findex, clear_x, clear_y,
1097                               clear_width, clear_height);
1098     }
1099 #if 0
1100   redisplay_clear_region (window, findex, xpos - xoffset, dl->ypos - dl->ascent,
1101                           width, lheight);
1102 #endif
1103   /* if we can't view the whole window we can't view any of it */
1104   if (IMAGE_INSTANCE_SUBWINDOW_HEIGHT (p) > lheight
1105       ||
1106       IMAGE_INSTANCE_SUBWINDOW_WIDTH (p) > width)
1107     {
1108       redisplay_clear_region (window, findex, xpos - xoffset, dl->ypos - dl->ascent,
1109                               width, lheight);
1110       unmap_subwindow (image_instance);
1111     }
1112   else
1113     map_subwindow (image_instance, xpos - xoffset, dl->ypos - dl->ascent);
1114 }
1115
1116 /****************************************************************************
1117  redisplay_clear_region
1118
1119  Clear the area in the box defined by the given parameters using the
1120  given face. This has been generalised so that subwindows can be
1121  coped with effectively.
1122  ****************************************************************************/
1123 void
1124 redisplay_clear_region (Lisp_Object locale, face_index findex, int x, int y,
1125                         int width, int height)
1126 {
1127   struct window *w = NULL;
1128   struct frame *f = NULL;
1129   struct device *d;
1130   Lisp_Object background_pixmap = Qunbound;
1131   Lisp_Object fcolor = Qnil, bcolor = Qnil;
1132
1133   if (!width || !height)
1134      return;
1135
1136   if (WINDOWP (locale))
1137     {
1138       w = XWINDOW (locale);
1139       f = XFRAME (w->frame);
1140     }
1141   else if (FRAMEP (locale))
1142     {
1143       w = NULL;
1144       f = XFRAME (locale);
1145     }
1146   else
1147     abort ();
1148
1149   d = XDEVICE (f->device);
1150
1151   /* if we have subwindows in the region we have to unmap them */
1152   if (Dynarr_length (FRAME_SUBWINDOW_CACHE (f)))
1153     {
1154       redisplay_unmap_subwindows (f, x, y, width, height);
1155     }
1156
1157   /* #### This isn't quite right for when this function is called
1158      from the toolbar code. */
1159   
1160   /* Don't use a backing pixmap in the border area */
1161   if (x >= FRAME_LEFT_BORDER_END (f)
1162       && x < FRAME_RIGHT_BORDER_START (f)
1163       && y >= FRAME_TOP_BORDER_END (f)
1164       && y < FRAME_BOTTOM_BORDER_START (f))
1165     {
1166       Lisp_Object temp;
1167       
1168       if (w)
1169         {
1170           temp = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, findex);
1171           
1172           if (IMAGE_INSTANCEP (temp)
1173               && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
1174             {
1175               /* #### maybe we could implement such that a string
1176                  can be a background pixmap? */
1177               background_pixmap = temp;
1178             }
1179         }
1180       else
1181         {
1182           temp = FACE_BACKGROUND_PIXMAP (Vdefault_face, locale);
1183           
1184           if (IMAGE_INSTANCEP (temp)
1185               && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
1186             {
1187               background_pixmap = temp;
1188             }
1189         }
1190     }      
1191
1192   if (!UNBOUNDP (background_pixmap) &&
1193       XIMAGE_INSTANCE_PIXMAP_DEPTH (background_pixmap) == 0)
1194     {
1195       if (w)
1196         {
1197           fcolor = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1198           bcolor = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1199         }
1200       else
1201         {
1202           fcolor = FACE_FOREGROUND (Vdefault_face, locale);
1203           bcolor = FACE_BACKGROUND (Vdefault_face, locale);
1204         }
1205     }
1206   else
1207     {
1208       fcolor = (w ?
1209                 WINDOW_FACE_CACHEL_BACKGROUND (w, findex) :
1210                 FACE_BACKGROUND (Vdefault_face, locale));
1211       
1212     }
1213   
1214   if (UNBOUNDP (background_pixmap))
1215     background_pixmap = Qnil;
1216   
1217   DEVMETH (d, clear_region, 
1218            (locale, d, f, findex, x, y, width, height, fcolor, bcolor, background_pixmap));
1219 }
1220
1221 /*****************************************************************************
1222  redisplay_clear_top_of_window
1223
1224  If window is topmost, clear the internal border above it.
1225  ****************************************************************************/
1226 static void
1227 redisplay_clear_top_of_window (struct window *w)
1228 {
1229   Lisp_Object window;
1230   XSETWINDOW (window, w);
1231
1232   if (!NILP (Fwindow_highest_p (window)))
1233     {
1234       struct frame *f = XFRAME (w->frame);
1235       int x, y, width, height;
1236
1237       x = w->pixel_left;
1238       width = w->pixel_width;
1239
1240       if (window_is_leftmost (w))
1241         {
1242           x -= FRAME_BORDER_WIDTH (f);
1243           width += FRAME_BORDER_WIDTH (f);
1244         }
1245       if (window_is_rightmost (w))
1246         width += FRAME_BORDER_WIDTH (f);
1247
1248       y = FRAME_TOP_BORDER_START (f) - 1;
1249       height = FRAME_BORDER_HEIGHT (f) + 1;
1250
1251       redisplay_clear_region (window, DEFAULT_INDEX, x, y, width, height);
1252     }
1253 }
1254
1255 /*****************************************************************************
1256  redisplay_clear_bottom_of_window
1257
1258  Clear window from right below the last display line to right above
1259  the modeline.  The calling function can limit the area actually
1260  erased by setting min_start and/or max_end to positive values.
1261  ****************************************************************************/
1262 void
1263 redisplay_clear_bottom_of_window (struct window *w, display_line_dynarr *ddla,
1264                                   int min_start, int max_end)
1265 {
1266   struct frame *f = XFRAME (w->frame);
1267   struct device *d = XDEVICE (f->device);
1268   int ypos1, ypos2;
1269   int ddla_len = Dynarr_length (ddla);
1270
1271   ypos2 = WINDOW_TEXT_BOTTOM (w);
1272 #ifdef HAVE_SCROLLBARS
1273   /* This adjustment is to catch the intersection of any scrollbars. */
1274   if (f->windows_structure_changed && NILP (w->scrollbar_on_top_p))
1275     ypos2 += window_scrollbar_height (w);
1276 #endif
1277
1278   if (ddla_len)
1279     {
1280       if (ddla_len == 1 && Dynarr_atp (ddla, 0)->modeline)
1281         {
1282           ypos1 = WINDOW_TEXT_TOP (w);
1283 #ifdef HAVE_SCROLLBARS
1284           /* This adjustment is to catch the intersection of any scrollbars. */
1285           if (f->windows_structure_changed && !NILP (w->scrollbar_on_top_p))
1286             ypos1 -= window_scrollbar_height (w);
1287 #endif
1288         }
1289       else
1290         {
1291           struct display_line *dl = Dynarr_atp (ddla, ddla_len - 1);
1292           ypos1 = dl->ypos + dl->descent - dl->clip;
1293         }
1294     }
1295   else
1296     ypos1 = WINDOW_TEXT_TOP (w);
1297
1298   /* #### See if this can be made conditional on the frame
1299      changing size. */
1300   if (MINI_WINDOW_P (w))
1301     ypos2 += FRAME_BORDER_HEIGHT (f);
1302
1303   if (min_start >= 0 && ypos1 < min_start)
1304     ypos1 = min_start;
1305   if (max_end >= 0 && ypos2 > max_end)
1306     ypos2 = max_end;
1307
1308   if (ypos2 <= ypos1)
1309     return;
1310
1311   DEVMETH (d, clear_to_window_end, (w, ypos1, ypos2));
1312 }
1313
1314 /*****************************************************************************
1315  redisplay_update_line
1316
1317  This is used during incremental updates to update a single line and
1318  correct the offsets on all lines below it.  At the moment
1319  update_values is false if we are only updating the modeline.
1320  ****************************************************************************/
1321 void
1322 redisplay_update_line (struct window *w, int first_line, int last_line,
1323                        int update_values)
1324 {
1325   struct frame *f = XFRAME (w->frame);
1326   struct device *d = XDEVICE (f->device);
1327
1328   display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1329   display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
1330
1331   DEVMETH (d, output_begin, (d));
1332
1333   while (first_line <= last_line)
1334     {
1335       Charcount old_len = (Dynarr_atp (cdla, first_line)->end_bufpos -
1336                            Dynarr_atp (cdla, first_line)->bufpos);
1337       Charcount new_len = (Dynarr_atp (ddla, first_line)->end_bufpos -
1338                            Dynarr_atp (ddla, first_line)->bufpos);
1339
1340       assert (Dynarr_length (cdla) == Dynarr_length (ddla));
1341
1342       /* Output the changes. */
1343       output_display_line (w, cdla, ddla, first_line, -1, -1);
1344
1345       /* Update the offsets. */
1346       if (update_values)
1347         {
1348           int cur_line = first_line + 1;
1349           while (cur_line < Dynarr_length (cdla))
1350             {
1351               Dynarr_atp (cdla, cur_line)->offset += (new_len - old_len);
1352               Dynarr_atp (ddla, cur_line)->offset += (new_len - old_len);
1353               cur_line++;
1354             }
1355         }
1356
1357       /* Update the window_end_pos and other settings. */
1358       if (update_values)
1359         {
1360           w->window_end_pos[CURRENT_DISP] -= (new_len - old_len);
1361
1362           if (Dynarr_atp (ddla, first_line)->cursor_elt != -1)
1363             {
1364               w->last_point_x[CURRENT_DISP] = w->last_point_x[DESIRED_DISP];
1365               w->last_point_y[CURRENT_DISP] = w->last_point_y[DESIRED_DISP];
1366             }
1367         }
1368
1369       first_line++;
1370     }
1371
1372   /* Update the window max line length.  We have to scan the entire
1373      set of display lines otherwise we might not detect if the max is
1374      supposed to shrink. */
1375   if (update_values)
1376     {
1377       int line = 0;
1378
1379       w->max_line_len = 0;
1380       while (line < Dynarr_length (ddla))
1381         {
1382           struct display_line *dl = Dynarr_atp (ddla, line);
1383
1384           if (!dl->modeline)
1385             w->max_line_len = max (dl->num_chars, w->max_line_len);
1386
1387           line++;
1388         }
1389     }
1390
1391   w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP];
1392   w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP];
1393   Fset_marker (w->last_point[CURRENT_DISP],
1394                Fmarker_position (w->last_point[DESIRED_DISP]), w->buffer);
1395   Fset_marker (w->last_start[CURRENT_DISP],
1396                Fmarker_position (w->last_start[DESIRED_DISP]), w->buffer);
1397
1398   /* We don't bother updating the vertical scrollbars here.  This
1399      gives us a performance increase while having minimal loss of
1400      quality to the scrollbar slider size and position since when this
1401      function is called we know that the changes to the buffer were
1402      very localized.  We have to update the horizontal scrollbars,
1403      though, because this routine could cause a change which has a
1404      larger impact on their sizing. */
1405   /* #### See if we can get away with only calling this if
1406      max_line_len is greater than the window_char_width. */
1407 #if defined(HAVE_SCROLLBARS) && defined(HAVE_X_WINDOWS)
1408   {
1409     extern int stupid_vertical_scrollbar_drag_hack;
1410
1411     update_window_scrollbars (w, NULL, 1, stupid_vertical_scrollbar_drag_hack);
1412     stupid_vertical_scrollbar_drag_hack = 1;
1413   }
1414 #endif
1415
1416   /* This has to be done after we've updated the values.  We don't
1417      call output_end for tty frames.  Redisplay will do this after all
1418      tty windows have been updated.  This cuts down on cursor
1419      flicker. */
1420   if (FRAME_TTY_P (f))
1421     redisplay_redraw_cursor (f, 0);
1422   else
1423     DEVMETH (d, output_end, (d));
1424 }
1425
1426 /*****************************************************************************
1427  redisplay_output_window
1428
1429  For the given window W, ensure that the current display lines are
1430  equal to the desired display lines, outputing changes as necessary.
1431
1432  #### Fuck me.  This just isn't going to cut it for tty's.  The output
1433  decisions for them must be based on the contents of the entire frame
1434  because that is how the available output capabilities think.  The
1435  solution is relatively simple.  Create redisplay_output_frame.  This
1436  will basically merge all of the separate window display structs into
1437  a single one for the frame.  This combination structure will be able
1438  to be passed to the same output_display_line which works for windows
1439  on X frames and the right things will happen.  It just takes time to
1440  do.
1441  ****************************************************************************/
1442 void
1443 redisplay_output_window (struct window *w)
1444 {
1445   struct frame *f = XFRAME (w->frame);
1446   struct device *d = XDEVICE (f->device);
1447
1448   display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1449   display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
1450
1451   int cdla_len = Dynarr_length (cdla);
1452   int ddla_len = Dynarr_length (ddla);
1453
1454   int line;
1455   int need_to_clear_bottom = 0;
1456   int need_to_clear_start = -1;
1457   int need_to_clear_end = -1;
1458
1459   /* Backgrounds may have changed or windows may have gone away
1460      leaving dividers lying around. */
1461   if (f->faces_changed
1462       || f->windows_structure_changed
1463       || w->shadow_thickness_changed)
1464     need_to_clear_bottom = 1;
1465
1466   /* The first thing we do is determine if we are going to need to
1467      clear the bottom of the window.  We only need to do this if the
1468      bottom of the current display lines is below the bottom of the
1469      desired display lines.  Note that the number of lines is
1470      irrelevant.  Only the position matters.  We also clear to the
1471      bottom of the window if the modeline has shifted position. */
1472   /* #### We can't blindly not clear the bottom if f->clear is true
1473      since there might be a window-local background.  However, for
1474      those cases where there isn't, clearing the end of the window in
1475      this case sucks. */
1476   if (!need_to_clear_bottom)
1477     {
1478       struct display_line *cdl, *ddl;
1479
1480       /* If the modeline has changed position or size, clear the bottom
1481          of the window. */
1482       if (!need_to_clear_bottom)
1483         {
1484           cdl = ddl = 0;
1485
1486           if (cdla_len)
1487             cdl = Dynarr_atp (cdla, 0);
1488           if (ddla_len)
1489             ddl = Dynarr_atp (ddla, 0);
1490
1491           if (!cdl || !ddl)
1492             need_to_clear_bottom = 1;
1493           else if ((!cdl->modeline && ddl->modeline)
1494                    || (cdl->modeline && !ddl->modeline))
1495             need_to_clear_bottom = 1;
1496           else if (cdl->ypos != ddl->ypos ||
1497                    cdl->ascent != ddl->ascent ||
1498                    cdl->descent != ddl->descent ||
1499                    cdl->clip != ddl->clip)
1500             need_to_clear_bottom = 1;
1501
1502           /* #### This kludge is to make sure the modeline shadows get
1503              redrawn if the modeline position shifts. */
1504           if (need_to_clear_bottom)
1505             w->shadow_thickness_changed = 1;
1506         }
1507
1508       if (!need_to_clear_bottom)
1509         {
1510           cdl = ddl = 0;
1511
1512           if (cdla_len)
1513             cdl = Dynarr_atp (cdla, cdla_len - 1);
1514           if (ddla_len)
1515             ddl = Dynarr_atp (ddla, ddla_len - 1);
1516
1517           if (!cdl || !ddl)
1518             need_to_clear_bottom = 1;
1519           else
1520             {
1521               int cdl_bottom, ddl_bottom;
1522
1523               cdl_bottom = cdl->ypos + cdl->descent;
1524               ddl_bottom = ddl->ypos + ddl->descent;
1525
1526               if (cdl_bottom > ddl_bottom)
1527                 {
1528                   need_to_clear_bottom = 1;
1529                   need_to_clear_start = ddl_bottom;
1530                   need_to_clear_end = cdl_bottom;
1531                 }
1532             }
1533         }
1534     }
1535
1536   /* Perform any output initialization. */
1537   DEVMETH (d, output_begin, (d));
1538
1539   /* If the window's structure has changed clear the internal border
1540      above it if it is topmost (the function will check). */
1541   if (f->windows_structure_changed)
1542     redisplay_clear_top_of_window (w);
1543
1544   /* Output each line. */
1545   for (line = 0; line < Dynarr_length (ddla); line++)
1546     {
1547       output_display_line (w, cdla, ddla, line, -1, -1);
1548     }
1549
1550   /* If the number of display lines has shrunk, adjust. */
1551   if (cdla_len > ddla_len)
1552     {
1553       Dynarr_length (cdla) = ddla_len;
1554     }
1555
1556   /* Output a vertical divider between windows, if necessary. */
1557   if (window_needs_vertical_divider (w)
1558       && (f->windows_structure_changed || f->clear))
1559     {
1560       DEVMETH (d, output_vertical_divider, (w, f->windows_structure_changed));
1561     }
1562
1563   /* Clear the rest of the window, if necessary. */
1564   if (need_to_clear_bottom)
1565     {
1566       redisplay_clear_bottom_of_window (w, ddla, need_to_clear_start,
1567                                         need_to_clear_end);
1568     }
1569
1570   w->window_end_pos[CURRENT_DISP] = w->window_end_pos[DESIRED_DISP];
1571   Fset_marker (w->start[CURRENT_DISP],
1572                make_int (marker_position (w->start[DESIRED_DISP])),
1573                w->buffer);
1574   Fset_marker (w->pointm[CURRENT_DISP],
1575                make_int (marker_position (w->pointm[DESIRED_DISP])),
1576                w->buffer);
1577   w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP];
1578   w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP];
1579   Fset_marker (w->last_start[CURRENT_DISP],
1580                Fmarker_position (w->last_start[DESIRED_DISP]), w->buffer);
1581   Fset_marker (w->last_point[CURRENT_DISP],
1582                Fmarker_position (w->last_point[DESIRED_DISP]), w->buffer);
1583   w->last_point_x[CURRENT_DISP] = w->last_point_x[DESIRED_DISP];
1584   w->last_point_y[CURRENT_DISP] = w->last_point_y[DESIRED_DISP];
1585   w->shadow_thickness_changed = 0;
1586
1587   set_window_display_buffer (w, XBUFFER (w->buffer));
1588   find_window_mirror (w)->truncate_win = window_truncation_on (w);
1589
1590   /* Overkill on invalidating the cache.  It is very bad for it to not
1591      get invalidated when it should be. */
1592   INVALIDATE_DEVICE_PIXEL_TO_GLYPH_CACHE (d);
1593
1594   /* We don't call output_end for tty frames.  Redisplay will do this
1595      after all tty windows have been updated.  This cuts down on
1596      cursor flicker. */
1597   if (FRAME_TTY_P (f))
1598     redisplay_redraw_cursor (f, 0);
1599   else
1600     DEVMETH (d, output_end, (d));
1601
1602 #ifdef HAVE_SCROLLBARS
1603   update_window_scrollbars (w, NULL, !MINI_WINDOW_P (w), 0);
1604 #endif
1605 }