(CHAR_TO_CHARC): New inline function.
[chise/xemacs-chise.git-] / 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    Copyright (C) 1999 Andy Piper.
6
7 This file is part of XEmacs.
8
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
12 later version.
13
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING.  If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 /* Synched up with: Not in FSF. */
25
26 /* This file has been Mule-ized. */
27
28 /* Author: Chuck Thompson */
29
30 /* Heavily hacked for modularity, gutter and subwindow support by Andy
31    Piper. */
32
33 #include <config.h>
34 #include "lisp.h"
35
36 #include "buffer.h"
37 #include "window.h"
38 #include "frame.h"
39 #include "device.h"
40 #include "glyphs.h"
41 #include "redisplay.h"
42 #include "faces.h"
43
44 static int compare_runes (struct window *w, struct rune *crb,
45                           struct rune *drb);
46 static void redraw_cursor_in_window (struct window *w,
47                                      int run_end_begin_glyphs);
48 static void redisplay_output_display_block (struct window *w, struct display_line *dl,
49                                             int block, int start, int end, int start_pixpos,
50                                             int cursor_start, int cursor_width,
51                                             int cursor_height);
52 static void redisplay_normalize_display_box (struct display_box* dest,
53                                              struct display_glyph_area* src);
54 static int redisplay_display_boxes_in_window_p (struct window* w,
55                                                 struct display_box* db,
56                                                 struct display_glyph_area* dga);
57 static void redisplay_clear_clipped_region (Lisp_Object locale, face_index findex,
58                                             struct display_box* dest,
59                                             struct display_glyph_area* glyphsrc,
60                                             int fullheight_p, Lisp_Object);
61
62 /*****************************************************************************
63  sync_rune_structs
64
65  Synchronize the given rune blocks.
66  ****************************************************************************/
67 static void
68 sync_rune_structs (struct window *w, rune_dynarr *cra, rune_dynarr *dra)
69 {
70   int rune_elt;
71   int max_move = ((Dynarr_length (dra) > Dynarr_largest (cra))
72                   ? Dynarr_largest (cra)
73                   : Dynarr_length (dra));
74
75   if (max_move)
76     {
77       /* #### Doing this directly breaks the encapsulation.  But, the
78          running time of this function has a measurable impact on
79          redisplay performance so avoiding all excess overhead is a
80          good thing.  Is all of this true? */
81       memcpy (cra->base, dra->base, sizeof (struct rune) * max_move);
82       Dynarr_set_size (cra, max_move);
83     }
84   else
85     Dynarr_reset (cra);
86
87   for (rune_elt = max_move; rune_elt < Dynarr_length (dra); rune_elt++)
88     {
89       struct rune rb, *crb;
90       struct rune *drb = Dynarr_atp (dra, rune_elt);
91
92       crb = &rb;
93       memcpy (crb, drb, sizeof (struct rune));
94       Dynarr_add (cra, *crb);
95     }
96 }
97
98 /*****************************************************************************
99  sync_display_line_structs
100
101  For the given LINE in window W, make the current display line equal
102  the desired display line.
103  ****************************************************************************/
104 void
105 sync_display_line_structs (struct window *w, int line, int do_blocks,
106                            display_line_dynarr *cdla,
107                            display_line_dynarr *ddla)
108 {
109   int cdla_len = Dynarr_length (cdla);
110
111   struct display_line dl, *clp, *dlp;
112   int db_elt;
113
114   dlp = Dynarr_atp (ddla, line);
115   if (line >= Dynarr_largest (cdla))
116     {
117       clp = &dl;
118       clp->display_blocks = Dynarr_new (display_block);
119     }
120   else
121     {
122       clp = Dynarr_atp (cdla, line);
123       if (clp->display_blocks)
124         Dynarr_reset (clp->display_blocks);
125       if (clp->left_glyphs)
126         {
127           Dynarr_free (clp->left_glyphs);
128           clp->left_glyphs = 0;
129         }
130       if (clp->right_glyphs)
131         {
132           Dynarr_free (clp->right_glyphs);
133           clp->right_glyphs = 0;
134         }
135     }
136   {
137     display_block_dynarr *tdb = clp->display_blocks;
138
139     memcpy (clp, dlp, sizeof (struct display_line));
140     clp->display_blocks = tdb;
141     clp->left_glyphs = 0;
142     clp->right_glyphs = 0;
143   }
144
145   if (!do_blocks && line >= cdla_len)
146     {
147       Dynarr_add (cdla, *clp);
148       return;
149     }
150
151   for (db_elt = 0; db_elt < Dynarr_length (dlp->display_blocks); db_elt++)
152     {
153       struct display_block db, *cdb;
154       struct display_block *ddb = Dynarr_atp (dlp->display_blocks, db_elt);
155
156       if (db_elt >= Dynarr_largest (clp->display_blocks))
157         {
158           cdb = &db;
159           memcpy (cdb, ddb, sizeof (struct display_block));
160           cdb->runes = Dynarr_new (rune);
161           Dynarr_add (clp->display_blocks, *cdb);
162         }
163       else
164         {
165           rune_dynarr *tr;
166
167           cdb = Dynarr_atp (clp->display_blocks, db_elt);
168           tr = cdb->runes;
169           memcpy (cdb, ddb, sizeof (struct display_block));
170           cdb->runes = tr;
171           Dynarr_increment (clp->display_blocks);
172         }
173
174       sync_rune_structs (w, cdb->runes, ddb->runes);
175     }
176
177   if (line >= cdla_len)
178     Dynarr_add (cdla, *clp);
179 }
180
181 /*****************************************************************************
182  compare_runes
183
184  Compare to runes to see if each of their fields is equal.  If so,
185  return true otherwise return false.
186  ****************************************************************************/
187 static int
188 compare_runes (struct window *w, struct rune *crb, struct rune *drb)
189 {
190   /* Do not compare the values of bufpos and endpos.  They do not
191      affect the display characteristics. */
192
193   /* Note: (hanoi 6) spends 95% of its time in redisplay, and about
194      30% here. Not using bitfields for rune.type alone gives a redisplay
195      speed up of 10%.
196
197      #### In profile arcs run of a normal Gnus session this function
198      is run 6.76 million times, only to return 1 in 6.73 million of
199      those.
200
201      In addition a quick look GCC sparc assembly shows that GCC is not
202      doing a good job here.
203      1. The function is not inlined (too complicated?)
204      2. It seems to be reloading the crb and drb variables all the
205      time.
206      3. It doesn't seem to notice that the second half of these if's
207      are really a switch statement.
208
209      So I (JV) conjecture
210
211      #### It would really be worth it to arrange for this function to
212      be (almost) a single call to memcmp. */
213
214   if (crb->xpos != drb->xpos)
215     return 0;
216   else if (crb->width != drb->width)
217     return 0;
218   else if (crb->cursor_type != drb->cursor_type)
219     return 0;
220   else if (crb->type != drb->type)
221     return 0;
222   else if (crb->type == RUNE_CHAR &&
223            (!EQ (crb->object.cglyph.charset, drb->object.cglyph.charset) ||
224             crb->object.cglyph.code_point != drb->object.cglyph.code_point))
225     return 0;
226   else if (crb->type == RUNE_HLINE &&
227            (crb->object.hline.thickness != drb->object.hline.thickness ||
228             crb->object.hline.yoffset != drb->object.hline.yoffset))
229     return 0;
230   else if (crb->type == RUNE_DGLYPH &&
231            (!EQ (crb->object.dglyph.glyph, drb->object.dglyph.glyph) ||
232             !EQ (crb->object.dglyph.extent, drb->object.dglyph.extent) ||
233             crb->object.dglyph.xoffset != drb->object.dglyph.xoffset))
234     return 0;
235   /* Only check dirtiness if we know something has changed. */
236   else if (crb->type == RUNE_DGLYPH &&
237            (XGLYPH_DIRTYP (crb->object.dglyph.glyph) || 
238             crb->findex != drb->findex))
239     {
240       /* We need some way of telling redisplay_output_layout () that the
241          only reason we are outputting it is because something has
242          changed internally. That way we can optimize whether we need
243          to clear the layout first and also only output the components
244          that have changed. The image_instance dirty flag and
245          display_hash are no good to us because these will invariably
246          have been set anyway if the layout has changed. So it looks
247          like we need yet another change flag that we can set here and
248          then clear in redisplay_output_layout (). */
249       Lisp_Object window, image;
250       Lisp_Image_Instance* ii;
251       XSETWINDOW (window, w);
252       image = glyph_image_instance (crb->object.dglyph.glyph,
253                                     window, ERROR_ME_NOT, 1);
254
255       if (!IMAGE_INSTANCEP (image))
256         return 0;
257       ii = XIMAGE_INSTANCE (image);
258
259       if (TEXT_IMAGE_INSTANCEP (image) && 
260           (crb->findex != drb->findex || 
261            WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)))
262         return 0;
263
264       /* It is quite common of the two glyphs to be EQ since in many
265          cases they will actually be the same object. This does not
266          mean, however, that nothing has changed. We therefore need to
267          check the current hash of the glyph against the last recorded
268          display hash and the pending display items. See
269          update_subwindow (). */
270       if (image_instance_changed (image) ||
271           crb->findex != drb->findex || 
272           WINDOW_FACE_CACHEL_DIRTY (w, drb->findex))
273         {
274           /* We now now we are going to re-output the glyph, but since
275              this is for some internal reason not related to geometry
276              changes, send a hint to the output routines that they can
277              take some short cuts. This is most useful for
278              layouts. This flag should get reset by the output
279              routines. 
280
281              #### It is possible for us to get here when the
282              face_cachel is dirty. I do not know what the implications
283              of this are.*/
284           IMAGE_INSTANCE_OPTIMIZE_OUTPUT (ii) = 1;
285           return 0;
286         }
287       else
288         return 1;
289     }
290   /* We now do this last so that glyph checks can do their own thing
291      for face changes. Face changes quite often happen when we are
292      trying to output something in the gutter, this would normally
293      lead to a lot of flashing. The indices can quite often be
294      different and yet the faces are the same, we do not want to
295      re-output in this instance. */
296   else  if (crb->findex != drb->findex ||
297             WINDOW_FACE_CACHEL_DIRTY (w, drb->findex))
298     return 0;
299   else
300     return 1;
301 }
302
303 /*****************************************************************************
304  get_next_display_block
305
306  Return the next display starting at or overlapping START_POS.  Return
307  the start of the next region in NEXT_START.
308  ****************************************************************************/
309 int
310 get_next_display_block (layout_bounds bounds, display_block_dynarr *dba,
311                         int start_pos, int *next_start)
312 {
313   int next_display_block = NO_BLOCK;
314   int priority = -1;
315   int block;
316
317   /* If we don't find a display block covering or starting at
318      start_pos, then we return the starting point of the next display
319      block or the next division boundary, whichever is closer to
320      start_pos. */
321   if (next_start)
322     {
323       if (start_pos >= bounds.left_out && start_pos < bounds.left_in)
324         *next_start = bounds.left_in;
325       else if (start_pos < bounds.left_white)
326         *next_start = bounds.left_white;
327       else if (start_pos < bounds.right_white)
328         *next_start = bounds.right_white;
329       else if (start_pos < bounds.right_in)
330         *next_start = bounds.right_in;
331       else if (start_pos <= bounds.right_out)
332         *next_start = bounds.right_out;
333       else
334         abort ();
335     }
336
337   for (block = 0; block < Dynarr_length (dba); block++)
338     {
339       struct display_block *db = Dynarr_atp (dba, block);
340
341       if (db->start_pos <= start_pos && db->end_pos > start_pos)
342         {
343           if ((int) db->type > priority)
344             {
345               priority = db->type;
346               next_display_block = block;
347               if (next_start)
348                 *next_start = db->end_pos;
349             }
350         }
351       else if (next_start && db->start_pos > start_pos)
352         {
353           if (db->start_pos < *next_start)
354             *next_start = db->start_pos;
355         }
356     }
357
358   return next_display_block;
359 }
360
361 /*****************************************************************************
362  get_cursor_size_and_location
363
364  Return the information defining the pixel location of the cursor.
365  ****************************************************************************/
366 static void
367 get_cursor_size_and_location (struct window *w, struct display_block *db,
368                               int cursor_location,
369                               int *cursor_start, int *cursor_width,
370                               int *cursor_height)
371 {
372   struct rune *rb;
373   Lisp_Object window;
374   int defheight, defwidth;
375
376   if (Dynarr_length (db->runes) <= cursor_location)
377     abort ();
378
379   XSETWINDOW (window, w);
380
381   rb = Dynarr_atp (db->runes, cursor_location);
382   *cursor_start = rb->xpos;
383
384   default_face_height_and_width (window, &defheight, &defwidth);
385   *cursor_height = defheight;
386
387   if (rb->type == RUNE_BLANK)
388     *cursor_width = defwidth;
389   else
390     *cursor_width = rb->width;
391 }
392
393 /*****************************************************************************
394  compare_display_blocks
395
396  Given two display blocks, output only those areas where they differ.
397  ****************************************************************************/
398 static int
399 compare_display_blocks (struct window *w, struct display_line *cdl,
400                         struct display_line *ddl, int c_block, int d_block,
401                         int start_pixpos, int cursor_start, int cursor_width,
402                         int cursor_height)
403 {
404   struct frame *f = XFRAME (w->frame);
405   struct display_block *cdb, *ddb;
406   int start_pos;
407   int stop_pos;
408   int force = 0;
409   int block_end;
410
411   cdb = Dynarr_atp (cdl->display_blocks, c_block);
412   ddb = Dynarr_atp (ddl->display_blocks, d_block);
413
414   assert (cdb->type == ddb->type);
415
416   start_pos = -1;
417   stop_pos = min (Dynarr_length (cdb->runes), Dynarr_length (ddb->runes));
418
419   block_end =
420     (!Dynarr_length (ddb->runes)
421      ? 0
422      : (Dynarr_atp (ddb->runes, Dynarr_length (ddb->runes) - 1)->xpos +
423         Dynarr_atp (ddb->runes, Dynarr_length (ddb->runes) - 1)->width));
424
425   /* If the new block type is not text and the cursor status is
426      changing and it overlaps the position of this block then force a
427      full redraw of the block in order to make sure that the cursor is
428      updated properly. */
429   if (ddb->type != TEXT
430 #if 0
431       /* I'm not sure exactly what this code wants to do, but it's
432        * not right--it doesn't update when cursor_elt changes from, e.g.,
433        * 0 to 8, and the new or old cursor loc overlaps this block.
434        * I've replaced it with the more conservative test below.
435        * -dkindred@cs.cmu.edu 23-Mar-1997 */
436       && ((cdl->cursor_elt == -1 && ddl->cursor_elt != -1)
437           || (cdl->cursor_elt != -1 && ddl->cursor_elt == -1))
438       && (ddl->cursor_elt == -1 ||
439           (cursor_start
440            && cursor_width
441            && (cursor_start + cursor_width) >= start_pixpos
442            && cursor_start <= block_end))
443 #else
444       && (cdl->cursor_elt != ddl->cursor_elt)
445 #endif
446       )
447     force = 1;
448
449   if (f->windows_structure_changed ||
450       /* #### Why is this so? We have face cachels so that we don't
451          have to recalculate all the display blocks when faces
452          change. I have fixed this for glyphs and am inclined to think
453          that faces should "Just Work", but I'm not feeling brave
454          today. Maybe its because the face cachels represent merged
455          faces rather than simply instantiations in a particular
456          domain. */
457       f->faces_changed ||
458       cdl->ypos != ddl->ypos ||
459       cdl->ascent != ddl->ascent ||
460       cdl->descent != ddl->descent ||
461       cdl->clip != ddl->clip ||
462       force)
463     {
464       start_pos = 0;
465       force = 1;
466     }
467   else
468     {
469       int elt = 0;
470
471       while (start_pos < 0 && elt < stop_pos)
472         {
473           if (!compare_runes (w, Dynarr_atp (cdb->runes, elt),
474                               Dynarr_atp (ddb->runes, elt)))
475             {
476               start_pos = elt;
477             }
478           else
479             {
480               elt++;
481             }
482         }
483
484       /* If nothing has changed in the area where the blocks overlap, but
485          there are new blocks in the desired block, then adjust the start
486          point accordingly. */
487       if (elt == stop_pos && stop_pos < Dynarr_length (ddb->runes))
488         start_pos = stop_pos;
489     }
490
491   if (start_pos >= 0)
492     {
493       if ((Dynarr_length (ddb->runes) != Dynarr_length (cdb->runes))
494           || force)
495         {
496           stop_pos = Dynarr_length (ddb->runes);
497         }
498       else
499         {
500           /* If the lines have the same number of runes and we are not
501              forcing a full redraw because the display line has
502              changed position then we try and optimize how much of the
503              line we actually redraw by scanning backwards from the
504              end for the first changed rune.  This optimization is
505              almost always triggered by face changes. */
506
507           int elt = Dynarr_length (ddb->runes) - 1;
508
509           while (elt > start_pos)
510             {
511               if (!compare_runes (w, Dynarr_atp (cdb->runes, elt),
512                                   Dynarr_atp (ddb->runes, elt)))
513                 break;
514               else
515                 elt--;
516             }
517           stop_pos = elt + 1;
518         }
519
520       redisplay_output_display_block (w, ddl, d_block, start_pos,
521                                       stop_pos, start_pixpos,
522                                       cursor_start, cursor_width,
523                                       cursor_height);
524       return 1;
525     }
526
527   return 0;
528 }
529
530 /*****************************************************************************
531  clear_left_border
532
533  Clear the lefthand outside border.
534  ****************************************************************************/
535 static void
536 clear_left_border (struct window *w, int y, int height)
537 {
538   struct frame *f = XFRAME (w->frame);
539   Lisp_Object window;
540
541   XSETWINDOW (window, w);
542   redisplay_clear_region (window, DEFAULT_INDEX,
543                 FRAME_LEFT_BORDER_START (f), y,
544                 FRAME_BORDER_WIDTH (f), height);
545 }
546
547 /*****************************************************************************
548  clear_right_border
549
550  Clear the righthand outside border.
551  ****************************************************************************/
552 static void
553 clear_right_border (struct window *w, int y, int height)
554 {
555   struct frame *f = XFRAME (w->frame);
556   Lisp_Object window;
557
558   XSETWINDOW (window, w);
559   redisplay_clear_region (window, DEFAULT_INDEX,
560                 FRAME_RIGHT_BORDER_START (f),
561                 y, FRAME_BORDER_WIDTH (f), height);
562 }
563
564 /*****************************************************************************
565  output_display_line
566
567  Ensure that the contents of the given display line is correct
568  on-screen.  The force_ parameters are used by redisplay_move_cursor
569  to correctly update cursor locations and only cursor locations.
570  ****************************************************************************/
571 void
572 output_display_line (struct window *w, display_line_dynarr *cdla,
573                      display_line_dynarr *ddla, int line, int force_start,
574                      int force_end)
575
576 {
577   struct frame *f = XFRAME (w->frame);
578   struct buffer *b = XBUFFER (w->buffer);
579   struct buffer *old_b = window_display_buffer (w);
580   struct display_line *cdl, *ddl;
581   display_block_dynarr *cdba, *ddba;
582   int start_pixpos, end_pixpos;
583   int cursor_start, cursor_width, cursor_height;
584
585   int force = (force_start >= 0 || force_end >= 0);
586   int clear_border = 0;
587   int must_sync = 0;
588
589   if (cdla && line < Dynarr_length (cdla))
590     {
591       cdl = Dynarr_atp (cdla, line);
592       cdba = cdl->display_blocks;
593     }
594   else
595     {
596       cdl = NULL;
597       cdba = NULL;
598     }
599
600   ddl = Dynarr_atp (ddla, line);      /* assert line < Dynarr_length (ddla) */
601   ddba = ddl->display_blocks;
602
603   if (force_start >= 0 && force_start >= ddl->bounds.left_out)
604     start_pixpos = force_start;
605   else
606     start_pixpos = ddl->bounds.left_out;
607
608   if (force_end >= 0 && force_end < ddl->bounds.right_out)
609     end_pixpos = force_end;
610   else
611     end_pixpos = ddl->bounds.right_out;
612
613   /* Get the cursor parameters. */
614   if (ddl->cursor_elt != -1)
615     {
616       struct display_block *db;
617
618       /* If the lines cursor parameter is not -1 then it indicates
619          which rune in the TEXT block contains the cursor.  This means
620          that there must be at least one display block.  The TEXT
621          block, if present, must always be the first display block. */
622       assert (Dynarr_length (ddba) != 0);
623
624       db = Dynarr_atp (ddba, 0);
625       assert (db->type == TEXT);
626
627       get_cursor_size_and_location (w, db, ddl->cursor_elt, &cursor_start,
628                                     &cursor_width, &cursor_height);
629     }
630   else
631     {
632       cursor_start = cursor_width = cursor_height = 0;
633     }
634
635   /* The modeline should only have a single block and it had better be
636      a TEXT block. */
637   if (ddl->modeline)
638     {
639       /* The shadow thickness check is necessary if only the sign of
640          the size changed. */
641       if (cdba && !w->shadow_thickness_changed)
642         {
643           must_sync |= compare_display_blocks (w, cdl, ddl, 0, 0,
644                                                start_pixpos, 0, 0, 0);
645         }
646       else
647         {
648           redisplay_output_display_block (w, ddl, 0, 0, -1, start_pixpos,
649                                           0, 0, 0);
650           must_sync = 1;
651         }
652
653       if (must_sync)
654         clear_border = 1;
655     }
656
657   while (!ddl->modeline && start_pixpos < end_pixpos)
658     {
659       int block;
660       int next_start_pixpos;
661
662       block = get_next_display_block (ddl->bounds, ddba, start_pixpos,
663                                       &next_start_pixpos);
664
665       /* If we didn't find a block then we should blank the area
666          between start_pos and next_start if necessary. */
667       if (block == NO_BLOCK)
668         {
669           /* We only erase those areas which were actually previously
670              covered by a display block unless the window structure
671              changed.  In that case we clear all areas since the current
672              structures may actually represent a different buffer. */
673           while (start_pixpos < next_start_pixpos)
674             {
675               int block_end;
676               int old_block;
677
678               if (cdba)
679                 old_block = get_next_display_block (ddl->bounds, cdba,
680                                                     start_pixpos, &block_end);
681               else
682                 {
683                   old_block = NO_BLOCK;
684                   block_end = next_start_pixpos;
685                 }
686
687               if (!cdba || old_block != NO_BLOCK || b != old_b ||
688                   f->windows_structure_changed ||
689                   f->faces_changed ||
690                   force ||
691                   (cdl && (cdl->ypos != ddl->ypos ||
692                            cdl->ascent != ddl->ascent ||
693                            cdl->descent != ddl->descent ||
694                            cdl->top_clip != ddl->top_clip ||
695                            cdl->clip != ddl->clip)))
696                 {
697                   int x, y, width, height;
698                   face_index findex;
699
700                   must_sync = 1;
701                   x = start_pixpos;
702                   y = DISPLAY_LINE_YPOS (ddl);
703                   width = min (next_start_pixpos, block_end) - x;
704                   height = DISPLAY_LINE_HEIGHT (ddl);
705
706                   if (x < ddl->bounds.left_in)
707                     {
708                       findex = ddl->left_margin_findex ?
709                         ddl->left_margin_findex
710                         : get_builtin_face_cache_index (w, Vleft_margin_face);
711                     }
712                   else if (x < ddl->bounds.right_in)
713                     {
714                       /* no check here because DEFAULT_INDEX == 0 anyway */
715                       findex = ddl->default_findex;
716                     }
717                   else if (x < ddl->bounds.right_out)
718                     {
719                       findex = ddl->right_margin_findex ?
720                         ddl->right_margin_findex
721                         : get_builtin_face_cache_index (w, Vright_margin_face);
722                     }
723                   else
724                     findex = (face_index) -1;
725
726                   if (findex != (face_index) -1)
727                     {
728                       Lisp_Object window;
729
730                       XSETWINDOW (window, w);
731
732                       /* Clear the empty area. */
733                       redisplay_clear_region (window, findex, x, y, width, height);
734
735                       /* Mark that we should clear the border.  This is
736                          necessary because italic fonts may leave
737                          droppings in the border. */
738                       clear_border = 1;
739                     }
740                 }
741
742               start_pixpos = min (next_start_pixpos, block_end);
743             }
744         }
745       else
746         {
747           struct display_block *cdb, *ddb;
748           int block_end;
749           int old_block;
750
751           if (cdba)
752             old_block = get_next_display_block (ddl->bounds, cdba,
753                                                 start_pixpos, &block_end);
754           else
755             old_block = NO_BLOCK;
756
757           ddb = Dynarr_atp (ddba, block);
758           cdb = (old_block != NO_BLOCK ? Dynarr_atp (cdba, old_block) : 0);
759
760           /* If there was formerly no block over the current
761              region or if it was a block of a different type, then
762              output the entire ddb.  Otherwise, compare cdb and
763              ddb and output only the changed region. */
764           if (!force && cdb && ddb->type == cdb->type
765               /* If there was no buffer being display before the
766                  compare anyway as we might be outputting a gutter. */
767               &&
768               (b == old_b || !old_b))
769             {
770               must_sync |= compare_display_blocks (w, cdl, ddl, old_block,
771                                                    block, start_pixpos,
772                                                    cursor_start, cursor_width,
773                                                    cursor_height);
774             }
775           else
776             {
777               int elt;
778               int first_elt = 0;
779               int last_elt = -1;
780
781               for (elt = 0; elt < Dynarr_length (ddb->runes); elt++)
782                 {
783                   struct rune *rb = Dynarr_atp (ddb->runes, elt);
784
785                   if (start_pixpos >= rb->xpos
786                       && start_pixpos < rb->xpos + rb->width)
787                     first_elt = elt;
788
789                   if (end_pixpos > rb->xpos
790                       && end_pixpos <= rb->xpos + rb->width)
791                     {
792                       last_elt = elt + 1;
793                       if (last_elt > Dynarr_length (ddb->runes))
794                         last_elt = Dynarr_length (ddb->runes);
795                       break;
796                     }
797                 }
798
799               must_sync = 1;
800               redisplay_output_display_block (w, ddl, block, first_elt,
801                                               last_elt,
802                                               start_pixpos,
803                                               cursor_start, cursor_width,
804                                               cursor_height);
805             }
806
807           start_pixpos = next_start_pixpos;
808         }
809     }
810
811   /* Clear the internal border if we are next to it and the window
812      structure or frame size has changed or if something caused
813      clear_border to be tripped.  */
814   /* #### Doing this on f->clear sucks but is necessary because of
815      window-local background values. */
816   if (f->windows_structure_changed || f->faces_changed || clear_border
817       || f->clear)
818     {
819       int y = DISPLAY_LINE_YPOS (ddl);
820       int height = DISPLAY_LINE_HEIGHT (ddl);
821
822       /* If we are in the gutter then we musn't clear the borders. */
823       if (y >= WINDOW_TEXT_TOP (w) && (y + height) <= WINDOW_TEXT_BOTTOM (w))
824         {
825           if (ddl->modeline)
826             {
827               y -= MODELINE_SHADOW_THICKNESS (w);
828               height += (2 * MODELINE_SHADOW_THICKNESS (w));
829             }
830
831           if (window_is_leftmost (w))
832             clear_left_border (w, y, height);
833           if (window_is_rightmost (w))
834             clear_right_border (w, y, height);
835         }
836     }
837
838   if (cdla)
839     sync_display_line_structs (w, line, must_sync, cdla, ddla);
840 }
841
842 /*****************************************************************************
843  redisplay_move_cursor
844
845  For the given window W, move the cursor to NEW_POINT.  Returns a
846  boolean indicating success or failure.
847  ****************************************************************************/
848
849 #define ADJ_BUFPOS (rb->bufpos + dl->offset)
850 #define ADJ_ENDPOS (rb->endpos + dl->offset)
851
852 int
853 redisplay_move_cursor (struct window *w, Bufpos new_point, int no_output_end)
854 {
855   struct frame *f = XFRAME (w->frame);
856   struct device *d = XDEVICE (f->device);
857
858   display_line_dynarr *cla = window_display_lines (w, CURRENT_DISP);
859   struct display_line *dl;
860   struct display_block *db;
861   struct rune *rb;
862   int x = w->last_point_x[CURRENT_DISP];
863   int y = w->last_point_y[CURRENT_DISP];
864
865   /*
866    * Bail if cursor_in_echo_area is non-zero and we're fiddling with
867    * the cursor in a non-active minibuffer window, since that is a
868    * special case that is handled elsewhere and this function need
869    * not handle it.  Return 1 so the caller will assume we
870    * succeeded.
871    */
872   if (cursor_in_echo_area && MINI_WINDOW_P (w) &&
873       w != XWINDOW (FRAME_SELECTED_WINDOW (f)))
874     return 1;
875
876   if (y < 0 || y >= Dynarr_length (cla))
877     return 0;
878
879   dl = Dynarr_atp (cla, y);
880   db = get_display_block_from_line (dl, TEXT);
881
882   if (x < 0 || x >= Dynarr_length (db->runes))
883     return 0;
884
885   rb = Dynarr_atp (db->runes, x);
886
887   if (rb->cursor_type == CURSOR_OFF)
888     return 0;
889   else if (ADJ_BUFPOS == new_point
890            || (ADJ_ENDPOS && (new_point >= ADJ_BUFPOS)
891                && (new_point <= ADJ_ENDPOS)))
892     {
893       w->last_point_x[CURRENT_DISP] = x;
894       w->last_point_y[CURRENT_DISP] = y;
895       Fset_marker (w->last_point[CURRENT_DISP], make_int (ADJ_BUFPOS),
896                    w->buffer);
897       dl->cursor_elt = x;
898       return 1;
899     }
900   else
901     {
902       {
903         MAYBE_DEVMETH (d, frame_output_begin, (f));
904         MAYBE_DEVMETH (d, window_output_begin, (w));
905       }
906       rb->cursor_type = CURSOR_OFF;
907       dl->cursor_elt = -1;
908       output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width);
909     }
910
911   w->last_point_x[CURRENT_DISP] = -1;
912   w->last_point_y[CURRENT_DISP] = -1;
913   Fset_marker (w->last_point[CURRENT_DISP], Qnil, w->buffer);
914
915   /* If this isn't the selected frame, then erasing the old cursor is
916      all we actually had to do. */
917   if (w != XWINDOW (FRAME_SELECTED_WINDOW (device_selected_frame (d))))
918     {
919       if (!no_output_end)
920         {
921           MAYBE_DEVMETH (d, window_output_end, (w));
922           MAYBE_DEVMETH (d, frame_output_end, (f));
923         }
924
925       return 1;
926     }
927
928   /* This should only occur in the minibuffer. */
929   if (new_point == 0)
930     {
931       w->last_point_x[CURRENT_DISP] = 0;
932       w->last_point_y[CURRENT_DISP] = y;
933       Fset_marker (w->last_point[CURRENT_DISP], Qzero, w->buffer);
934
935       rb = Dynarr_atp (db->runes, 0);
936       rb->cursor_type = CURSOR_ON;
937       dl->cursor_elt = 0;
938
939       output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width);
940
941       if (!no_output_end)
942         {
943           MAYBE_DEVMETH (d, window_output_end, (w));
944           MAYBE_DEVMETH (d, frame_output_end, (f));
945         }
946       return 1;
947     }
948   else
949     {
950       int cur_rb = 0;
951       int first = 0;
952       int cur_dl, up;
953
954       if (ADJ_BUFPOS < new_point)
955         {
956           up = 1;
957           cur_rb = x + 1;
958           cur_dl = y;
959         }
960       else /* (rb->bufpos + dl->offset) > new_point */
961         {
962           up = 0;
963
964           if (!x)
965             {
966               cur_dl = y - 1;
967               first = 0;
968             }
969           else
970             {
971               cur_rb = x - 1;
972               cur_dl = y;
973               first = 1;
974             }
975         }
976
977       while (up ? (cur_dl < Dynarr_length (cla)) : (cur_dl >= 0))
978         {
979           dl = Dynarr_atp (cla, cur_dl);
980           db = get_display_block_from_line (dl, TEXT);
981
982           if (!up && !first)
983             cur_rb = Dynarr_length (db->runes) - 1;
984
985           while ((!scroll_on_clipped_lines || !dl->clip) &&
986                  (up ? (cur_rb < Dynarr_length (db->runes)) : (cur_rb >= 0)))
987             {
988               rb = Dynarr_atp (db->runes, cur_rb);
989
990               if (rb->cursor_type != IGNORE_CURSOR
991                   && rb->cursor_type != NO_CURSOR &&
992                   (ADJ_BUFPOS == new_point
993                    || (ADJ_ENDPOS && (new_point >= ADJ_BUFPOS)
994                        && (new_point <= ADJ_BUFPOS))))
995                 {
996                   rb->cursor_type = CURSOR_ON;
997                   dl->cursor_elt = cur_rb;
998
999
1000                   output_display_line (w, 0, cla, cur_dl, rb->xpos,
1001                                        rb->xpos + rb->width);
1002
1003                   w->last_point_x[CURRENT_DISP] = cur_rb;
1004                   w->last_point_y[CURRENT_DISP] = cur_dl;
1005                   Fset_marker (w->last_point[CURRENT_DISP],
1006                                make_int (ADJ_BUFPOS), w->buffer);
1007
1008                   if (!no_output_end)
1009                     {
1010                       MAYBE_DEVMETH (d, window_output_end, (w));
1011                       MAYBE_DEVMETH (d, frame_output_end, (f));
1012                     }
1013                   return 1;
1014                 }
1015
1016               (up ? cur_rb++ : cur_rb--);
1017             }
1018
1019           (up ? (cur_rb = 0) : (first = 0));
1020           (up ? cur_dl++ : cur_dl--);
1021         }
1022     }
1023
1024   if (!no_output_end)
1025     {
1026       MAYBE_DEVMETH (d, window_output_end, (w));
1027       MAYBE_DEVMETH (d, frame_output_end, (f));
1028     }
1029   return 0;
1030 }
1031 #undef ADJ_BUFPOS
1032 #undef ADJ_ENDPOS
1033
1034 /*****************************************************************************
1035  redraw_cursor_in_window
1036
1037  For the given window W, redraw the cursor if it is contained within
1038  the window.
1039  ****************************************************************************/
1040 static void
1041 redraw_cursor_in_window (struct window *w, int run_end_begin_meths)
1042 {
1043   struct frame *f = XFRAME (w->frame);
1044   struct device *d = XDEVICE (f->device);
1045
1046   display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
1047   struct display_line *dl;
1048   struct display_block *db;
1049   struct rune *rb;
1050
1051   int x = w->last_point_x[CURRENT_DISP];
1052   int y = w->last_point_y[CURRENT_DISP];
1053
1054   if (cursor_in_echo_area && MINI_WINDOW_P (w) &&
1055       !echo_area_active (f) && minibuf_level == 0)
1056     {
1057       MAYBE_DEVMETH (d, set_final_cursor_coords, (f, w->pixel_top, 0));
1058     }
1059
1060   if (y < 0 || y >= Dynarr_length (dla))
1061     return;
1062
1063   if (MINI_WINDOW_P (w) && f != device_selected_frame (d) &&
1064       !is_surrogate_for_selected_frame (f))
1065     return;
1066
1067   dl = Dynarr_atp (dla, y);
1068   db = get_display_block_from_line (dl, TEXT);
1069
1070   if (x < 0 || x >= Dynarr_length (db->runes))
1071     return;
1072
1073   rb = Dynarr_atp (db->runes, x);
1074
1075   /* Don't call the output routine if the block isn't actually the
1076      cursor. */
1077   if (rb->cursor_type == CURSOR_ON)
1078     {
1079       MAYBE_DEVMETH (d, set_final_cursor_coords,
1080                      (f, dl->ypos - 1, rb->xpos));
1081
1082       if (run_end_begin_meths)
1083         {
1084           MAYBE_DEVMETH (d, frame_output_begin, (f));
1085           MAYBE_DEVMETH (d, window_output_begin, (w));
1086         }
1087
1088       output_display_line (w, 0, dla, y, rb->xpos, rb->xpos + rb->width);
1089
1090       if (run_end_begin_meths)
1091         {
1092           MAYBE_DEVMETH (d, window_output_end, (w));
1093           MAYBE_DEVMETH (d, frame_output_end, (f));
1094         }
1095     }
1096 }
1097
1098 /*****************************************************************************
1099  redisplay_redraw_cursor
1100
1101  For the given frame F, redraw the cursor on the selected window.
1102  This is used to update the cursor after focus changes.
1103  ****************************************************************************/
1104 void
1105 redisplay_redraw_cursor (struct frame *f, int run_end_begin_meths)
1106 {
1107   Lisp_Object window;
1108
1109   if (!cursor_in_echo_area)
1110     window = FRAME_SELECTED_WINDOW (f);
1111   else if (FRAME_HAS_MINIBUF_P (f))
1112     window = FRAME_MINIBUF_WINDOW (f);
1113   else
1114     return;
1115
1116   redraw_cursor_in_window (XWINDOW (window), run_end_begin_meths);
1117 }
1118
1119 /****************************************************************************
1120  redisplay_output_display_block
1121
1122  Given a display line, a block number for that start line, output all
1123  runes between start and end in the specified display block.
1124  ****************************************************************************/
1125 static void
1126 redisplay_output_display_block (struct window *w, struct display_line *dl, int block,
1127                                 int start, int end, int start_pixpos, int cursor_start,
1128                                 int cursor_width, int cursor_height)
1129 {
1130   struct frame *f = XFRAME (w->frame);
1131   struct device *d = XDEVICE (f->device);
1132   /* Temporarily disabled until generalization is done. */
1133 #if 0
1134   struct display_block *db = Dynarr_atp (dl->display_blocks, block);
1135   rune_dynarr *rba = db->runes;
1136   struct rune *rb;
1137   int xpos, width;
1138   rb = Dynarr_atp (rba, start);
1139
1140   if (!rb)
1141       /* Nothing to do so don't do anything. */
1142       return;
1143
1144   xpos = max (start_pixpos, rb->xpos);
1145
1146   if (end < 0)
1147     end = Dynarr_length (rba);
1148
1149   rb  = Dynarr_atp (rba, end - 1);
1150   width = rb->xpos + rb->width - xpos;
1151 #endif
1152   /* now actually output the block. */
1153   DEVMETH (d, output_display_block, (w, dl, block, start,
1154                                      end, start_pixpos,
1155                                      cursor_start, cursor_width,
1156                                      cursor_height));
1157 }
1158
1159 /****************************************************************************
1160  redisplay_unmap_subwindows
1161
1162  Remove subwindows from the area in the box defined by the given
1163  parameters.
1164  ****************************************************************************/
1165 static void redisplay_unmap_subwindows (struct frame* f, int x, int y, int width, int height,
1166                                         Lisp_Object ignored_window)
1167 {
1168   Lisp_Object rest;
1169
1170   LIST_LOOP (rest, XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f)))
1171     {
1172       Lisp_Image_Instance *ii = XIMAGE_INSTANCE (XCAR (rest));
1173
1174       if (IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (ii)
1175           &&
1176           IMAGE_INSTANCE_DISPLAY_X (ii)
1177           + IMAGE_INSTANCE_DISPLAY_WIDTH (ii) > x 
1178           && 
1179           IMAGE_INSTANCE_DISPLAY_X (ii) < x + width
1180           &&
1181           IMAGE_INSTANCE_DISPLAY_Y (ii)
1182           + IMAGE_INSTANCE_DISPLAY_HEIGHT (ii) > y 
1183           && 
1184           IMAGE_INSTANCE_DISPLAY_Y (ii) < y + height
1185           &&
1186           !EQ (XCAR (rest), ignored_window))
1187         {
1188           unmap_subwindow (XCAR (rest));
1189         }
1190     }
1191 }
1192
1193 /****************************************************************************
1194  redisplay_unmap_subwindows_maybe
1195
1196  Potentially subwindows from the area in the box defined by the given
1197  parameters.
1198  ****************************************************************************/
1199 void redisplay_unmap_subwindows_maybe (struct frame* f, int x, int y, int width, int height)
1200 {
1201   if (!NILP (XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f))))
1202     {
1203       redisplay_unmap_subwindows (f, x, y, width, height, Qnil);
1204     }
1205 }
1206
1207 static void redisplay_unmap_subwindows_except_us (struct frame* f, int x, int y, int width,
1208                                                   int height, Lisp_Object subwindow)
1209 {
1210   if (!NILP (XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f))))
1211     {
1212       redisplay_unmap_subwindows (f, x, y, width, height, subwindow);
1213     }
1214 }
1215
1216 /****************************************************************************
1217  redisplay_output_subwindow
1218
1219  output a subwindow.  This code borrows heavily from the pixmap stuff,
1220  although is much simpler not needing to account for partial
1221  pixmaps, backgrounds etc.
1222  ****************************************************************************/
1223 void
1224 redisplay_output_subwindow (struct window *w,
1225                             Lisp_Object image_instance,
1226                             struct display_box* db, struct display_glyph_area* dga,
1227                             face_index findex, int cursor_start, int cursor_width,
1228                             int cursor_height)
1229 {
1230   Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1231   Lisp_Object window;
1232   struct display_glyph_area sdga;
1233
1234   dga->height = IMAGE_INSTANCE_HEIGHT (p);
1235   dga->width = IMAGE_INSTANCE_WIDTH (p);
1236
1237   /* The first thing we are going to do is update the display
1238      characteristics of the subwindow. This also clears the dirty
1239      flags as a side effect. */
1240   update_subwindow (image_instance);
1241
1242   /* This makes the glyph area fit into the display area. */
1243   if (!redisplay_normalize_glyph_area (db, dga))
1244     return;
1245
1246   XSETWINDOW (window, w);
1247
1248   /* Clear the area the subwindow is going into. */
1249   redisplay_clear_clipped_region (window, findex,
1250                                   db, dga, 0, image_instance);
1251
1252   /* This shrinks the display box to exactly enclose the glyph
1253      area. */
1254   redisplay_normalize_display_box (db, dga);
1255
1256   /* if we can't view the whole window we can't view any of it. We
1257      have to be careful here since we may be being asked to display
1258      part of a subwindow, the rest of which is on-screen as well. We
1259      need to allow this case and map the entire subwindow. We also
1260      need to be careful since the subwindow could be outside the
1261      window in the gutter or modeline - we also need to allow these
1262      cases.*/
1263   sdga.xoffset = -dga->xoffset;
1264   sdga.yoffset = -dga->yoffset;
1265   sdga.height = IMAGE_INSTANCE_HEIGHT (p);
1266   sdga.width = IMAGE_INSTANCE_WIDTH (p);
1267
1268   if (redisplay_display_boxes_in_window_p (w, db, &sdga) < 0)
1269     {
1270       map_subwindow (image_instance, db->xpos, db->ypos, dga);
1271     }
1272   else
1273     {
1274       sdga.xoffset = sdga.yoffset = 0;
1275       map_subwindow (image_instance, db->xpos - dga->xoffset,
1276                      db->ypos - dga->yoffset, &sdga);
1277     }
1278 }
1279
1280 /****************************************************************************
1281  redisplay_output_layout
1282
1283  Output a widget hierarchy. This can safely call itself recursively.
1284
1285  The complexity of outputting layouts is deciding whether to do it or
1286  not. Consider a layout enclosing some text, the text changes and is
1287  marked as dirty, but the enclosing layout has not been marked as
1288  dirty so no updates occur and the text will potentially be truncated.
1289  Alternatively we hold a back pointer in the image instance to the
1290  parent and mark the parent as dirty. But the layout code assumes that
1291  if the layout is dirty then the whole layout should be redisplayed,
1292  so we then get lots of flashing even though only the text has changed
1293  size. Of course if the text shrinks in size then we do actually need
1294  to redisplay the layout to repaint the exposed area. So what happens
1295  if we make a non-structural change like changing color? Either we
1296  redisplay everything, or we redisplay nothing. These are exactly the
1297  issues lwlib has to grapple with. We really need to know what has
1298  actually changed and make a layout decision based on that. We also
1299  really need to know what has changed so that we can only make the
1300  neccessary changes in update_subwindow.  This has all now been
1301  implemented, Viva la revolution!
1302  ****************************************************************************/
1303 void
1304 redisplay_output_layout (struct window *w,
1305                          Lisp_Object image_instance,
1306                          struct display_box* db, struct display_glyph_area* dga,
1307                          face_index findex, int cursor_start, int cursor_width,
1308                          int cursor_height)
1309 {
1310   Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1311   Lisp_Object window, rest;
1312   Charc_dynarr *buf = Dynarr_new (Charc);
1313   struct frame *f = XFRAME (w->frame);
1314   struct device *d = XDEVICE (f->device);
1315   int layout_height, layout_width;
1316
1317   XSETWINDOW (window, w);
1318
1319   layout_height = glyph_height (image_instance, window);
1320   layout_width = glyph_width (image_instance, window);
1321
1322   dga->height = layout_height;
1323   dga->width = layout_width;
1324 #ifdef DEBUG_WIDGET_OUTPUT
1325   printf ("outputing layout glyph %p\n", p);
1326 #endif
1327   /* This makes the glyph area fit into the display area. */
1328   if (!redisplay_normalize_glyph_area (db, dga))
1329     return;
1330
1331   /* Highly dodgy optimization. We want to only output the whole
1332      layout if we really have to. */
1333   if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (p)
1334       || IMAGE_INSTANCE_LAYOUT_CHANGED (p)
1335       || IMAGE_INSTANCE_WIDGET_FACE_CHANGED (p)
1336       || IMAGE_INSTANCE_SIZE_CHANGED (p)
1337       || IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p))
1338     {
1339       /* First clear the area we are drawing into. This is the easiest
1340          thing to do since we have many gaps that we have to make sure are
1341          filled in. */
1342       redisplay_clear_clipped_region (window, findex, db, dga, 1, Qnil);
1343
1344       /* Output a border if required */
1345       if (!NILP (IMAGE_INSTANCE_LAYOUT_BORDER (p)))
1346         {
1347           int edges = 0;
1348           enum edge_style style;
1349           int ypos = db->ypos;
1350           int height = dga->height;
1351
1352           if (dga->xoffset >= 0)
1353             edges |= EDGE_LEFT;
1354           if (dga->width - dga->xoffset == layout_width)
1355             edges |= EDGE_RIGHT;
1356           if (dga->yoffset >= 0)
1357             edges |= EDGE_TOP;
1358           if (dga->height - dga->yoffset == layout_height)
1359             edges |= EDGE_BOTTOM;
1360
1361           if (EQ (IMAGE_INSTANCE_LAYOUT_BORDER (p), Qetched_in))
1362             style = EDGE_ETCHED_IN;
1363           else if (EQ (IMAGE_INSTANCE_LAYOUT_BORDER (p), Qetched_out))
1364             style = EDGE_ETCHED_OUT;
1365           else if (EQ (IMAGE_INSTANCE_LAYOUT_BORDER (p), Qbevel_in))
1366             style = EDGE_BEVEL_IN;
1367           else if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (p)))
1368             {
1369               style = EDGE_ETCHED_IN;
1370               if (edges & EDGE_TOP)
1371                 {
1372                   ypos += XINT (IMAGE_INSTANCE_LAYOUT_BORDER (p));
1373                   height -= XINT (IMAGE_INSTANCE_LAYOUT_BORDER (p));
1374                 }
1375             }
1376           else
1377             style = EDGE_BEVEL_OUT;
1378
1379           MAYBE_DEVMETH (d, bevel_area,
1380                          (w, findex, db->xpos,
1381                           ypos,
1382                           dga->width, height, 2, edges, style));
1383         }
1384     }
1385
1386   /* This shrinks the display box to exactly enclose the glyph
1387      area. */
1388   redisplay_normalize_display_box (db, dga);
1389
1390   /* Flip through the widgets in the layout displaying as necessary */
1391   LIST_LOOP (rest, IMAGE_INSTANCE_LAYOUT_CHILDREN (p))
1392     {
1393       Lisp_Object child = XCAR (rest);
1394
1395       struct display_box cdb;
1396       /* For losing HP-UX */
1397       cdb.xpos = db->xpos;
1398       cdb.ypos = db->ypos;
1399       cdb.width = db->width;
1400       cdb.height = db->height;
1401
1402       /* First determine if the image is visible at all */
1403       if (IMAGE_INSTANCEP (child))
1404         {
1405           Lisp_Image_Instance* childii = XIMAGE_INSTANCE (child);
1406
1407           /* The enclosing layout offsets are +ve at this point */
1408           struct display_glyph_area cdga;
1409           cdga.xoffset  = IMAGE_INSTANCE_XOFFSET (childii) - dga->xoffset;
1410           cdga.yoffset = IMAGE_INSTANCE_YOFFSET (childii) - dga->yoffset;
1411           cdga.width = glyph_width (child, window);
1412           cdga.height = glyph_height (child, window);
1413
1414           IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) = 
1415             IMAGE_INSTANCE_OPTIMIZE_OUTPUT (p);
1416
1417           /* Although normalization is done by the output routines
1418              we have to do it here so that they don't try and
1419              clear all of db. This is true below also. */
1420           if (redisplay_normalize_glyph_area (&cdb, &cdga))
1421             {
1422               redisplay_normalize_display_box (&cdb, &cdga);
1423               /* Since the display boxes will now be totally in the
1424                  window if they are visible at all we can now check this easily. */
1425               if (cdb.xpos < db->xpos || cdb.ypos < db->ypos
1426                   || cdb.xpos + cdb.width > db->xpos + db->width
1427                   || cdb.ypos + cdb.height > db->ypos + db->height)
1428                 continue;
1429               /* We have to invert the offset here as normalization
1430                  will have made them positive which the output
1431                  routines will treat as a truly +ve offset. */
1432               cdga.xoffset = -cdga.xoffset;
1433               cdga.yoffset = -cdga.yoffset;
1434
1435               switch (IMAGE_INSTANCE_TYPE (childii))
1436                 {
1437                 case IMAGE_TEXT:
1438                   {
1439                     /* #### This is well hacked and could use some
1440                        generalisation.*/
1441                     if (redisplay_normalize_glyph_area (&cdb, &cdga)
1442                         &&
1443                         (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) ||
1444                          IMAGE_INSTANCE_DIRTYP (childii)))
1445                       {
1446                         struct display_line dl; /* this is fake */
1447                         Lisp_Object string =
1448                           IMAGE_INSTANCE_TEXT_STRING (childii);
1449                         Charset_ID charsets[NUM_LEADING_BYTES];
1450                         struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
1451
1452                         find_charsets_in_bufbyte_string (charsets,
1453                                                          XSTRING_DATA (string),
1454                                                          XSTRING_LENGTH (string));
1455                         ensure_face_cachel_complete (cachel, window, charsets);
1456
1457                         convert_bufbyte_string_into_charc_dynarr
1458                           (XSTRING_DATA (string), XSTRING_LENGTH (string),
1459                            buf);
1460
1461                         redisplay_normalize_display_box (&cdb, &cdga);
1462                         /* Offsets are now +ve again so be careful
1463                            when fixing up the display line. */
1464                         xzero (dl);
1465                         /* Munge boxes into display lines. */
1466                         dl.ypos = (cdb.ypos - cdga.yoffset)
1467                           + glyph_ascent (child, window);
1468                         dl.ascent = glyph_ascent (child, window);
1469                         dl.descent = glyph_descent (child, window);
1470                         dl.top_clip = cdga.yoffset;
1471                         dl.clip = (dl.ypos + dl.descent) - (cdb.ypos + cdb.height);
1472                         /* output_string doesn't understand offsets in
1473                            the same way as other routines - we have to
1474                            add the offset to the width so that we
1475                            output the full string. */
1476                         MAYBE_DEVMETH (d, output_string, (w, &dl, buf, cdb.xpos,
1477                                                           cdga.xoffset, cdb.xpos,
1478                                                           cdga.width + cdga.xoffset,
1479                                                           findex, 0, 0, 0, 0));
1480                         Dynarr_reset (buf);
1481                       }
1482                   }
1483                   break;
1484
1485                 case IMAGE_MONO_PIXMAP:
1486                 case IMAGE_COLOR_PIXMAP:
1487                   if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii)
1488                       || IMAGE_INSTANCE_DIRTYP (childii))
1489                     redisplay_output_pixmap (w, child, &cdb, &cdga, findex,
1490                                              0, 0, 0, 0);
1491                   break;
1492
1493                 case IMAGE_WIDGET:
1494                   if (EQ (IMAGE_INSTANCE_WIDGET_TYPE (childii), Qlayout))
1495                     {
1496                       redisplay_output_layout (w, child, &cdb, &cdga, findex,
1497                                                0, 0, 0);
1498                       break;
1499                     }
1500                 case IMAGE_SUBWINDOW:
1501                   if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) ||
1502                       IMAGE_INSTANCE_DIRTYP (childii))
1503                     redisplay_output_subwindow (w, child, &cdb, &cdga, findex,
1504                                                 0, 0, 0);
1505                   break;
1506
1507                 case IMAGE_NOTHING:
1508                   /* nothing is as nothing does */
1509                   break;
1510
1511                 case IMAGE_POINTER:
1512                 default:
1513                   abort ();
1514                 }
1515             }
1516           IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) = 0;
1517         }
1518     }
1519   
1520   /* Update any display properties. I'm not sure whether this actually
1521      does anything for layouts except clear the changed flags. */
1522   update_subwindow (image_instance);
1523
1524   Dynarr_free (buf);
1525 }
1526
1527 /****************************************************************************
1528  redisplay_output_pixmap
1529
1530
1531  output a pixmap.
1532  ****************************************************************************/
1533 void
1534 redisplay_output_pixmap (struct window *w,
1535                          Lisp_Object image_instance,
1536                          struct display_box* db, struct display_glyph_area* dga,
1537                          face_index findex, int cursor_start, int cursor_width,
1538                          int cursor_height, int offset_bitmap)
1539 {
1540   struct frame *f = XFRAME (w->frame);
1541   struct device *d = XDEVICE (f->device);
1542   Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1543   Lisp_Object window;
1544   XSETWINDOW (window, w);
1545
1546   dga->height = IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
1547   dga->width = IMAGE_INSTANCE_PIXMAP_WIDTH (p);
1548
1549   /* This makes the glyph area fit into the display area. */
1550   if (!redisplay_normalize_glyph_area (db, dga))
1551     return;
1552
1553   /* Clear the area the pixmap is going into.  The pixmap itself will
1554      always take care of the full width.  We don't want to clear where
1555      it is going to go in order to avoid flicker.  So, all we have to
1556      take care of is any area above or below the pixmap. If the pixmap
1557      has a mask in which case we have to clear the whole damn thing
1558      since we can't yet clear just the area not included in the
1559      mask. */
1560   if (!offset_bitmap)
1561     {
1562       redisplay_clear_clipped_region (window, findex,
1563                                       db, dga,
1564                                       (int)IMAGE_INSTANCE_PIXMAP_MASK (p),
1565                                       Qnil);
1566
1567       /* This shrinks the display box to exactly enclose the glyph
1568          area. */
1569       redisplay_normalize_display_box (db, dga);
1570     }
1571   assert (db->xpos >= 0 && db->ypos >= 0);
1572
1573   MAYBE_DEVMETH (d, output_pixmap, (w, image_instance,
1574                                     db, dga,
1575                                     findex, cursor_start,
1576                                     cursor_width, cursor_height,
1577                                     offset_bitmap));
1578 }
1579
1580 /****************************************************************************
1581  redisplay_clear_region
1582
1583  Clear the area in the box defined by the given parameters using the
1584  given face. This has been generalised so that subwindows can be
1585  coped with effectively.
1586  ****************************************************************************/
1587 void
1588 redisplay_clear_region (Lisp_Object locale, face_index findex, int x, int y,
1589                         int width, int height)
1590 {
1591   struct window *w = NULL;
1592   struct frame *f = NULL;
1593   struct device *d;
1594   Lisp_Object background_pixmap = Qunbound;
1595   Lisp_Object fcolor = Qnil, bcolor = Qnil;
1596
1597   if (!width || !height)
1598      return;
1599
1600   if (WINDOWP (locale))
1601     {
1602       w = XWINDOW (locale);
1603       f = XFRAME (w->frame);
1604     }
1605   else if (FRAMEP (locale))
1606     {
1607       w = NULL;
1608       f = XFRAME (locale);
1609     }
1610   else
1611     abort ();
1612
1613   d = XDEVICE (f->device);
1614
1615   /* if we have subwindows in the region we have to unmap them */
1616   redisplay_unmap_subwindows_maybe (f, x, y, width, height);
1617
1618   /* #### This isn't quite right for when this function is called
1619      from the toolbar code. */
1620
1621   /* Don't use a backing pixmap in the border area */
1622   if (x >= FRAME_LEFT_BORDER_END (f)
1623       && x < FRAME_RIGHT_BORDER_START (f)
1624       && y >= FRAME_TOP_BORDER_END (f)
1625       && y < FRAME_BOTTOM_BORDER_START (f))
1626     {
1627       Lisp_Object temp;
1628
1629       if (w)
1630         {
1631           temp = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, findex);
1632
1633           if (IMAGE_INSTANCEP (temp)
1634               && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
1635             {
1636               /* #### maybe we could implement such that a string
1637                  can be a background pixmap? */
1638               background_pixmap = temp;
1639             }
1640         }
1641       else
1642         {
1643           temp = FACE_BACKGROUND_PIXMAP (Vdefault_face, locale);
1644
1645           if (IMAGE_INSTANCEP (temp)
1646               && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
1647             {
1648               background_pixmap = temp;
1649             }
1650         }
1651     }
1652
1653   if (!UNBOUNDP (background_pixmap) &&
1654       XIMAGE_INSTANCE_PIXMAP_DEPTH (background_pixmap) == 0)
1655     {
1656       if (w)
1657         {
1658           fcolor = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1659           bcolor = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1660         }
1661       else
1662         {
1663           fcolor = FACE_FOREGROUND (Vdefault_face, locale);
1664           bcolor = FACE_BACKGROUND (Vdefault_face, locale);
1665         }
1666     }
1667   else
1668     {
1669       fcolor = (w ?
1670                 WINDOW_FACE_CACHEL_BACKGROUND (w, findex) :
1671                 FACE_BACKGROUND (Vdefault_face, locale));
1672
1673     }
1674
1675   if (UNBOUNDP (background_pixmap))
1676     background_pixmap = Qnil;
1677
1678   DEVMETH (d, clear_region,
1679            (locale, d, f, findex, x, y, width, height, fcolor, bcolor, background_pixmap));
1680 }
1681
1682 /****************************************************************************
1683  redisplay_clear_clipped_region
1684
1685  Clear the area in the dest display_box not covered by the src
1686  display_glyph_area using the given face. This is a common occurance
1687  for images shorter than the display line. Clipping can be played
1688  around with by altering these. glyphsrc should be normalized.
1689  ****************************************************************************/
1690 static void
1691 redisplay_clear_clipped_region (Lisp_Object window, face_index findex,
1692         struct display_box* dest, struct display_glyph_area* glyphsrc,
1693         int fullheight_p, Lisp_Object ignored_subwindow)
1694 {
1695   /* assume dest->xpos >= 0 */
1696   int clear_x;
1697   struct frame* f = XFRAME (XWINDOW (window)->frame);
1698
1699   if (glyphsrc->xoffset > 0)
1700     {
1701       clear_x = dest->xpos + glyphsrc->xoffset;
1702     }
1703   else
1704     {
1705       clear_x = dest->xpos;
1706     }
1707
1708   /* If we need the whole height cleared then just do it. */
1709   if (fullheight_p)
1710     {
1711       redisplay_clear_region (window, findex, clear_x, dest->ypos,
1712                               glyphsrc->width, dest->height);
1713     }
1714   else
1715     {
1716       int yoffset = (glyphsrc->yoffset > 0 ? glyphsrc->yoffset : 0);
1717
1718       /* We need to make sure that subwindows are unmapped from the
1719          whole area. */
1720       redisplay_unmap_subwindows_except_us (f, clear_x, dest->ypos,
1721                                             glyphsrc->width, dest->height,
1722                                             ignored_subwindow);
1723       /* first the top box */
1724       if (yoffset > 0)
1725         {
1726           redisplay_clear_region (window, findex, clear_x, dest->ypos,
1727                                   glyphsrc->width, yoffset);
1728
1729         }
1730       /* Then the bottom box */
1731       if (yoffset + glyphsrc->height < dest->height)
1732         {
1733           redisplay_clear_region (window, findex, clear_x,
1734                                   dest->ypos + yoffset + glyphsrc->height,
1735                                   glyphsrc->width,
1736                                   dest->height - (yoffset + glyphsrc->height));
1737
1738         }
1739     }
1740 }
1741
1742 /*****************************************************************************
1743  redisplay_normalize_glyph_area
1744  redisplay_normalize_display_box
1745
1746  Calculate the visible box for displaying src in dest.
1747  ****************************************************************************/
1748 int
1749 redisplay_normalize_glyph_area (struct display_box* dest,
1750                                 struct display_glyph_area* glyphsrc)
1751 {
1752   if (dest->xpos + glyphsrc->xoffset > dest->xpos + dest->width
1753       ||
1754       dest->ypos + glyphsrc->yoffset > dest->ypos + dest->height
1755       ||
1756       -glyphsrc->xoffset >= glyphsrc->width
1757       ||
1758       -glyphsrc->yoffset >= glyphsrc->height)
1759     {
1760       /* It's all clipped out */
1761       return 0;
1762     }
1763
1764   /* Horizontal offsets. This works because xoffset can be -ve as well as +ve */
1765   if (dest->xpos + glyphsrc->xoffset + glyphsrc->width > dest->xpos + dest->width)
1766     {
1767       if (glyphsrc->xoffset > 0)
1768         glyphsrc->width = dest->width - glyphsrc->xoffset;
1769       else
1770         glyphsrc->width = dest->width;
1771     }
1772
1773   if (glyphsrc->xoffset < 0)
1774     glyphsrc->width += glyphsrc->xoffset;
1775
1776   /* Vertical offsets. This works because yoffset can be -ve as well as +ve */
1777   if (dest->ypos + glyphsrc->yoffset + glyphsrc->height > dest->ypos + dest->height)
1778     {
1779       if (glyphsrc->yoffset > 0)
1780         glyphsrc->height = dest->height - glyphsrc->yoffset;
1781       else
1782         glyphsrc->height = dest->height;
1783     }
1784
1785   if (glyphsrc->yoffset < 0)
1786     glyphsrc->height += glyphsrc->yoffset;
1787
1788   return 1;
1789 }
1790
1791 static void
1792 redisplay_normalize_display_box (struct display_box* dest,
1793                                  struct display_glyph_area* glyphsrc)
1794 {
1795   /* Adjust the destination area. At the end of this the destination
1796    area will exactly enclose the glyph area. The only remaining
1797    adjustment will be offsets into the glyph area. */
1798
1799   /* Horizontal adjustment. */
1800   if (glyphsrc->xoffset > 0)
1801     {
1802       dest->xpos += glyphsrc->xoffset;
1803       dest->width -= glyphsrc->xoffset;
1804       glyphsrc->xoffset = 0;
1805     }
1806   else
1807     glyphsrc->xoffset = -glyphsrc->xoffset;
1808
1809   if (glyphsrc->width < dest->width)
1810     dest->width = glyphsrc->width;
1811
1812   /* Vertical adjustment. */
1813   if (glyphsrc->yoffset > 0)
1814     {
1815       dest->ypos += glyphsrc->yoffset;
1816       dest->height -= glyphsrc->yoffset;
1817       glyphsrc->yoffset = 0;
1818     }
1819   else
1820     glyphsrc->yoffset = -glyphsrc->yoffset;
1821
1822   if (glyphsrc->height < dest->height)
1823     dest->height = glyphsrc->height;
1824 }
1825
1826 /*****************************************************************************
1827  redisplay_display_boxes_in_window_p
1828
1829  Determine whether the require display_glyph_area is completely inside
1830  the window. 0 means the display_box is not in the window. 1 means the
1831  display_box and the display_glyph_area are in the window. -1 means
1832  the display_box is in the window but the display_glyph_area is not.
1833  ****************************************************************************/
1834 static int
1835 redisplay_display_boxes_in_window_p (struct window* w,
1836                                      struct display_box* db,
1837                                      struct display_glyph_area* dga)
1838 {
1839   int left = WINDOW_TEXT_LEFT (w);
1840   int right = WINDOW_TEXT_RIGHT (w);
1841   int top = WINDOW_TEXT_TOP (w);
1842   int bottom = WINDOW_TEXT_BOTTOM (w);
1843
1844   if (db->xpos < left || db->ypos < top
1845       || db->xpos + db->width > right
1846       || db->ypos + db->height > bottom)
1847     /* We are not displaying in a window at all */
1848     return 0;
1849
1850   if (db->xpos + dga->xoffset >= left
1851       &&
1852       db->ypos + dga->yoffset >= top
1853       &&
1854       db->xpos + dga->xoffset + dga->width <= right
1855       &&
1856       db->ypos + dga->yoffset + dga->height <= bottom)
1857     return 1;
1858
1859   return -1;
1860 }
1861
1862 /*****************************************************************************
1863  redisplay_calculate_display_boxes
1864
1865  Convert from rune/display_line co-ordinates to display_box
1866  co-ordinates.
1867  ****************************************************************************/
1868 int
1869 redisplay_calculate_display_boxes (struct display_line *dl, int xpos,
1870                                    int xoffset, int start_pixpos, int width,
1871                                    struct display_box* dest,
1872                                    struct display_glyph_area* src)
1873 {
1874   dest->xpos = xpos;
1875   dest->ypos = DISPLAY_LINE_YPOS (dl);
1876   dest->width = width;
1877   dest->height = DISPLAY_LINE_HEIGHT (dl);
1878
1879   src->xoffset = -xoffset;
1880   src->yoffset = -dl->top_clip;
1881   src->width = 0;
1882   src->height = 0;
1883
1884   if (start_pixpos >=0 && start_pixpos > xpos)
1885     {
1886       /* Oops, we're asking for a start outside of the displayable
1887          area. */
1888       if (start_pixpos > xpos + width)
1889         return 0;
1890       dest->xpos = start_pixpos;
1891       dest->width -= (start_pixpos - xpos);
1892       /* Offsets are -ve when we want to clip pixels off the displayed
1893          glyph. */
1894       src->xoffset -= (start_pixpos - xpos);
1895     }
1896
1897   return 1;
1898 }
1899
1900 /*****************************************************************************
1901  redisplay_clear_top_of_window
1902
1903  If window is topmost, clear the internal border above it.
1904  ****************************************************************************/
1905 static void
1906 redisplay_clear_top_of_window (struct window *w)
1907 {
1908   Lisp_Object window;
1909   XSETWINDOW (window, w);
1910
1911   if (!NILP (Fwindow_highest_p (window)))
1912     {
1913       struct frame *f = XFRAME (w->frame);
1914       int x, y, width, height;
1915
1916       x = w->pixel_left;
1917       width = w->pixel_width;
1918
1919       if (window_is_leftmost (w))
1920         {
1921           x -= FRAME_BORDER_WIDTH (f);
1922           width += FRAME_BORDER_WIDTH (f);
1923         }
1924       if (window_is_rightmost (w))
1925         width += FRAME_BORDER_WIDTH (f);
1926
1927       y = FRAME_TOP_BORDER_START (f) - 1;
1928       height = FRAME_BORDER_HEIGHT (f) + 1;
1929
1930       redisplay_clear_region (window, DEFAULT_INDEX, x, y, width, height);
1931     }
1932 }
1933
1934 /*****************************************************************************
1935  redisplay_clear_to_window_end
1936
1937  Clear the area between ypos1 and ypos2.  Each margin area and the
1938  text area is handled separately since they may each have their own
1939  background color.
1940  ****************************************************************************/
1941 void
1942 redisplay_clear_to_window_end (struct window *w, int ypos1, int ypos2)
1943 {
1944   struct frame *f = XFRAME (w->frame);
1945   struct device *d = XDEVICE (f->device);
1946
1947   if (HAS_DEVMETH_P (d, clear_to_window_end))
1948     DEVMETH (d, clear_to_window_end, (w, ypos1, ypos2));
1949   else
1950     {
1951       int height = ypos2 - ypos1;
1952
1953       if (height)
1954         {
1955           Lisp_Object window;
1956           int bflag = 0 ; /* (window_needs_vertical_divider (w) ? 0 : 1);*/
1957           layout_bounds bounds;
1958
1959           bounds = calculate_display_line_boundaries (w, bflag);
1960           XSETWINDOW (window, w);
1961
1962           if (window_is_leftmost (w))
1963             redisplay_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f),
1964                                     ypos1, FRAME_BORDER_WIDTH (f), height);
1965
1966           if (bounds.left_in - bounds.left_out > 0)
1967             redisplay_clear_region (window,
1968                                     get_builtin_face_cache_index (w, Vleft_margin_face),
1969                                     bounds.left_out, ypos1,
1970                                     bounds.left_in - bounds.left_out, height);
1971
1972           if (bounds.right_in - bounds.left_in > 0)
1973             redisplay_clear_region (window,
1974                                     DEFAULT_INDEX,
1975                                     bounds.left_in, ypos1,
1976                                     bounds.right_in - bounds.left_in, height);
1977
1978           if (bounds.right_out - bounds.right_in > 0)
1979             redisplay_clear_region (window,
1980                                     get_builtin_face_cache_index (w, Vright_margin_face),
1981                                     bounds.right_in, ypos1,
1982                                     bounds.right_out - bounds.right_in, height);
1983
1984           if (window_is_rightmost (w))
1985             redisplay_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f),
1986                                     ypos1, FRAME_BORDER_WIDTH (f), height);
1987         }
1988     }
1989 }
1990
1991 /*****************************************************************************
1992  redisplay_clear_bottom_of_window
1993
1994  Clear window from right below the last display line to right above
1995  the modeline.  The calling function can limit the area actually
1996  erased by setting min_start and/or max_end to positive values.
1997  ****************************************************************************/
1998 void
1999 redisplay_clear_bottom_of_window (struct window *w, display_line_dynarr *ddla,
2000                                   int min_start, int max_end)
2001 {
2002   struct frame *f = XFRAME (w->frame);
2003   int ypos1, ypos2;
2004   int ddla_len = Dynarr_length (ddla);
2005
2006   ypos2 = WINDOW_TEXT_BOTTOM (w);
2007 #ifdef HAVE_SCROLLBARS
2008   /* This adjustment is to catch the intersection of any scrollbars. */
2009   if (f->windows_structure_changed && NILP (w->scrollbar_on_top_p))
2010     ypos2 += window_scrollbar_height (w);
2011 #endif
2012
2013   if (ddla_len)
2014     {
2015       if (ddla_len == 1 && Dynarr_atp (ddla, 0)->modeline)
2016         {
2017           ypos1 = WINDOW_TEXT_TOP (w);
2018 #ifdef HAVE_SCROLLBARS
2019           /* This adjustment is to catch the intersection of any scrollbars. */
2020           if (f->windows_structure_changed && !NILP (w->scrollbar_on_top_p))
2021             ypos1 -= window_scrollbar_height (w);
2022 #endif
2023         }
2024       else
2025         {
2026           struct display_line *dl = Dynarr_atp (ddla, ddla_len - 1);
2027           ypos1 = dl->ypos + dl->descent - dl->clip;
2028         }
2029     }
2030   else
2031     ypos1 = WINDOW_TEXT_TOP (w);
2032
2033   /* #### See if this can be made conditional on the frame
2034      changing size. */
2035   if (MINI_WINDOW_P (w))
2036     ypos2 += FRAME_BORDER_HEIGHT (f);
2037
2038   if (min_start >= 0 && ypos1 < min_start)
2039     ypos1 = min_start;
2040   if (max_end >= 0 && ypos2 > max_end)
2041     ypos2 = max_end;
2042
2043   if (ypos2 <= ypos1)
2044     return;
2045
2046   redisplay_clear_to_window_end (w, ypos1, ypos2);
2047 }
2048
2049 /*****************************************************************************
2050  redisplay_update_line
2051
2052  This is used during incremental updates to update a single line and
2053  correct the offsets on all lines below it.  At the moment
2054  update_values is false if we are only updating the modeline.
2055  ****************************************************************************/
2056 void
2057 redisplay_update_line (struct window *w, int first_line, int last_line,
2058                        int update_values)
2059 {
2060   struct frame *f = XFRAME (w->frame);
2061   struct device *d = XDEVICE (f->device);
2062
2063   display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
2064   display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
2065
2066   MAYBE_DEVMETH (d, window_output_begin, (w));
2067
2068   while (first_line <= last_line)
2069     {
2070       Charcount old_len = (Dynarr_atp (cdla, first_line)->end_bufpos -
2071                            Dynarr_atp (cdla, first_line)->bufpos);
2072       Charcount new_len = (Dynarr_atp (ddla, first_line)->end_bufpos -
2073                            Dynarr_atp (ddla, first_line)->bufpos);
2074
2075       assert (Dynarr_length (cdla) == Dynarr_length (ddla));
2076
2077       /* Output the changes. */
2078       output_display_line (w, cdla, ddla, first_line, -1, -1);
2079
2080       /* Update the offsets. */
2081       if (update_values)
2082         {
2083           int cur_line = first_line + 1;
2084           while (cur_line < Dynarr_length (cdla))
2085             {
2086               Dynarr_atp (cdla, cur_line)->offset += (new_len - old_len);
2087               Dynarr_atp (ddla, cur_line)->offset += (new_len - old_len);
2088               cur_line++;
2089             }
2090         }
2091
2092       /* Update the window_end_pos and other settings. */
2093       if (update_values)
2094         {
2095           w->window_end_pos[CURRENT_DISP] -= (new_len - old_len);
2096
2097           if (Dynarr_atp (ddla, first_line)->cursor_elt != -1)
2098             {
2099               w->last_point_x[CURRENT_DISP] = w->last_point_x[DESIRED_DISP];
2100               w->last_point_y[CURRENT_DISP] = w->last_point_y[DESIRED_DISP];
2101             }
2102         }
2103
2104       first_line++;
2105     }
2106
2107   /* Update the window max line length.  We have to scan the entire
2108      set of display lines otherwise we might not detect if the max is
2109      supposed to shrink. */
2110   if (update_values)
2111     {
2112       int line = 0;
2113
2114       w->max_line_len = 0;
2115       while (line < Dynarr_length (ddla))
2116         {
2117           struct display_line *dl = Dynarr_atp (ddla, line);
2118
2119           if (!dl->modeline)
2120             w->max_line_len = max (dl->num_chars, w->max_line_len);
2121
2122           line++;
2123         }
2124     }
2125
2126   w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP];
2127   w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP];
2128   Fset_marker (w->last_point[CURRENT_DISP],
2129                Fmarker_position (w->last_point[DESIRED_DISP]), w->buffer);
2130   Fset_marker (w->last_start[CURRENT_DISP],
2131                Fmarker_position (w->last_start[DESIRED_DISP]), w->buffer);
2132
2133   /* We don't bother updating the vertical scrollbars here.  This
2134      gives us a performance increase while having minimal loss of
2135      quality to the scrollbar slider size and position since when this
2136      function is called we know that the changes to the buffer were
2137      very localized.  We have to update the horizontal scrollbars,
2138      though, because this routine could cause a change which has a
2139      larger impact on their sizing. */
2140   /* #### See if we can get away with only calling this if
2141      max_line_len is greater than the window_char_width. */
2142 #if defined(HAVE_SCROLLBARS) && defined(HAVE_X_WINDOWS)
2143   {
2144     extern int stupid_vertical_scrollbar_drag_hack;
2145
2146     update_window_scrollbars (w, NULL, 1, stupid_vertical_scrollbar_drag_hack);
2147     stupid_vertical_scrollbar_drag_hack = 1;
2148   }
2149 #endif
2150
2151   redisplay_redraw_cursor (f, 0);
2152   MAYBE_DEVMETH (d, window_output_end, (w));
2153 }
2154
2155 /*****************************************************************************
2156  redisplay_output_window
2157
2158  For the given window W, ensure that the current display lines are
2159  equal to the desired display lines, outputing changes as necessary.
2160
2161  #### Fuck me.  This just isn't going to cut it for tty's.  The output
2162  decisions for them must be based on the contents of the entire frame
2163  because that is how the available output capabilities think.  The
2164  solution is relatively simple.  Create redisplay_output_frame.  This
2165  will basically merge all of the separate window display structs into
2166  a single one for the frame.  This combination structure will be able
2167  to be passed to the same output_display_line which works for windows
2168  on X frames and the right things will happen.  It just takes time to
2169  do.
2170  ****************************************************************************/
2171 void
2172 redisplay_output_window (struct window *w)
2173 {
2174   struct frame *f = XFRAME (w->frame);
2175   struct device *d = XDEVICE (f->device);
2176
2177   display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
2178   display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
2179
2180   int cdla_len = Dynarr_length (cdla);
2181   int ddla_len = Dynarr_length (ddla);
2182
2183   int line;
2184   int need_to_clear_bottom = 0;
2185   int need_to_clear_start = -1;
2186   int need_to_clear_end = -1;
2187
2188   /* Backgrounds may have changed or windows may have gone away
2189      leaving dividers lying around. */
2190   if (f->faces_changed
2191       || f->windows_structure_changed
2192       || w->shadow_thickness_changed)
2193     need_to_clear_bottom = 1;
2194
2195   /* The first thing we do is determine if we are going to need to
2196      clear the bottom of the window.  We only need to do this if the
2197      bottom of the current display lines is below the bottom of the
2198      desired display lines.  Note that the number of lines is
2199      irrelevant.  Only the position matters.  We also clear to the
2200      bottom of the window if the modeline has shifted position. */
2201   /* #### We can't blindly not clear the bottom if f->clear is true
2202      since there might be a window-local background.  However, for
2203      those cases where there isn't, clearing the end of the window in
2204      this case sucks. */
2205   if (!need_to_clear_bottom)
2206     {
2207       struct display_line *cdl, *ddl;
2208
2209       /* If the modeline has changed position or size, clear the bottom
2210          of the window. */
2211       if (!need_to_clear_bottom)
2212         {
2213           cdl = ddl = 0;
2214
2215           if (cdla_len)
2216             cdl = Dynarr_atp (cdla, 0);
2217           if (ddla_len)
2218             ddl = Dynarr_atp (ddla, 0);
2219
2220           if (!cdl || !ddl)
2221             need_to_clear_bottom = 1;
2222           else if ((!cdl->modeline && ddl->modeline)
2223                    || (cdl->modeline && !ddl->modeline))
2224             need_to_clear_bottom = 1;
2225           else if (cdl->ypos != ddl->ypos ||
2226                    cdl->ascent != ddl->ascent ||
2227                    cdl->descent != ddl->descent ||
2228                    cdl->clip != ddl->clip)
2229             need_to_clear_bottom = 1;
2230
2231           /* #### This kludge is to make sure the modeline shadows get
2232              redrawn if the modeline position shifts. */
2233           if (need_to_clear_bottom)
2234             w->shadow_thickness_changed = 1;
2235         }
2236
2237       if (!need_to_clear_bottom)
2238         {
2239           cdl = ddl = 0;
2240
2241           if (cdla_len)
2242             cdl = Dynarr_atp (cdla, cdla_len - 1);
2243           if (ddla_len)
2244             ddl = Dynarr_atp (ddla, ddla_len - 1);
2245
2246           if (!cdl || !ddl)
2247             need_to_clear_bottom = 1;
2248           else
2249             {
2250               int cdl_bottom, ddl_bottom;
2251
2252               cdl_bottom = cdl->ypos + cdl->descent;
2253               ddl_bottom = ddl->ypos + ddl->descent;
2254
2255               if (cdl_bottom > ddl_bottom)
2256                 {
2257                   need_to_clear_bottom = 1;
2258                   need_to_clear_start = ddl_bottom;
2259                   need_to_clear_end = cdl_bottom;
2260                 }
2261             }
2262         }
2263     }
2264
2265   /* Perform any output initialization. */
2266   MAYBE_DEVMETH (d, window_output_begin, (w));
2267
2268   /* If the window's structure has changed clear the internal border
2269      above it if it is topmost (the function will check). */
2270   if (f->windows_structure_changed)
2271     redisplay_clear_top_of_window (w);
2272
2273   /* Output each line. */
2274   for (line = 0; line < Dynarr_length (ddla); line++)
2275     {
2276       output_display_line (w, cdla, ddla, line, -1, -1);
2277     }
2278
2279   /* If the number of display lines has shrunk, adjust. */
2280   if (cdla_len > ddla_len)
2281     {
2282       Dynarr_length (cdla) = ddla_len;
2283     }
2284
2285   /* Output a vertical divider between windows, if necessary. */
2286   if (window_needs_vertical_divider (w)
2287       && (f->windows_structure_changed || f->clear))
2288     {
2289       MAYBE_DEVMETH (d, output_vertical_divider, (w, f->windows_structure_changed));
2290     }
2291
2292   /* Clear the rest of the window, if necessary. */
2293   if (need_to_clear_bottom)
2294     {
2295       redisplay_clear_bottom_of_window (w, ddla, need_to_clear_start,
2296                                         need_to_clear_end);
2297     }
2298
2299   w->window_end_pos[CURRENT_DISP] = w->window_end_pos[DESIRED_DISP];
2300   Fset_marker (w->start[CURRENT_DISP],
2301                make_int (marker_position (w->start[DESIRED_DISP])),
2302                w->buffer);
2303   Fset_marker (w->pointm[CURRENT_DISP],
2304                make_int (marker_position (w->pointm[DESIRED_DISP])),
2305                w->buffer);
2306   w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP];
2307   w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP];
2308   Fset_marker (w->last_start[CURRENT_DISP],
2309                Fmarker_position (w->last_start[DESIRED_DISP]), w->buffer);
2310   Fset_marker (w->last_point[CURRENT_DISP],
2311                Fmarker_position (w->last_point[DESIRED_DISP]), w->buffer);
2312   w->last_point_x[CURRENT_DISP] = w->last_point_x[DESIRED_DISP];
2313   w->last_point_y[CURRENT_DISP] = w->last_point_y[DESIRED_DISP];
2314   w->shadow_thickness_changed = 0;
2315
2316   set_window_display_buffer (w, XBUFFER (w->buffer));
2317   find_window_mirror (w)->truncate_win = window_truncation_on (w);
2318
2319   /* Overkill on invalidating the cache.  It is very bad for it to not
2320      get invalidated when it should be. */
2321   INVALIDATE_DEVICE_PIXEL_TO_GLYPH_CACHE (d);
2322
2323   redisplay_redraw_cursor (f, 0);
2324   MAYBE_DEVMETH (d, window_output_end, (w));
2325
2326 #ifdef HAVE_SCROLLBARS
2327   update_window_scrollbars (w, NULL, !MINI_WINDOW_P (w), 0);
2328 #endif
2329 }
2330
2331 /*****************************************************************************
2332  bevel_modeline
2333
2334  Draw a 3d border around the modeline on window W.
2335  ****************************************************************************/
2336 void
2337 bevel_modeline (struct window *w, struct display_line *dl)
2338 {
2339   struct frame *f = XFRAME (w->frame);
2340   struct device *d = XDEVICE (f->device);
2341   int x, y, width, height;
2342   int shadow_thickness = MODELINE_SHADOW_THICKNESS (w);
2343   enum edge_style style;
2344
2345   x = WINDOW_MODELINE_LEFT (w);
2346   width = WINDOW_MODELINE_RIGHT (w) - x;
2347   y = dl->ypos - dl->ascent - shadow_thickness;
2348   height = dl->ascent + dl->descent + 2 * shadow_thickness;
2349
2350   if (XINT (w->modeline_shadow_thickness) < 0)
2351     {
2352       style = EDGE_BEVEL_IN;
2353     }
2354   else
2355     {
2356       style = EDGE_BEVEL_OUT;
2357     }
2358
2359   MAYBE_DEVMETH (d, bevel_area,
2360                  (w, MODELINE_INDEX, x, y, width, height, shadow_thickness,
2361                   EDGE_ALL, style));
2362 }