From d98b963d75afa9d412ab56c9e2f1217cb9e1a699 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 10 Nov 2003 01:32:01 +0000 Subject: Add drop shadows. --- ChangeLog | 7 ++ Makefile | 2 +- xcompmgr.c | 318 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 308 insertions(+), 19 deletions(-) create mode 100644 ChangeLog diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..16ae2a2 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,7 @@ +2003-11-09 Keith Packard + + * Makefile: + * xcompmgr.c: (gaussian), (make_gaussian_map), (sum_gaussian), + (make_shadow), (shadow_picture), (win_extents), (paint_all), + (map_win), (unmap_win), (add_win), (configure_win), (main): + Add drop shadows. diff --git a/Makefile b/Makefile index ad7079a..f3c7dea 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -LIBS=`pkg-config --cflags --libs xcomposite xfixes xdamage xrender` +LIBS=`pkg-config --cflags --libs xcomposite xfixes xdamage xrender` -lm xcompmgr: xcompmgr.c $(CC) -o $@ $(CFLAGS) xcompmgr.c $(LIBS) diff --git a/xcompmgr.c b/xcompmgr.c index 8aa2c94..2640221 100644 --- a/xcompmgr.c +++ b/xcompmgr.c @@ -1,6 +1,8 @@ #include #include +#include #include +#include #include #include #include @@ -14,6 +16,12 @@ typedef struct _win { Damage damage; Picture picture; XserverRegion borderSize; + XserverRegion extents; + Picture shadow; + int shadow_dx; + int shadow_dy; + int shadow_width; + int shadow_height; /* for drawing translucent windows */ XserverRegion borderClip; @@ -32,6 +40,239 @@ XserverRegion allDamage; #define WINDOW_PLAIN 0 #define WINDOW_DROP 1 #define WINDOW_TRANS 2 +#define TRANS_OPACITY 0.75 +#define SHADOW_RADIUS 15 +#define SHADOW_OPACITY 0.75 +#define SHADOW_OFFSET_X (-SHADOW_RADIUS) +#define SHADOW_OFFSET_Y (-SHADOW_RADIUS) + + +double +gaussian (double r, double x, double y) +{ + return ((1 / (sqrt (2 * M_PI * r))) * + exp ((- (x * x + y * y)) / (2 * r * r))); +} + +typedef struct _conv { + int size; + double *data; +} conv; + +conv * +make_gaussian_map (Display *dpy, double r) +{ + conv *c; + int size = ((int) ceil ((r * 3)) + 1) & ~1; + int center = size / 2; + int x, y; + double t; + double g; + + c = malloc (sizeof (conv) + size * size * sizeof (double)); + c->size = size; + c->data = (double *) (c + 1); + for (y = 0; y < size; y++) + for (x = 0; x < size; x++) + { + g = gaussian (r, (double) (x - center), (double) (y - center)); + t += g; + c->data[y * size + x] = g; + } + printf ("gaussian total %f\n", t); + for (y = 0; y < size; y++) + for (x = 0; x < size; x++) + { + c->data[y*size + x] /= t; + } + return c; +} + +/* + * A picture will help + * + * -center 0 width width+center + * -center +-----+-------------------+-----+ + * | | | | + * | | | | + * 0 +-----+-------------------+-----+ + * | | | | + * | | | | + * | | | | + * height +-----+-------------------+-----+ + * | | | | + * height+ | | | | + * center +-----+-------------------+-----+ + */ + +unsigned int +sum_gaussian (conv *map, double opacity, int x, int y, int width, int height) +{ + int fx, fy; + int sx, sy; + double *g_data; + double *g_line = map->data; + int g_size = map->size; + int center = g_size / 2; + int fx_start, fx_end; + int fy_start, fy_end; + double v; + + /* + * Compute set of filter values which are "in range", + * that's the set with: + * 0 <= x + (fx-center) && x + (fx-center) < width && + * 0 <= y + (fy-center) && y + (fy-center) < height + * + * 0 <= x + (fx - center) x + fx - center < width + * center - x <= fx fx < width + center - x + */ + + fx_start = center - x; + if (fx_start < 0) + fx_start = 0; + fx_end = width + center - x; + if (fx_end > g_size) + fx_end = g_size; + + fy_start = center - y; + if (fy_start < 0) + fy_start = 0; + fy_end = height + center - y; + if (fy_end > g_size) + fy_end = g_size; + + g_line = g_line + fy_start * g_size + fx_start; + + v = 0; + for (fy = fy_start; fy < fy_end; fy++) + { + g_data = g_line; + g_line += g_size; + + for (fx = fx_start; fx < fx_end; fx++) + v += *g_data++; + } + if (v > 1) + v = 1; + + return ((unsigned int) (v * opacity * 255.0)) << 24; +} + +XImage * +make_shadow (Display *dpy, double opacity, double r, int width, int height) +{ + conv *map = make_gaussian_map (dpy, r); + XImage *ximage; + double *gdata = map->data; + unsigned int *data; + int gsize = map->size; + int ylimit, xlimit; + int swidth = width + gsize; + int sheight = height + gsize; + int center = gsize / 2; + int x, y; + int fx, fy; + int sx, sy; + unsigned int d; + double v; + unsigned char c; + + data = malloc (swidth * sheight * sizeof (int)); + ximage = XCreateImage (dpy, + DefaultVisual(dpy, DefaultScreen(dpy)), + 32, + ZPixmap, + 0, + (char *) data, + swidth, sheight, 32, swidth * sizeof (int)); + /* + * Build the gaussian in sections + */ + + /* + * corners + */ + ylimit = gsize; + if (ylimit > sheight / 2) + ylimit = (sheight + 1) / 2; + xlimit = gsize; + if (xlimit > swidth / 2) + xlimit = (swidth + 1) / 2; + + for (y = 0; y < ylimit; y++) + for (x = 0; x < xlimit; x++) + { + d = sum_gaussian (map, opacity, x - center, y - center, width, height); + data[y * swidth + x] = d; + data[(sheight - y - 1) * swidth + x] = d; + data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d; + data[y * swidth + (swidth - x - 1)] = d; + } + + /* + * top/bottom + */ + for (y = 0; y < ylimit; y++) + { + d = sum_gaussian (map, opacity, center, y - center, width, height); + for (x = gsize; x < swidth - gsize; x++) + { + data[y * swidth + x] = d; + data[(sheight - y - 1) * swidth + x] = d; + } + } + + /* + * sides + */ + + for (x = 0; x < xlimit; x++) + { + d = sum_gaussian (map, opacity, x - center, center, width, height); + for (y = gsize; y < sheight - gsize; y++) + { + data[y * swidth + x] = d; + data[y * swidth + (swidth - x - 1)] = d; + } + } + + /* + * center + */ + + d = sum_gaussian (map, opacity, center, center, width, height); + for (y = ylimit; y < sheight - ylimit; y++) + for (x = xlimit; x < swidth - xlimit; x++) + data[y * swidth + x] = d; + + free (map); + return ximage; +} + +Picture +shadow_picture (Display *dpy, double opacity, double r, int width, int height, int *wp, int *hp) +{ + XImage *shadowImage = make_shadow (dpy, opacity, r, width, height); + Pixmap shadowPixmap = XCreatePixmap (dpy, root, + shadowImage->width, + shadowImage->height, + 32); + Picture shadowPicture = XRenderCreatePicture (dpy, shadowPixmap, + XRenderFindStandardFormat (dpy, PictStandardARGB32), + 0, 0); + GC gc = XCreateGC (dpy, shadowPixmap, 0, 0); + + XPutImage (dpy, shadowPixmap, gc, shadowImage, 0, 0, 0, 0, + shadowImage->width, + shadowImage->height); + *wp = shadowImage->width; + *hp = shadowImage->height; + XFreeGC (dpy, gc); + XDestroyImage (shadowImage); + XFreePixmap (dpy, shadowPixmap); + return shadowPicture; +} win * find_win (Display *dpy, Window id) @@ -55,6 +296,29 @@ paint_root (Display *dpy) 0, 0, 32767, 32767); } +XserverRegion +win_extents (Display *dpy, win *w) +{ + XRectangle r; + + if (!w->shadow) + { + double opacity = SHADOW_OPACITY; + if (w->mode == WINDOW_TRANS) + opacity = opacity * TRANS_OPACITY; + w->shadow = shadow_picture (dpy, opacity, SHADOW_RADIUS, + w->a.width, w->a.height, + &w->shadow_width, &w->shadow_height); + w->shadow_dx = SHADOW_OFFSET_X; + w->shadow_dy = SHADOW_OFFSET_Y; + } + r.x = w->a.x + w->a.border_width + w->shadow_dx; + r.y = w->a.y + w->a.border_width + w->shadow_dy; + r.width = w->shadow_width; + r.height = w->shadow_height; + return XFixesCreateRegion (dpy, &r, 1); +} + XserverRegion border_size (Display *dpy, win *w) { @@ -77,19 +341,15 @@ paint_all (Display *dpy, XserverRegion region) if (w->a.map_state != IsViewable) continue; - if (w->mode == WINDOW_TRANS) - { - w->borderClip = XFixesCreateRegion (dpy, 0, 0); - XFixesUnionRegion (dpy, w->borderClip, region, 0, 0, None, 0, 0); - w->prev_trans = t; - t = w; - } - else + if (w->borderSize) + XFixesDestroyRegion (dpy, w->borderSize); + w->borderSize = border_size (dpy, w); + if (w->extents) + XFixesDestroyRegion (dpy, w->extents); + w->extents = win_extents (dpy, w); + if (w->mode != WINDOW_TRANS) { XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, region); - if (w->borderSize) - XFixesDestroyRegion (dpy, w->borderSize); - w->borderSize = border_size (dpy, w); XFixesSubtractRegion (dpy, region, region, 0, 0, w->borderSize, 0, 0); XRenderComposite (dpy, PictOpSrc, w->picture, None, rootPicture, 0, 0, 0, 0, @@ -98,13 +358,26 @@ paint_all (Display *dpy, XserverRegion region) w->a.width, w->a.height); } + w->borderClip = XFixesCreateRegion (dpy, 0, 0); + XFixesUnionRegion (dpy, w->borderClip, region, 0, 0, None, 0, 0); + w->prev_trans = t; + t = w; } XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, region); paint_root (dpy); for (w = t; w; w = w->prev_trans) { XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, w->borderClip); - XRenderComposite (dpy, PictOpOver, w->picture, transPicture, rootPicture, + if (w->shadow) + { + XRenderComposite (dpy, PictOpOver, w->shadow, None, rootPicture, + 0, 0, 0, 0, + w->a.x + w->a.border_width + w->shadow_dx, + w->a.y + w->a.border_width + w->shadow_dy, + w->shadow_width, w->shadow_height); + } + if (w->mode == WINDOW_TRANS) + XRenderComposite (dpy, PictOpOver, w->picture, transPicture, rootPicture, 0, 0, 0, 0, w->a.x + w->a.border_width, w->a.y + w->a.border_width, @@ -154,7 +427,7 @@ map_win (Display *dpy, Window id) return; w->a.map_state = IsViewable; w->damage = XDamageCreate (dpy, id, XDamageReportNonEmpty); - region = border_size (dpy, w); + region = win_extents (dpy, w); add_damage (dpy, region); } @@ -171,10 +444,10 @@ unmap_win (Display *dpy, Window id) XDamageDestroy (dpy, w->damage); w->damage = None; } - if (w->borderSize != None) + if (w->extents != None) { - add_damage (dpy, w->borderSize); /* destroys region */ - w->borderSize = None; + add_damage (dpy, w->extents); /* destroys region */ + w->extents = None; } } @@ -211,7 +484,9 @@ add_win (Display *dpy, Window id, Window prev) CPSubwindowMode, &pa); + new->shadow = None; new->borderSize = None; + new->extents = None; if (new->a.override_redirect) new->mode = WINDOW_TRANS; else @@ -234,11 +509,17 @@ configure_win (Display *dpy, XConfigureEvent *ce) if (w->a.map_state == IsViewable) { damage = XFixesCreateRegion (dpy, 0, 0); - if (w->borderSize != None) - XFixesUnionRegion (dpy, damage, w->borderSize, 0, 0, None, 0, 0); + if (w->extents != None) + XFixesUnionRegion (dpy, damage, w->extents, 0, 0, None, 0, 0); } w->a.x = ce->x; w->a.y = ce->y; + if (w->a.width != ce->width || w->a.height != ce->height) + if (w->shadow) + { + XRenderFreePicture (dpy, w->shadow); + w->shadow = None; + } w->a.width = ce->width; w->a.height = ce->height; w->a.border_width = ce->border_width; @@ -345,6 +626,7 @@ main () XRenderPictureAttributes pa; XRenderColor c; XRectangle *expose_rects = 0; + GC gc; int size_expose = 0; int n_expose = 0; -- cgit v1.2.3