diff -ruwN old/gtk+-2.2.1/gtk/gtkhsv.c new/gtk+-2.2.1/gtk/gtkhsv.c
--- old/gtk+-2.2.1/gtk/gtkhsv.c	Thu Nov 14 06:52:10 2002
+++ new/gtk+-2.2.1/gtk/gtkhsv.c	Tue May 20 22:21:52 2003
@@ -108,8 +108,10 @@
 					GtkDirectionType  direction);
 static void     gtk_hsv_move           (GtkHSV           *hsv,
 					GtkDirectionType  dir);
+#if 0
 static GdkGC *  gtk_hsv_get_focus_gc   (GtkHSV           *hsv,
 					gint             *line_width);
+#endif
 
 static guint hsv_signals[LAST_SIGNAL];
 static GtkWidgetClass *parent_class;
@@ -249,6 +251,8 @@
   
   priv->size = DEFAULT_SIZE;
   priv->ring_width = DEFAULT_RING_WIDTH;
+
+  gtk_widget_set_double_buffered (GTK_WIDGET (hsv), FALSE);
 }
 
 /* Destroy handler for the HSV color selector */
@@ -581,8 +585,8 @@
   priv = hsv->priv;
   
   center = priv->size / 2.0;
-  outer = priv->size / 2.0;
-  inner = outer - priv->ring_width;
+  outer = priv->size / 2.0 - 1.0;
+  inner = outer - priv->ring_width - 1;
   angle = priv->h * 2.0 * G_PI;
   
   *hx = floor (center + cos (angle) * inner + 0.5);
@@ -798,6 +802,7 @@
 			 priv->v);
 
       gtk_widget_grab_focus (widget);
+      if (priv->focus_on_ring != TRUE) gtk_widget_queue_draw (widget);
       priv->focus_on_ring = TRUE;
       
       return TRUE;
@@ -814,6 +819,7 @@
       gtk_hsv_set_color (hsv, priv->h, s, v);
 
       gtk_widget_grab_focus (widget);
+      if (priv->focus_on_ring != FALSE) gtk_widget_queue_draw (widget);
       priv->focus_on_ring = FALSE;
       
       return TRUE;
@@ -910,116 +916,498 @@
   return FALSE;
 }
 
-
 /* Redrawing */
 
-/* Paints the hue ring */
+#define SWAP(a,b,t) ((t) = (a), (a) = (b), (b) = (t))
+/* Sre's approximation */
+#define MUL255(a, b) (((((guint)a) + 1) * (b)) >> 8)
+/* operands must have >= 32 bits */
+#define ITOFIX(i) ((i) << 16)
+#define FIXTOI(f) ((f) >> 16)
+
 static void
-paint_ring (GtkHSV      *hsv,
-	    GdkDrawable *drawable,
-	    gint         x,
-	    gint         y,
-	    gint         width,
-	    gint         height)
+blendover(guchar *dst, gint width, gint height, gint x, gint y,
+	  gint r, gint g, gint b, gint a)
 {
-  HSVPrivate *priv;
-  int xx, yy;
-  gdouble dx, dy, dist;
-  gdouble center;
-  gdouble inner, outer;
-  guchar *buf, *p;
-  gdouble angle;
-  gdouble hue;
-  gdouble r, g, b;
-  GdkBitmap *mask;
-  GdkGC *gc;
-  GdkColor color;
+    guint resr, resg, resb;
   
-  priv = hsv->priv;
+    /* clip to viewport */
+    if ((x < 0 || x >= width) || (y < 0 || y >= height)) return;
   
-  center = priv->size / 2.0;
+    resr = dst[(width * y + x) * 3 + 0];
+    resg = dst[(width * y + x) * 3 + 1];
+    resb = dst[(width * y + x) * 3 + 2];
   
-  outer = priv->size / 2.0;
-  inner = outer - priv->ring_width;
+    resr = MUL255(a, r - resr) + resr;
+    resg = MUL255(a, g - resg) + resg;
+    resb = MUL255(a, b - resb) + resb;
   
-  /* Paint the ring */
+    dst[(width * y + x) * 3 + 0] = resr;
+    dst[(width * y + x) * 3 + 1] = resg;
+    dst[(width * y + x) * 3 + 2] = resb;
+}
   
-  buf = g_new (guchar, width * height * 3);
+static void
+blendoverconst(guchar *dst, gint width, gint height, gint x, gint y,
+	       gint r, gint g, gint b, gint a,
+	       gint resr, gint resg, gint resb)
+{
+    /* clip to viewport */
+    if ((x < 0 || x >= width) || (y < 0 || y >= height)) return;
+
+    resr = MUL255(a, r - resr) + resr;
+    resg = MUL255(a, g - resg) + resg;
+    resb = MUL255(a, b - resb) + resb;
+
+    dst[(width * y + x) * 3 + 0] = resr;
+    dst[(width * y + x) * 3 + 1] = resg;
+    dst[(width * y + x) * 3 + 2] = resb;
+}
   
