diff src/redisplay-output.c @ 442:abe6d1db359e r21-2-36

Import from CVS: tag r21-2-36
author cvs
date Mon, 13 Aug 2007 11:35:02 +0200
parents 8de8e3f6228a
children 1ccc32a20af4
line wrap: on
line diff
--- a/src/redisplay-output.c	Mon Aug 13 11:33:40 2007 +0200
+++ b/src/redisplay-output.c	Mon Aug 13 11:35:02 2007 +0200
@@ -101,7 +101,7 @@
  For the given LINE in window W, make the current display line equal
  the desired display line.
  ****************************************************************************/
-static void
+void
 sync_display_line_structs (struct window *w, int line, int do_blocks,
 			   display_line_dynarr *cdla,
 			   display_line_dynarr *ddla)
@@ -211,10 +211,7 @@
      #### It would really be worth it to arrange for this function to
      be (almost) a single call to memcmp. */
 
-  if ((crb->findex != drb->findex) ||
-      (WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)))
-    return 0;
-  else if (crb->xpos != drb->xpos)
+  if (crb->xpos != drb->xpos)
     return 0;
   else if (crb->width != drb->width)
     return 0;
@@ -236,17 +233,68 @@
     return 0;
   /* Only check dirtiness if we know something has changed. */
   else if (crb->type == RUNE_DGLYPH &&
-	   XFRAME (w->frame)->glyphs_changed)
+	   (XGLYPH_DIRTYP (crb->object.dglyph.glyph) ||
+	    crb->findex != drb->findex))
     {
-      glyph_index gindex = get_glyph_cachel_index (w, drb->object.dglyph.glyph);
-      /* Although doing the cachel lookup for every comparison is
-	 very expensive.we have to do it to make sure the cache is
-	 up-to-date. */
-      if (GLYPH_CACHEL_DIRTYP (w, gindex))
+      /* We need some way of telling redisplay_output_layout () that the
+         only reason we are outputting it is because something has
+         changed internally. That way we can optimize whether we need
+         to clear the layout first and also only output the components
+         that have changed. The image_instance dirty flag and
+         display_hash are no good to us because these will invariably
+         have been set anyway if the layout has changed. So it looks
+         like we need yet another change flag that we can set here and
+         then clear in redisplay_output_layout (). */
+      Lisp_Object window, image;
+      Lisp_Image_Instance* ii;
+      XSETWINDOW (window, w);
+      image = glyph_image_instance (crb->object.dglyph.glyph,
+				    window, ERROR_ME_NOT, 1);
+
+      if (!IMAGE_INSTANCEP (image))
+	return 0;
+      ii = XIMAGE_INSTANCE (image);
+
+      if (TEXT_IMAGE_INSTANCEP (image) &&
+	  (crb->findex != drb->findex ||
+	   WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)))
 	return 0;
+
+      /* It is quite common for the two glyphs to be EQ since in many
+	 cases they will actually be the same object. This does not
+	 mean, however, that nothing has changed. We therefore need to
+	 check the current hash of the glyph against the last recorded
+	 display hash and the pending display items. See
+	 update_subwindow (). */
+      if (image_instance_changed (image) ||
+	  crb->findex != drb->findex ||
+	  WINDOW_FACE_CACHEL_DIRTY (w, drb->findex))
+	{
+	  /* We now now we are going to re-output the glyph, but since
+	     this is for some internal reason not related to geometry
+	     changes, send a hint to the output routines that they can
+	     take some short cuts. This is most useful for
+	     layouts. This flag should get reset by the output
+	     routines.
+
+	     #### It is possible for us to get here when the
+	     face_cachel is dirty. I do not know what the implications
+	     of this are.*/
+	  IMAGE_INSTANCE_OPTIMIZE_OUTPUT (ii) = 1;
+	  return 0;
+	}
       else
 	return 1;
     }
