From 8a78b5283dd40bc38d2c1065f290a68a9c0d65bf Mon Sep 17 00:00:00 2001 From: Dylan Simon Date: Sun, 27 Sep 2009 14:44:35 -0400 Subject: Add xrender support Optionally draw all components (except shape) with xrender. Enabled by default. Xlib rendering can be restored by "configure --without-xrender" or "xeyes +render". Change-Id: Ib63621e450e6f75ef76a160634ae2186a7db9456 Signed-off-by: Dylan Simon Signed-off-by: James Cloos --- Eyes.c | 275 ++++++++++++++++++++++++++++++++++++++++++----------------- Eyes.h | 13 +++ EyesP.h | 17 ++-- configure.ac | 9 ++ transform.c | 31 +++---- transform.h | 5 +- xeyes.c | 12 +++ xeyes.man | 9 +- 8 files changed, 261 insertions(+), 110 deletions(-) diff --git a/Eyes.c b/Eyes.c index 3965833..1bb36db 100644 --- a/Eyes.c +++ b/Eyes.c @@ -36,6 +36,10 @@ from the X Consortium. * a widget which follows the mouse around */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + # include # include # include @@ -44,6 +48,8 @@ from the X Consortium. # include "EyesP.h" # include # include +# include +# include #if (defined(SVR4) || defined(SYSV) && defined(i386)) extern double hypot(double, double); @@ -58,17 +64,21 @@ static XtResource resources[] = { {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension), goffset(height), XtRImmediate, (XtPointer) 100}, {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), - offset(puppixel), XtRString, XtDefaultForeground}, + offset(pixel[PART_PUPIL]), XtRString, XtDefaultForeground}, {XtNoutline, XtCForeground, XtRPixel, sizeof(Pixel), - offset(outline), XtRString, XtDefaultForeground}, + offset(pixel[PART_OUTLINE]), XtRString, XtDefaultForeground}, {XtNcenterColor, XtCBackground, XtRPixel, sizeof (Pixel), - offset(center), XtRString, XtDefaultBackground}, + offset(pixel[PART_CENTER]), XtRString, XtDefaultBackground}, {XtNreverseVideo, XtCReverseVideo, XtRBoolean, sizeof (Boolean), offset (reverse_video), XtRImmediate, (XtPointer) FALSE}, {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int), offset (backing_store), XtRString, "default"}, {XtNshapeWindow, XtCShapeWindow, XtRBoolean, sizeof (Boolean), offset (shape_window), XtRImmediate, (XtPointer) TRUE}, +#ifdef XRENDER + {XtNrender, XtCBoolean, XtRBoolean, sizeof(Boolean), + offset(render), XtRImmediate, (XtPointer) TRUE }, +#endif }; #undef offset @@ -91,6 +101,7 @@ static XtResource resources[] = { # define W_MIN_Y (-1.0 + EYE_OFFSET) # define W_MAX_Y (1.0 - EYE_OFFSET) +# define TPOINT_NONE (-1000) /* special value meaning "not yet set" */ # define TPointEqual(a, b) ((a).x == (b).x && (a).y == (b).y) # define XPointEqual(a, b) ((a).x == (b).x && (a).y == (b).y) @@ -115,6 +126,9 @@ static void Initialize ( XtGCMask valuemask; XGCValues myXGCV; int shape_event_base, shape_error_base; +#ifdef XRENDER + enum EyesPart i; +#endif /* * set the colors if reverse video; these are the colors used: @@ -127,72 +141,153 @@ static void Initialize ( * border. Sigh. */ if (w->eyes.reverse_video) { - Pixel fg = w->eyes.puppixel; + Pixel fg = w->eyes.pixel[PART_PUPIL]; Pixel bg = w->core.background_pixel; if (w->core.border_pixel == fg) w->core.border_pixel = bg; - if (w->eyes.outline == fg) - w->eyes.outline = bg; - if (w->eyes.center == bg) - w->eyes.center = fg; - w->eyes.puppixel = bg; + if (w->eyes.pixel[PART_OUTLINE] == fg) + w->eyes.pixel[PART_OUTLINE] = bg; + if (w->eyes.pixel[PART_CENTER] == bg) + w->eyes.pixel[PART_CENTER] = fg; + w->eyes.pixel[PART_PUPIL] = bg; w->core.background_pixel = fg; } - myXGCV.foreground = w->eyes.puppixel; + myXGCV.foreground = w->eyes.pixel[PART_PUPIL]; myXGCV.background = w->core.background_pixel; valuemask = GCForeground | GCBackground; - w->eyes.pupGC = XtGetGC(gnew, valuemask, &myXGCV); + w->eyes.gc[PART_PUPIL] = XtGetGC(gnew, valuemask, &myXGCV); - myXGCV.foreground = w->eyes.outline; + myXGCV.foreground = w->eyes.pixel[PART_OUTLINE]; valuemask = GCForeground | GCBackground; - w->eyes.outGC = XtGetGC(gnew, valuemask, &myXGCV); + w->eyes.gc[PART_OUTLINE] = XtGetGC(gnew, valuemask, &myXGCV); - myXGCV.foreground = w->eyes.center; - myXGCV.background = w->eyes.puppixel; + myXGCV.foreground = w->eyes.pixel[PART_CENTER]; + myXGCV.background = w->eyes.pixel[PART_PUPIL]; valuemask = GCForeground | GCBackground; - w->eyes.centerGC = XtGetGC(gnew, valuemask, &myXGCV); + w->eyes.gc[PART_CENTER] = XtGetGC(gnew, valuemask, &myXGCV); w->eyes.update = 0; /* wait for Realize to add the timeout */ w->eyes.interval_id = 0; - w->eyes.pupil[0].x = w->eyes.pupil[1].x = -1000; - w->eyes.pupil[0].y = w->eyes.pupil[1].y = -1000; + w->eyes.pupil[0].x = w->eyes.pupil[1].x = TPOINT_NONE; + w->eyes.pupil[0].y = w->eyes.pupil[1].y = TPOINT_NONE; - w->eyes.mouse.x = w->eyes.mouse.y = -1000; + w->eyes.mouse.x = w->eyes.mouse.y = TPOINT_NONE; if (w->eyes.shape_window && !XShapeQueryExtension (XtDisplay (w), &shape_event_base, &shape_error_base)) w->eyes.shape_window = False; w->eyes.shape_mask = 0; - w->eyes.shapeGC = NULL; + w->eyes.gc[PART_SHAPE] = NULL; + +#ifdef XRENDER + for (i = 0; i < PART_SHAPE; i ++) { + XColor c; + XRenderColor rc; + + c.pixel = w->eyes.pixel[i]; + XQueryColor(XtDisplay (w), w->core.colormap, &c); + + rc.red = c.red; + rc.green = c.green; + rc.blue = c.blue; + rc.alpha = -1; + w->eyes.fill[i] = XRenderCreateSolidFill(XtDisplay (w), &rc); + } +#endif } -static void eyeLiner ( - EyesWidget w, - Drawable d, - GC outgc, - GC centergc, - int num) +static void +drawEllipse(EyesWidget w, enum EyesPart part, + double centerx, double centery, double width, double height) { - Display *dpy = XtDisplay(w); - - TFillArc (dpy, d, outgc, &w->eyes.t, - EYE_X(num) - EYE_HWIDTH - EYE_THICK, - EYE_Y(num) - EYE_HHEIGHT - EYE_THICK, - EYE_WIDTH + EYE_THICK * 2.0, - EYE_HEIGHT + EYE_THICK * 2.0, - 90 * 64, 360 * 64); - if (centergc) { - TFillArc (dpy, d, centergc, &w->eyes.t, - EYE_X(num) - EYE_HWIDTH, - EYE_Y(num) - EYE_HHEIGHT, - EYE_WIDTH, EYE_HEIGHT, - 90 * 64, 360 * 64); + const TRectangle tpos = { + centerx - width/2.0, + centery - height/2.0, + width, height }; + TRectangle pos; + Trectangle(&w->eyes.t, &tpos, &pos); + + if (part == PART_CLEAR) { + XFillRectangle(XtDisplay(w), XtWindow(w), + w->eyes.gc[PART_CENTER], + (int)pos.x, (int)pos.y, + (int)pos.width+2, (int)pos.height+2); + return; + } +#ifdef XRENDER + if (w->eyes.render && part != PART_SHAPE && (!w->eyes.shape_window || + part != PART_OUTLINE) && + w->eyes.picture) { + int n, i; + double hd, c, s, sx, sy, x, y, px, py; + XPointDouble *p; + + pos.x = pos.x + pos.width/2.0; + pos.y = pos.y + pos.height/2.0; + + /* determine number of segments to draw */ + hd = hypot(pos.width, pos.height)/2; + n = (M_PI / acos(hd/(hd+1.0))) + 0.5; + if (n < 2) n = 2; + + c = cos(M_PI/n); + s = sin(M_PI/n); + sx = -(pos.width*s)/pos.height; + sy = (pos.height*s)/pos.width; + + n *= 2; + p = Xmalloc(sizeof(*p)*n); + if (!p) + return; + x = 0; + y = pos.height/2.0; + for (i = 0; i < n; i ++) + { + p[i].x = x + pos.x; + p[i].y = y + pos.y; + px = x; + py = y; + x = c*px + sx*py; + y = c*py + sy*px; } + + XRenderCompositeDoublePoly(XtDisplay(w), PictOpOver, + w->eyes.fill[part], w->eyes.picture, + XRenderFindStandardFormat(XtDisplay(w), + PictStandardA8), + 0, 0, 0, 0, p, n, 0); + + Xfree(p); + return; + } +#endif + XFillArc(XtDisplay(w), + part == PART_SHAPE ? w->eyes.shape_mask : XtWindow(w), + w->eyes.gc[part], + (int)(pos.x + 0.5), (int)(pos.y + 0.5), + (int)(pos.width + 0.0), (int)(pos.height + 0.0), + 90*64, 360*64); +} + + +static void +eyeLiner(EyesWidget w, + Boolean draw, + int num) +{ + drawEllipse(w, draw ? PART_OUTLINE : PART_SHAPE, + EYE_X(num), EYE_Y(num), + EYE_WIDTH + 2.0*EYE_THICK, + EYE_HEIGHT + 2.0*EYE_THICK); + if (draw) { + drawEllipse(w, PART_CENTER, EYE_X(num), EYE_Y(num), + EYE_WIDTH, EYE_HEIGHT); + } } static TPoint computePupil ( @@ -242,29 +337,24 @@ static void computePupils ( pupils[1] = computePupil (1, mouse); } -static void eyeBall ( - EyesWidget w, - GC gc, - int num) +static void +eyeBall(EyesWidget w, + Boolean draw, + int num) { - Display *dpy = XtDisplay(w); - Window win = XtWindow(w); - - TFillArc (dpy, win, gc, &w->eyes.t, - w->eyes.pupil[num].x - BALL_WIDTH / 2.0, - w->eyes.pupil[num].y - BALL_HEIGHT / 2.0, - BALL_WIDTH, BALL_HEIGHT, - 90 * 64, 360 * 64); + drawEllipse(w, draw ? PART_PUPIL : PART_CLEAR, + w->eyes.pupil[num].x, w->eyes.pupil[num].y, + BALL_WIDTH, BALL_HEIGHT); } static void repaint_window (EyesWidget w) { if (XtIsRealized ((Widget) w)) { - eyeLiner (w, XtWindow (w), w->eyes.outGC, w->eyes.centerGC, 0); - eyeLiner (w, XtWindow (w), w->eyes.outGC, w->eyes.centerGC, 1); + eyeLiner (w, TRUE, 0); + eyeLiner (w, TRUE, 1); computePupils (w->eyes.mouse, w->eyes.pupil); - eyeBall (w, w->eyes.pupGC, 0); - eyeBall (w, w->eyes.pupGC, 1); + eyeBall (w, TRUE, 0); + eyeBall (w, TRUE, 1); } } @@ -280,10 +370,11 @@ static void draw_eye(EyesWidget w, TPoint mouse, int eye1, int eye2) xpupil.x = Xx(newpupil[0].x, newpupil[0].y, &w->eyes.t); xpupil.y = Xy(newpupil[0].x, newpupil[0].y, &w->eyes.t); if (!XPointEqual (xpupil, xnewpupil)) { - if (w->eyes.pupil[0].x != -1000 || w->eyes.pupil[0].y != -1000) - eyeBall (w, w->eyes.centerGC, eye1); + if (w->eyes.pupil[0].x != TPOINT_NONE || + w->eyes.pupil[0].y != TPOINT_NONE) + eyeBall (w, FALSE, eye1); w->eyes.pupil[0] = newpupil[0]; - eyeBall (w, w->eyes.pupGC, eye1); + eyeBall (w, TRUE, eye1); } w->eyes.mouse = mouse; @@ -298,10 +389,11 @@ static void draw_eye(EyesWidget w, TPoint mouse, int eye1, int eye2) xpupil.x = Xx(newpupil[1].x, newpupil[1].y, &w->eyes.t); xpupil.y = Xy(newpupil[1].x, newpupil[1].y, &w->eyes.t); if (!XPointEqual (xpupil, xnewpupil)) { - if (w->eyes.pupil[1].x != -1 || w->eyes.pupil[1].y != -1) - eyeBall (w, w->eyes.centerGC, eye2); + if (w->eyes.pupil[1].x != TPOINT_NONE || + w->eyes.pupil[1].y != TPOINT_NONE) + eyeBall (w, FALSE, eye2); w->eyes.pupil[1] = newpupil[1]; - eyeBall (w, w->eyes.pupGC, eye2); + eyeBall (w, TRUE, eye2); } } else { if (delays[w->eyes.update + 1] != 0) @@ -347,27 +439,35 @@ static void Resize (Widget gw) EyesWidget w = (EyesWidget) gw; XGCValues xgcv; Widget parent; + Display *dpy = XtDisplay (w); int x, y; if (XtIsRealized (gw)) { - XClearWindow (XtDisplay (w), XtWindow (w)); + XClearWindow (dpy, XtWindow (w)); SetTransform (&w->eyes.t, 0, w->core.width, w->core.height, 0, W_MIN_X, W_MAX_X, W_MIN_Y, W_MAX_Y); +#ifdef XRENDER + if (w->eyes.picture) { + XRenderFreePicture(dpy, w->eyes.picture); + w->eyes.picture = 0; + } +#endif if (w->eyes.shape_window) { - w->eyes.shape_mask = XCreatePixmap (XtDisplay (w), XtWindow (w), + w->eyes.shape_mask = XCreatePixmap (dpy, XtWindow (w), w->core.width, w->core.height, 1); - if (!w->eyes.shapeGC) - w->eyes.shapeGC = XCreateGC (XtDisplay (w), w->eyes.shape_mask, 0, &xgcv); - XSetForeground (XtDisplay (w), w->eyes.shapeGC, 0); - XFillRectangle (XtDisplay (w), w->eyes.shape_mask, w->eyes.shapeGC, 0, 0, - w->core.width, w->core.height); - XSetForeground (XtDisplay (w), w->eyes.shapeGC, 1); - eyeLiner (w, w->eyes.shape_mask, w->eyes.shapeGC, (GC) 0, 0); - eyeLiner (w, w->eyes.shape_mask, w->eyes.shapeGC, (GC) 0, 1); + if (!w->eyes.gc[PART_SHAPE]) + w->eyes.gc[PART_SHAPE] = XCreateGC (dpy, w->eyes.shape_mask, + 0, &xgcv); + XSetForeground (dpy, w->eyes.gc[PART_SHAPE], 0); + XFillRectangle (dpy, w->eyes.shape_mask, w->eyes.gc[PART_SHAPE], + 0, 0, w->core.width, w->core.height); + XSetForeground (dpy, w->eyes.gc[PART_SHAPE], 1); + eyeLiner (w, FALSE, 0); + eyeLiner (w, FALSE, 1); x = y = 0; for (parent = (Widget) w; XtParent (parent); parent = XtParent (parent)) { x += parent->core.x + parent->core.border_width; @@ -375,8 +475,19 @@ static void Resize (Widget gw) } XShapeCombineMask (XtDisplay (parent), XtWindow (parent), ShapeBounding, x, y, w->eyes.shape_mask, ShapeSet); - XFreePixmap (XtDisplay (w), w->eyes.shape_mask); + XFreePixmap (dpy, w->eyes.shape_mask); } +#ifdef XRENDER + if (w->eyes.render) { + XRenderPictureAttributes pa; + XRenderPictFormat *pf; + pf = XRenderFindVisualFormat(dpy, + DefaultVisualOfScreen(w->core.screen)); + if (pf) + w->eyes.picture = XRenderCreatePicture(dpy, XtWindow (w), + pf, 0, &pa); + } +#endif } } @@ -402,12 +513,16 @@ static void Realize ( static void Destroy (Widget gw) { EyesWidget w = (EyesWidget)gw; + int i; if (w->eyes.interval_id) XtRemoveTimeOut (w->eyes.interval_id); - XtReleaseGC(gw, w->eyes.pupGC); - XtReleaseGC(gw, w->eyes.outGC); - XtReleaseGC(gw, w->eyes.centerGC); + for (i = 0; i < PART_MAX; i ++) + XtReleaseGC(gw, w->eyes.gc[i]); +#ifdef XRENDER + if (w->eyes.picture) + XRenderFreePicture (XtDisplay(w), w->eyes.picture); +#endif } /* ARGSUSED */ @@ -419,10 +534,10 @@ static void Redisplay( EyesWidget w; w = (EyesWidget) gw; - w->eyes.pupil[0].x = -1000; - w->eyes.pupil[0].y = -1000; - w->eyes.pupil[1].x = -1000; - w->eyes.pupil[1].y = -1000; + w->eyes.pupil[0].x = TPOINT_NONE; + w->eyes.pupil[0].y = TPOINT_NONE; + w->eyes.pupil[1].x = TPOINT_NONE; + w->eyes.pupil[1].y = TPOINT_NONE; (void) repaint_window ((EyesWidget)gw); } diff --git a/Eyes.h b/Eyes.h index 239a127..d9893a3 100644 --- a/Eyes.h +++ b/Eyes.h @@ -35,6 +35,19 @@ #define XtNshapeWindow "shapeWindow" #define XtCShapeWindow "ShapeWindow" +#define XtNrender "render" + +enum EyesPart { + PART_CLEAR = -1, + + PART_OUTLINE, + PART_CENTER, + PART_PUPIL, + + PART_SHAPE, + PART_MAX +}; + typedef struct _EyesRec *EyesWidget; /* completely defined in EyesPrivate.h */ typedef struct _EyesClassRec *EyesWidgetClass; /* completely defined in EyesPrivate.h */ diff --git a/EyesP.h b/EyesP.h index 7dea77a..1cffdb4 100644 --- a/EyesP.h +++ b/EyesP.h @@ -7,19 +7,17 @@ #include "Eyes.h" #include +#ifdef XRENDER +#include +#endif #include "transform.h" #define SEG_BUFF_SIZE 128 /* New fields for the eyes widget instance record */ typedef struct { - Pixel puppixel; /* foreground pixel */ - Pixel outline; /* outline pixel */ - Pixel center; /* inside pixel */ - GC outGC; /* pointer to GraphicsContext */ - GC pupGC; /* pointer to GraphicsContext */ - GC centerGC; /* pointer to GraphicsContext */ - GC shapeGC; /* pointer to GraphicsContext */ + Pixel pixel[PART_SHAPE]; + GC gc[PART_MAX]; /* start of graph stuff */ int backing_store; /* backing store variety */ Boolean reverse_video; /* swap fg and bg pixels */ @@ -31,6 +29,11 @@ typedef struct { Transform maskt; XtIntervalId interval_id; Pixmap shape_mask; /* window shape */ +#ifdef XRENDER + Boolean render; + Picture picture; + Picture fill[PART_SHAPE]; +#endif } EyesPart; /* Full instance record declaration */ diff --git a/configure.ac b/configure.ac index 188d2ca..d1fb5a5 100644 --- a/configure.ac +++ b/configure.ac @@ -43,6 +43,15 @@ XEYES_CFLAGS="$CWARNFLAGS $XEYES_CFLAGS" AC_SUBST(XEYES_CFLAGS) AC_SUBST(XEYES_LIBS) +dnl Optional dependencies +AC_ARG_WITH(xrender, AC_HELP_STRING([--with-xrender],[Use Xrender for rendering (Default is YES)]),use_xrender="$withval",use_xrender="try") +if test x$use_xrender != xno ; then + PKG_CHECK_MODULES(XRENDER, [xrender >= 0.4]) + XEYES_CFLAGS="$XEYES_CFLAGS $XRENDER_CFLAGS" + XEYES_LIBS="$XEYES_LIBS $XRENDER_LIBS" + AC_DEFINE([XRENDER],1,[Define to use X Render Extension]) +fi + XORG_MANPAGE_SECTIONS XORG_RELEASE_VERSION XORG_CHANGELOG diff --git a/transform.c b/transform.c index 0f02498..5f63516 100644 --- a/transform.c +++ b/transform.c @@ -83,25 +83,20 @@ TDrawArc ( #endif void -TFillArc (Display *dpy, Drawable d, GC gc, Transform *t, - double x, double y, double width, double height, - int angle1, int angle2) +Trectangle(const Transform *t, const TRectangle *i, TRectangle *o) { - int xx, xy, xw, xh; - - xx = Xx(x,y,t); - xy = Xy(x,y,t); - xw = Xwidth (width, height, t); - xh = Xheight (width, height, t); - if (xw < 0) { - xx += xw; - xw = -xw; - } - if (xh < 0) { - xy += xh; - xh = -xh; - } - XFillArc (dpy, d, gc, xx, xy, xw, xh, angle1, angle2); + o->x = t->mx * i->x + t->bx; + o->y = t->my * i->y + t->by; + o->width = t->mx * i->width; + o->height = t->my * i->height; + if (o->width < 0) { + o->x += o->width; + o->width = -o->width; + } + if (o->height < 0) { + o->y += o->height; + o->height = -o->height; + } } void diff --git a/transform.h b/transform.h index 5bd5182..7567fcc 100644 --- a/transform.h +++ b/transform.h @@ -26,10 +26,7 @@ typedef struct _TRectangle { # define Twidth(w,h,t) (((double) (w)) / (t)->mx) # define Theight(w,h,t) (((double) (h)) / (t)->my) -extern void TFillArc (Display *dpy, Drawable d, GC gc, - Transform *t, - double x, double y, double width, double height, - int angle1, int angle2); +extern void Trectangle (const Transform *t, const TRectangle *in, TRectangle *out); extern void SetTransform (Transform *t, int xx1, int xx2, int xy1, int xy2, double tx1, double tx2, double ty1, double ty2); diff --git a/xeyes.c b/xeyes.c index 24b36b0..1bca7ab 100644 --- a/xeyes.c +++ b/xeyes.c @@ -30,6 +30,10 @@ from the X Consortium. */ /* $XFree86: xc/programs/xeyes/xeyes.c,v 1.3 2000/02/17 14:00:35 dawes Exp $ */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include #include @@ -54,6 +58,10 @@ usage(void) fprintf(stderr, "\n"); fprintf(stderr, " [-outline {color}] [-center {color}] [-backing {backing-store}]\n"); +#ifdef XRENDER + fprintf(stderr, +" [-render | +render]\n"); +#endif exit(1); } @@ -66,6 +74,10 @@ static XrmOptionDescRec options[] = { {"-backing", "*eyes.backingStore", XrmoptionSepArg, NULL}, {"-shape", "*eyes.shapeWindow", XrmoptionNoArg, "TRUE"}, {"+shape", "*eyes.shapeWindow", XrmoptionNoArg, "FALSE"}, +#ifdef XRENDER +{"-render", "*eyes.render", XrmoptionNoArg, "TRUE"}, +{"+render", "*eyes.render", XrmoptionNoArg, "FALSE"}, +#endif }; static Atom wm_delete_window; diff --git a/xeyes.man b/xeyes.man index 0d74d7e..4484d3d 100644 --- a/xeyes.man +++ b/xeyes.man @@ -44,7 +44,14 @@ choose a different width for the window border. uses the SHAPE extension to shape the window. This is the default. .TP 8 .B \+shape -Disables uses the SHAPE extension to shape the window. +disables use of the SHAPE extension to shape the window. +.TP 8 +.B \-render +uses Xrender to draw anti-aliased eyes. +This is the default if \fIxeyes\fP has been compiled with Xrender support. +.TP 8 +.B \+render +disables Xrender and draws traditional eyes. .SH "SEE ALSO" X(__miscmansuffix__), X Toolkit documentation .br -- cgit v1.2.3