X11GraphicsContext.st
author Claus Gittinger <cg@exept.de>
Tue, 23 Apr 2019 16:30:55 +0200
changeset 8674 e29a561c0fbe
parent 8357 f1060ceb2b3c
permissions -rw-r--r--
#FEATURE by cg class: SimpleView added: #isDialogBox

"{ Encoding: utf8 }"

"
COPYRIGHT (c) 1989 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
"{ Package: 'stx:libview' }"

"{ NameSpace: Smalltalk }"

DeviceGraphicsContext subclass:#X11GraphicsContext
	instanceVariableNames:'depth xftDrawId'
	classVariableNames:''
	poolDictionaries:''
	category:'Interface-Graphics'
!

!X11GraphicsContext primitiveDefinitions!
%{

#define SUPPORT_MOTIF_WM_HINTS

#ifdef LINUX
# ifndef __arm__
#  define SHM
# endif
#endif

/*
 * x does a typedef Time - I need Object Time ...
 */
#undef Time
#define Time XTime

/*
 * x does a #define True / False
 * we are lucky - the ST/X True/False are not needed
 */
#undef True
#undef False

#include <stdio.h>

#if defined(__osx__)
# include <malloc/malloc.h>
extern void *malloc();
#else
# ifndef FREEBSD
#  include <malloc.h>
# endif
#endif
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>

#define XK_MISCELLANY
#include <X11/keysymdef.h>

#include <X11/cursorfont.h>

#ifdef LINUX
# include <sys/socket.h>
#endif

extern OBJ __GLOBAL_GET_BY_NAME(char *);

# define __HANDLE_VAL(type, externalAddress) \
	((type)__externalAddressVal(externalAddress))

# define __HANDLE_NEW(ptr, __cls)                    \
	({                                           \
	    OBJ handle = __MKEXTERNALADDRESS(ptr);   \
	    OBJ clsObj = __GLOBAL_GET_BY_NAME(__cls);\
	    __InstPtr(handle)->o_class = clsObj;     \
	    __STORE(handle, clsObj);                 \
	    handle;                                  \
	})

/*
 * this define suppresses XAllocColor/XFreeColor on
 * TrueColor systems - I am not certain, if this is
 * always legal to do (it works with XFree servers).
 */
#define QUICK_TRUE_COLORS

/*
 * shape support works; enabled by -DSHAPE in makefile
 * see RoundClock and RoundGlobe examples
 */
#ifdef SHAPE
# include <X11/extensions/shape.h>
#endif

/*
 * shared memory extension access is currently not supported
 * (only query is implemented)
 */
#ifdef SHM
# include <X11/extensions/XShm.h>
#endif

/*
 * multiBuffer extension access is currently not supported
 * (only query is implemented)
 */
#ifdef MBUF
# include <X11/extensions/multibuf.h>
#endif

/*
 * XVideo extension access is currently not supported
 * (only query is implemented)
 */
#ifdef XVIDEO
# include <X11/extensions/Xv.h>
#endif

/*
 * PEX extension - if available
 */
#ifdef PEX5
# include <PEX5/PEX.h>
#endif

/*
 * XImage extension - if available
 */
#ifdef XIE
# include <X11/extensions/XIE.h>
#endif

/*
 * multiscreen extension - if available
 */
#ifdef XINERAMA
# include <X11/extensions/Xinerama.h>
#endif

/*
 * XCURSOR extension - if available
 */
#ifdef XCURSOR
# include <X11/Xcursor/Xcursor.h>
#endif

/*
 * xft library (based on RENDER extension) - if available
 */
#ifdef XFT
# include <X11/Xft/Xft.h>
# include <X11/extensions/Xrender.h>
# include <X11/extensions/render.h>

# define XFT_FONT(x)            __HANDLE_VAL(XftFont*, x)
# define XFT_FONT_HANDLE_NEW(x) __HANDLE_NEW(x, "XftFontDescription::XftFontHandle")

# define XFT_DRAW(x)            __HANDLE_VAL(XftDraw*, x)
# define XFT_DRAW_HANDLE_NEW(x) __HANDLE_NEW(x, "XftFontDescription::XftDrawHandle")
#endif // XFT

/*
 * when I have more time to check it out, I will support display-PS
 */
#ifdef DPS
# ifdef sgi
#  include <X11/extensions/XDPS.h>
#  include <X11/extensions/XDPSlib.h>
#  include <X11/extensions/dpsXclient.h>
# else
#  include <DPS/XDPS.h>
#  include <DPS/XDPSlib.h>
#  include <DPS/dpsXclient.h>
# endif
#endif

#if defined(someMachine)
/*
 * if nformats cannot be found in the Display structure ...
 */
# define NO_PRIVATE_DISPLAY_ACCESS
#endif

#if defined(IRIX5) || defined(__VMS) || (XlibSpecificationRelease == 6)
  /*
   * accessing private data in Display ... sorry
   */
# define DISPLAYACCESS(d) ((_XPrivDisplay)d)
#else
# define DISPLAYACCESS(d) d
#endif

# define DISPLAY(x)    __HANDLE_VAL(Display*, x)
# define SCREEN(x)     ((int)(__intVal(x)))
# define DRAWABLE(x)   __HANDLE_VAL(Drawable, x)
# define GC(x)         __HANDLE_VAL(GC, x)
# define VISUAL(x)     __HANDLE_VAL(Visual*, x)
# define COLORMAP(x)   __HANDLE_VAL(Colormap, x)


/*
 * some defines - tired of typing ...
 */
#define __DisplayVal(o)      (Display *)(__externalAddressVal(o))
#define __DrawableVal(o)     (Drawable)(__externalAddressVal(o))
#define __WindowVal(o)       (Window)(__externalAddressVal(o))
#define __PixmapVal(o)       (Pixmap)(__externalAddressVal(o))
#define __GCVal(o)           (GC)(__externalAddressVal(o))
#define __CursorVal(o)       (Cursor)(__externalAddressVal(o))
#define __FontVal(o)         (XFontStruct *)(__externalAddressVal(o))
#define __DPSContextVal(o)   (DPSContext)(__externalAddressVal(o))

#define __MKATOMOBJ(a)       __MKSMALLINT(a)   /* add STORE macro if ever changed */
#define __AtomVal(o)         __intVal(o)
#define __isAtomID(o)        __isSmallInteger(o)

#define myDpy                __DisplayVal(__INST(displayId))
#define ISCONNECTED          ((__INST(displayId) != nil) && (__INST(hasConnectionBroken) != nil))

#ifdef __VMS__
# include "vms_Xnames.h"
#endif

void __XTimeoutErrorHandler();
int __XErrorHandler__();
int __XIOErrorHandler__();

/*
 * these two macros should be placed around X-lib calls,
 * which may block due to a broken connection.
 * They setup/remove a VM-timeout which raises an exception
 * after xlibTimeout seconds.
 * This exception will shutDown the connection.
 * Q: is this a good idea for the local display ?
 */
#define __ENTER_XLIB(whichTimeout)   \
    { \
	__blockingPrimitiveTimoutHandler__ = (voidFUNC)__XTimeoutErrorHandler; \
	__blockingPrimitiveTimeoutArg__ = self; \
	__blockingPrimitiveTimeout__ = whichTimeout; \
    } {

#define LEAVE_XLIB()   \
    { \
	__blockingPrimitiveTimoutHandler__ = (voidFUNC)0; \
	__blockingPrimitiveTimeoutArg__ = nil; \
	__blockingPrimitiveTimeout__ = 0; \
    } }

#define ENTER_XLIB()   __ENTER_XLIB(__intVal(__INST(xlibTimeout)) * 1000)
#define ENTER_XLIB2()  __ENTER_XLIB(__intVal(__INST(xlibTimeoutForWindowCreation)) * 1000)

#ifdef SUPPORT_MOTIF_WM_HINTS
# ifdef SOME_MACHINE
#  include <anIncludeFileWhichDefinesTheStuffBelow>
# endif

# ifndef MWM_HINTS_FUNCTIONS
#  define MWM_HINTS_FUNCTIONS       (1L << 0)
#  define MWM_HINTS_DECORATIONS     (1L << 1)
#  define MWM_HINTS_INPUT_MODE      (1L << 2)
#  define MWM_HINTS_STATUS          (1L << 3)

#  define MWM_FUNC_ALL              (1L << 0)
#  define MWM_FUNC_RESIZE           (1L << 1)
#  define MWM_FUNC_MOVE             (1L << 2)
#  define MWM_FUNC_MINIMIZE         (1L << 3)
#  define MWM_FUNC_MAXIMIZE         (1L << 4)
#  define MWM_FUNC_CLOSE            (1L << 5)

#  define MWM_INPUT_MODELESS                      0
#  define MWM_INPUT_PRIMARY_APPLICATION_MODAL     1
#  define MWM_INPUT_SYSTEM_MODAL                  2
#  define MWM_INPUT_FULL_APPLICATION_MODAL        3

#  define MWM_DECOR_NONE            0
#  define MWM_DECOR_ALL             (1L << 0)
#  define MWM_DECOR_BORDER          (1L << 1)
#  define MWM_DECOR_RESIZEH         (1L << 2)
#  define MWM_DECOR_TITLE           (1L << 3)
#  define MWM_DECOR_MENU            (1L << 4)
#  define MWM_DECOR_MINIMIZE        (1L << 5)
#  define MWM_DECOR_MAXIMIZE        (1L << 6)
# endif
#endif /* SUPPORT_MOTIF_WM_HINTS */

/*
 * openlook hints are not supported yet
 * - noone needs them anymore ;-(
 */
#ifdef SUPPORT_OPENLOOCK_WM_HINTS
# ifdef SOME_MACHINE
#  include <anIncludeFileWhichDefinesTheStuffBelow>
# endif

# ifndef OL_DECOR_CLOSE
#  define OL_DECOR_CLOSE            (1L << 0)
#  define OL_DECOR_RESIZEH          (1L << 1)
#  define OL_DECOR_HEADER           (1L << 2)
#  define OL_DECOR_ICON_NAME        (1L << 3)
#  define OL_DECOR_ALL              (OL_DECOR_CLOSE | OL_DECOR_RESIZEH | OL_DECOR_HEADER | OL_DECOR_ICON_NAME)
#  define OL_ANY_HINTS              (1L << 7)
# endif
#endif /* SUPPORT_OPENLOOCK_WM_HINTS */


%}
! !