+  /* We now do this last so that glyph checks can do their own thing
+     for face changes. Face changes quite often happen when we are
+     trying to output something in the gutter, this would normally
+     lead to a lot of flashing. The indices can quite often be
+     different and yet the faces are the same, we do not want to
+     re-output in this instance. */
+  else  if (crb->findex != drb->findex ||
+	    WINDOW_FACE_CACHEL_DIRTY (w, drb->findex))
+    return 0;
   else
     return 1;
 }
@@ -850,16 +898,11 @@
     }
   else
     {
-      DEVMETH (d, output_begin, (d));
-
-      /* #### This is a gross kludge.  Cursor handling is such a royal
-         pain in the ass. */
-      if (rb->type == RUNE_DGLYPH &&
-	  (EQ (rb->object.dglyph.glyph, Vtruncation_glyph) ||
-	   EQ (rb->object.dglyph.glyph, Vcontinuation_glyph)))
-	rb->cursor_type = NO_CURSOR;
-      else
-	rb->cursor_type = CURSOR_OFF;
+      {
+	MAYBE_DEVMETH (d, frame_output_begin, (f));
+	MAYBE_DEVMETH (d, window_output_begin, (w));
+      }
+      rb->cursor_type = CURSOR_OFF;
       dl->cursor_elt = -1;
       output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width);
     }
@@ -873,7 +916,10 @@
   if (w != XWINDOW (FRAME_SELECTED_WINDOW (device_selected_frame (d))))
     {
       if (!no_output_end)
-	DEVMETH (d, output_end, (d));
+	{
+	  MAYBE_DEVMETH (d, window_output_end, (w));
+	  MAYBE_DEVMETH (d, frame_output_end, (f));
+	}
 
       return 1;
     }
@@ -892,7 +938,10 @@
       output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width);
 
       if (!no_output_end)
-	DEVMETH (d, output_end, (d));
+	{
+	  MAYBE_DEVMETH (d, window_output_end, (w));
+	  MAYBE_DEVMETH (d, frame_output_end, (f));
+	}
       return 1;
     }
   else
@@ -956,7 +1005,10 @@
 			       make_int (ADJ_BUFPOS), w->buffer);
 
 		  if (!no_output_end)
-		    DEVMETH (d, output_end, (d));
+		    {
+		      MAYBE_DEVMETH (d, window_output_end, (w));
+		      MAYBE_DEVMETH (d, frame_output_end, (f));
+		    }
 		  return 1;
 		}
 
@@ -969,7 +1021,10 @@
     }
 
   if (!no_output_end)
-    DEVMETH (d, output_end, (d));
+    {
+      MAYBE_DEVMETH (d, window_output_end, (w));
+      MAYBE_DEVMETH (d, frame_output_end, (f));
+    }
   return 0;
 }
 #undef ADJ_BUFPOS
@@ -1024,12 +1079,18 @@
 		     (f, dl->ypos - 1, rb->xpos));
 
       if (run_end_begin_meths)
-	DEVMETH (d, output_begin, (d));
+	{
+	  MAYBE_DEVMETH (d, frame_output_begin, (f));
+	  MAYBE_DEVMETH (d, window_output_begin, (w));
+	}
 
       output_display_line (w, 0, dla, y, rb->xpos, rb->xpos + rb->width);
 
       if (run_end_begin_meths)
-	DEVMETH (d, output_end, (d));
+	{
+	  MAYBE_DEVMETH (d, window_output_end, (w));
+	  MAYBE_DEVMETH (d, frame_output_end, (f));
+	}
     }
 }
 