-  for (yy = 0; yy < height; yy++)
+static void
+setpixel(guchar *dst, gint width, gint height, gint x, gint y,
+	 gint r, gint g, gint b)
     {
-      p = buf + yy * width * 3;
+    /* clip to viewport */
+    if ((x < 0 || x >= width) || (y < 0 || y >= height)) return;
       
-      dy = -(yy + y - center);
+    dst[(width * y + x) * 3 + 0] = r;
+    dst[(width * y + x) * 3 + 1] = g;
+    dst[(width * y + x) * 3 + 2] = b;
+}
+
+#define COLOROP(c0, op, c1, dst)		\
+	dst##r = c0##r op c1##r;		\
+	dst##g = c0##g op c1##g;		\
+	dst##b = c0##b op c1##b;
+#define COLOROPCONST(col, op, c, dst)		\
+	dst##r = col##r op c;			\
+	dst##g = col##g op c;			\
+	dst##b = col##b op c;
+#define COLORTOFIX(c, f)			\
+	f##r = ITOFIX(c##r);			\
+	f##g = ITOFIX(c##g);			\
+	f##b = ITOFIX(c##b);
+#define COLORNEG(s, d)				\
+	d##r = - s##r;				\
+	d##g = - s##g;				\
+	d##b = - s##b;
+#define COLORSWAP(c0, c1, t)			\
+	SWAP(c0##r, c1##r, t);			\
+	SWAP(c0##g, c1##g, t);			\
+	SWAP(c0##b, c1##b, t);
+#define COLORSET(val, c)			\
+	c##r = val;				\
+	c##g = val;				\
+	c##b = val;
+#define COLORCOPY(from, to)			\
+	to##r = from##r;			\
+	to##g = from##g;			\
+	to##b = from##b;
+#define COLORDIV
+
+/*
+  Antialiased line, circle & triangle drawing, using a variant of
+  Wu's algorithm [1].
+
+  [1] Wu, Xaolin.
+  "An Efficient Antialiasing Technique",
+  Computer Graphics, SIGGRAPH 1991 Proceedings 25(4):143-152
+ */
+static void
+aagouraudline(guchar *dst, gint width, gint height,
+	      gint x0, gint y0, gint x1, gint y1,
+	      gint c0r, gint c0g, gint c0b,
+	      gint c1r, gint c1g, gint c1b)
+{
+    gint x, y, inc; // these must be >= 32 bits
+    gint dx, dy;
+    gint dr, dg, db;
+    gint cr, cg, cb;
+    gint t;
       
-      for (xx = 0; xx < width; xx++)
-	{
-	  dx = xx + x - center;
+    dx = x1 - x0;
+    dy = y1 - y0;
+    COLOROP(c1, -, c0, d);
+    COLORTOFIX(d, d);
+
+    if (ABS(dx) > ABS(dy)) {
+        if (dx < 0) {
+            dx = -dx;
+            dy = -dy;
+            SWAP(x0, x1, t);
+            SWAP(y0, y1, t);
+	    COLORNEG(d, d);
+	    COLORSWAP(c0, c1, t);
+        }
+        x = x0;
+        y = ITOFIX(y0);
+	if (dx) {
+	    inc = ITOFIX(dy) / dx;
+	    COLOROPCONST(d, /, dx, d);
+	}
+	else {
+	    inc = 0;
+	    COLORSET(0, d);
+	}
+	COLORTOFIX(c0, c);
 	  
-	  dist = dx * dx + dy * dy;
-	  if (dist < ((inner-1) * (inner-1)) || dist > ((outer+1) * (outer+1)))
+        while (x < x1) {
+	    blendover(dst, width, height, x, FIXTOI(y),
+		      FIXTOI(cr), FIXTOI(cg), FIXTOI(cb), (~y >> 8) & 0xFF);
+	    blendover(dst, width, height, x, FIXTOI(y) + 1,
+		      FIXTOI(cr), FIXTOI(cg), FIXTOI(cb), (y >> 8) & 0xFF);
+            x ++;
+            y += inc;
+	    COLOROP(c, +, d, c);
+        }
+    }
+    else {
+        if (dy < 0) {
+            dx = -dx;
+            dy = -dy;
+            SWAP(x0, x1, t);
+            SWAP(y0, y1, t);
+	    COLORNEG(d, d);
+	    COLORSWAP(c0, c1, t);
+        }
+        x = ITOFIX(x0);
+        y = y0;
+	if (dy) {
+	    inc = ITOFIX(dx) / dy;
+	    COLOROPCONST(d, /, dy, d);
+	}
+	else {
+	    inc = 0;
+	    COLORSET(0, d);
+	}
+	COLORTOFIX(c0, c);
+
+        while (y < y1) {
+	    blendover(dst, width, height, FIXTOI(x), y,
+		      FIXTOI(cr), FIXTOI(cg), FIXTOI(cb), (~x >> 8) & 0xFF);
+	    blendover(dst, width, height, FIXTOI(x) + 1, y,
+		      FIXTOI(cr), FIXTOI(cg), FIXTOI(cb), (x >> 8) & 0xFF);
+            x += inc;
+            y ++;
+	    COLOROP(c, +, d, c);
+        }
+    }
+}
+
+static void
+drawcirclepixels(guchar *dst, gint width, gint height,
+		 gint centerx, gint centery, gint x, gint y,
+		 gint r, gint g, gint b, gint alpha)
+{
+    blendover(dst, width, height, centerx + x, centery - y, r, g, b, alpha);
+    blendover(dst, width, height, centerx + y, centery - x, r, g, b, alpha);
+    blendover(dst, width, height, centerx + y, centery + x, r, g, b, alpha);
+    blendover(dst, width, height, centerx + x, centery + y, r, g, b, alpha);
+    blendover(dst, width, height, centerx - x, centery - y, r, g, b, alpha);
+    blendover(dst, width, height, centerx - y, centery - x, r, g, b, alpha);
+    blendover(dst, width, height, centerx - y, centery + x, r, g, b, alpha);
+    blendover(dst, width, height, centerx - x, centery + y, r, g, b, alpha);
+}
+
+static void
+aacircle(guchar *dst, gint width, gint height,
+	 gint centerx, gint centery, gint radius,
+	 gint r, gint g, gint b)
+{
+    float r2 = radius * radius;
+    float h;
+    float D, T;
+    gint x, y;
+
+    T = 0;
+    x = 0;
+    y = radius;
+
+    drawcirclepixels(dst, width, height,
+		     centerx, centery, x, y, r, g, b, 255);
+
+    while (++x < y) {
+	h = sqrtf(r2 - x * x);
+	D = floorf(255 * (ceilf(h) - h) + 0.5f);
+	if (D <= T) y--;
+
+	drawcirclepixels(dst, width, height,
+			 centerx, centery, x, y, r, g, b, 255-D);
+	drawcirclepixels(dst, width, height,
+			 centerx, centery, x, y-1, r, g, b, D);
+
+	T = D;
+    }
+}
+
+static void
+aagouraudtriangle(guchar *dst, gint width, gint height,
+		  gint x0, gint y0, gint x1, gint y1, gint x2, gint y2,
+		  gint c0r, gint c0g, gint c0b,
+		  gint c1r, gint c1g, gint c1b,
+		  gint c2r, gint c2g, gint c2b)
 	    {
-	      *p++ = 0;
-	      *p++ = 0;
-	      *p++ = 0;
-	      continue;
+    gint t;
+    gint xs, xe;
+    gint x, y;
+    gint ldy, rdy;
+    gint lx, rx, ldx, rdx; // >= 32 bits
+    gint ldr, ldg, ldb;
+    gint lcr, lcg, lcb;
+    gint rdr, rdg, rdb;
+    gint rcr, rcg, rcb;
+    gint xr, xg, xb; /* x span current color */
+    gint dxr, dxg, dxb; /* x span color delta */
+    gint dx;
+
+    /* sort points */
+    if (y0 > y1) {
+	SWAP(x0, x1, t);
+	SWAP(y0, y1, t);
+	COLORSWAP(c0, c1, t);
+    }
+    if (y0 > y2) {
+	SWAP(x0, x2, t);
+	SWAP(y0, y2, t);
+	COLORSWAP(c0, c2, t);
+    }
+    if (y1 > y2) {
+	SWAP(x1, x2, t);
+	SWAP(y1, y2, t);
+	COLORSWAP(c1, c2, t);
 	    }
 	  
-	  angle = atan2 (dy, dx);
-	  if (angle < 0.0)
-	    angle += 2.0 * G_PI;
+    /* plot aa outlines */
+    aagouraudline(dst, width, height, x0, y0, x1, y1,
+		  c0r, c0g, c0b, c1r, c1g, c1b);
+    aagouraudline(dst, width, height, x1, y1, x2, y2,
+		  c1r, c1g, c1b, c2r, c2g, c2b);
+    aagouraudline(dst, width, height, x2, y2, x0, y0,
+		  c2r, c2g, c2b, c0r, c0g, c0b);
+
+    /* left and right edge slope and start + color */
+    ldx = x2 - x0;
+    ldy = y2 - y0;
+    COLOROP(c2, -, c0, ld);
+    COLORTOFIX(ld, ld);
+    if (ldy) {
+	ldx = ITOFIX(ldx) / ldy;
+	COLOROPCONST(ld, /, ldy, ld);
+    }
+    else {
+	ldx = 0;
+	COLORSET(0, ld);
+    }
+    lx = ITOFIX(x0);
+    COLORTOFIX(c0, lc);
 	  
-	  hue = angle / (2.0 * G_PI);
+    rdx = x1 - x0;
+    rdy = y1 - y0;
+    COLOROP(c1, -, c0, rd);
+    COLORTOFIX(rd, rd);
+    if (rdy) {
+	rdx = ITOFIX(rdx) / rdy;
+	COLOROPCONST(rd, /, rdy, rd);
+    }
+    else {
+	rdx = 0;
+	COLORSET(0, rd);
+    }
+    rx = ITOFIX(x0);
+    COLORTOFIX(c0, rc);
 	  
-	  r = hue;
-	  g = 1.0;
-	  b = 1.0;
-	  hsv_to_rgb (&r, &g, &b);
+    /* top half */
+    for (y = y0; y < y1; y++) {
+	/* determine left edge & color start */
+	if (lx < rx) {
+	    xs = FIXTOI(lx);
+	    xe = FIXTOI(rx);
+	    COLORCOPY(lc, x);
+	    dx = xe - xs;
+	}
+	else {
+	    xs = FIXTOI(rx);
+	    xe = FIXTOI(lx);
+	    COLORCOPY(rc, x);
+	    dx = xs - xe;
+	}
+	/* compute color gradient */
+	COLOROP(rc, -, lc, dx);
+
+	if (dx) {
+	    COLOROPCONST(dx, /, dx, dx);
+	} else {
+	    COLORSET(0, dx);
+	}
+	/* fill x span */
+	for (x = xs + 1; x < xe + 1; x++) {
+	    setpixel(dst, width, height, x, y,
+		     FIXTOI(xr), FIXTOI(xg), FIXTOI(xb));
+	    COLOROP(x, +, dx, x);
+	}
+	lx += ldx;
+	rx += rdx;
+	COLOROP(lc, +, ld, lc);
+	COLOROP(rc, +, rd, rc);
+    }
+
+    rdx = x2 - x1;
+    rdy = y2 - y1;
+    COLOROP(c2, -, c1, rd);
+    COLORTOFIX(rd, rd);
+    if (rdy) {
+	rdx = ITOFIX(rdx) / rdy;
+	COLOROPCONST(rd, /, rdy, rd);
+    }
+    else {
+	rdx = 0;
+	COLORSET(0, ld);
+    }
+    rx = ITOFIX(x1);
+    COLORTOFIX(c1, rc);
 	  
-	  *p++ = floor (r * 255 + 0.5);
-	  *p++ = floor (g * 255 + 0.5);
-	  *p++ = floor (b * 255 + 0.5);
+    /* bottom half */
+    for (y = y1; y < y2; y++) {
+	/* determine left edge & color start */
+	if (lx < rx) {
+	    xs = FIXTOI(lx);
+	    xe = FIXTOI(rx);
+	    COLORCOPY(lc, x);
+	    dx = xe - xs;
+	}
+	else {
+	    xs = FIXTOI(rx);
+	    xe = FIXTOI(lx);
+	    COLORCOPY(rc, x);
+	    dx = xs - xe;
+	}
+	/* compute color gradient */
+	COLOROP(rc, -, lc, dx);
+
+	if (dx) {
+	    COLOROPCONST(dx, /, dx, dx);
+	} else {
+	    COLORSET(0, dx);
+	}
+	/* fill x span */
+	for (x = xs + 1; x < xe + 1; x++) {
+	    setpixel(dst, width, height, x, y,
+		     FIXTOI(xr), FIXTOI(xg), FIXTOI(xb));
+	    COLOROP(x, +, dx, x);
+	}
+	lx += ldx;
+	rx += rdx;
+	COLOROP(lc, +, ld, lc);
+	COLOROP(rc, +, rd, rc);
 	}
     }
   
-  /* Create clipping mask */
+#define OUTER_RADIUS 4
+#define INNER_RADIUS 3
   
-  mask = gdk_pixmap_new (GTK_WIDGET (hsv)->window, width, height, 1);
+/* Paints the hue ring */
+static void
+paint_ring (GtkHSV *hsv,
+	    guchar *dst,
+	    gint width,
+	    gint height,
+	    gint xoffs,
+	    gint yoffs)
+{
+  HSVPrivate *priv;
+  GtkStyle *style;
+  gfloat center, inner, outer;
+  gdouble r, g, b;
+  gdouble hue;
+  gint cr, cg, cb;
+  gint x, y;
+  gint bgr, bgg, bgb; /* widget background color */
+  gint alpha; /* pixel coverage */
+  gfloat fx, fy, f;
+  gfloat dist; /* distance to center */
+  gfloat h;
+  gfloat angle; /* pixel angle relative center */
 
-  gc = gdk_gc_new (mask);
+  priv = hsv->priv;
   
-  color.pixel = 0;
-  gdk_gc_set_foreground (gc, &color);
-  gdk_draw_rectangle (mask, gc, TRUE,
-		      0, 0, width, height);
+  center = priv->size / 2.0f;
+  outer = priv->size / 2.0f - 1.0f;
+  inner = outer - priv->ring_width;
   
+  /* get widget background color */
+  style = gtk_widget_get_style (GTK_WIDGET (hsv));
   
-  color.pixel = 1;
-  gdk_gc_set_foreground (gc, &color);
-  gdk_draw_arc (mask, gc, TRUE,
-		-x, -y,
-		priv->size - 1, priv->size - 1,
-		0, 360 * 64);
+  bgr = style->bg[GTK_STATE_NORMAL].red >> 8;
+  bgg = style->bg[GTK_STATE_NORMAL].green >> 8;
+  bgb = style->bg[GTK_STATE_NORMAL].blue >> 8;
   
-  color.pixel = 0;
-  gdk_gc_set_foreground (gc, &color);
-  gdk_draw_arc (mask, gc, TRUE,
-		-x + priv->ring_width - 1, -y + priv->ring_width - 1,
-		priv->size - 2 * priv->ring_width + 1, priv->size - 2 * priv->ring_width + 1,
-		0, 360 * 64);
+  /* Paint the ring */
   
-  g_object_unref (gc);
+  /* this code is a bit slow... */
+  for (y = 0; y < height; y++)
+  {
+      fy = -(y + yoffs - center);
+      for (x = 0; x < width; x++)
+      {
+	  fx = x + xoffs - center;
+	  dist = fx * fx + fy * fy;
+	  if (dist < (inner - 0.8f) * (inner - 0.8f) ||
+	      dist > (outer + 0.8f) * (outer + 0.8f))
+	  {
+	      /* outside of ring */
+	      setpixel(dst, width, height, x, y, bgr, bgg, bgb);
+	      continue;
+	  }
   
-  gdk_gc_set_clip_mask (priv->gc, mask);
-  gdk_gc_set_clip_origin (priv->gc, 0, 0);
+	  /* inside ring */
   
-  /* Draw ring */
+	  /* compute color */
+	  angle = atan2f(fy, fx); /* slow... */
+	  if (angle < 0.0f)
+	      angle += 2.0f * M_PI;
   
-  gdk_draw_rgb_image_dithalign (drawable, priv->gc, 0, 0, width, height,
-				GDK_RGB_DITHER_MAX,
-				buf,
-				width * 3,
-				x, y);
+	  hue = angle / (2.0f * M_PI);
+	  r = hue;
+	  g = 1.0;
+	  b = 1.0;
+	  hsv_to_rgb (&r, &g, &b);
+	  cr = floorf(r * 255 + 0.5f);
+	  cg = floorf(g * 255 + 0.5f);
+	  cb = floorf(b * 255 + 0.5f);
+
+	  /* compute (approximate) pixel coverage for sample */
+	  if (fabsf(fx) < fabsf(fy))
+	  {
+	      f = fx;
+	  }
+	  else
+	  {
+	      f = fy;
+	  }
+
+	  if (dist > outer * outer)
+	  {
+	      h = sqrtf(outer * outer - f * f);
+	      alpha = floorf(255 * (h - floorf(h)) + 0.5f);
+	  }
+	  else if (dist < inner * inner)
+	  {
+	      h = sqrtf(inner * inner - f * f);
+	      alpha = floorf(255 * (ceilf(h) - h) + 0.5f);
+	  }
+	  else
+	  {
+	      /* fully inside */
+	      setpixel(dst, width, height, x, y, cr, cg, cb);
+	      continue;
+	  }
+
+	  /* edge pixel */
+	  blendoverconst(dst, width, height, x, y, cr, cg, cb, alpha,
+			 bgr, bgg, bgb);
+      }
+  }
   
   /* Draw value marker */
   
@@ -1030,50 +1418,42 @@
   
   if (INTENSITY (r, g, b) > 0.5)
     {
-      color.red = 0x0000;
-      color.green = 0x0000;
-      color.blue = 0x0000;
+    cr = 0;
+    cg = 0;
+    cb = 0;
     }
   else
     {
-      color.red = 0xffff;
-      color.green = 0xffff;
-      color.blue = 0xffff;
+    cr = 255;
+    cg = 255;
+    cb = 255;
     }
 
-  gdk_gc_set_rgb_fg_color (priv->gc, &color);
-  
-  gdk_draw_line (drawable, priv->gc,
-		 -x + center, -y + center,
-		 -x + center + cos (priv->h * 2.0 * G_PI) * center,
-		 -y + center - sin (priv->h * 2.0 * G_PI) * center);
-  
-  gdk_gc_set_clip_mask (priv->gc, NULL);
-  g_object_unref (mask);
+  aagouraudline (dst, width, height,
+		 center /* + cos (priv->h * 2.0 * G_PI) * inner */ - xoffs,
+		 center /* - sin (priv->h * 2.0 * G_PI) * inner */ - yoffs,
+		 center + ceil(cos (priv->h * 2.0 * G_PI) * outer) - xoffs,
+		 center - floor(sin (priv->h * 2.0 * G_PI) * outer) - yoffs,
+		 cr, cg, cb, cr, cg, cb);
   
-  g_free (buf);
-  
-  /* Draw ring outline */
+  /* Draw ring focus outline */
 
   if (GTK_WIDGET_HAS_FOCUS (hsv) &&
       priv->focus_on_ring)
     {
-      gint focus_width;
-      gint focus_halfwidth;
-      GdkGC *gc = gtk_hsv_get_focus_gc (hsv, &focus_width);
-      focus_halfwidth = (focus_width + 1) / 2;
-      
-      gdk_draw_arc (drawable, gc, FALSE,
-                    -x + focus_width/2, -y + focus_width/2,
-                    priv->size - focus_width, priv->size - focus_width,
-                    0, 360 * 64);
-      gdk_draw_arc (drawable, gc, FALSE,
-                    -x + priv->ring_width - focus_halfwidth, -y + priv->ring_width - focus_halfwidth,
-                    priv->size - 2 * priv->ring_width + focus_width,
-		    priv->size - 2 * priv->ring_width + focus_width,
-                    0, 360 * 64);
+    /* focus line width/style is ignored */
+    GtkStyle *style;
       
-      g_object_unref (gc);
+    style = gtk_widget_get_style (GTK_WIDGET (hsv));
+
+    cr = style->fg[GTK_STATE_ACTIVE].red >> 8;
+    cg = style->fg[GTK_STATE_ACTIVE].green >> 8;
+    cb = style->fg[GTK_STATE_ACTIVE].blue >> 8;
+
+    aacircle (dst, width, height, center - xoffs, center - yoffs,
+	      inner, cr, cg, cb);
+    aacircle (dst, width, height, center - xoffs, center - yoffs,
+	      outer, cr, cg, cb);
     }
 }
 
@@ -1093,234 +1473,89 @@
   *b = floor (v * 255 + 0.5);
 }
 
-#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
-
-#define LERP(a, b, v1, v2, i) (((v2) - (v1) != 0)					\
-			       ? ((a) + ((b) - (a)) * ((i) - (v1)) / ((v2) - (v1)))	\
-			       : (a))
-
 /* Paints the HSV triangle */
 static void
 paint_triangle (GtkHSV      *hsv,
-		GdkDrawable *drawable,
-		gint         x,
-		gint         y,
+		guchar *dst,
 		gint         width,
-		gint         height)
+		gint height,
+		gint xoffs,
+		gint yoffs)
 {
   HSVPrivate *priv;
+  gdouble r, g, b;
+  gint cr, cg, cb;
+  gint xx, yy;
   gint hx, hy, sx, sy, vx, vy; /* HSV vertices */
-  gint x1, y1, r1, g1, b1; /* First vertex in scanline order */
+  gint x1, y1, r1, g1, b1; /* First vertex */
   gint x2, y2, r2, g2, b2; /* Second vertex */
   gint x3, y3, r3, g3, b3; /* Third vertex */
-  gint t;
-  guchar *buf, *p;
-  gint xl, xr, rl, rr, gl, gr, bl, br; /* Scanline data */
-  gint xx, yy;
-  GdkBitmap *mask;
-  GdkGC *gc;
-  GdkColor color;
-  GdkPoint points[3];
-  gdouble r, g, b;
+
   
   priv = hsv->priv;
   
   /* Compute triangle's vertices */
-  
   compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy);
   
-  x1 = hx;
-  y1 = hy;
+  x1 = hx - xoffs;
+  y1 = hy - yoffs;
   get_color (priv->h, 1.0, 1.0, &r1, &g1, &b1);
   
-  x2 = sx;
-  y2 = sy;
+  x2 = sx - xoffs;
+  y2 = sy - yoffs;
   get_color (priv->h, 1.0, 0.0, &r2, &g2, &b2);
   
-  x3 = vx;
-  y3 = vy;
+  x3 = vx - xoffs;
+  y3 = vy - yoffs;
   get_color (priv->h, 0.0, 1.0, &r3, &g3, &b3);
   
-  if (y2 > y3)
-    {
-      SWAP (x2, x3, t);
-      SWAP (y2, y3, t);
-      SWAP (r2, r3, t);
-      SWAP (g2, g3, t);
-      SWAP (b2, b3, t);
-    }
-  
-  if (y1 > y3)
-    {
-      SWAP (x1, x3, t);
-      SWAP (y1, y3, t);
-      SWAP (r1, r3, t);
-      SWAP (g1, g3, t);
-      SWAP (b1, b3, t);
-    }
-  
-  if (y1 > y2)
-    {
-      SWAP (x1, x2, t);
-      SWAP (y1, y2, t);
-      SWAP (r1, r2, t);
-      SWAP (g1, g2, t);
-      SWAP (b1, b2, t);
-    }
-  
-  /* Shade the triangle */
-  
-  buf = g_new (guchar, width * height * 3);
-  
-  for (yy = 0; yy < height; yy++)
-    {
-      p = buf + yy * width * 3;
-      
-      if (yy + y < y1 || yy + y > y3)
-	for (xx = 0; xx < width; xx++)
-	  {
-	    *p++ = 0;
-	    *p++ = 0;
-	    *p++ = 0;
-	  }
-      else {
-	if (yy + y < y2)
-	  {
-	    xl = LERP (x1, x2, y1, y2, yy + y);
-	    
-	    rl = LERP (r1, r2, y1, y2, yy + y);
-	    gl = LERP (g1, g2, y1, y2, yy + y);
-	    bl = LERP (b1, b2, y1, y2, yy + y);
-	  }
-	else
-	  {
-	    xl = LERP (x2, x3, y2, y3, yy + y);
-	    
-	    rl = LERP (r2, r3, y2, y3, yy + y);
-	    gl = LERP (g2, g3, y2, y3, yy + y);
-	    bl = LERP (b2, b3, y2, y3, yy + y);
-	  }
-	
-	xr = LERP (x1, x3, y1, y3, yy + y);
-	
-	rr = LERP (r1, r3, y1, y3, yy + y);
-	gr = LERP (g1, g3, y1, y3, yy + y);
-	br = LERP (b1, b3, y1, y3, yy + y);
-	
-	if (xl > xr)
-	  {
-	    SWAP (xl, xr, t);
-	    SWAP (rl, rr, t);
-	    SWAP (gl, gr, t);
-	    SWAP (bl, br, t);
-	  }
-	
-	for (xx = 0; xx < width; xx++)
-	  {
-	    if (xx + x < xl || xx + x > xr)
-	      {
-		*p++ = 0;
-		*p++ = 0;
-		*p++ = 0;
-	      }
-	    else
-	      {
-		*p++ = LERP (rl, rr, xl, xr, xx + x);
-		*p++ = LERP (gl, gr, xl, xr, xx + x);
-		*p++ = LERP (bl, br, xl, xr, xx + x);
-	      }
-	  }
-      }
-    }
-  
-  /* Create clipping mask */
-  
-  mask = gdk_pixmap_new (GTK_WIDGET (hsv)->window, width, height, 1);
-
-  gc = gdk_gc_new (mask);
-  
-  color.pixel = 0;
-  gdk_gc_set_foreground (gc, &color);
-  gdk_draw_rectangle (mask, gc, TRUE,
-		      0, 0, width, height);
-  
-  color.pixel = 1;
-  gdk_gc_set_foreground (gc, &color);
-  
-  points[0].x = x1 - x;
-  points[0].y = y1 - y;
-  points[1].x = x2 - x;
-  points[1].y = y2 - y;
-  points[2].x = x3 - x;
-  points[2].y = y3 - y;
-  gdk_draw_polygon (mask, gc, TRUE, points, 3);
-  
-  g_object_unref (gc);
-  
-  gdk_gc_set_clip_mask (priv->gc, mask);
-  gdk_gc_set_clip_origin (priv->gc, 0, 0);
-  
   /* Draw triangle */
-  
-  gdk_draw_rgb_image_dithalign (drawable, priv->gc, 0, 0, width, height,
-				GDK_RGB_DITHER_MAX,
-				buf,
-				width * 3,
-				x, y);
-  
-  gdk_gc_set_clip_mask (priv->gc, NULL);
-  g_object_unref (mask);
-  
-  g_free (buf);
+  aagouraudtriangle (dst, width, height, x1, y1, x2, y2, x3, y3,
+		     r1, g1, b1, r2, g2, b2, r3, g3, b3);
   
   /* Draw triangle focus outline */
 
   if (GTK_WIDGET_HAS_FOCUS (hsv) &&
       !priv->focus_on_ring)
     {
-      gint focus_width = 1;	    
-      GdkGC *gc = gtk_hsv_get_focus_gc (hsv, &focus_width);
+    /* focus line width/style is ignored */
+    GtkStyle *style;
+
+    style = gtk_widget_get_style (GTK_WIDGET (hsv));
   
-      gdk_draw_polygon (drawable, gc, FALSE, points, 3);
-      g_object_unref (gc);
+    cr = style->fg[GTK_STATE_ACTIVE].red >> 8;
+    cg = style->fg[GTK_STATE_ACTIVE].green >> 8;
+    cb = style->fg[GTK_STATE_ACTIVE].blue >> 8;
+
+    aagouraudline (dst, width, height, x1, y1, x2, y2, cr, cg, cb, cr, cg, cb);
+    aagouraudline (dst, width, height, x2, y2, x3, y3, cr, cg, cb, cr, cg, cb);
+    aagouraudline (dst, width, height, x3, y3, x1, y1, cr, cg, cb, cr, cg, cb);
     }
   
   /* Draw value marker */
   
-  xx = floor (sx + (vx - sx) * priv->v + (hx - vx) * priv->s * priv->v + 0.5) - x;
-  yy = floor (sy + (vy - sy) * priv->v + (hy - vy) * priv->s * priv->v + 0.5) - y;
-  
   r = priv->h;
   g = priv->s;
   b = priv->v;
+  xx = floor (sx + (vx - sx) * b + (hx - vx) * g * b + 0.5) - xoffs;
+  yy = floor (sy + (vy - sy) * b + (hy - vy) * g * b + 0.5) - yoffs;
+
   hsv_to_rgb (&r, &g, &b);
 
   if (INTENSITY (r, g, b) > 0.5)
     {
-      color.red = 0x0000;
-      color.green = 0x0000;
-      color.blue = 0x0000;
+    cr = 0;
+    cg = 0;
+    cb = 0;
     }
   else
     {
-      color.red = 0xffff;
-      color.green = 0xffff;
-      color.blue = 0xffff;
+    cr = 255;
+    cg = 255;
+    cb = 255;
     }
 
-  gdk_gc_set_rgb_fg_color (priv->gc, &color);
-
-#define OUTER_RADIUS 4
-#define INNER_RADIUS 3 
-  
-  gdk_draw_arc (drawable, priv->gc, FALSE,
-		xx - OUTER_RADIUS, yy - OUTER_RADIUS,
-		OUTER_RADIUS * 2, OUTER_RADIUS * 2,
-		0, 360 * 64);
-  gdk_draw_arc (drawable, priv->gc, FALSE,
-		xx - INNER_RADIUS, yy - INNER_RADIUS,
-		INNER_RADIUS * 2, INNER_RADIUS * 2,
-		0, 360 * 64);
+  aacircle(dst, width, height, xx, yy, OUTER_RADIUS, cr, cg, cb);
 }
 
 /* Paints the contents of the HSV color selector */