!X11GraphicsContext methodsFor:'accessing'!

depth
    ^ depth
!

xftDrawId
    ^ xftDrawId
! !

!X11GraphicsContext methodsFor:'destroying'!

destroy
    xftDrawId notNil ifTrue:[
	self destroyXftDrawId.
    ].
    super destroy.
!

destroyXftDrawId
    |id|

    id := xftDrawId.
    xftDrawId := nil.
%{
#ifdef XFT
    if (__isExternalAddress(id)) {
	XftDraw *address = (XftDraw *)__externalAddressVal(id);
	if (address) {
	    XftDrawDestroy(address);
	    __externalAddressVal(id) = 0;
	}
    }
#endif
%}.
! !

!X11GraphicsContext methodsFor:'displaying'!

displayDeviceString:aString from:index1 to:index2 x:x y:y opaque:opaque
    "draw a sub-string - if opaque is false, draw foreground only; otherwise, draw both
     foreground and background characters.
     If the coordinates are not integers, an error is triggered."

    <context: #return>

    |displayId|

    font isXftFont ifTrue:[
	self displayDeviceXftString:aString from:index1 to:index2 x:x y:y opaque:opaque.
	^ self.
    ].

    device flushIfAppropriate.
    displayId := device displayIdOrErrorIfBroken.

