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