Enhancing AA-but-no-RENDER performance



Basic idea
==========

If you use, Xft + anti-aliasing without RENDER, it's no great
surprise that the performance is rather poor, especially on
a remote X server.

But the following observations occurred to me:

 - Almost all rendering with Xft is actually on a solid
   background.

 - With GTK+, drawing is typically very controlled ... we
   create a backing pixmap, fill it with a constant 
   color, then draw some lines, images and shapes on it.

   So, it's not hard for GTK+ to _know_ that it is drawing
   on a solid colored background.

Taking advantage of this requires hooking the part of 
Xft that gets the background on to which to composite.

I did this by making it possible for a program to "hook"
the following operations in Xft:

 - Get an XImage from a drawable
 - Put the XImage back to a drawable
 - Release an image that was retrieved earlier

Then, when GTK+ knows that an area is solid, rather than
getting it from the X server, it can 

Xft details
===========

The full API added to Xft is:

====
typedef struct _XftDrawHooks XftDrawHooks;

struct _XftDrawHooks {
  void *user_data;

  void     (*destroy)      (XftDraw  *draw,
                            void     *user_data);
  XImage * (*get_image)    (XftDraw  *draw,
                            void     *user_data,
                            int       x,
                            int       y,
                            int       width,
                            int       height,
                            int      *x_offset,
                            int      *y_offset,
                            void    **image_data);
  void     (*put_image)    (XftDraw  *draw,
                            void     *user_data,
                            XImage   *ximage,
                            void     *image_data,
                            int       src_x,
                            int       src_y,
                            int       dest_x,
                            int       dest_y,
                            int       width,
                            int       height);
  void    (*destroy_image) (XftDraw  *draw,
                            void     *user_data,
                            XImage   *ximage,
                            void     *image_data);
};

typedef void (*XftDrawInstallHooksFunc) (XftDraw      *draw,
                                         XftDrawHooks *hooks,
                                         void         *user_data);

void
XftDrawInstallHooks (XftDraw                 *draw,
                     XftDrawInstallHooksFunc  func,
                     void                    *user_data);

===

The extra indirection of providing a function to fill in
the hooks structure probably looks weird at first
glance, but my experience is that passing in the hook
structure (and thus making the hook structure size
part of the API/ABI) is something that you always regret
later when you decide you needed one more hook.

You could also have separate functions to set each hook
(XftDrawSetGetImageFunc()) but this would be really 
cumbersome, especially as you would then need separate
user-data and destroy callbacks for each hook.

GTK+ details
============

The algorithm used for tracking solid regions is very simple:

 - Whenever a rectangle is drawn that covers
   the entire drawable, initialize 
   drawable->solid_region to that area.

 - Whenever anything else is drawn, subtract
   a bounding region for it from drawable->solid_region,
   if drawable->solid_region exists.

It turns out that when I set things up in the right
fashion - putting the magic inside 
_gdk_drawable_copy_to_image() - I got free optimization of
image-on-constant background without any extra code
changes.

Some timings
============

The benchmark here is the time (in seconds) it takes to layout
and draw:

20,000 10 digit strings "0123456789".

             Render  No-AA  Nothing   [A]     [B]     [C]
[1] Local    3.6     2.6    1.3       4.4     3.4     2.7
[2] Remote   3.5     2.2    1.2       19.1    4.7     3.8

20,000 20 digit strings "01234567890123456789".

             Render  No-AA  Nothing   [A]     [B]     [C] 
[1] Local    6.3     4.5    2.1       7.2     5.9     4.3
[2] Remote   6.8     4.2    1.8       27.5    7.6     7.6

Render  - Using RENDER
No-AA   - Antialiasing off
Nothing - XftGlyphSpecCore a no-op
[A]     - No RENDER, Standard Xft CVS
[B]     - No RENDER, Xft CVS with attached patch
[C]     - No RENDER,  Xft CVS with attached patch and optimized
          compositing code (will mail patch separately)

[A] and [B] also are with the GDK changes to track solid 
colored regions, which has some overhead.

[1] 1.13ghz PIII, SuperSavage video (no accelerated render),
    depth-24 color
[2] Machine in [1], remote displaying over 100mbit
    network to a dual 733mhz PII, G400 (accelerated
    render disabled as buggy, IIRC), depth-16 color

Notes:

*) For case [C] (and the 20 digit case in [B]), 
   the remote performance is bandwidth limited - using the figure 
   that the 10-digit string is 13x80 pixels, you can calculate 
   that it is pushing about 84Mbit/sec over a 100Mbit/sec link.

*) It's important to keep the parallelization for the 
   remote case in mind when looking at the numbers ... that's
   why the remote numbers are _faster_ for the no-AA case,
   for instance.


Possible improvements to Xft changes
====================================

 - One thing that the current set of patches doesn't
   do is optimize the case where only a partial area
   needs to be composited. A common case for this
   is where a string goes off the edge of the backing
   pixmap.

   GTK+ knows this (it knows the size of the pixmap)
   but Xft will try to composite the full area, so
   GTK+ currently has to create a larger image, and
   let Xft composite on top of junk.

   It probably makes sense to change the GetImage hook
   to something like:

  XImage * (*get_image)    (XftDraw    *draw,
                            void       *user_data,
                            XRectangle *area_to_get,
                            XRectangle *area_gotten,
                            int        *x_offset,
                            int        *y_offset,
                            void      **image_data);

   Using XRectangle's to avoid a truly ridiculous 
   number of out parameters.

   [ I decided to get some reaction on the current
     patch before making this change, but I'm pretty
     sure it makes sense ]

 - An entirely different way of doing the Xft work would
   have been to provide hooks at a higher level:

    - Prep an area for compositing
    - Composite a glyph
    - Finish with compositing area

   This would allow further optimizations in some cases ...
   as an example ... with the patches above, GTK+ doesn't
   use shared memory for compositing areas _larger_ than
   256x64 pixels because shared memory allocation inside
   GDK is done using a tile-based system with tiles of that
   size. With a higher level set of hooks, it would be
   possible break down a large area into several small areas.

   Another you could do here is make the compositing operation
   go faster by special-casing composite-on-solid background.
   
   However, a high-level set of hooks puts a lot more burden 
   on the person doing the hooking ... they'd need to
   duplicate all the compositing logic, so I think the
   simpler XImage based approach is better.

Possible improvements to GTK+ changes
=====================================

 - The bounding box calculations for X primitives 
   could/should be improved (especially arc, but 
   also lines)

 - The patch is going to be buggy when rectangles
   are drawn with tiles/stipples ... the code will
   think that that creates a solid region when
   it doesn't. (Should be straightforward to fix.)

 - It probably isn't a good idea to turn on the solid
   area tracking for every pixmap; rather it should
   only be turned on only for the backing pixmaps.
   This requires an additional gdk-internal API
   addition.

 - The solid area tracking needs to be turned off when
   someone calls gdk_window_get_internal_paint_info(),
   since they then can use X calls directly and 
   screw up the tracking.

 - The totally-solid approach the current patch uses 
   now doesn't catch:

    - selected text
    - tree-views with the rules hint on
    - prelighted buttons

   Or anything where we have text on something
   other than the window's background color.
   I suspect the hit rate could be made almost 100%
   by extending the current one-region approach to
   two regions:
    
    - The last rectangle that covered the entire 
      draw.

    - The last solid rectangle (perhaps excluding 
      very small rectangles)

   This would take some experimentation to find out
   what the current hit rate is and how much it
   would be improved by such a change.