%{
    GC gc;
    Window win;
    char *cp;
    int  i1, i2, l, n;
#   define NLOCALBUFFER 200
    XChar2b xlatebuffer[NLOCALBUFFER];
    int nInstBytes;

    if (__isExternalAddress(displayId)
     && __isExternalAddress(__INST(gcId))
     && __isExternalAddress(__INST(drawableId))
     && __isNonNilObject(aString)
     && __bothSmallInteger(index1, index2)
     && __bothSmallInteger(x, y)) {
	int lMax = __intVal(@global(XWorkstation:MaxStringLength));
	Display *dpy = __DisplayVal(displayId);
	gc = __GCVal(__INST(gcId));
	win = __WindowVal(__INST(drawableId));

	i1 = __intVal(index1) - 1;
	if (i1 >= 0) {
	    OBJ cls;

	    i2 = __intVal(index2) - 1;
	    if (i2 < i1) {
		RETURN (self);
	    }
	    cp = (char *) __stringVal(aString);
	    l = i2 - i1 + 1;

	    if (__isStringLike(aString)) {
		n = __stringSize(aString);
		if (i2 < n) {
		    cp += i1;
		    if (l > lMax) l = lMax;
		    __ENTER_XLIB(1000 * __intVal(@global(XWorkstation:DefaultXLibTimeout)));
		    if (opaque == true)
			XDrawImageString(dpy, win, gc, __intVal(x), __intVal(y), cp, l);
		    else
			XDrawString(dpy, win, gc, __intVal(x), __intVal(y), cp, l);
		    LEAVE_XLIB();
		    RETURN ( self );
		}
	    }

	    cls = __qClass(aString);
	    nInstBytes = __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
	    cp += nInstBytes;

	    if (__isBytes(aString)) {
		n = __byteArraySize(aString) - nInstBytes - 1;

		if (i2 < n) {
		    cp += i1;
		    if (l > lMax) l = lMax;
		    __ENTER_XLIB(1000 * __intVal(@global(XWorkstation:DefaultXLibTimeout)));
		    if (opaque == true)
			XDrawImageString(dpy, win, gc, __intVal(x), __intVal(y), cp, l);
		    else
			XDrawString(dpy, win, gc, __intVal(x), __intVal(y), cp, l);
		    LEAVE_XLIB();
		    RETURN ( self );
		}
	    }

	    /* TWOBYTESTRINGS */
	    if (__isWords(aString)) {
		n = (__byteArraySize(aString) - nInstBytes) / 2;
		if (i2 < n) {
		    union {
			char b[2];
			unsigned short s;
		    } u;
		    int i;
		    XChar2b *cp2 = (XChar2b *)0;
		    int mustFree = 0;

		    cp += (i1 * 2);
		    if (l > lMax) l = lMax;

#if defined(MSBFIRST) || defined(__MSBFIRST)
		    /*
		     * chars already in correct order
		     */
#else
# if ! (defined(LSBFIRST) || defined(__LSBFIRST))
		    /*
		     * ST/X TwoByteStrings store the asciiValue in native byteOrder;
		     * X expects them MSB first
		     * convert as required
		     */
		    u.s = 0x1234;
		    if (u.b[0] != 0x12)
# endif  // ! (defined(LSBFIRST) || defined(__LSBFIRST))
		    {
			if (l <= NLOCALBUFFER) {
			    cp2 = xlatebuffer;
			} else {
			    cp2 = (XChar2b *)(malloc(l * 2));
			    mustFree = 1;
			}
			for (i=0; i<l; i++) {
			    cp2[i].byte1 = (((XChar2b *)cp)[i]).byte2;
			    cp2[i].byte2 = (((XChar2b *)cp)[i]).byte1;
			}
			cp = (char *) cp2;
		    }
#endif  // ! (defined(MSBFIRST) || defined(__MSBFIRST))
		    __ENTER_XLIB(1000 * __intVal(@global(XWorkstation:DefaultXLibTimeout)));
		    if (opaque == true)
			XDrawImageString16(dpy, win, gc, __intVal(x), __intVal(y), (XChar2b *)cp, l);
		    else
			XDrawString16(dpy, win, gc, __intVal(x), __intVal(y), (XChar2b *)cp, l);
		    LEAVE_XLIB();

		    if (mustFree) {
			free(cp2);
		    }

		    RETURN ( self );
		}
	    }

	    /* FOURBYTESTRINGS */
	    if (__isLongs(aString)) {
		n = (__byteArraySize(aString) - nInstBytes) / 4;
		if (i2 < n) {
		    union {
			char b[2];
			unsigned short s;
		    } u;
		    int i;
		    XChar2b *cp2 = (XChar2b *)0;
		    int32 *ip;
		    int mustFree = 0;

		    cp += (i1 * 4);
		    if (l > lMax) l = lMax;

		    /*
		     * all codePoints <= 16rFFFF are draw; above 16bit range are drawn as 16rFFFF.
		     */
		    if (l <= NLOCALBUFFER) {
			cp2 = xlatebuffer;
		    } else {
			cp2 = (XChar2b *)(malloc(l * 2));
			mustFree = 1;
		    }
		    for (i=0; i<l; i++) {
			int32 codePoint = ((int32 *)cp)[i];

			if (codePoint > 0xFFFF) {
			    codePoint = 0xFFFF;
			}
			cp2[i].byte1 = (codePoint >> 8) & 0xFF;
			cp2[i].byte2 = codePoint & 0xFF;
		    }

		    __ENTER_XLIB(1000 * __intVal(@global(XWorkstation:DefaultXLibTimeout)));
		    if (opaque == true)
			XDrawImageString16(dpy, win, gc, __intVal(x), __intVal(y), (XChar2b *)cp2, l);
		    else
			XDrawString16(dpy, win, gc, __intVal(x), __intVal(y), (XChar2b *)cp2, l);
		    LEAVE_XLIB();

		    if (mustFree) {
			free(cp2);
		    }

		    RETURN ( self );
		}
	    }
	}
    }
#undef NLOCALBUFFER
%}.

    "x/y not integer, badGC or drawable, or not a string"
    device primitiveFailedOrClosedConnection