@@ -1067,6 +1128,8 @@
 {
   struct frame *f = XFRAME (w->frame);
   struct device *d = XDEVICE (f->device);
+  /* Temporarily disabled until generalization is done. */
+#if 0
   struct display_block *db = Dynarr_atp (dl->display_blocks, block);
   rune_dynarr *rba = db->runes;
   struct rune *rb;
@@ -1084,6 +1147,7 @@
 
   rb  = Dynarr_atp (rba, end - 1);
   width = rb->xpos + rb->width - xpos;
+#endif
   /* now actually output the block. */
   DEVMETH (d, output_display_block, (w, dl, block, start,
 				     end, start_pixpos,
@@ -1100,22 +1164,26 @@
 static void redisplay_unmap_subwindows (struct frame* f, int x, int y, int width, int height,
 					Lisp_Object ignored_window)
 {
-  int elt;
-
-  for (elt = 0; elt < Dynarr_length (f->subwindow_cachels); elt++)
-    {
-      struct subwindow_cachel *cachel =
-	Dynarr_atp (f->subwindow_cachels, elt);
+  Lisp_Object rest;
 
-      if (cachel->being_displayed
+  LIST_LOOP (rest, XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f)))
+    {
+      Lisp_Image_Instance *ii = XIMAGE_INSTANCE (XCAR (rest));
+      if (IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (ii)
 	  &&
-	  cachel->x + cachel->width > x && cachel->x < x + width
+	  IMAGE_INSTANCE_DISPLAY_X (ii)
+	  + IMAGE_INSTANCE_DISPLAY_WIDTH (ii) > x
 	  &&
-	  cachel->y + cachel->height > y && cachel->y < y + height
+	  IMAGE_INSTANCE_DISPLAY_X (ii) < x + width
+	  &&
+	  IMAGE_INSTANCE_DISPLAY_Y (ii)
+	  + IMAGE_INSTANCE_DISPLAY_HEIGHT (ii) > y
 	  &&
-	  !EQ (cachel->subwindow, ignored_window))
+	  IMAGE_INSTANCE_DISPLAY_Y (ii) < y + height
+	  &&
+	  !EQ (XCAR (rest), ignored_window))
 	{
-	  unmap_subwindow (cachel->subwindow);
+	  unmap_subwindow (XCAR (rest));
 	}
     }
 }
@@ -1128,7 +1196,7 @@
  ****************************************************************************/
 void redisplay_unmap_subwindows_maybe (struct frame* f, int x, int y, int width, int height)
 {
-  if (Dynarr_length (FRAME_SUBWINDOW_CACHE (f)))
+  if (!NILP (XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f))))
     {
       redisplay_unmap_subwindows (f, x, y, width, height, Qnil);
     }
@@ -1137,7 +1205,7 @@
 static void redisplay_unmap_subwindows_except_us (struct frame* f, int x, int y, int width,
 						  int height, Lisp_Object subwindow)
 {
-  if (Dynarr_length (FRAME_SUBWINDOW_CACHE (f)))
+  if (!NILP (XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f))))
     {
       redisplay_unmap_subwindows (f, x, y, width, height, subwindow);
     }
@@ -1161,8 +1229,13 @@
   Lisp_Object window;
   struct display_glyph_area sdga;
 
-  dga->height = IMAGE_INSTANCE_SUBWINDOW_HEIGHT (p);
-  dga->width = IMAGE_INSTANCE_SUBWINDOW_WIDTH (p);
+  dga->height = IMAGE_INSTANCE_HEIGHT (p);
+  dga->width = IMAGE_INSTANCE_WIDTH (p);
+
+  /* The first thing we are going to do is update the display
+     characteristics of the subwindow. This also clears the dirty
+     flags as a side effect. */
+  redisplay_subwindow (image_instance);
 
   /* This makes the glyph area fit into the display area. */
   if (!redisplay_normalize_glyph_area (db, dga))
@@ -1187,8 +1260,8 @@
      cases.*/
   sdga.xoffset = -dga->xoffset;
   sdga.yoffset = -dga->yoffset;