Regards,
                                           Owen

Index: Xft.h
===================================================================
RCS file: /cvs/xc/lib/Xft/Xft.h,v
retrieving revision 1.32
diff -u -p -r1.32 Xft.h
--- Xft.h	2003/02/25 21:57:53	1.32
+++ Xft.h	2003/03/06 17:00:43
@@ -287,6 +287,54 @@ void
 XftDrawSetSubwindowMode (XftDraw    *draw,
 			 int	    mode);
 
+typedef struct _XftDrawHooks XftDrawHooks;
+
+struct _XftDrawHooks {
+  void *user_data;
+
+  void     (*destroy)      (XftDraw  *draw,
+		            void     *user_data);
+  XImage * (*get_image)    (XftDraw  *draw,
+			    void     *user_data,
+			    int       x,
+			    int       y,
+			    int       width,
+			    int       height,
+			    int      *x_offset,
+			    int      *y_offset,
+			    void    **image_data);
+  void     (*put_image)    (XftDraw  *draw,
+			    void     *user_data,
+			    XImage   *ximage,
+			    void     *image_data,
+			    int       src_x,
+			    int       src_y,
+			    int       dest_x,
+			    int       dest_y,
+			    int       width,
+			    int       height);
+  void    (*destroy_image) (XftDraw  *draw,
+			    void     *user_data,
+			    XImage   *ximage,
+			    void     *image_data);
+};
+
+typedef void (*XftDrawInstallHooksFunc) (XftDraw      *draw,
+					 XftDrawHooks *hooks,
+					 void         *user_data);
+
+/* To hook into the process of getting/putting the image data,
+ * call this function passing in a point to a function that
+ * actually fills in the XftDrawHooks. The extra indirection
+ * is to allow future expansion of XftDrawHooks.
+ */
+void
+XftDrawInstallHooks (XftDraw                 *draw,
+		     XftDrawInstallHooksFunc  func,
+		     void                    *user_data);
+
+				 
+
 /* xftextent.c */
 
 void
Index: xftcore.c
===================================================================
RCS file: /cvs/xc/lib/Xft/xftcore.c,v
retrieving revision 1.13
diff -u -p -r1.13 xftcore.c
--- xftcore.c	2003/02/15 22:30:51	1.13
+++ xftcore.c	2003/03/06 17:00:43
@@ -932,6 +1175,124 @@ static int XftGetImageErrorHandler (Disp
     return 0;
 }
 