!

displayDeviceXftString:aString from:index1 to:index2Arg x:drawX y:drawY opaque:opaque
    "draw a sub-string - if opaque is false, draw foreground only; otherwise, draw both
     foreground and background characters.
     If the coordinates are not integers, an error is triggered."

    <context: #return>

    |index2 bytesPerCharacter
     clipX clipY clipW clipH
     fgR fgG fgB fgA fgPixel bgR bgG bgB bgA bgPixel
     displayId screen error stringLen
     newXftDrawId pixmapDepth fontId|

"/    device flushIfAppropriate.
    displayId := device displayIdOrErrorIfBroken.

    "limit the string len, otherwise bad output is generated"
    stringLen := index2Arg - index1 + 1.
    stringLen > 1000 "8000" ifTrue:[
	index2 := index1 + 1000 "8000" - 1.
    ]  ifFalse:[
	stringLen <= 0 ifTrue:[^ self].
	index2 := index2Arg.
    ].
    bytesPerCharacter := aString bytesPerCharacter.

    clipRect notNil ifTrue:[
	clipX := clipRect left.
	clipY := clipRect top.
	clipW := clipRect width.
	clipH := clipRect height.
"/clipW > 32767 ifTrue:['clipW > 32767: ' errorPrint. clipW errorPrintCR. clipW := 32767].
"/(clipX > 16384 or:[clipX < -16384]) ifTrue:['clipX > 16384: ' errorPrint. clipX errorPrintCR.].
	"/ YES YES YES: this MUST be transformed!!
	"/ (see htmlView) fix the notebook, please.
    ].

    fgR := paint scaledRed.
    fgR notNil ifTrue:[
	fgG := paint scaledGreen.
	fgB := paint scaledBlue.
	fgA := paint scaledAlpha.
    ] ifFalse:[
	"/ when drawing into a pixmap...
	fgPixel := paint colorId.
	fgPixel == 0 ifTrue:[
	    fgR := fgG := fgB := 0.
	] ifFalse:[
	    fgR := fgG := fgB := 16rFFFF.
	].
	fgA := 16rFFFF.
    ].

    opaque ifTrue:[
	bgPaint isColor ifTrue:[
	    bgR := bgPaint scaledRed.
	    bgR notNil ifTrue:[
		bgG := bgPaint scaledGreen.
		bgB := bgPaint scaledBlue.
		bgA := bgPaint scaledAlpha.
	    ] ifFalse:[
		"/ when drawing into a pixmap...
		bgPixel := bgPaint colorId.
		bgPixel == 0 ifTrue:[
		    bgR := bgG := bgB := 0.
		] ifFalse:[
		    bgR := bgG := bgB := 16rFFFF.
		].
		bgA := 16rFFFF.
	    ].
	] ifFalse:[
	    "images as background are not yet implemented"
	    "/ #todo: fill background rectangle
	    bgR := bgG := bgB := bgA := 16rFFFF.
	].
    ].

    screen := device screen.
    self isPixmap ifTrue:[
	pixmapDepth := depth.
    ].
    fontId := font getXftFontId.