-  sdga.height = IMAGE_INSTANCE_SUBWINDOW_HEIGHT (p);
-  sdga.width = IMAGE_INSTANCE_SUBWINDOW_WIDTH (p);
+  sdga.height = IMAGE_INSTANCE_HEIGHT (p);
+  sdga.width = IMAGE_INSTANCE_WIDTH (p);
 
   if (redisplay_display_boxes_in_window_p (w, db, &sdga) < 0)
     {
@@ -1206,47 +1279,58 @@
  redisplay_output_layout
 
  Output a widget hierarchy. This can safely call itself recursively.
+
+ The complexity of outputting layouts is deciding whether to do it or
+ not. Consider a layout enclosing some text, the text changes and is
+ marked as dirty, but the enclosing layout has not been marked as
+ dirty so no updates occur and the text will potentially be truncated.
+ Alternatively we hold a back pointer in the image instance to the
+ parent and mark the parent as dirty. But the layout code assumes that
+ if the layout is dirty then the whole layout should be redisplayed,
+ so we then get lots of flashing even though only the text has changed
+ size. Of course if the text shrinks in size then we do actually need
+ to redisplay the layout to repaint the exposed area. So what happens
+ if we make a non-structural change like changing color? Either we
+ redisplay everything, or we redisplay nothing. These are exactly the
+ issues lwlib has to grapple with. We really need to know what has
+ actually changed and make a layout decision based on that. We also
+ really need to know what has changed so that we can only make the
+ necessary changes in update_subwindow.  This has all now been
+ implemented, Viva la revolution!
  ****************************************************************************/
 void
-redisplay_output_layout (struct window *w,
+redisplay_output_layout (Lisp_Object domain,
 			 Lisp_Object image_instance,
 			 struct display_box* db, struct display_glyph_area* dga,
 			 face_index findex, int cursor_start, int cursor_width,
 			 int cursor_height)
 {
   Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
-  Lisp_Object window, rest;
+  Lisp_Object rest, window = DOMAIN_WINDOW (domain);
   Emchar_dynarr *buf = Dynarr_new (Emchar);
-  struct frame *f = XFRAME (w->frame);
-  struct device *d = XDEVICE (f->device);
+  struct window *w = XWINDOW (window);
+  struct device *d = DOMAIN_XDEVICE (domain);
   int layout_height, layout_width;
-  /* We bogusly don't take f->extents_changed and f->glyphs_changed
-     into account. This is because if we do we always redisplay the
-     entire layout. So far I have seen no ill effects so we'll see. */
-  int frame_really_changed = (f->buffers_changed ||
-			      f->clip_changed ||
-			      f->faces_changed    ||
-			      f->frame_changed    ||
-			      f->modeline_changed ||
-			      f->subwindows_changed ||
-			      f->windows_changed ||
-			      f->windows_structure_changed);
 
-  XSETWINDOW (window, w);
-
-  layout_height = glyph_height (image_instance, window);
-  layout_width = glyph_width (image_instance, window);
+  layout_height = glyph_height (image_instance, domain);
+  layout_width = glyph_width (image_instance, domain);
 
   dga->height = layout_height;
   dga->width = layout_width;
-
+#ifdef DEBUG_WIDGET_OUTPUT
+  printf ("outputing layout glyph %p\n", p);
+#endif
   /* This makes the glyph area fit into the display area. */
   if (!redisplay_normalize_glyph_area (db, dga))
     return;
 
   /* Highly dodgy optimization. We want to only output the whole
      layout if we really have to. */
-  if (frame_really_changed || IMAGE_INSTANCE_DIRTYP (p))
+  if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (p)
+      || IMAGE_INSTANCE_LAYOUT_CHANGED (p)
+      || IMAGE_INSTANCE_WIDGET_FACE_CHANGED (p)
+      || IMAGE_INSTANCE_SIZE_CHANGED (p)
+      || IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p))
     {
       /* First clear the area we are drawing into. This is the easiest
 	 thing to do since we have many gaps that we have to make sure are
@@ -1302,7 +1386,8 @@
   /* Flip through the widgets in the layout displaying as necessary */
   LIST_LOOP (rest, IMAGE_INSTANCE_LAYOUT_CHILDREN (p))
     {
-      Lisp_Object child = XCAR (rest);
+      Lisp_Object child = glyph_image_instance (XCAR (rest), image_instance,
+						ERROR_ME_NOT, 1);
 
       struct display_box cdb;
       /* For losing HP-UX */
@@ -1315,12 +1400,16 @@
       if (IMAGE_INSTANCEP (child))
 	{
 	  Lisp_Image_Instance* childii = XIMAGE_INSTANCE (child);
+
 	  /* The enclosing layout offsets are +ve at this point */
 	  struct display_glyph_area cdga;
 	  cdga.xoffset  = IMAGE_INSTANCE_XOFFSET (childii) - dga->xoffset;
 	  cdga.yoffset = IMAGE_INSTANCE_YOFFSET (childii) - dga->yoffset;
-	  cdga.width = glyph_width (child, window);
-	  cdga.height = glyph_height (child, window);
+	  cdga.width = glyph_width (child, image_instance);
+	  cdga.height = glyph_height (child, image_instance);
+
+	  IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) =
+	    IMAGE_INSTANCE_OPTIMIZE_OUTPUT (p);
 
 	  /* Although normalization is done by the output routines
 	     we have to do it here so that they don't try and
@@ -1336,7 +1425,7 @@
 		continue;
 	      /* We have to invert the offset here as normalization
 		 will have made them positive which the output
-		 routines will treat as a truely +ve offset. */
+		 routines will treat as a truly +ve offset. */
 	      cdga.xoffset = -cdga.xoffset;
 	      cdga.yoffset = -cdga.yoffset;
 
@@ -1348,11 +1437,20 @@
 		       generalisation.*/
 		    if (redisplay_normalize_glyph_area (&cdb, &cdga)
 			&&
-			(frame_really_changed || IMAGE_INSTANCE_DIRTYP (childii)))
+			(!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) ||
+			 IMAGE_INSTANCE_DIRTYP (childii)))
 		      {
 			struct display_line dl;	/* this is fake */
 			Lisp_Object string =
 			  IMAGE_INSTANCE_TEXT_STRING (childii);
+			unsigned char charsets[NUM_LEADING_BYTES];
+			struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
+
+			find_charsets_in_bufbyte_string (charsets,
+							 XSTRING_DATA (string),
+							 XSTRING_LENGTH (string));
+			ensure_face_cachel_complete (cachel, window, charsets);
+
 			convert_bufbyte_string_into_emchar_dynarr
 			  (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
 
@@ -1362,9 +1460,9 @@
 			xzero (dl);
 			/* Munge boxes into display lines. */
 			dl.ypos = (cdb.ypos - cdga.yoffset)
-			  + glyph_ascent (child, window);
-			dl.ascent = glyph_ascent (child, window);
-			dl.descent = glyph_descent (child, window);
+			  + glyph_ascent (child, image_instance);
+			dl.ascent = glyph_ascent (child, image_instance);
+			dl.descent = glyph_descent (child, image_instance);
 			dl.top_clip = cdga.yoffset;
 			dl.clip = (dl.ypos + dl.descent) - (cdb.ypos + cdb.height);
 			/* output_string doesn't understand offsets in
@@ -1382,23 +1480,26 @@
 
 		case IMAGE_MONO_PIXMAP:
 		case IMAGE_COLOR_PIXMAP:
-		  if (frame_really_changed || IMAGE_INSTANCE_DIRTYP (childii))
+		  if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii)
+		      || IMAGE_INSTANCE_DIRTYP (childii))
 		    redisplay_output_pixmap (w, child, &cdb, &cdga, findex,
 					     0, 0, 0, 0);
 		  break;
 
 		case IMAGE_WIDGET:
+		  if (EQ (IMAGE_INSTANCE_WIDGET_TYPE (childii), Qlayout))
+		    {
+		      redisplay_output_layout (image_instance, child, &cdb, &cdga, findex,
+					       0, 0, 0);
+		      break;
+		    }
 		case IMAGE_SUBWINDOW:
-		  if (frame_really_changed || IMAGE_INSTANCE_DIRTYP (childii))
+		  if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) ||
+		      IMAGE_INSTANCE_DIRTYP (childii))
 		    redisplay_output_subwindow (w, child, &cdb, &cdga, findex,
 						0, 0, 0);
 		  break;
 
-		case IMAGE_LAYOUT:
-		  redisplay_output_layout (w, child, &cdb, &cdga, findex,
-					   0, 0, 0);
-		  break;
-
 		case IMAGE_NOTHING:
 		  /* nothing is as nothing does */
 		  break;
@@ -1408,8 +1509,14 @@
 		  abort ();
 		}
 	    }
+	  IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) = 0;
 	}
     }
