f57e3ee
--- control-center-2.15.92/libkbdraw/keyboard-drawing.c.corner	2006-08-27 00:37:45.000000000 -0400
f57e3ee
+++ control-center-2.15.92/libkbdraw/keyboard-drawing.c	2006-08-27 00:44:04.000000000 -0400
f57e3ee
@@ -76,6 +76,219 @@
f57e3ee
     cos (M_PI * angle / 1800.0);
fa96951
 }
fa96951
 
f57e3ee
+static gdouble
f57e3ee
+length (gdouble x, gdouble y)
f57e3ee
+{
f57e3ee
+  return sqrt (x*x + y*y);
f57e3ee
+}
f57e3ee
+
f57e3ee
+static gdouble
f57e3ee
+point_line_distance (gdouble ax, gdouble ay,
f57e3ee
+		     gdouble nx, gdouble ny)
f57e3ee
+{
f57e3ee
+  return ax * nx + ay * ny;
f57e3ee
+}
f57e3ee
+
f57e3ee
+static void
f57e3ee
+normal_form (gdouble ax, gdouble ay,
f57e3ee
+	     gdouble bx, gdouble by,
f57e3ee
+	     gdouble *nx, gdouble *ny, gdouble *d)
f57e3ee
+{
f57e3ee
+  gdouble l;
f57e3ee
+
f57e3ee
+  *nx = by - ay;
f57e3ee
+  *ny = ax - bx;
f57e3ee
+
f57e3ee
+  l = length (*nx, *ny);
f57e3ee
+
f57e3ee
+  *nx /= l;
f57e3ee
+  *ny /= l;
f57e3ee
+
f57e3ee
+  *d = point_line_distance (ax, ay, *nx, *ny);
f57e3ee
+}
f57e3ee
+
f57e3ee
+static void
f57e3ee
+inverse (gdouble a, gdouble b, gdouble c, gdouble d,
f57e3ee
+	 gdouble *e, gdouble *f, gdouble *g, gdouble *h)
f57e3ee
+{
f57e3ee
+  gdouble det;
f57e3ee
+
f57e3ee
+  det = a*d - b*c;
f57e3ee
+
f57e3ee
+  *e =  d / det;
f57e3ee
+  *f = -b / det;
f57e3ee
+  *g = -c / det;
f57e3ee
+  *h =  a / det; 
f57e3ee
+}
f57e3ee
+
f57e3ee
+static void
f57e3ee
+multiply (gdouble a, gdouble b, gdouble c, gdouble d,
f57e3ee
+	  gdouble e, gdouble f, 
f57e3ee
+	  gdouble *x, gdouble *y)
f57e3ee
+{
f57e3ee
+  *x = a*e + b*f;
f57e3ee
+  *y = c*e + d*f;
f57e3ee
+}
f57e3ee
+
f57e3ee
+static void
f57e3ee
+intersect (gdouble n1x, gdouble n1y, gdouble d1, 
f57e3ee
+	   gdouble n2x, gdouble n2y, gdouble d2, 
f57e3ee
+	   gdouble *x, gdouble *y)
f57e3ee
+{
f57e3ee
+  gdouble e, f, g, h;
f57e3ee
+
f57e3ee
+  inverse (n1x, n1y, n2x, n2y, &e, &f, &g, &h);
f57e3ee
+  multiply (e, f, g, h, d1, d2, x, y);
f57e3ee
+}
f57e3ee
+
f57e3ee
+
f57e3ee
+/* draw an angle from the current point to b and then to c,
f57e3ee
+ * with a rounded corner of the given radius.
f57e3ee
+ */
f57e3ee
+static void 
f57e3ee
+rounded_corner (cairo_t *cr, 
f57e3ee
+		gdouble bx, gdouble by, 
f57e3ee
+		gdouble cx, gdouble cy,
f57e3ee
+		gdouble radius)
f57e3ee
+{
f57e3ee
+  gdouble ax, ay;
f57e3ee
+  gdouble n1x, n1y, d1;
f57e3ee
+  gdouble n2x, n2y, d2;
f57e3ee
+  gdouble pd1, pd2;
f57e3ee
+  gdouble ix, iy;
f57e3ee
+  gdouble dist1, dist2;
f57e3ee
+  gdouble nx, ny, d;
f57e3ee
+  gdouble a1x, a1y, c1x, c1y;
f57e3ee
+  gdouble phi1, phi2;
f57e3ee
+
f57e3ee
+  cairo_get_current_point (cr, &ax, &ay;;
f57e3ee
+
f57e3ee
+  /* make sure radius is not too large */
f57e3ee
+  dist1 = length (bx - ax, by - ay);
f57e3ee
+  dist2 = length (cx - bx, cy - by);
f57e3ee
+  
f57e3ee
+  radius = MIN (radius, MIN (dist1, dist2));
f57e3ee
+
f57e3ee
+  /* construct normal forms of the lines */
f57e3ee
+  normal_form (ax, ay, bx, by, &n1x, &n1y, &d1;;
f57e3ee
+  normal_form (bx, by, cx, cy, &n2x, &n2y, &d2;;
f57e3ee
+
f57e3ee
+  /* find which side of the line a,b the point c is on */
f57e3ee
+  if (point_line_distance (cx, cy, n1x, n1y) < d1)
f57e3ee
+    pd1 = d1 - radius;
f57e3ee
+  else
f57e3ee
+    pd1 = d1 + radius;
f57e3ee
+
f57e3ee
+  /* find which side of the line b,c the point a is on */
f57e3ee
+  if (point_line_distance (ax, ay, n2x, n2y) < d2)
f57e3ee
+    pd2 = d2 - radius;
f57e3ee
+  else
f57e3ee
+    pd2 = d2 + radius;
f57e3ee
+						
f57e3ee
+  /* intersect the parallels to find the center of the arc */
f57e3ee
+  intersect (n1x, n1y, pd1, n2x, n2y, pd2, &ix, &iy;; 
f57e3ee
+
f57e3ee
+  nx = (bx - ax) / dist1;
f57e3ee
+  ny = (by - ay) / dist1;
f57e3ee
+  d = point_line_distance (ix, iy, nx, ny);
f57e3ee
+
f57e3ee
+  /* a1 is the point on the line a-b where the arc starts */
f57e3ee
+  intersect (n1x, n1y, d1, nx, ny, d, &a1x, &a1y);
f57e3ee
+
f57e3ee
+  nx = (cx - bx) / dist2;
f57e3ee
+  ny = (cy - by) / dist2;
f57e3ee
+  d = point_line_distance (ix, iy, nx, ny);
f57e3ee
+
f57e3ee
+  /* c1 is the point on the line b-c where the arc ends */
f57e3ee
+  intersect (n2x, n2y, d2, nx, ny, d, &c1x, &c1y);
f57e3ee
+
f57e3ee
+  /* determine the first angle */
f57e3ee
+  if (a1x - ix == 0)
f57e3ee
+    phi1 = (a1y - iy > 0) ? M_PI_2 : 3*M_PI_2;
f57e3ee
+  else if (a1x - ix > 0)
f57e3ee
+    phi1 = atan ((a1y - iy)/(a1x - ix));
f57e3ee
+  else 
f57e3ee
+    phi1 = M_PI + atan ((a1y - iy)/(a1x - ix));
f57e3ee
+
f57e3ee
+  /* determine the second angle */
f57e3ee
+  if (c1x - ix == 0)
f57e3ee
+    phi2 = (c1y - iy > 0) ? M_PI_2 : 3*M_PI_2;
f57e3ee
+  else if (c1x - ix > 0)
f57e3ee
+    phi2 = atan ((c1y - iy)/(c1x - ix));
f57e3ee
+  else 
f57e3ee
+    phi2 = M_PI + atan ((c1y - iy)/(c1x - ix));
f57e3ee
+
f57e3ee
+  /* compute the difference between phi2 and phi1 mod 2pi */
f57e3ee
+  d = phi2 - phi1;
f57e3ee
+  while (d < 0)
f57e3ee
+    d += 2*M_PI;
f57e3ee
+  while (d > 2*M_PI)
f57e3ee
+    d -= 2*M_PI;
f57e3ee
+
f57e3ee
+  cairo_line_to (cr, a1x, a1y);
f57e3ee
+
f57e3ee
+  /* pick the short arc from phi1 to phi2 */
f57e3ee
+  if (d < M_PI)
f57e3ee
+    cairo_arc (cr, ix, iy, radius, phi1, phi2);
f57e3ee
+  else
f57e3ee
+    cairo_arc_negative (cr, ix, iy, radius, phi1, phi2);
f57e3ee
+
f57e3ee
+  cairo_line_to (cr, cx, cy);
f57e3ee
+}
f57e3ee
+
f57e3ee
+static void
f57e3ee
+draw (cairo_t *cr,
f57e3ee
+      gint     width,
f57e3ee
+      gint     height)
f57e3ee
+{
f57e3ee
+  gdouble x0 = 100;
f57e3ee
+  gdouble y0 = 100;
f57e3ee
+  gdouble x1 = 200;
f57e3ee
+  gdouble y1 = 100;
f57e3ee
+  gdouble x2 = 180;
f57e3ee
+  gdouble y2 = 200;
f57e3ee
+  gdouble x3 = 240;
f57e3ee
+  gdouble y3 = 190;
f57e3ee
+
f57e3ee
+  gdouble radius = 20;
f57e3ee
+
f57e3ee
+  cairo_move_to (cr, x0, y0);
f57e3ee
+
f57e3ee
+  rounded_corner (cr, x1, y1, (x1+x2)/2, (y1+y2)/2, radius);
f57e3ee
+  rounded_corner (cr, x2, y2, x3, y3, radius);
f57e3ee
+
f57e3ee
+  cairo_stroke (cr);
f57e3ee
+}
f57e3ee
+
f57e3ee
+static void 
f57e3ee
+rounded_polygon (cairo_t  *cr, 
f57e3ee
+		 gboolean  filled,
f57e3ee
+		 gdouble   radius,
f57e3ee
+		 GdkPoint *points,
f57e3ee
+		 gint      num_points)
f57e3ee
+{
f57e3ee
+  gint i, j;
f57e3ee
+
f57e3ee
+  cairo_move_to (cr, 
f57e3ee
+		 (gdouble)(points[num_points - 1].x + points[0].x)/2, 
f57e3ee
+		 (gdouble)(points[num_points - 1].y + points[0].y)/2); 
f57e3ee
+ 
f57e3ee
+ for (i = 0; i < num_points; i++)
f57e3ee
+   {
f57e3ee
+     j = (i + 1) % num_points; 
f57e3ee
+     rounded_corner (cr, (gdouble)points[i].x, (gdouble)points[i].y, 
f57e3ee
+		     (gdouble)(points[i].x + points[j].x)/2, 
f57e3ee
+		     (gdouble)(points[i].y + points[j].y)/2,
f57e3ee
+		     radius);
f57e3ee
+   };
f57e3ee
+ cairo_close_path (cr);
f57e3ee
+ 
f57e3ee
+ if (filled)
f57e3ee
+   cairo_fill (cr);
f57e3ee
+ else
f57e3ee
+  cairo_stroke (cr);
f57e3ee
+}
f57e3ee
+
f57e3ee
 static void
f57e3ee
 draw_polygon (
f57e3ee
   KeyboardDrawing * drawing,
f57e3ee
@@ -83,10 +296,11 @@
f57e3ee
   gint xkb_x,
f57e3ee
   gint xkb_y,
f57e3ee
   XkbPointRec * xkb_points,
f57e3ee
-  guint num_points)
f57e3ee
+  guint num_points,
f57e3ee
+  gdouble radius)
f57e3ee
 {
f57e3ee
   GtkStateType state = GTK_WIDGET_STATE (GTK_WIDGET (drawing));
f57e3ee
-  GdkGC *gc;
f57e3ee
+  cairo_t *cr;
f57e3ee
   GdkPoint *points;
f57e3ee
   gboolean filled;
f57e3ee
   gint i;
f57e3ee
@@ -95,17 +309,16 @@
f57e3ee
     return;
f57e3ee
 
f57e3ee
   if (fill_color)
f57e3ee
-    {
f57e3ee
-      gc = gdk_gc_new (GTK_WIDGET (drawing)->window);
f57e3ee
-      gdk_gc_set_rgb_fg_color (gc, fill_color);
f57e3ee
-      filled = TRUE;
f57e3ee
-    }
f57e3ee
+    filled = TRUE;
f57e3ee
   else
f57e3ee
     {
f57e3ee
-      gc = GTK_WIDGET (drawing)->style->dark_gc[state];
f57e3ee
+      fill_color = &GTK_WIDGET (drawing)->style->dark[state];
f57e3ee
       filled = FALSE;
f57e3ee
     }
f57e3ee
 
f57e3ee
+  cr = gdk_cairo_create (GDK_DRAWABLE (drawing->pixmap));
f57e3ee
+  gdk_cairo_set_source_color (cr, fill_color);
f57e3ee
+
f57e3ee
   points = g_new (GdkPoint, num_points);
f57e3ee
 
f57e3ee
   for (i = 0; i < num_points; i++)
f57e3ee
@@ -114,11 +327,64 @@
f57e3ee
       points[i].y = xkb_to_pixmap_coord (drawing, xkb_y + xkb_points[i].y);
f57e3ee
     }
f57e3ee
 
f57e3ee
-  gdk_draw_polygon (drawing->pixmap, gc, filled, points, num_points);
f57e3ee
+  rounded_polygon (cr, filled, radius, points, num_points);
f57e3ee
 
f57e3ee
   g_free (points);
f57e3ee
-  if (fill_color)
f57e3ee
-    g_object_unref (gc);
f57e3ee
+}
f57e3ee
+
fa96951
+static void
fa96951
+curve_rectangle (cairo_t *cr,
fa96951
+		 gdouble  x0,
fa96951
+		 gdouble  y0,
fa96951
+		 gdouble  width,
fa96951
+		 gdouble  height,
fa96951
+		 gdouble  radius)
fa96951
+{
fa96951
+  gdouble x1, y1;
fa96951
+  
fa96951
+  if (!width || !height)
fa96951
+    return;
fa96951
+
fa96951
+  x1 = x0 + width;
fa96951
+  y1 = y0 + height;
fa96951
+
fa96951
+  radius = MIN(radius, MIN(width / 2, height / 2));
fa96951
+
fa96951
+  cairo_move_to (cr, x0, y0 + radius);
fa96951
+  cairo_arc (cr, x0 + radius, y0 + radius, radius, M_PI, 3*M_PI/2);  
fa96951
+  cairo_line_to (cr, x1 - radius, y0);
fa96951
+  cairo_arc (cr, x1 - radius, y0 + radius, radius, 3*M_PI/2, 2*M_PI);  
fa96951
+  cairo_line_to (cr, x1, y1 - radius);
fa96951
+  cairo_arc (cr, x1 - radius, y1 - radius, radius, 0, M_PI/2);  
fa96951
+  cairo_line_to (cr, x0 + radius, y1);
fa96951
+  cairo_arc (cr, x0 + radius, y1 - radius, radius, M_PI/2, M_PI);  
fa96951
+
fa96951
+  cairo_close_path (cr);  
fa96951
+}
fa96951
+
fa96951
+static void
fa96951
+draw_curve_rectangle (GdkPixmap *pixmap,
fa96951
+		      gboolean   filled,
fa96951
+		      GdkColor  *fill_color,
fa96951
+		      gint       x,
fa96951
+		      gint       y,
fa96951
+		      gint       width,
fa96951
+		      gint       height,
fa96951
+		      gint       radius)
fa96951
+{
fa96951
+  cairo_t *cr;
fa96951
+
fa96951
+  cr = gdk_cairo_create (GDK_DRAWABLE (pixmap));
fa96951
+  curve_rectangle (cr, x, y, width, height, radius);
fa96951
+
fa96951
+  gdk_cairo_set_source_color (cr, fill_color);
fa96951
+  
fa96951
+  if (filled)
fa96951
+    cairo_fill (cr);
fa96951
+  else
fa96951
+    cairo_stroke (cr);
fa96951
+  
fa96951
+  cairo_destroy (cr);
f57e3ee
 }
f57e3ee
 
fa96951
 /* x, y, width, height are in the xkb coordinate system */
f57e3ee
@@ -130,7 +396,8 @@
fa96951
   gint xkb_x,
fa96951
   gint xkb_y,
fa96951
   gint xkb_width,
fa96951
-  gint xkb_height)
fa96951
+  gint xkb_height,
fa96951
+  gint radius)
fa96951
 {
fa96951
   if (drawing->pixmap == NULL)
fa96951
     return;
f57e3ee
@@ -140,17 +407,12 @@
fa96951
       GtkStateType state = GTK_WIDGET_STATE (GTK_WIDGET (drawing));
fa96951
       gint x, y, width, height;
fa96951
       gboolean filled;
fa96951
-      GdkGC *gc;
fa96951
 
fa96951
       if (fill_color)
fa96951
-        {
fa96951
-          gc = gdk_gc_new (GTK_WIDGET (drawing)->window);
fa96951
-          gdk_gc_set_rgb_fg_color (gc, fill_color);
fa96951
-          filled = TRUE;
fa96951
-        }
fa96951
+	filled = TRUE;
fa96951
       else
fa96951
         {
fa96951
-          gc = GTK_WIDGET (drawing)->style->dark_gc[state];
fa96951
+          fill_color = &GTK_WIDGET (drawing)->style->dark[state];
fa96951
           filled = FALSE;
fa96951
         }
fa96951
 
f57e3ee
@@ -159,10 +421,8 @@
fa96951
       width = xkb_to_pixmap_coord (drawing, xkb_x + xkb_width) - x;
fa96951
       height = xkb_to_pixmap_coord (drawing, xkb_y + xkb_height) - y;
fa96951
 
fa96951
-      gdk_draw_rectangle (drawing->pixmap, gc, filled, x, y, width, height);
fa96951
-
fa96951
-      if (fill_color)
fa96951
-        g_object_unref (gc);
fa96951
+      draw_curve_rectangle (drawing->pixmap, filled, fill_color, 
fa96951
+			    x, y, width, height, radius);
fa96951
     }