%{ /* STACK: 64000 */
#ifdef XFT
    XftColor color;
    XGlyphInfo extents;
    XRectangle clipRX;
    char *string;
    int len;
    int __bytesPerCharacter;
    XftDraw *__xftDrawId;
    XftFont *__xftFont;

    if (!(__bothSmallInteger(drawX, drawY)
	  && __bothSmallInteger(index1, index2)
	  && __isSmallInteger(bytesPerCharacter)
	  && (__isSmallInteger(fgPixel) || (__bothSmallInteger(fgR, fgG) && __bothSmallInteger(fgB, fgA)))
	  && (opaque == false || __isSmallInteger(bgPixel) || (__bothSmallInteger(bgR, bgG) && __bothSmallInteger(bgB, bgA)))
	  && __isNonNilObject(aString)
	  && __isExternalAddress(displayId)
	  && __isExternalAddressLike(fontId)
    )) {
	error = @symbol(badArgument);
	goto out;
    }

    __xftFont = XFT_FONT(fontId);
    __bytesPerCharacter = __intVal(bytesPerCharacter);

    if (__INST(xftDrawId) != nil) {
	__xftDrawId = __externalAddressVal(__INST(xftDrawId));
    } else {
	if (pixmapDepth != nil) {
	    int __pixmapDepth = __intVal(pixmapDepth);

	    if (__pixmapDepth == 1) {
		__xftDrawId = XftDrawCreateBitmap(DISPLAY(displayId), DRAWABLE(__INST(drawableId)));
	    } else {
		__xftDrawId = XftDrawCreateAlpha(DISPLAY(displayId), DRAWABLE(__INST(drawableId)), __pixmapDepth);
	    }
	} else {
	    __xftDrawId = XftDrawCreate(DISPLAY(displayId),
					   DRAWABLE(__INST(drawableId)),
					   DefaultVisual(DISPLAY(displayId), SCREEN(screen)),
					   DefaultColormap(DISPLAY(displayId), SCREEN(screen)));
	}
	__INST(xftDrawId) = newXftDrawId = XFT_DRAW_HANDLE_NEW(__xftDrawId);
	__STORE(self, newXftDrawId);
    }

    string = __stringVal(aString) + ((__intVal(index1) - 1 ) * __bytesPerCharacter);
    len = __intVal(index2) - __intVal(index1) + 1;

    if (clipX != nil) {
	clipRX.x = __intVal(clipX);
	clipRX.y = __intVal(clipY);
	clipRX.width = __intVal(clipW);
	clipRX.height = __intVal(clipH);
	XftDrawSetClipRectangles(__xftDrawId, 0, 0, &clipRX, 1);
    } else {
	XftDrawSetClip(__xftDrawId, 0);
    }

    if (opaque == true) {
	if (bgPixel != nil) {
	    color.pixel = (unsigned long)__intVal(bgPixel);
	}
	color.color.red = __intVal(bgR);
	color.color.green = __intVal(bgG);
	color.color.blue = __intVal(bgB);
	color.color.alpha = __intVal(bgA);

	switch (__bytesPerCharacter) {
	case 1:
	    XftTextExtents8(DISPLAY(displayId), __xftFont, (FcChar8*)string, len, &extents);
	    break;
	case 2:
	    XftTextExtents16(DISPLAY(displayId), __xftFont, (FcChar16*)string, len, &extents);
	    break;
	case 4:
	    XftTextExtents32(DISPLAY(displayId), __xftFont, (FcChar32*)string, len, &extents);
	    break;
	}
if (extents.width < 0) printf("width: %d  < 0\n", extents.width);

	XftDrawRect(__xftDrawId, &color, __intVal(drawX) - extents.x, __intVal(drawY) - __xftFont->ascent, extents.width, __xftFont->height);
    }
    if (__isSmallInteger(fgPixel)) {
	color.pixel = (unsigned long)__intVal(fgPixel);
    }
    color.color.red = __intVal(fgR);
    color.color.green = __intVal(fgG);
    color.color.blue = __intVal(fgB);
    color.color.alpha = __intVal(fgA);

    switch (__bytesPerCharacter) {
    case 1:
	XftDrawString8(__xftDrawId, &color,__xftFont,
			__intVal(drawX),
			__intVal(drawY),
			(FcChar8*)string,
			len);
	break;

    case 2:
	XftDrawString16(__xftDrawId, &color, __xftFont,
			__intVal(drawX),
			__intVal(drawY),
			(FcChar16*)string,
			len);
	break;

    case 4:
	XftDrawString32(__xftDrawId, &color, __xftFont,
			__intVal(drawX),
			__intVal(drawY),
			(FcChar32*)string,
			len);
	break;

    default:
	error = @symbol(invalidStringSize);
	goto out;
    }

out:;
#endif
%}.
    error notNil ifTrue:[
	self primitiveFailed: error.
    ].
