#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xftint.h"
#include <X11/Xutil.h>
XftDraw *
XftDrawCreate (Display *dpy,
Drawable drawable,
Visual *visual,
Colormap colormap)
{
XftDraw *draw;
draw = (XftDraw *) malloc (sizeof (XftDraw));
if (!draw)
return 0;
draw->dpy = dpy;
draw->drawable = drawable;
draw->visual = visual;
draw->colormap = colormap;
draw->core_set = False;
draw->render_set = False;
draw->render_able = False;
draw->clip = 0;
return draw;
}
XftDraw *
XftDrawCreateBitmap (Display *dpy,
Pixmap bitmap)
{
XftDraw *draw;
draw = (XftDraw *) malloc (sizeof (XftDraw));
if (!draw)
return 0;
draw->dpy = dpy;
draw->drawable = (Drawable) bitmap;
draw->visual = 0;
draw->colormap = 0;
draw->core_set = False;
draw->render_set = False;
draw->render_able = False;
draw->clip = 0;
return draw;
}
static XRenderPictFormat *
_XftDrawFormat (XftDraw *draw)
{
if (draw->visual == 0)
{
XRenderPictFormat pf;
pf.type = PictTypeDirect;
pf.depth = 1;
pf.direct.alpha = 0;
pf.direct.alphaMask = 1;
return XRenderFindFormat (draw->dpy,
(PictFormatType|
PictFormatDepth|
PictFormatAlpha|
PictFormatAlphaMask),
&pf,
0);
}
else
return XRenderFindVisualFormat (draw->dpy, draw->visual);
}
static XRenderPictFormat *
_XftDrawFgFormat (XftDraw *draw)
{
XRenderPictFormat pf;
if (draw->visual == 0)
{
pf.type = PictTypeDirect;
pf.depth = 1;
pf.direct.alpha = 0;
pf.direct.alphaMask = 1;
return XRenderFindFormat (draw->dpy,
(PictFormatType|
PictFormatDepth|
PictFormatAlpha|
PictFormatAlphaMask),
&pf,
0);
}
else
{
pf.type = PictTypeDirect;
pf.depth = 32;
pf.direct.redMask = 0xff;
pf.direct.greenMask = 0xff;
pf.direct.blueMask = 0xff;
pf.direct.alphaMask = 0xff;
return XRenderFindFormat (draw->dpy,
(PictFormatType|
PictFormatDepth|
PictFormatRedMask|
PictFormatGreenMask|
PictFormatBlueMask|
PictFormatAlphaMask),
&pf,
0);
}
}
void
XftDrawChange (XftDraw *draw,
Drawable drawable)
{
draw->drawable = drawable;
if (draw->render_able)
{
XRenderPictFormat *format;
XRenderFreePicture (draw->dpy, draw->render.pict);
format = XRenderFindVisualFormat (draw->dpy, draw->visual);
draw->render.pict = XRenderCreatePicture (draw->dpy, draw->drawable,
format, 0, 0);
}
}
void
XftDrawDestroy (XftDraw *draw)
{
int n;
if (draw->render_able)
{
XRenderFreePicture (draw->dpy, draw->render.pict);
for (n = 0; n < XFT_DRAW_N_SRC; n++)
XRenderFreePicture (draw->dpy, draw->render.src[n].pict);
}
if (draw->core_set)
XFreeGC (draw->dpy, draw->core.draw_gc);
if (draw->clip)
XDestroyRegion (draw->clip);
free (draw);
}
Bool
XftDrawRenderPrepare (XftDraw *draw,
XftColor *color,
XftFont *font,
int src)
{
if (!draw->render_set)
{
XRenderPictFormat *format;
XRenderPictFormat *pix_format;
XRenderPictureAttributes pa;
int n;
Pixmap pix;
draw->render_set = True;
draw->render_able = False;
format = _XftDrawFormat (draw);
pix_format = _XftDrawFgFormat (draw);
if (format && pix_format)
{
draw->render_able = True;
draw->render.pict = XRenderCreatePicture (draw->dpy, draw->drawable,
format, 0, 0);
for (n = 0; n < XFT_DRAW_N_SRC; n++)
{
pix = XCreatePixmap (draw->dpy, draw->drawable,
1, 1, pix_format->depth);
pa.repeat = True;
draw->render.src[n].pict = XRenderCreatePicture (draw->dpy,
pix,
pix_format,
CPRepeat, &pa);
XFreePixmap (draw->dpy, pix);
draw->render.src[n].color = color->color;
XRenderFillRectangle (draw->dpy, PictOpSrc,
draw->render.src[n].pict,
&color->color, 0, 0, 1, 1);
}
if (draw->clip)
XRenderSetPictureClipRegion (draw->dpy, draw->render.pict,
draw->clip);
}
}
if (!draw->render_able)
return False;
if (memcmp (&color->color, &draw->render.src[src].color,
sizeof (XRenderColor)))
{
if (_XftFontDebug () & XFT_DBG_DRAW)
{
printf ("Switching to color %04x,%04x,%04x,%04x\n",
color->color.alpha,
color->color.red,
color->color.green,
color->color.blue);
}
XRenderFillRectangle (draw->dpy, PictOpSrc,
draw->render.src[src].pict,
&color->color, 0, 0, 1, 1);
draw->render.src[src].color = color->color;
}
return True;
}
Bool
XftDrawCorePrepare (XftDraw *draw,
XftColor *color,
XftFont *font)
{
if (!draw->core_set)
{
XGCValues gcv;
unsigned long mask;
draw->core_set = True;
draw->core.fg = color->pixel;
gcv.foreground = draw->core.fg;
mask = GCForeground;
if (font)
{
draw->core.font = font->u.core.font->fid;
gcv.font = draw->core.font;
mask |= GCFont;
}
draw->core.draw_gc = XCreateGC (draw->dpy, draw->drawable,
mask, &gcv);
if (draw->clip)
XSetRegion (draw->dpy, draw->core.draw_gc, draw->clip);
}
if (draw->core.fg != color->pixel)
{
draw->core.fg = color->pixel;
XSetForeground (draw->dpy, draw->core.draw_gc, draw->core.fg);
}
if (font && draw->core.font != font->u.core.font->fid)
{
draw->core.font = font->u.core.font->fid;
XSetFont (draw->dpy, draw->core.draw_gc, draw->core.font);
}
return True;
}
void
XftDrawString8 (XftDraw *draw,
XftColor *color,
XftFont *font,
int x,
int y,
XftChar8 *string,
int len)
{
if (_XftFontDebug () & XFT_DBG_DRAW)
{
printf ("DrawString \"%*.*s\"\n", len, len, string);
}
if (font->core)
{
XftDrawCorePrepare (draw, color, font);
XDrawString (draw->dpy, draw->drawable, draw->core.draw_gc, x, y,
(char *) string, len);
}
#ifdef FREETYPE2
else if (XftDrawRenderPrepare (draw, color, font, XFT_DRAW_SRC_TEXT))
{
XftRenderString8 (draw->dpy,
draw->render.src[XFT_DRAW_SRC_TEXT].pict,
font->u.ft.font,
draw->render.pict, 0, 0, x, y, string, len);
}
#endif
}
#define N16LOCAL 256
void
XftDrawString16 (XftDraw *draw,
XftColor *color,
XftFont *font,
int x,
int y,
XftChar16 *string,
int len)
{
if (font->core)
{
XChar2b *xc;
XChar2b xcloc[XFT_CORE_N16LOCAL];
XftDrawCorePrepare (draw, color, font);
xc = XftCoreConvert16 (string, len, xcloc);
XDrawString16 (draw->dpy, draw->drawable, draw->core.draw_gc, x, y,
xc, len);
if (xc != xcloc)
free (xc);
}
#ifdef FREETYPE2
else if (XftDrawRenderPrepare (draw, color, font, XFT_DRAW_SRC_TEXT))
{
XftRenderString16 (draw->dpy,
draw->render.src[XFT_DRAW_SRC_TEXT].pict,
font->u.ft.font,
draw->render.pict, 0, 0, x, y, string, len);
}
#endif
}
void
XftDrawString32 (XftDraw *draw,
XftColor *color,
XftFont *font,
int x,
int y,
XftChar32 *string,
int len)
{
if (font->core)
{
XChar2b *xc;
XChar2b xcloc[XFT_CORE_N16LOCAL];
XftDrawCorePrepare (draw, color, font);
xc = XftCoreConvert32 (string, len, xcloc);
XDrawString16 (draw->dpy, draw->drawable, draw->core.draw_gc, x, y,
xc, len);
if (xc != xcloc)
free (xc);
}
#ifdef FREETYPE2
else if (XftDrawRenderPrepare (draw, color, font, XFT_DRAW_SRC_TEXT))
{
XftRenderString32 (draw->dpy,
draw->render.src[XFT_DRAW_SRC_TEXT].pict,
font->u.ft.font,
draw->render.pict, 0, 0, x, y, string, len);
}
#endif
}
void
XftDrawStringUtf8 (XftDraw *draw,
XftColor *color,
XftFont *font,
int x,
int y,
XftChar8 *string,
int len)
{
if (font->core)
{
XChar2b *xc;
XChar2b xcloc[XFT_CORE_N16LOCAL];
int n;
XftDrawCorePrepare (draw, color, font);
xc = XftCoreConvertUtf8 (string, len, xcloc, &n);
if (xc)
{
XDrawString16 (draw->dpy, draw->drawable, draw->core.draw_gc, x, y,
xc, n);
}
if (xc != xcloc)
free (xc);
}
#ifdef FREETYPE2
else if (XftDrawRenderPrepare (draw, color, font, XFT_DRAW_SRC_TEXT))
{
XftRenderStringUtf8 (draw->dpy,
draw->render.src[XFT_DRAW_SRC_TEXT].pict,
font->u.ft.font,
draw->render.pict, 0, 0, x, y, string, len);
}
#endif
}
void
XftDrawRect (XftDraw *draw,
XftColor *color,
int x,
int y,
unsigned int width,
unsigned int height)
{
if (XftDrawRenderPrepare (draw, color, 0, XFT_DRAW_SRC_RECT))
{
XRenderFillRectangle (draw->dpy, PictOpOver, draw->render.pict,
&color->color, x, y, width, height);
}
else
{
XftDrawCorePrepare (draw, color, 0);
XFillRectangle (draw->dpy, draw->drawable, draw->core.draw_gc,
x, y, width, height);
}
}
Bool
XftDrawSetClip (XftDraw *draw,
Region r)
{
Region n = 0;
if (!r && !draw->clip)
return True;
if (r)
{
n = XCreateRegion ();
if (n)
{
if (!XUnionRegion (n, r, n))
{
XDestroyRegion (n);
return False;
}
}
}
if (draw->clip)
{
XDestroyRegion (draw->clip);
}
draw->clip = n;
if (draw->render_able)
{
XRenderPictureAttributes pa;
if (n)
{
XRenderSetPictureClipRegion (draw->dpy, draw->render.pict, n);
}
else
{
pa.clip_mask = None;
XRenderChangePicture (draw->dpy, draw->render.pict,
CPClipMask, &pa);
}
}
if (draw->core_set)
{
XGCValues gv;
if (n)
XSetRegion (draw->dpy, draw->core.draw_gc, n);
else
{
gv.clip_mask = None;
XChangeGC (draw->dpy, draw->core.draw_gc,
GCClipMask, &gv);
}
}
return True;
}