@@ -1332,8 +1567,24 @@
        gint         width,
        gint         height)
 {
-  paint_ring (hsv, drawable, x, y, width, height);
-  paint_triangle (hsv, drawable, x, y, width, height);
+  HSVPrivate *priv;
+  guchar *buf;
+
+  priv = hsv->priv;
+
+  buf = g_new (guchar, width * height * 3);
+
+  paint_ring(hsv, buf, width, height, x, y);
+
+  paint_triangle(hsv, buf, width, height, x, y);
+
+  gdk_draw_rgb_image_dithalign (drawable, priv->gc, 0, 0,
+				width, height,
+				GDK_RGB_DITHER_MAX,
+				buf,
+				width * 3,
+				x, y);
+  g_free(buf);
 }
 
 /* Expose_event handler for the HSV color selector */
@@ -1367,10 +1618,12 @@
   rect.x = 0;
   rect.y = 0;
   
+#if 0
   gdk_draw_rectangle (pixmap,
 		      widget->style->bg_gc[GTK_WIDGET_STATE (widget)],
 		      TRUE,
 		      0, 0, dest.width, dest.height);
+#endif
   paint (hsv, pixmap,
 	 dest.x - widget->allocation.x, dest.y - widget->allocation.y,
 	 dest.width, dest.height);