+static XImage *
+XftGetImage (XftDraw *draw,
+	     int      x,
+	     int      y,
+	     int      width,
+	     int      height,
+	     int     *x_offset,
+	     int     *y_offset,
+	     void   **image_data)
+{
+    Display *dpy = draw->dpy;
+    XImage *image;
+    XErrorHandler   prev_error;
+    unsigned int    depth;
+
+    *x_offset = 0;
+    *y_offset = 0;
+    *image_data = 0;
+
+    if (draw->hooks && draw->hooks->get_image) {
+	image = (*draw->hooks->get_image) (draw, draw->hooks->user_data,
+					   x, y, width, height,
+					   x_offset, y_offset, image_data);
+	if (!image)
+	    return 0;
+    }
+    /*
+     * Try to get bits directly from the drawable; if that fails,
+     * use a temporary pixmap.  When it does fail, assume it
+     * will probably fail for a while and keep using temporary
+     * pixmaps for a while to avoid double round trips.
+     */
+    else if (draw->core.use_pixmap == 0)
+    {
+	prev_error = XSetErrorHandler (XftGetImageErrorHandler);
+	image = XGetImage (dpy, draw->drawable,
+			   x, y,
+			   width, height, AllPlanes,
+			   ZPixmap);
+	XSetErrorHandler (prev_error);
+	if (!image)
+	    draw->core.use_pixmap = XFT_ASSUME_PIXMAP;
+    }
+    else
+    {
+	draw->core.use_pixmap--;
+	image = 0;
+    }
+
+    if (!image && (depth = XftDrawDepth (draw)))
+	{
+	    Pixmap	pix;
+	    GC		gc;
+	    XGCValues	gcv;
+
+	    pix = XCreatePixmap (dpy, draw->drawable,
+				 width, height, depth);
+	    gcv.graphics_exposures = False;
+	    gc = XCreateGC (dpy, pix, GCGraphicsExposures, &gcv);
+	    XCopyArea (dpy, draw->drawable, pix, gc, x, y,
+		       width, height, 0, 0);
+	    XFreeGC (dpy, gc);
+	    image = XGetImage (dpy, pix, 0, 0, width, height, AllPlanes,
+			       ZPixmap);
+	    XFreePixmap (dpy, pix);
+	}
+
+    if (image) {
+	image->red_mask = draw->visual->red_mask;
+	image->green_mask = draw->visual->green_mask;
+	image->blue_mask = draw->visual->blue_mask;
+    }
+
+    return image;
+
+}
+
+static void
+XftPutImage (XftDraw *draw,
+	     XImage  *image,
+	     void    *image_data,
+	     int      src_x,
+	     int      src_y,
+	     int      dest_x,
+	     int      dest_y,
+	     int      width,
+	     int      height)
+{
+    Display *dpy = draw->dpy;
+
+    if (draw->hooks && (*draw->hooks->put_image)) {
+	(*draw->hooks->put_image) (draw, draw->hooks->user_data,
+				   image, image_data,
+				   src_x, src_y,
+				   dest_x, dest_y,
+				   width, height);
+	return;
+    }
+
+    XPutImage (dpy, draw->drawable, draw->core.gc, image,
+	       src_x, src_y,
+	       dest_x, dest_y,
+	       width, height);
+}
+
+static void
+XftDestroyImage (XftDraw *draw,
+		 XImage  *image,
+		 void    *image_data)
+{
+    if (draw->hooks && (*draw->hooks->destroy_image)) {
+	(*draw->hooks->destroy_image) (draw, draw->hooks->user_data, image, image_data);
+	return;
+    }
+
+    XDestroyImage (image);
+}
+
 void
 XftGlyphCore (XftDraw		*draw,
 	      _Xconst XftColor	*color,
@@ -950,7 +1311,6 @@ XftGlyphCore (XftDraw		*draw,
     FcBool	    glyphs_loaded;
     int		    nmissing;
     int		    n;
-    XErrorHandler   prev_error;
 
     /*
      * Load missing glyphs
@@ -972,8 +1332,9 @@ XftGlyphCore (XftDraw		*draw,
     {
 	XGlyphInfo	gi;
 	XImage		*image;
-        unsigned int    depth;
+	void            *image_data;
 	int		ox, oy;
+	int             x_offset, y_offset;
 	XftSmoothGlyph	smooth = _XftSmoothGlyphFind (draw, public);
 	
 	XftGlyphExtents (dpy, public, glyphs, nglyphs, &gi);
@@ -981,50 +1342,10 @@ XftGlyphCore (XftDraw		*draw,
 	    goto bail1;
 	ox = x - gi.x;
 	oy = y - gi.y;
-	/*
-	 * Try to get bits directly from the drawable; if that fails,
-	 * use a temporary pixmap.  When it does fail, assume it
-	 * will probably fail for a while and keep using temporary
-	 * pixmaps for a while to avoid double round trips.
-	 */
-	if (draw->core.use_pixmap == 0)
-	{
-	    prev_error = XSetErrorHandler (XftGetImageErrorHandler);
-	    image = XGetImage (dpy, draw->drawable,
-			       ox, oy,
-			       gi.width, gi.height, AllPlanes,
-			       ZPixmap);
-	    XSetErrorHandler (prev_error);
-	    if (!image)
-		draw->core.use_pixmap = XFT_ASSUME_PIXMAP;
-	}
-	else
-	{
-	    draw->core.use_pixmap--;
-	    image = 0;
-	}
-	if (!image && (depth = XftDrawDepth (draw)))
-	{
-	    Pixmap	pix;
-	    GC		gc;
-	    XGCValues	gcv;
 
-	    pix = XCreatePixmap (dpy, draw->drawable,
-				 gi.width, gi.height, depth);
-	    gcv.graphics_exposures = False;
-	    gc = XCreateGC (dpy, pix, GCGraphicsExposures, &gcv);
-	    XCopyArea (dpy, draw->drawable, pix, gc, ox, oy,
-		       gi.width, gi.height, 0, 0);
-	    XFreeGC (dpy, gc);
-	    image = XGetImage (dpy, pix, 0, 0, gi.width, gi.height, AllPlanes,
-			       ZPixmap);
-	    XFreePixmap (dpy, pix);
-	}
+	image = XftGetImage (draw, ox, oy, gi.width, gi.height, &x_offset, &y_offset, &image_data);
 	if (!image)
 	    goto bail1;
-	image->red_mask = draw->visual->red_mask;
-	image->green_mask = draw->visual->green_mask;
-	image->blue_mask = draw->visual->blue_mask;
 	if (image->byte_order != XftNativeByteOrder ())
 	    XftSwapImage (image);
 	while (n--)
@@ -1034,16 +1355,15 @@ XftGlyphCore (XftDraw		*draw,
 		xftg = _XftGlyphDefault (dpy, public);
 	    if (xftg)
 	    {
-		(*smooth) (image, xftg, x - ox, y - oy, color);
+		(*smooth) (image, xftg, x_offset + x - ox, y_offset + y - oy, color);
 		x += xftg->metrics.xOff;
 		y += xftg->metrics.yOff;
 	    }
 	}
 	if (image->byte_order != XftNativeByteOrder ())
 	    XftSwapImage (image);
-	XPutImage (dpy, draw->drawable, draw->core.gc, image, 0, 0, ox, oy,
-		   gi.width, gi.height);
-	XDestroyImage (image);
+	XftPutImage (draw, image, image_data, x_offset, y_offset, ox, oy, gi.width, gi.height);
+	XftDestroyImage (draw, image, image_data);
     }
     else
     {
@@ -1082,7 +1402,6 @@ XftGlyphSpecCore (XftDraw		*draw,
     FcBool	    glyphs_loaded;
     int		    nmissing;
     int		    i;
-    XErrorHandler   prev_error;
     int		    x1, y1, x2, y2;
 
     /*
@@ -1133,54 +1452,14 @@ XftGlyphSpecCore (XftDraw		*draw,
 	_XftSmoothGlyphPossible (draw))
     {
 	XImage		*image;
-        unsigned int    depth;
+	int              x_offset, y_offset;
+	void            *image_data;
 	int		width = x2 - x1, height = y2 - y1;
 	XftSmoothGlyph	smooth = _XftSmoothGlyphFind (draw, public);
 
-	/*
-	 * Try to get bits directly from the drawable; if that fails,
-	 * use a temporary pixmap.  When it does fail, assume it
-	 * will probably fail for a while and keep using temporary
-	 * pixmaps for a while to avoid double round trips.
-	 */
-	if (draw->core.use_pixmap == 0)
-	{
-	    prev_error = XSetErrorHandler (XftGetImageErrorHandler);
-	    image = XGetImage (dpy, draw->drawable,
-			       x1, y1,
-			       width, height, AllPlanes,
-			       ZPixmap);
-	    XSetErrorHandler (prev_error);
-	    if (!image)
-		draw->core.use_pixmap = XFT_ASSUME_PIXMAP;
-	}
-	else
-	{
-	    draw->core.use_pixmap--;
-	    image = 0;
-	}
-	if (!image && (depth = XftDrawDepth (draw)))
-	{
-	    Pixmap	pix;
-	    GC		gc;
-	    XGCValues	gcv;
-
-	    pix = XCreatePixmap (dpy, draw->drawable,
-				 width, height, depth);
-	    gcv.graphics_exposures = False;
-	    gc = XCreateGC (dpy, pix, GCGraphicsExposures, &gcv);
-	    XCopyArea (dpy, draw->drawable, pix, gc, x1, y1,
-		       width, height, 0, 0);
-	    XFreeGC (dpy, gc);
-	    image = XGetImage (dpy, pix, 0, 0, width, height, AllPlanes,
-			       ZPixmap);
-	    XFreePixmap (dpy, pix);
-	}
+	image = XftGetImage (draw, x1, y1, width, height, &x_offset, &y_offset, &image_data);
 	if (!image)
 	    goto bail1;
-	image->red_mask = draw->visual->red_mask;
-	image->green_mask = draw->visual->green_mask;
-	image->blue_mask = draw->visual->blue_mask;
 	if (image->byte_order != XftNativeByteOrder ())
 	    XftSwapImage (image);
 	for (i = 0; i < nglyphs; i++)
@@ -1190,15 +1469,14 @@ XftGlyphSpecCore (XftDraw		*draw,
 		xftg = _XftGlyphDefault (dpy, public);
 	    if (xftg)
 	    {
-		(*smooth) (image, xftg, glyphs[i].x - x1, 
-			   glyphs[i].y - y1, color);
+		(*smooth) (image, xftg, x_offset + glyphs[i].x - x1, 
+			   y_offset + glyphs[i].y - y1, color);
 	    }
 	}
 	if (image->byte_order != XftNativeByteOrder ())
 	    XftSwapImage (image);
-	XPutImage (dpy, draw->drawable, draw->core.gc, image, 0, 0, x1, y1,
-		   width, height);
-	XDestroyImage (image);
+	XftPutImage (draw, image, image_data, x_offset, y_offset, x1, y1, width, height);
+	XftDestroyImage (draw, image, image_data);
     }
     else
     {
@@ -1229,7 +1507,6 @@ XftGlyphFontSpecCore (XftDraw			*draw,
     FcBool	    glyphs_loaded;
     int		    nmissing;
     int		    i;
-    XErrorHandler   prev_error;
     int		    x1, y1, x2, y2;
 
     /*
@@ -1285,53 +1562,13 @@ XftGlyphFontSpecCore (XftDraw			*draw,
 	_XftSmoothGlyphPossible (draw))
     {
 	XImage		*image;
-        unsigned int    depth;
+	void            *image_data;
 	int		width = x2 - x1, height = y2 - y1;
-
-	/*
-	 * Try to get bits directly from the drawable; if that fails,
-	 * use a temporary pixmap.  When it does fail, assume it
-	 * will probably fail for a while and keep using temporary
-	 * pixmaps for a while to avoid double round trips.
-	 */
-	if (draw->core.use_pixmap == 0)
-	{
-	    prev_error = XSetErrorHandler (XftGetImageErrorHandler);
-	    image = XGetImage (dpy, draw->drawable,
-			       x1, y1,
-			       width, height, AllPlanes,
-			       ZPixmap);
-	    XSetErrorHandler (prev_error);
-	    if (!image)
-		draw->core.use_pixmap = XFT_ASSUME_PIXMAP;
-	}
-	else
-	{
-	    draw->core.use_pixmap--;
-	    image = 0;
-	}
-	if (!image && (depth = XftDrawDepth (draw)))
-	{
-	    Pixmap	pix;
-	    GC		gc;
-	    XGCValues	gcv;
+	int             x_offset, y_offset;
 
-	    pix = XCreatePixmap (dpy, draw->drawable,
-				 width, height, depth);
-	    gcv.graphics_exposures = False;
-	    gc = XCreateGC (dpy, pix, GCGraphicsExposures, &gcv);
-	    XCopyArea (dpy, draw->drawable, pix, gc, x1, y1,
-		       width, height, 0, 0);
-	    XFreeGC (dpy, gc);
-	    image = XGetImage (dpy, pix, 0, 0, width, height, AllPlanes,
-			       ZPixmap);
-	    XFreePixmap (dpy, pix);
-	}
+	image = XftGetImage (draw, x1, y1, width, height, &x_offset, &y_offset, &image_data);
 	if (!image)
 	    goto bail1;
-	image->red_mask = draw->visual->red_mask;
-	image->green_mask = draw->visual->green_mask;
-	image->blue_mask = draw->visual->blue_mask;
 	if (image->byte_order != XftNativeByteOrder ())
 	    XftSwapImage (image);
 	for (i = 0; i < nglyphs; i++)
@@ -1345,15 +1582,14 @@ XftGlyphFontSpecCore (XftDraw			*draw,
 		xftg = _XftGlyphDefault (dpy, public);
 	    if (xftg)
 	    {
-		(*smooth) (image, xftg, glyphs[i].x - x1, 
-			   glyphs[i].y - y1, color);
+		(*smooth) (image, xftg, x_offset + glyphs[i].x - x1, 
+			   y_offset + glyphs[i].y - y1, color);
 	    }
 	}
 	if (image->byte_order != XftNativeByteOrder ())
 	    XftSwapImage (image);
-	XPutImage (dpy, draw->drawable, draw->core.gc, image, 0, 0, x1, y1,
-		   width, height);
-	XDestroyImage (image);
+	XftPutImage (draw, image, image_data, x_offset, y_offset, x1, y1, width, height);
+	XftDestroyImage (draw, image, image_data);
     }
     else
     {
Index: xftdraw.c
===================================================================
RCS file: /cvs/xc/lib/Xft/xftdraw.c,v
retrieving revision 1.25
diff -u -p -r1.25 xftdraw.c
--- xftdraw.c	2002/10/11 17:53:02	1.25
+++ xftdraw.c	2003/03/06 17:00:43
@@ -155,6 +155,7 @@ XftDrawCreate (Display   *dpy,
     draw->core.use_pixmap = 0;
     draw->clip_type = XftClipTypeNone;
     draw->subwindow_mode = ClipByChildren;
+    draw->hooks = 0;
     XftMemAlloc (XFT_MEM_DRAW, sizeof (XftDraw));
     return draw;
 }
@@ -280,6 +281,12 @@ XftDrawVisual (XftDraw *draw)
 void
 XftDrawDestroy (XftDraw	*draw)
 {
+    if (draw->hooks) {
+	if (draw->hooks->destroy)
+	    (*draw->hooks->destroy) (draw, draw->hooks->user_data);
+
+	free (draw->hooks);
+    }
     if (draw->render.pict)
 	XRenderFreePicture (draw->dpy, draw->render.pict);
     if (draw->core.gc)
@@ -294,6 +301,7 @@ XftDrawDestroy (XftDraw	*draw)
     case XftClipTypeNone:
 	break;
     }
+
     XftMemFree (XFT_MEM_DRAW, sizeof (XftDraw));
     free (draw);
 }
@@ -990,4 +998,27 @@ XftDrawSetSubwindowMode (XftDraw *draw, 
     }
     if (draw->core.gc)
 	XSetSubwindowMode (draw->dpy, draw->core.gc, mode);
+}
+
+void
+XftDrawInstallHooks (XftDraw                 *draw,
+		     XftDrawInstallHooksFunc  func,
+		     void                    *user_data)
+{
+    XftDrawHooks *new_hooks;
+
+    new_hooks = calloc (sizeof (XftDrawHooks), 1);
+    if (!new_hooks)
+	return;
+    
+    if (draw->hooks) {
+	if (draw->hooks->destroy)
+	    (*draw->hooks->destroy) (draw, draw->hooks->user_data);
+
+	free (draw->hooks);
+    }
+    
+    draw->hooks = new_hooks;
+
+    (*func) (draw, new_hooks, user_data);
 }
Index: xftint.h
===================================================================
RCS file: /cvs/xc/lib/Xft/xftint.h,v
retrieving revision 1.37
diff -u -p -r1.37 xftint.h
--- xftint.h	2002/10/11 17:53:02	1.37
+++ xftint.h	2003/03/06 17:00:43
@@ -182,6 +182,7 @@ struct _XftDraw {
     XftClipType	    clip_type;
     XftClip	    clip;
     int		    subwindow_mode;
+    XftDrawHooks   *hooks;
     struct {
 	Picture		pict;
     } render;
? x11/childinfo.c
? x11/childinfo.h
Index: x11/gdkdisplay-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkdisplay-x11.c,v
retrieving revision 1.25
diff -u -p -r1.25 gdkdisplay-x11.c
--- x11/gdkdisplay-x11.c	9 Jan 2003 02:38:12 -0000	1.25
+++ x11/gdkdisplay-x11.c	6 Mar 2003 16:59:40 -0000
@@ -127,6 +127,7 @@ gdk_display_open (const gchar *display_n
   display_x11 = GDK_DISPLAY_X11 (display);
 
   display_x11->use_xft = -1;
+  display_x11->use_xshm = TRUE;
   display_x11->xdisplay = xdisplay;
 
   /* Set up handlers for Xlib internal connections */
Index: x11/gdkdrawable-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkdrawable-x11.c,v
retrieving revision 1.25
diff -u -p -r1.25 gdkdrawable-x11.c
--- x11/gdkdrawable-x11.c	7 Nov 2002 22:27:22 -0000	1.25
+++ x11/gdkdrawable-x11.c	6 Mar 2003 16:59:40 -0000
@@ -24,6 +24,10 @@
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
+#undef GDK_DISABLE_DEPRECATED
+#include "gdkfont.h"
+#define GDK_DISABLE_DEPRECATED
+
 #include "gdkx.h"
 #include "gdkregion-generic.h"
 
@@ -149,6 +153,14 @@ static void gdk_drawable_impl_x11_class_
 
 static void gdk_drawable_impl_x11_finalize   (GObject *object);
 
+static GdkDrawable *get_impl_drawable (GdkDrawable *drawable);
+
+static void solid_colored_subtract (GdkDrawable *drawable,
+				    gint         x,
+				    gint         y,
+				    gint         width,
+				    gint         height);
+
 static gpointer parent_class = NULL;
 
 GType
@@ -218,8 +230,13 @@ gdk_drawable_impl_x11_class_init (GdkDra
 static void
 gdk_drawable_impl_x11_finalize (GObject *object)
 {
+  GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (object);
+  
   gdk_drawable_set_colormap (GDK_DRAWABLE (object), NULL);
 
+  if (impl->solid_region)
+    gdk_region_destroy (impl->solid_region);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -236,9 +253,124 @@ _gdk_x11_have_render (GdkDisplay *displa
 				&event_base, &error_base);
 }
 
+static XImage *
+get_xft_image (XftDraw  *draw,
+	       void     *user_data,
+	       int       x,
+	       int       y,
+	       int       width,
+	       int       height,
+	       int      *x_offset,
+	       int      *y_offset,
+	       void    **image_data)
+{
+  GdkDrawable *drawable = user_data;
+  GdkImage *image;
+
+  if (width <= GDK_SCRATCH_IMAGE_WIDTH && height <= GDK_SCRATCH_IMAGE_HEIGHT)
+    {
+      gint xs0, ys0;
+      gint xoff = 0, yoff = 0;
+      int depth = gdk_drawable_get_depth (drawable);
+      
+      image = _gdk_image_get_scratch (gdk_drawable_get_screen (drawable),
+				     width, height,
+				     depth, &xs0, &ys0);
+
+      if (x < 0)
+	{
+	  width += x;
+	  xoff = -x;
+	  x = 0;
+	}
+	  
+      if (y < 0)
+	{
+	  height += y;
+	  yoff = -y;
+	  y = 0;
+	}
+	  
+	    
+      _gdk_drawable_copy_to_image (drawable, image,
+				   x, y, xs0 + xoff, ys0 + yoff, width, height);
+
+      *x_offset = xs0;
+      *y_offset = ys0;
+      *image_data = g_object_ref (image);
+
+      return GDK_IMAGE_XIMAGE (image);
+    }
+  else
+    {
+      image = gdk_image_new (GDK_IMAGE_NORMAL,
+			     gdk_drawable_get_visual (drawable),
+			     width, height);
+
+      _gdk_drawable_copy_to_image (drawable, image,
+				   x, y, 0, 0, width, height);
+
+      *x_offset = 0;
+      *y_offset = 0;
+      *image_data = image;
+
+      return GDK_IMAGE_XIMAGE (image);
+    }
+}
+
+static void
+put_xft_image (XftDraw  *draw,
+	       void     *user_data,
+	       XImage   *ximage,
+	       void     *image_data,
+	       int       src_x,
+	       int       src_y,
+	       int       dest_x,
+	       int       dest_y,
+	       int       width,
+	       int       height)
+{
+  GdkVisual *visual = gdk_drawable_get_visual (user_data);
+  GdkDrawable *drawable = user_data;
+  GdkDrawable *impl = get_impl_drawable (drawable);
+  
+  gdk_draw_image (drawable,
+		  _gdk_x11_visual_get_scratch_gc (visual),
+		  image_data,
+		  src_x, src_y, dest_x, dest_y,
+		  width, height);
+
+
+  if (GDK_DRAWABLE_IMPL_X11 (impl)->solid_region)
+    solid_colored_subtract (impl, dest_x, dest_y, width, height);
+}
+
+static void
+destroy_xft_image (XftDraw  *draw,
+		   void     *user_data,
+		   XImage   *ximage,
+		   void     *image_data)
+{
+  g_object_unref (image_data);
+
+  return;
+}
+
+static void
+install_xft_draw_hooks (XftDraw      *draw,
+			XftDrawHooks *hooks,
+			void         *user_data)
+{
+  hooks->user_data = user_data = user_data;
+  hooks->get_image = get_xft_image;
+  hooks->put_image = put_xft_image;
+  hooks->destroy_image = destroy_xft_image;
+}
+
 #ifdef HAVE_XFT2
 static XftDraw *
-gdk_x11_drawable_get_xft_draw (GdkDrawable *drawable)
+gdk_x11_drawable_get_xft_draw (GdkDrawable *drawable,
+			       gboolean     warn)
 {
   GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable);
 
@@ -249,11 +381,12 @@ gdk_x11_drawable_get_xft_draw (GdkDrawab
 
       if (!colormap)
 	{
-	  g_warning ("Using Xft rendering requires the drawable argument to\n"
-		     "have a specified colormap. All windows have a colormap,\n"
-		     "however, pixmaps only have colormap by default if they\n"
-		     "were created with a non-NULL window argument. Otherwise\n"
-		     "a colormap must be set on them with gdk_drawable_set_colormap");
+	  if (warn)
+	    g_warning ("Using Xft rendering requires the drawable argument to\n"
+		       "have a specified colormap. All windows have a colormap,\n"
+		       "however, pixmaps only have colormap by default if they\n"
+		       "were created with a non-NULL window argument. Otherwise\n"
+		       "a colormap must be set on them with gdk_drawable_set_colormap");
  	  return NULL;
 	}
 
@@ -261,6 +394,7 @@ gdk_x11_drawable_get_xft_draw (GdkDrawab
       
       impl->xft_draw = XftDrawCreate (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
  				      GDK_VISUAL_XVISUAL (visual), GDK_COLORMAP_XCOLORMAP (colormap));
+      XftDrawInstallHooks (impl->xft_draw, install_xft_draw_hooks, impl->wrapper);
     }
 
    return impl->xft_draw;
@@ -269,7 +403,7 @@ gdk_x11_drawable_get_xft_draw (GdkDrawab
 static Picture
 gdk_x11_drawable_get_picture (GdkDrawable *drawable)
 {
-  XftDraw *draw = gdk_x11_drawable_get_xft_draw (drawable);
+  XftDraw *draw = gdk_x11_drawable_get_xft_draw (drawable, TRUE);
 
   return draw ? XftDrawPicture (draw) : None;
 }
@@ -279,7 +413,7 @@ gdk_x11_drawable_update_xft_clip (GdkDra
 				  GdkGC       *gc)
 {
   GdkGCX11 *gc_private = gc ? GDK_GC_X11 (gc) : NULL;
-  XftDraw *xft_draw = gdk_x11_drawable_get_xft_draw (drawable);
+  XftDraw *xft_draw = gdk_x11_drawable_get_xft_draw (drawable, TRUE);
 
   if (gc && gc_private->clip_region)
     {
@@ -436,6 +570,104 @@ gdk_x11_set_colormap (GdkDrawable *drawa
  */
 
 static void
+solid_colored_subtract (GdkDrawable *drawable,
+			gint         x,
+			gint         y,
+			gint         width,
+			gint         height)
+{
+  GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable);
+  GdkRegion *tmp_region;
+  GdkRectangle r;
+
+  r.x = x; r.y = y; r.width = width; r.height = height;
+  tmp_region = gdk_region_rectangle (&r);
+  gdk_region_subtract (impl->solid_region, tmp_region);
+  gdk_region_destroy (tmp_region);
+}
+
+static void
+solid_colored_subtract_points (GdkDrawable *drawable,
+			       GdkPoint    *points,
+			       gint         npoints,
+			       gboolean     filled)
+{
+  gint xmin = G_MININT, ymin = G_MININT;
+  gint xmax = G_MAXINT, ymax = G_MAXINT;
+  gint i;
+  
+  for (i=0; i<npoints; i++)
+    {
+      xmin = MIN (xmin, points[i].x); ymin = MIN (ymin, points[i].y);
+      if (filled)
+	{
+	  xmax = MAX (xmax, points[i].x); ymax = MAX (ymax, points[i].y);
+	}
+      else
+	{
+	  xmax = MAX (xmax, points[i].x + 1); ymax = MAX (ymax, points[i].y + 1);
+	}
+    }
+      
+  solid_colored_subtract (drawable, xmin, ymin, xmax - xmin, ymax - ymin);
+}
+
+static void
+solid_colored_subtract_line (GdkDrawable *drawable,
+			     GdkGC       *gc,
+			     gint         x1,
+			     gint         x2,
+			     gint         y1,
+			     gint         y2)
+{
+  GdkGCX11 *gc_x11 = GDK_GC_X11 (gc);
+  int lw = gc_x11->line_width;
+
+  gint xmin = MIN (x1, x2); gint ymin = MIN (y1, y2);
+  gint xmax = MAX (x1, x2); gint ymax = MAX (y1, y2);
+
+  if (lw == 0)
+    lw = 1;
+
+  /* Instead of computing the exact line bounds, we compute
+   * the exact bounds for a rectangle with X's rasterization
+   * rules, which should give the line bounding box + a bit
+   * of slop
+   */
+  solid_colored_subtract (drawable,
+			  xmin - lw / 2,  ymin - lw/2,
+			  xmax + lw - lw / 2, ymax + lw - lw / 2);
+}
+
+static void
+solid_colored_subtract_polyline (GdkDrawable *drawable,
+				 GdkGC       *gc,
+				 XPoint      *points,
+				 gint         npoints)
+{
+  gint i;
+  
+  for (i = 1; i < npoints; i++)
+    solid_colored_subtract_line (drawable, gc,
+				 points[i - 1].x, points[i - 1].y,
+				 points[i].x, points[i].y);
+}
+
+static void
+solid_colored_subtract_segments (GdkDrawable *drawable,
+				 GdkGC       *gc,
+				 GdkSegment  *segs,
+				 gint         nsegs)
+{
+  gint i;
+  
+  for (i = 0; i < nsegs; i++)
+    solid_colored_subtract_line (drawable, gc,
+				 segs[i].x1, segs[i].y1,
+				 segs[i].x2, segs[i].y2);
+}
+
+static void
 gdk_x11_draw_rectangle (GdkDrawable *drawable,
 			GdkGC       *gc,
 			gboolean     filled,
@@ -447,6 +679,46 @@ gdk_x11_draw_rectangle (GdkDrawable *dra
   GdkDrawableImplX11 *impl;
 
   impl = GDK_DRAWABLE_IMPL_X11 (drawable);
+
+  if (impl->do_solid_colored)
+    {
+      int w, h;
+      
+      gdk_drawable_get_size (impl->wrapper, &w, &h);
+	  
+      if (filled &&
+	  x <= 0 && y <= 0 &&
+	  x + width >= w && y + height >= h)
+	{
+	  GdkGCX11 *gc_x11 = GDK_GC_X11 (gc);
+	  
+	  GdkRectangle r;
+
+	  r.x = 0; r.y = 0; r.width = w; r.height = h;
+
+	  if (impl->solid_region)
+	    gdk_region_destroy (impl->solid_region);
+	  
+	  impl->solid_region = gdk_region_rectangle (&r);
+	  impl->solid_pixel = gc_x11->fg_pixel;
+	}
+      else if (impl->solid_region)
+	{
+	  if (filled)
+	    {
+	      GdkGCX11 *gc_x11 = GDK_GC_X11 (gc);
+
+	      if (gc_x11->fg_pixel != impl->solid_pixel)
+		solid_colored_subtract (drawable, x, y, width, height);
+	    }
+	  else
+	    {
+	      /* We actually use the rectangle bounding box for lines */
+	      solid_colored_subtract_line (drawable, gc, x, y, x + width, y + height);
+	    }
+	  
+	}
+    }
   
   if (filled)
     XFillRectangle (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
@@ -471,6 +743,14 @@ gdk_x11_draw_arc (GdkDrawable *drawable,
 
   impl = GDK_DRAWABLE_IMPL_X11 (drawable);
 
+  if (impl->solid_region)
+    {
+      /* Could do a lot better */
+      if (filled)
+	solid_colored_subtract (drawable, x, y, width, height);
+      else
+	solid_colored_subtract_line (drawable, gc, x, y, x + width, y + height);
+    }
   
   if (filled)
     XFillArc (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
@@ -493,7 +773,6 @@ gdk_x11_draw_polygon (GdkDrawable *drawa
 
   impl = GDK_DRAWABLE_IMPL_X11 (drawable);
 
-  
   if (!filled &&
       (points[0].x != points[npoints-1].x || points[0].y != points[npoints-1].y))
     {
@@ -508,6 +787,14 @@ gdk_x11_draw_polygon (GdkDrawable *drawa
       tmp_points = g_new (XPoint, tmp_npoints);
     }
 
+  if (impl->solid_region)
+    {
+      if (filled)
+	solid_colored_subtract_points (drawable, points, npoints, TRUE);
+      else
+	solid_colored_subtract_polyline (drawable, gc, tmp_points, tmp_npoints);
+    }
+
   for (i=0; i<npoints; i++)
     {
       tmp_points[i].x = points[i].x;
@@ -544,6 +831,21 @@ gdk_x11_draw_text (GdkDrawable *drawable
 
   impl = GDK_DRAWABLE_IMPL_X11 (drawable);
   xdisplay = GDK_SCREEN_XDISPLAY (impl->screen);
+
+  if (impl->solid_region)
+    {
+      gint lbearing;
+      gint rbearing;
+      gint ascent;
+      gint descent;
+
+      gdk_text_extents (font, text, text_length,
+			&lbearing, &rbearing, NULL, &ascent, &descent);
+
+      solid_colored_subtract (drawable,
+			      x + lbearing, y - ascent,
+			      rbearing, descent);
+    }
   
   if (font->type == GDK_FONT_FONT)
     {
@@ -585,6 +887,21 @@ gdk_x11_draw_text_wc (GdkDrawable    *dr
   impl = GDK_DRAWABLE_IMPL_X11 (drawable);
   xdisplay = GDK_SCREEN_XDISPLAY (impl->screen);
   
+  if (impl->solid_region)
+    {
+      gint lbearing;
+      gint rbearing;
+      gint ascent;
+      gint descent;
+
+      gdk_text_extents_wc (font, text, text_length,
+			   &lbearing, &rbearing, NULL, &ascent, &descent);
+
+      solid_colored_subtract (drawable,
+			      x + lbearing, y - ascent,
+			      rbearing, descent);
+    }
+  
   if (font->type == GDK_FONT_FONT)
     {
       XFontStruct *xfont = (XFontStruct *) GDK_FONT_XFONT (font);
@@ -639,6 +956,9 @@ gdk_x11_draw_drawable (GdkDrawable *draw
   
   impl = GDK_DRAWABLE_IMPL_X11 (drawable);
 
+  if (impl->solid_region)
+    solid_colored_subtract (drawable, xdest, ydest, width, height);
+
   if (GDK_IS_DRAWABLE_IMPL_X11 (src))
     src_impl = GDK_DRAWABLE_IMPL_X11 (src);
   else
@@ -679,6 +999,8 @@ gdk_x11_draw_points (GdkDrawable *drawab
 
   impl = GDK_DRAWABLE_IMPL_X11 (drawable);
 
+  if (impl->solid_region)
+    solid_colored_subtract_points (drawable, points, npoints, FALSE);
   
   /* We special-case npoints == 1, because X will merge multiple
    * consecutive XDrawPoint requests into a PolyPoint request
@@ -722,6 +1044,8 @@ gdk_x11_draw_segments (GdkDrawable *draw
 
   impl = GDK_DRAWABLE_IMPL_X11 (drawable);
 
+  if (impl->solid_region)
+    solid_colored_subtract_segments (drawable, gc, segs, nsegs);
   
   /* We special-case nsegs == 1, because X will merge multiple
    * consecutive XDrawLine requests into a PolySegment request
@@ -765,13 +1089,15 @@ gdk_x11_draw_lines (GdkDrawable *drawabl
   GdkDrawableImplX11 *impl;
 
   impl = GDK_DRAWABLE_IMPL_X11 (drawable);
-
   
   for (i=0; i<npoints; i++)
     {
       tmp_points[i].x = points[i].x;
       tmp_points[i].y = points[i].y;
     }
+
+  if (impl->solid_region)
+    solid_colored_subtract_polyline (drawable, gc, tmp_points, npoints);
       
   XDrawLines (GDK_SCREEN_XDISPLAY (impl->screen),
 	      impl->xid,
@@ -804,7 +1130,7 @@ gdk_x11_draw_glyphs (GdkDrawable      *d
       _gdk_gc_x11_get_fg_xft_color (gc, &color);
        
       gdk_x11_drawable_update_xft_clip (drawable, gc);
-      draw = gdk_x11_drawable_get_xft_draw (drawable);
+      draw = gdk_x11_drawable_get_xft_draw (drawable, TRUE);
       
       pango_xft_render (draw, &color, font, glyphs, x, y);
 #else /* !HAVE_XFT2 */
@@ -844,6 +1170,9 @@ gdk_x11_draw_image     (GdkDrawable     
   
   impl = GDK_DRAWABLE_IMPL_X11 (drawable);
 
+  if (impl->solid_region)
+    solid_colored_subtract (drawable, xdest, ydest, width, height);
+
   if (image->type == GDK_IMAGE_SHARED)
     XShmPutImage (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
                   GDK_GC_GET_XGC (gc), GDK_IMAGE_XIMAGE (image),
@@ -863,7 +1192,8 @@ gdk_x11_get_depth (GdkDrawable *drawable
 }
 
 
-static GdkDrawable * get_impl_drawable (GdkDrawable *drawable)
+static GdkDrawable *
+get_impl_drawable (GdkDrawable *drawable)
 {
   GdkDrawable *impl;
   
@@ -1429,12 +1759,16 @@ gdk_x11_draw_pixbuf (GdkDrawable     *dr
 		     gint             x_dither,
 		     gint             y_dither)
 {
+  GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable);
   FormatType format_type;
   XRenderPictFormat *format, *mask_format;
   gint rowstride;
 #ifdef USE_SHM  
   gboolean use_pixmaps = TRUE;
 #endif /* USE_SHM */
+
+  if (impl->solid_region)
+    solid_colored_subtract (drawable, dest_x, dest_y, width, height);
     
   format_type = select_format (gdk_drawable_get_display (drawable),
 			       &format, &mask_format);
@@ -1444,7 +1778,7 @@ gdk_x11_draw_pixbuf (GdkDrawable     *dr
       (dither == GDK_RGB_DITHER_MAX && gdk_drawable_get_depth (drawable) != 24) ||
       gdk_x11_drawable_get_picture (drawable) == None)
     {
-      GdkDrawable *wrapper = GDK_DRAWABLE_IMPL_X11 (drawable)->wrapper;
+      GdkDrawable *wrapper = impl->wrapper;
       GDK_DRAWABLE_CLASS (parent_class)->draw_pixbuf (wrapper, gc, pixbuf,
 						      src_x, src_y, dest_x, dest_y,
 						      width, height,
Index: x11/gdkdrawable-x11.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkdrawable-x11.h,v
retrieving revision 1.9
diff -u -p -r1.9 gdkdrawable-x11.h
--- x11/gdkdrawable-x11.h	3 Oct 2002 21:17:07 -0000	1.9
+++ x11/gdkdrawable-x11.h	6 Mar 2003 16:59:40 -0000
@@ -69,7 +69,13 @@ struct _GdkDrawableImplX11
   XftDraw *xft_draw;
 #elif defined (HAVE_XFT)
   Picture picture;
-#endif  
+#endif
+
+  GdkRegion *solid_region;
+  guint solid_pixel;
+  
+  guint do_solid_colored : 1;
+  guint solid_colored : 1;
 };
  
 struct _GdkDrawableImplX11Class 
Index: x11/gdkgc-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkgc-x11.c,v
retrieving revision 1.26
diff -u -p -r1.26 gdkgc-x11.c
--- x11/gdkgc-x11.c	28 Nov 2002 00:33:05 -0000	1.26
+++ x11/gdkgc-x11.c	6 Mar 2003 16:59:40 -0000
@@ -159,6 +159,11 @@ _gdk_x11_gc_new (GdkDrawable      *drawa
   if (values_mask & GDK_GC_FOREGROUND)
     private->fg_pixel = values->foreground.pixel;
   
+  if (values_mask & GDK_GC_LINE_WIDTH)
+    private->line_width = values->line_width;
+  else
+    private->line_width = 0;
+  
   xvalues.function = GXcopy;
   xvalues.fill_style = FillSolid;
   xvalues.arc_mode = ArcPieSlice;
@@ -400,6 +405,9 @@ gdk_x11_gc_set_values (GdkGC           *
 
   if (values_mask & GDK_GC_FOREGROUND)
     x11_gc->fg_pixel = values->foreground.pixel;
+  
+  if (values_mask & GDK_GC_LINE_WIDTH)
+    x11_gc->line_width = values->line_width;
   
   gdk_x11_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask);
 
Index: x11/gdkimage-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkimage-x11.c,v
retrieving revision 1.50
diff -u -p -r1.50 gdkimage-x11.c
--- x11/gdkimage-x11.c	22 Oct 2002 22:11:22 -0000	1.50
+++ x11/gdkimage-x11.c	6 Mar 2003 16:59:40 -0000
@@ -496,6 +496,31 @@ get_full_image (GdkDrawable    *drawable
   return image;
 }
 
+static void
+fill_solid_image (GdkDrawable *drawable,
+		  GdkImage    *image,
+		  guint        pixel,
+		  gint         x,
+		  gint         y,
+		  gint         width,
+		  gint         height)
+{
+  XImage *ximage = GDK_IMAGE_XIMAGE (image);
+  
+  int i;
+  guchar *base;
+  
+  /* Now fill in the image
+   */
+  for (i = 0; i < width; i++)
+    XPutPixel (ximage, x + i, y, pixel);
+
+  base = (guchar *)image->mem + y * image->bpl + x * image->bpp;
+  
+  for (i = 1; i < height; i++)
+    memcpy (base + i * image->bpl, base, width * image->bpp);
+}
+
 GdkImage*
 _gdk_x11_copy_to_image (GdkDrawable    *drawable,
 			GdkImage       *image,
@@ -512,6 +537,7 @@ _gdk_x11_copy_to_image (GdkDrawable    *
   GdkDisplay *display;
   Display *xdisplay;
   gboolean have_grab;
+  gboolean have_trap;
   GdkRectangle req;
   GdkRectangle window_rect;
   Pixmap shm_pixmap = None;
@@ -529,6 +555,7 @@ _gdk_x11_copy_to_image (GdkDrawable    *
     return NULL;
   
   have_grab = FALSE;
+  have_trap = FALSE;
 
 #define UNGRAB() G_STMT_START {					\
     if (have_grab) {						\
@@ -537,6 +564,25 @@ _gdk_x11_copy_to_image (GdkDrawable    *
       have_grab = FALSE; }					\
   } G_STMT_END
 
+  if (impl->solid_region)
+    {
+      GdkRectangle r;
+
+      r.x = src_x; r.y = src_y; r.width = width; r.height = height;
+
+      if (gdk_region_rect_in (impl->solid_region, &r) == GDK_OVERLAP_RECTANGLE_IN)
+	{
+	  if (!image)
+	    image = _gdk_image_new_for_depth (impl->screen, GDK_IMAGE_NORMAL, 
+					      visual, width, height,
+					      gdk_drawable_get_depth (drawable));
+	  
+	  fill_solid_image (drawable, image, impl->solid_pixel, dest_x, dest_y, width, height);
+	  
+	  return image;
+	}
+    }
+
   if (!image && !GDK_IS_WINDOW_IMPL_X11 (drawable))
     return get_full_image (drawable, src_x, src_y, width, height);
 
@@ -628,7 +674,8 @@ _gdk_x11_copy_to_image (GdkDrawable    *
     goto out;
 
   gdk_error_trap_push ();
-  
+  have_trap = TRUE;
+      
   if (!image &&
       req.x == src_x && req.y == src_y && req.width == width && req.height == height)
     {
@@ -674,7 +721,8 @@ _gdk_x11_copy_to_image (GdkDrawable    *
       XFlush (xdisplay);
       have_grab = FALSE;
     }
-  
+
+  if (have_trap)
   gdk_error_trap_pop ();
 
   if (success && !image)
Index: x11/gdkpixmap-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkpixmap-x11.c,v
retrieving revision 1.57
diff -u -p -r1.57 gdkpixmap-x11.c
--- x11/gdkpixmap-x11.c	9 Dec 2002 23:34:49 -0000	1.57
+++ x11/gdkpixmap-x11.c	6 Mar 2003 16:59:40 -0000
@@ -208,6 +208,8 @@ gdk_pixmap_new (GdkDrawable *drawable,
   pix_impl->height = height;
   GDK_PIXMAP_OBJECT (pixmap)->depth = depth;
 
+  draw_impl->do_solid_colored = TRUE;
+
   if (depth == window_depth)
     {
       cmap = gdk_drawable_get_colormap (drawable);
Index: x11/gdkprivate-x11.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkprivate-x11.h,v
retrieving revision 1.27
diff -u -p -r1.27 gdkprivate-x11.h
--- x11/gdkprivate-x11.h	24 Sep 2002 20:20:03 -0000	1.27
+++ x11/gdkprivate-x11.h	6 Mar 2003 16:59:40 -0000
@@ -71,6 +71,7 @@ struct _GdkGCX11
   XRenderColor fg_picture_color; 
 #endif  
   gulong fg_pixel;
+  gint line_width;
 };
 
 struct _GdkGCX11Class
@@ -90,6 +91,9 @@ struct _GdkVisualPrivate
   GdkVisual visual;
   Visual *xvisual;
   GdkScreen *screen;
+
+  GdkDrawable *scratch_pixmap;
+  GdkGC *scratch_gc;
 };
 
 void _gdk_xid_table_insert (GdkDisplay *display,
@@ -168,6 +172,9 @@ gboolean _gdk_x11_display_is_root_window
 
 void _gdk_x11_events_init_screen   (GdkScreen *screen);
 void _gdk_x11_events_uninit_screen (GdkScreen *screen);
+
+GdkGC *_gdk_x11_visual_get_scratch_gc (GdkVisual *visual);
+
 
 void _gdk_events_init           (GdkDisplay *display);
 void _gdk_windowing_window_init (GdkScreen *screen);
Index: x11/gdkvisual-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkvisual-x11.c,v
retrieving revision 1.34
diff -u -p -r1.34 gdkvisual-x11.c
--- x11/gdkvisual-x11.c	6 Feb 2003 19:18:19 -0000	1.34
+++ x11/gdkvisual-x11.c	6 Mar 2003 16:59:40 -0000
@@ -663,3 +663,19 @@ gdk_visual_get_screen (GdkVisual *visual
 
   return  ((GdkVisualPrivate*) visual)->screen;
 }
+
+GdkGC *
+_gdk_x11_visual_get_scratch_gc (GdkVisual *visual)
+{
+  GdkVisualPrivate *private = (GdkVisualPrivate *) visual;
+
+  if (!private->scratch_gc)
+    {
+      private->scratch_pixmap = gdk_pixmap_new (gdk_screen_get_root_window (private->screen),
+						1, 1, visual->depth);
+      private->scratch_gc = gdk_gc_new (private->scratch_pixmap);
+    }
+  
+  return private->scratch_gc;
+}
+


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]