/**
 * @file render.c
 * @author Joe Wingbermuehle
 * @date 2005-2006
 *
 * @brief Functions to render icons using the XRender extension.
 *
 */

#include "jwm.h"
#include "render.h"
#include "icon.h"
#include "image.h"
#include "main.h"
#include "color.h"
#include "error.h"

#ifdef USE_XRENDER
static int haveRender = 0;
#endif

/** Determine if the render extension is available. */
void QueryRenderExtension()
{

#ifdef USE_XRENDER
   int event, error;
   Bool rc;

   rc = JXRenderQueryExtension(display, &event, &error);
   if(rc == True) {
      haveRender = 1;
      Debug("render extension enabled");
   } else {
      haveRender = 0;
      Debug("render extension disabled");
   }

   if(haveRender && rootDepth < 24) {
      Warning("color depth is %d, disabling icon alpha channel", rootDepth);
      haveRender = 0;
   }

#endif

}

/** Draw a scaled icon. */
int PutScaledRenderIcon(IconNode *icon, ScaledIconNode *node, Drawable d,
   int x, int y)
{

#ifdef USE_XRENDER

   Picture dest;
   Picture source;
   XRenderPictFormat *fp;
   int width, height;

   Assert(icon);

   if(!haveRender || !icon->useRender) {
      return 0;
   }

   source = node->imagePicture;
   if(source != None) {

      fp = JXRenderFindVisualFormat(display, rootVisual);
      Assert(fp);

      dest = JXRenderCreatePicture(display, d, fp, 0, NULL);

      if(node->width == 0) {
         width = icon->image->width;
      } else {
         width = node->width;
      }
      if(node->height == 0) {
         height = icon->image->height;
      } else {
         height = node->height;
      }

      JXRenderComposite(display, PictOpOver, source, None, dest,
         0, 0, 0, 0, x, y, width, height);

      JXRenderFreePicture(display, dest);

   }

   return 1;

#else

   return 0;

#endif

}

/** Create a scaled icon. */
ScaledIconNode *CreateScaledRenderIcon(IconNode *icon,
   int width, int height) {

   ScaledIconNode *result = NULL;

#ifdef USE_XRENDER

   XRenderPictureAttributes picAttributes;
   XRenderPictFormat picFormat;
   XRenderPictFormat *fp;
   XColor color;
   GC maskGC;
   XImage *destImage;
   XImage *destMask;
   unsigned long alpha;
   int index, yindex;
   int x, y;
   double scalex, scaley;
   double srcx, srcy;
   int imageLine;
   int maskLine;

   Assert(icon);

   if(!haveRender || !icon->useRender) {
      return NULL;
   }

   result = Allocate(sizeof(ScaledIconNode));
   result->next = icon->nodes;
   icon->nodes = result;

   if(width == 0) {
      width = icon->image->width;
   }
   if(height == 0) {
      height = icon->image->height;
   }
   result->width = width;
   result->height = height;

   scalex = (double)icon->image->width / width;
   scaley = (double)icon->image->height / 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;
   srcy = 0.0;
   for(y = 0; y < height; y++) {
      srcx = 0.0;
      yindex = (int)srcy * icon->image->width;
      for(x = 0; x < width; x++) {

         index = 4 * (yindex + (int)srcx);
         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;

         GetColor(&color);
         XPutPixel(destImage, x, y, color.pixel);
         destMask->data[maskLine + x] = alpha | (alpha << 8);

         srcx += scalex;

      }
      srcy += scaley;
      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 render picture. */
   picFormat.type = PictTypeDirect;
   picFormat.depth = 8;
   picFormat.direct.alphaMask = 0xFF;
   fp = JXRenderFindFormat(display,
      PictFormatType | PictFormatDepth | PictFormatAlphaMask,
      &picFormat, 0);
   Assert(fp);
   result->maskPicture = JXRenderCreatePicture(display, result->mask,
      fp, 0, NULL);
   picAttributes.alpha_map = result->maskPicture;
   fp = JXRenderFindVisualFormat(display, rootVisual);
   Assert(fp);
   result->imagePicture = JXRenderCreatePicture(display, result->image,
      fp, CPAlphaMap, &picAttributes);

   /* Free unneeded pixmaps. */
   JXFreePixmap(display, result->image);
   result->image = None;
   JXFreePixmap(display, result->mask);
   result->mask = None;

#endif

   return result;

}



syntax highlighted by Code2HTML, v. 0.9.1