! !

!X11GraphicsContext methodsFor:'drawing'!

XXclearDeviceRectangleX:x y:y width:width height:height
    device clearRectangleX:x y:y width:width height:height in:drawableId with:gcId
!

XXclearRectangleX:x y:y width:w height:h
    "draw a filled rectangle; apply transformation if nonNil"

    |pX pY nW nH pO pC|

    gcId isNil ifTrue:[
	self initGC
    ].
    transformation notNil ifTrue:[
	pO := transformation transformPoint:x@y.
	pC := transformation transformPoint:(x+w-1)@(y+h-1).
	pX := pO x.
	pY := pO y.
	nW := pC x - pX + 1.
	nH := pC y - pY + 1.

	nW < 0 ifTrue:[
	      nW := nW abs.
	      pX := pX - nW.
	].
	nH < 0 ifTrue:[
	      nH := nH abs.
	      pY := pY - nH.
	].
    ] ifFalse:[
	pX := x.
	pY := y.
	nW := w.
	nH := h.
    ].
    pX := pX rounded.
    pY := pY rounded.
    nW := nW rounded.
    nH := nH rounded.

    device
	clearRectangleX:pX
		     y:pY
		 width:nW
		height:nH
		    in:drawableId with:gcId
! !

!X11GraphicsContext methodsFor:'view creation'!

createBitmapFromArray:data width:width height:height
    depth := 1.
    super createBitmapFromArray:data width:width height:height
!

createPixmapWidth:w height:h depth:d
    depth := d.
    super createPixmapWidth:w height:h depth:d
! !

!X11GraphicsContext class methodsFor:'documentation'!

version
    ^ '$Header$'
!

version_CVS
    ^ '$Header$'
! !


X11GraphicsContext initialize!