fa96951
   else
fa96951
     {
f57e3ee
@@ -182,7 +442,7 @@
f57e3ee
       points[3].x = x; points[3].y = y;
f57e3ee
 
f57e3ee
       /* the points we've calculated are relative to 0,0 */
f57e3ee
-      draw_polygon (drawing, fill_color, 0, 0, points, 4);
f57e3ee
+      draw_polygon (drawing, fill_color, 0, 0, points, 4, radius);
f57e3ee
     }
f57e3ee
 }
f57e3ee
 
f57e3ee
@@ -203,7 +463,8 @@
fa96951
     {
fa96951
       if (color)
fa96951
         draw_rectangle (drawing, color, angle, origin_x, origin_y,
fa96951
-                        outline->points[0].x, outline->points[0].y);
fa96951
+                        outline->points[0].x, outline->points[0].y,
fa96951
+			outline->corner_radius);
fa96951
 
fa96951
 #ifdef KBDRAW_DEBUG
fa96951
       printf("points:%p\n", outline->points);
f57e3ee
@@ -211,7 +472,8 @@
fa96951
 #endif
fa96951
 
fa96951
       draw_rectangle (drawing, NULL, angle, origin_x, origin_y,
fa96951
-                      outline->points[0].x, outline->points[0].y);
fa96951
+                      outline->points[0].x, outline->points[0].y,
fa96951
+		      outline->corner_radius);
fa96951
     }