@@ -1478,6 +1731,15 @@
 		   gdouble v)
 {
   HSVPrivate *priv;
+  gint hx, hy, sx, sy, vx, vy;
+  gint xx, yy;
+  gdouble minx, miny, maxx, maxy, t;
+  gfloat center;
+  gfloat outer;
+  gfloat inner;
+  gdouble oldh, olds, oldv;
+  GdkRegion *region;
+  GdkRectangle rect;
   
   g_return_if_fail (hsv != NULL);
   g_return_if_fail (GTK_IS_HSV (hsv));
@@ -1487,13 +1749,131 @@
   
   priv = hsv->priv;
   
+  /* try to be smart about what to update - ugly code in need of cleanup */
+
+  center = priv->size / 2.0f;
+  outer = priv->size / 2.0f - 1.0f;
+  inner = outer - priv->ring_width;
+
+  oldh = priv->h;
+  olds = priv->s;
+  oldv = priv->v;
+
+  region = gdk_region_new ();
+
+  if (h != oldh) {
+    /* redraw old/new hue marker bounding boxes */
+    maxx = center + cos (oldh * 2.0 * G_PI) * outer;
+    maxy = center - sin (oldh * 2.0 * G_PI) * outer;
+    minx = center + cos (oldh * 2.0 * G_PI) * inner;
+    miny = center - sin (oldh * 2.0 * G_PI) * inner;
+    if (maxx < minx) SWAP (maxx, minx, t);
+    if (maxy < miny) SWAP (maxy, miny, t);
+    minx = floor(minx) - 1;
+    miny = floor(miny) - 1;
+    maxx = ceil(maxx) + 1;
+    maxy = ceil(maxy) + 1;
+    rect.x = minx;
+    rect.y = miny;
+    rect.width = maxx - minx;
+    rect.height = maxy - miny;
+    gdk_region_union_with_rect (region, &rect);
+
+    maxx = center + cos (h * 2.0 * G_PI) * outer;
+    maxy = center - sin (h * 2.0 * G_PI) * outer;
+    minx = center + cos (h * 2.0 * G_PI) * inner;
+    miny = center - sin (h * 2.0 * G_PI) * inner;
+    if (maxx < minx) SWAP (maxx, minx, t);
+    if (maxy < miny) SWAP (maxy, miny, t);
+    minx = floor(minx) - 1;
+    miny = floor(miny) - 1;
+    maxx = ceil(maxx) + 1;
+    maxy = ceil(maxy) + 1;
+    rect.x = minx;
+    rect.y = miny;
+    rect.width = maxx - minx;
+    rect.height = maxy - miny;
+    gdk_region_union_with_rect (region, &rect);
+
+    /* redraw triangle bounding box */
+    compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy);
+    minx = floor (MIN (hx, MIN (sx, vx))) - 1;
+    miny = floor (MIN (hy, MIN (sy, vy))) - 1;
+    maxx = ceil (MAX (hx, MAX (sx, vx))) + 1;
+    maxy = ceil (MAX (hy, MAX (sy, vy))) + 1;
+    rect.x = minx;
+    rect.y = miny;
+    rect.width = maxx - minx;
+    rect.height = maxy - miny;
+    gdk_region_union_with_rect (region, &rect);
+
   priv->h = h;
   priv->s = s;
   priv->v = v;
+    compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy);
+    minx = floor (MIN (hx, MIN (sx, vx))) - 1;
+    miny = floor (MIN (hy, MIN (sy, vy))) - 1;
+    maxx = ceil (MAX (hx, MAX (sx, vx))) + 1;
+    maxy = ceil (MAX (hy, MAX (sy, vy))) + 1;
+    rect.x = minx;
+    rect.y = miny;
+    rect.width = maxx - minx;
+    rect.height = maxy - miny;
+    gdk_region_union_with_rect (region, &rect);
+  }
+  else if (s == olds && v == oldv) {
+    /* nothing changed */
+    return;
+  }
+
+  /* redraw old/new value marker */
+  priv->h = oldh;
+  priv->s = olds;
+  priv->v = oldv;
+  compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy);
+  xx = floor (sx + (vx - sx)* oldv + (hx - vx) * olds * oldv + 0.5);
+  yy = floor (sy + (vy - sy)* oldv + (hy - vy) * olds * oldv + 0.5);
+  minx = xx - OUTER_RADIUS - 1;
+  miny = yy - OUTER_RADIUS - 1;
+  maxx = xx + OUTER_RADIUS + 1;
+  maxy = yy + OUTER_RADIUS + 1;
+  rect.x = minx;
+  rect.y = miny;
+  rect.width = maxx - minx;
+  rect.height = maxy - miny;
+  gdk_region_union_with_rect (region, &rect);
   