+
+  /* Update any display properties. I'm not sure whether this actually
+     does anything for layouts except clear the changed flags. */
+  redisplay_subwindow (image_instance);
+
   Dynarr_free (buf);
 }
 
@@ -1450,7 +1557,7 @@
     {
       redisplay_clear_clipped_region (window, findex,
 				      db, dga,
-				      (int)IMAGE_INSTANCE_PIXMAP_MASK (p),
+				      (IMAGE_INSTANCE_PIXMAP_MASK (p) != 0),
 				      Qnil);
 
       /* This shrinks the display box to exactly enclose the glyph
@@ -1572,7 +1679,7 @@
  redisplay_clear_clipped_region
 
  Clear the area in the dest display_box not covered by the src
- display_glyph_area using the given face. This is a common occurance
+ display_glyph_area using the given face. This is a common occurrence
  for images shorter than the display line. Clipping can be played
  around with by altering these. glyphsrc should be normalized.
  ****************************************************************************/
@@ -1952,7 +2059,7 @@
   display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
   display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
 
-  DEVMETH (d, output_begin, (d));
+  MAYBE_DEVMETH (d, window_output_begin, (w));
 
   while (first_line <= last_line)
     {
@@ -2037,14 +2144,8 @@
   }
 #endif
 
-  /* This has to be done after we've updated the values.  We don't
-     call output_end for tty frames.  Redisplay will do this after all
-     tty windows have been updated.  This cuts down on cursor
-     flicker. */
-  if (FRAME_TTY_P (f))
-    redisplay_redraw_cursor (f, 0);
-  else
-    DEVMETH (d, output_end, (d));
+  redisplay_redraw_cursor (f, 0);
+  MAYBE_DEVMETH (d, window_output_end, (w));
 }
 
 /*****************************************************************************
@@ -2158,7 +2259,7 @@
     }
 
   /* Perform any output initialization. */