fa96951
   else if (outline->num_points == 2)
fa96951
     {
f57e3ee
@@ -223,19 +485,23 @@
fa96951
                          angle, &rotated_x0, &rotated_y0);
fa96951
       if (color)
fa96951
         draw_rectangle (drawing, color, angle, rotated_x0, rotated_y0,
fa96951
-                        outline->points[1].x, outline->points[1].y);
f57e3ee
+                        outline->points[1].x - outline->points[0].x, 
f57e3ee
+			outline->points[1].y - outline->points[0].y,
fa96951
+			outline->corner_radius);
fa96951
 
fa96951
       draw_rectangle (drawing, NULL, angle, rotated_x0, rotated_y0,
fa96951
-                      outline->points[1].x, outline->points[1].y);
f57e3ee
+		      outline->points[1].x - outline->points[0].x, 
f57e3ee
+		      outline->points[1].y - outline->points[0].y,
fa96951
+		      outline->corner_radius);
fa96951
     }
fa96951
   else
fa96951
     {
f57e3ee
       if (color)
f57e3ee
         draw_polygon (drawing, color, origin_x, origin_y, outline->points,
f57e3ee
-                      outline->num_points);
f57e3ee
+                      outline->num_points, outline->corner_radius);
f57e3ee
 
f57e3ee
       draw_polygon (drawing, NULL, origin_x, origin_y, outline->points,
f57e3ee
-                    outline->num_points);
f57e3ee
+                    outline->num_points, outline->corner_radius);
f57e3ee
     }
f57e3ee
 }
f57e3ee