-  g_signal_emit (hsv, hsv_signals[CHANGED], 0);
+  priv->h = h;
+  priv->s = s;
+  priv->v = v;
+  compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy);
+  xx = floor (sx + (vx - sx)* v + (hx - vx) * s * v + 0.5);
+  yy = floor (sy + (vy - sy)* v + (hy - vy) * s * v + 0.5);
+  minx = xx - OUTER_RADIUS - 1;
+  miny = yy - OUTER_RADIUS - 1;
+  maxx = xx + OUTER_RADIUS + 1;
+  maxy = yy + OUTER_RADIUS + 1;
+  rect.x = minx;
+  rect.y = miny;
+  rect.width = maxx - minx;
+  rect.height = maxy - miny;
+  gdk_region_union_with_rect (region, &rect);
   
-  gtk_widget_queue_draw (GTK_WIDGET (hsv));
+  priv->h = h;
+  priv->s = s;
+  priv->v = v;
+
+  if (GTK_WIDGET_DRAWABLE(hsv) && !gdk_region_empty (region)) {
+    gdk_region_get_clipbox (region, &rect);
+    gtk_widget_queue_draw_area (GTK_WIDGET (hsv),
+				GTK_WIDGET (hsv)->allocation.x + rect.x,
+				GTK_WIDGET (hsv)->allocation.y + rect.y,
+				rect.width, rect.height);
+    gdk_window_process_updates(GTK_WIDGET(hsv)->window, FALSE);
+  }
+  gdk_region_destroy (region);
+
+  g_signal_emit (hsv, hsv_signals[CHANGED], 0);
 }
 
 /**
@@ -1758,31 +2138,4 @@
     hue = 0.0;
   
   gtk_hsv_set_color (hsv, hue, sat, val);
-}
-
-static GdkGC *
-gtk_hsv_get_focus_gc (GtkHSV *hsv,
-		      gint   *line_width)
-{
-  GdkGC *focus_gc;
-  GtkWidget *widget = GTK_WIDGET (hsv);
-  gint8 *dash_list;
-  
-  focus_gc = gdk_gc_new (widget->window);
-  gdk_gc_copy (focus_gc, widget->style->fg_gc[GTK_WIDGET_STATE (widget)]);
-
-  gtk_widget_style_get (widget,
-			"focus-line-width", line_width,
-			"focus-line-pattern", (gchar *)&dash_list,
-			NULL);
-  
-  gdk_gc_set_line_attributes (focus_gc, *line_width,
-			      dash_list[0] ? GDK_LINE_ON_OFF_DASH : GDK_LINE_SOLID,
-			      GDK_CAP_BUTT, GDK_JOIN_MITER);
-  if (dash_list[0])
-    gdk_gc_set_dashes (focus_gc, 0, dash_list, strlen (dash_list));
-
-  g_free (dash_list);
-  
-  return focus_gc;
 }