-  DEVMETH (d, output_begin, (d));
+  MAYBE_DEVMETH (d, window_output_begin, (w));
 
   /* If the window's structure has changed clear the internal border
      above it if it is topmost (the function will check). */
@@ -2181,7 +2282,7 @@
   if (window_needs_vertical_divider (w)
       && (f->windows_structure_changed || f->clear))
     {
-      DEVMETH (d, output_vertical_divider, (w, f->windows_structure_changed));
+      MAYBE_DEVMETH (d, output_vertical_divider, (w, f->windows_structure_changed));
     }
 
   /* Clear the rest of the window, if necessary. */
@@ -2215,13 +2316,8 @@
      get invalidated when it should be. */
   INVALIDATE_DEVICE_PIXEL_TO_GLYPH_CACHE (d);
 
-  /* We don't call output_end for tty frames.  Redisplay will do this
-     after all tty windows have been updated.  This cuts down on
-     cursor flicker. */
-  if (FRAME_TTY_P (f))
-    redisplay_redraw_cursor (f, 0);
-  else
-    DEVMETH (d, output_end, (d));
+  redisplay_redraw_cursor (f, 0);
+  MAYBE_DEVMETH (d, window_output_end, (w));
 
 #ifdef HAVE_SCROLLBARS
   update_window_scrollbars (w, NULL, !MINI_WINDOW_P (w), 0);