/** Create a scaled icon. */ ScaledIconNode *CreateScaledRenderIcon(IconNode *icon, int width, int height) { ScaledIconNode *result = NULL; #ifdef USE_XRENDER XRenderPictFormat *fp; XColor color; GC maskGC; XImage *destImage; XImage *destMask; unsigned long alpha; int index, yindex; int x, y; int imageLine; int maskLine; Assert(icon); if(!haveRender || !icon->useRender) { return NULL; } result = Allocate(sizeof(ScaledIconNode)); result->next = icon->nodes; icon->nodes = result; result->width = width; result->height = height; width = icon->image->width; height = icon->image->height; result->mask = JXCreatePixmap(display, rootWindow, width, height, 8); maskGC = JXCreateGC(display, result->mask, 0, NULL); result->image = JXCreatePixmap(display, rootWindow, width, height, rootDepth); destImage = JXCreateImage(display, rootVisual, rootDepth, ZPixmap, 0, NULL, width, height, 8, 0); destImage->data = Allocate(sizeof(unsigned long) * width * height); destMask = JXCreateImage(display, rootVisual, 8, ZPixmap, 0, NULL, width, height, 8, 0); destMask->data = Allocate(width * height); imageLine = 0; maskLine = 0; for(y = 0; y < height; y++) { yindex = y * icon->image->width; for(x = 0; x < width; x++) { index = 4 * (yindex + x); alpha = icon->image->data[index]; color.red = icon->image->data[index + 1]; color.red |= color.red << 8; color.green = icon->image->data[index + 2]; color.green |= color.green << 8; color.blue = icon->image->data[index + 3]; color.blue |= color.blue << 8; color.red = (color.red * alpha) >> 8; color.green = (color.green * alpha) >> 8; color.blue = (color.blue * alpha) >> 8; GetColor(&color); XPutPixel(destImage, x, y, color.pixel); destMask->data[maskLine + x] = alpha; } imageLine += destImage->bytes_per_line; maskLine += destMask->bytes_per_line; } /* Render the image data to the image pixmap. */ JXPutImage(display, result->image, rootGC, destImage, 0, 0, 0, 0, width, height); Release(destImage->data); destImage->data = NULL; JXDestroyImage(destImage); /* Render the alpha data to the mask pixmap. */ JXPutImage(display, result->mask, maskGC, destMask, 0, 0, 0, 0, width, height); Release(destMask->data); destMask->data = NULL; JXDestroyImage(destMask); JXFreeGC(display, maskGC); /* Create the alpha picture. */ fp = JXRenderFindStandardFormat(display, PictStandardA8); Assert(fp); result->alphaPicture = JXRenderCreatePicture(display, result->mask, fp, 0, NULL); /* Create the render picture. */ fp = JXRenderFindVisualFormat(display, rootVisual); Assert(fp); result->imagePicture = JXRenderCreatePicture(display, result->image, fp, 0, NULL); /* Free unneeded pixmaps. */ JXFreePixmap(display, result->image); result->image = None; JXFreePixmap(display, result->mask); result->mask = None; #endif return result; }
/** Get a scaled icon. */ ScaledIconNode *GetScaledIcon(IconNode *icon, long fg, int rwidth, int rheight) { XColor color; XImage *image; ScaledIconNode *np; GC maskGC; int x, y; int scalex, scaley; /* Fixed point. */ int srcx, srcy; /* Fixed point. */ int ratio; /* Fixed point. */ int nwidth, nheight; unsigned char *data; Assert(icon); Assert(icon->image); if(rwidth == 0) { rwidth = icon->image->width; } if(rheight == 0) { rheight = icon->image->height; } ratio = (icon->image->width << 16) / icon->image->height; nwidth = Min(rwidth, (rheight * ratio) >> 16); nheight = Min(rheight, (nwidth << 16) / ratio); nwidth = (nheight * ratio) >> 16; if(nwidth < 1) { nwidth = 1; } if(nheight < 1) { nheight = 1; } /* Check if this size already exists. * Note that XRender scales on the fly. */ for(np = icon->nodes; np; np = np->next) { #ifdef USE_XRENDER if(np->imagePicture != None) { np->width = nwidth; np->height = nheight; return np; } #endif if(np->width == nwidth && np->height == nheight) { if(!icon->image->bitmap || np->fg == fg) { return np; } } } /* See if we can use XRender to create the icon. */ #ifdef USE_XRENDER if(haveRender) { np = CreateScaledRenderIcon(icon, fg, nwidth, nheight); /* Don't keep the image data around after creating the icon. */ Release(icon->image->data); icon->image->data = NULL; return np; } #endif /* Create a new ScaledIconNode the old-fashioned way. */ np = Allocate(sizeof(ScaledIconNode)); np->fg = fg; np->width = nwidth; np->height = nheight; np->next = icon->nodes; #ifdef USE_XRENDER np->imagePicture = None; #endif icon->nodes = np; /* Create a mask. */ np->mask = JXCreatePixmap(display, rootWindow, nwidth, nheight, 1); maskGC = JXCreateGC(display, np->mask, 0, NULL); JXSetForeground(display, maskGC, 0); JXFillRectangle(display, np->mask, maskGC, 0, 0, nwidth, nheight); JXSetForeground(display, maskGC, 1); /* Create a temporary XImage for scaling. */ image = JXCreateImage(display, rootVisual, rootDepth, ZPixmap, 0, NULL, nwidth, nheight, 8, 0); image->data = Allocate(sizeof(unsigned long) * nwidth * nheight); /* Determine the scale factor. */ scalex = (icon->image->width << 16) / nwidth; scaley = (icon->image->height << 16) / nheight; data = icon->image->data; srcy = 0; for(y = 0; y < nheight; y++) { const int yindex = (srcy >> 16) * icon->image->width; srcx = 0; for(x = 0; x < nwidth; x++) { if(icon->image->bitmap) { const int index = yindex + (srcx >> 16); const int offset = index >> 3; const int mask = 1 << (index & 7); if(data[offset] & mask) { JXDrawPoint(display, np->mask, maskGC, x, y); XPutPixel(image, x, y, fg); } } else { const int yindex = (srcy >> 16) * icon->image->width; const int index = 4 * (yindex + (srcx >> 16)); color.red = data[index + 1]; color.red |= color.red << 8; color.green = data[index + 2]; color.green |= color.green << 8; color.blue = data[index + 3]; color.blue |= color.blue << 8; GetColor(&color); XPutPixel(image, x, y, color.pixel); if(data[index] >= 128) { JXDrawPoint(display, np->mask, maskGC, x, y); } } srcx += scalex; } srcy += scaley; }