XWorkstation.st
changeset 7416 bd3b9e9edd9e
parent 7413 3ecf41208027
child 7443 e2d05b756727
--- a/XWorkstation.st	Sat Jul 16 18:24:24 2016 +0200
+++ b/XWorkstation.st	Tue Jul 19 21:44:36 2016 +0200
@@ -1,3 +1,5 @@
+"{ Encoding: utf8 }"
+
 "
 COPYRIGHT (c) 1989 by Claus Gittinger
 	      All Rights Reserved
@@ -9,6 +11,8 @@
  other person.  No title to or ownership of the software is
  hereby transferred.
 "
+'From Smalltalk/X, Version:7.1.0.0 on 19-07-2016 at 15:46:14'                   !
+
 "{ Package: 'stx:libview' }"
 
 "{ NameSpace: Smalltalk }"
@@ -53,7 +57,7 @@
 !
 
 DeviceGraphicsContext subclass:#X11GraphicsContext
-	instanceVariableNames:'useXftFont xftDrawId'
+	instanceVariableNames:'depth xftDrawId'
 	classVariableNames:''
 	poolDictionaries:''
 	privateIn:XWorkstation
@@ -123,6 +127,19 @@
 # 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
@@ -198,7 +215,13 @@
 # include <X11/Xft/Xft.h>
 # include <X11/extensions/Xrender.h>
 # include <X11/extensions/render.h>
-#endif
+
+# 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
@@ -231,6 +254,14 @@
 # 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 ...
  */
@@ -268,20 +299,20 @@
  */
 #define __ENTER_XLIB(whichTimeout)   \
     { \
-	__blockingPrimitiveTimoutHandler__ = (VOIDFUNC)__XTimeoutErrorHandler; \
-	__blockingPrimitiveTimeoutArg__ = self; \
-	__blockingPrimitiveTimeout__ = __intVal(__INST(whichTimeout)) * 1000; \
+        __blockingPrimitiveTimoutHandler__ = (VOIDFUNC)__XTimeoutErrorHandler; \
+        __blockingPrimitiveTimeoutArg__ = self; \
+        __blockingPrimitiveTimeout__ = whichTimeout; \
     } {
 
 #define LEAVE_XLIB()   \
     { \
-	__blockingPrimitiveTimoutHandler__ = (VOIDFUNC)0; \
-	__blockingPrimitiveTimeoutArg__ = nil; \
-	__blockingPrimitiveTimeout__ = 0; \
+        __blockingPrimitiveTimoutHandler__ = (VOIDFUNC)0; \
+        __blockingPrimitiveTimeoutArg__ = nil; \
+        __blockingPrimitiveTimeout__ = 0; \
     } }
 
-#define ENTER_XLIB()   __ENTER_XLIB(xlibTimeout)
-#define ENTER_XLIB2()  __ENTER_XLIB(xlibTimeoutForWindowCreation)
+#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
@@ -365,30 +396,26 @@
  * to include that stuff. Should be #ifdef'd ...
  */
 #ifndef ELF
-
 # ifdef __GNUC__
 VOLATILE
 # endif
 static void
 dummyToForceLoading() {
-	XCreateSimpleWindow(0, 0, 0, 0, 0, 0, 0, 0, 0);
-	XCloseDisplay(0);
-	XCreateImage(0, 0, 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0);
-	XSetWindowColormap(0, 0, 0);
-	XQueryColors(0,0,0,0);
+        XCreateSimpleWindow(0, 0, 0, 0, 0, 0, 0, 0, 0);
+        XCloseDisplay(0);
+        XCreateImage(0, 0, 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0);
+        XSetWindowColormap(0, 0, 0);
+        XQueryColors(0,0,0,0);
 # ifdef SHM
-	XShmAttach(0, 0);
-	XShmCreateImage(0, 0, 0, 0, 0, 0, 0 ,0);
-	XShmDetach(0, 0);
-	XShmPutImage(0, 0, 0, 0 , 0,0,0,0,0,0,0);
-	shmctl(0,0,0);
-	fgetc(0);
-# endif
+        XShmAttach(0, 0);
+        XShmCreateImage(0, 0, 0, 0, 0, 0, 0 ,0);
+        XShmDetach(0, 0);
+        XShmPutImage(0, 0, 0, 0 , 0,0,0,0,0,0,0);
+        shmctl(0,0,0);
+        fgetc(0);
+# endif  // SHM
 }
-#endif
-
-#undef __myInstPtr
-#define __myInstPtr(obj) ((struct __XWorkstation_struct *)(obj))
+#endif // !ELF
 
 static char* requestNames[] = {
     "X_CreateWindow",               // 0
@@ -512,6 +539,11 @@
     "X_GetModifierMapping",
 };
 
+#if !defined(__INCREMENTAL_COMPILE__)
+// __myInstPtr has been redefined/overwritten by private classes - restore
+#undef __myInstPtr
+#define __myInstPtr(obj) ((struct __XWorkstation_struct *)(obj))
+
 /*
  * catch X-errors and forward as errorInterrupt:#DisplayError,
  * (which itself invokes my handler and optionally raises an exceptionSignal)
@@ -521,50 +553,48 @@
  * allows passing an additional argument, which is the displayID ...)
  */
 int
-__XErrorHandler__(dpy, event)
-    Display *dpy;
-    XErrorEvent *event;
+__XErrorHandler__(Display *dpy, XErrorEvent *event)
 {
     XGetErrorText(dpy, event->error_code, lastErrorMsg, 127);
     lastErrorMsg[127] = '\0';
 
     if (lastErrorMsg[0] == '\0') {
-	sprintf(lastErrorMsg, "code: %d", event->error_code);
+        sprintf(lastErrorMsg, "code: %d", event->error_code);
     }
     lastRequestCode = event->request_code;
     lastMinorCode = event->minor_code;
     lastResource = event->resourceid;
     if ((event->error_code == BadWindow) && (lastRequestCode == 4) && (lastMinorCode == 0)) {
-	/*
-	 * this is a BadWindow error for X_DestroyWindow.
-	 * ignore it here, since it results from the GC freeing windows
-	 * in non bottom-up window order.
-	 */
-	return 0;
+        /*
+         * this is a BadWindow error for X_DestroyWindow.
+         * ignore it here, since it results from the GC freeing windows
+         * in non bottom-up window order.
+         */
+        return 0;
     }
 
     if (@global(DeviceWorkstation:ErrorPrinting) == true) {
-	char *requestName = "?";
-
-	if (event->request_code < (sizeof(requestNames)/sizeof(char *))) {
-	    requestName = requestNames[event->request_code];
-	}
-	console_fprintf(stderr, "XWorkstation [error]: x-error caught maj=%d (0x%x) \"%s\", min=%d (0x%x), resource=%"_lx_"\n",
-			event->request_code, event->request_code, requestName,
-			event->minor_code, event->minor_code, (INT)(event->resourceid));
-	console_fprintf(stderr, "XWorkstation [error]: x-error message is [%d] '%s'\n",
-			event->error_code, lastErrorMsg);
+        char *requestName = "?";
+
+        if (event->request_code < (sizeof(requestNames)/sizeof(char *))) {
+            requestName = requestNames[event->request_code];
+        }
+        console_fprintf(stderr, "XWorkstation [error]: x-error caught maj=%d (0x%x) \"%s\", min=%d (0x%x), resource=%"_lx_"\n",
+                        event->request_code, event->request_code, requestName,
+                        event->minor_code, event->minor_code, (INT)(event->resourceid));
+        console_fprintf(stderr, "XWorkstation [error]: x-error message is [%d] '%s'\n",
+                        event->error_code, lastErrorMsg);
     }
 #if 0
     // cg: should no longer be needed - librun no longer sends an errorInterrupt while running on C-stack
 #ifdef XFT
     if ((strncmp(lastErrorMsg, "RenderBadPicture", 16) == 0)) {
-	/*
-	 * this is a RenderBadPicture error from XFT drawing.
-	 * ignore it for now, as this is due to an incomplete implementation
-	 */
-	console_fprintf(stderr, "XWorkstation [info]: x-error ignored\n");
-	return 0;
+        /*
+         * this is a RenderBadPicture error from XFT drawing.
+         * ignore it for now, as this is due to an incomplete implementation
+         */
+        console_fprintf(stderr, "XWorkstation [info]: x-error ignored\n");
+        return 0;
     }
 #endif
 #endif
@@ -581,14 +611,13 @@
  * connection should not affect the other users.
  */
 int
-__XIOErrorHandler__(dpy)
-    Display *dpy;
+__XIOErrorHandler__(Display *dpy)
 {
     if (@global(DeviceWorkstation:ErrorPrinting) == true) {
-	console_fprintf(stderr, "XWorkstation [error]: I/O error\n");
+        console_fprintf(stderr, "XWorkstation [error]: I/O error\n");
     }
     __immediateErrorInterruptWithIDAndParameter__(@symbol(DisplayIOError),
-						  __MKEXTERNALADDRESS(dpy));
+                                                  __MKEXTERNALADDRESS(dpy));
 
 #if 0
     /*
@@ -616,16 +645,15 @@
  * timeoutHandler has been set.
  */
 void
-__XTimeoutErrorHandler(displayDeviceInst)
-    OBJ displayDeviceInst;
+__XTimeoutErrorHandler(OBJ displayDeviceInst)
 {
     if ((displayDeviceInst == @global(MainDisplay))
-	|| (displayDeviceInst == @global(DeviceWorkstation:DefaultScreen))) {
-	console_fprintf(stderr, "XWorkstation [error]: keep display connection for master display after X11 timeout (no shutdown)\n");
-	return;
+        || (displayDeviceInst == @global(DeviceWorkstation:DefaultScreen))) {
+        console_fprintf(stderr, "XWorkstation [error]: keep display connection for master display after X11 timeout (no shutdown)\n");
+        return;
     }
     if (@global(DeviceWorkstation:ErrorPrinting) == true) {
-	console_fprintf(stderr, "XWorkstation [error]: X11 request timeout dpy=%"_lx_"\n", (INT)displayDeviceInst);
+        console_fprintf(stderr, "XWorkstation [error]: X11 request timeout dpy=%"_lx_"\n", (INT)displayDeviceInst);
     }
     __OINST(displayDeviceInst, hasConnectionBroken) = true;
 
@@ -637,16 +665,17 @@
      * if we return from the error interrupt ...
      */
     if (__OINST(displayDeviceInst, displayId) != nil) {
-	__internalError("unhandled X11 display timeout error");
-
-	/*
-	 * the current process failed to do an X11 request.
-	 * Terminate it!
-	 */
-	__terminateProcess(0);      /* soft terminate */
-	__terminateProcess(1);      /* hard terminate */
+        __internalError("unhandled X11 display timeout error");
+
+        /*
+         * the current process failed to do an X11 request.
+         * Terminate it!
+         */
+        __terminateProcess(0);      /* soft terminate */
+        __terminateProcess(1);      /* hard terminate */
     }
 }
+#endif // __INCREMENTAL_COMPILE__
 
 %}
 ! !
@@ -1795,10 +1824,7 @@
      except for XQuartz, which has."
 
     "XQuartz seems to have a bug here..."
-    OperatingSystem isOSXlike ifTrue:[^ false].
-    ^ true
-
-    "Created: / 4.5.1999 / 12:16:43 / cg"
+    ^ OperatingSystem isOSXlike not.
 !
 
 supportsScreenReading
@@ -1992,19 +2018,19 @@
     Pixmap newBitmap;
 
     if (__bothSmallInteger(w, h) && ISCONNECTED) {
-	Display *dpy = myDpy;
-
-
-	ENTER_XLIB();
-	newBitmap = XCreatePixmap(dpy, RootWindow(dpy, screen),
-				       __intVal(w), __intVal(h), 1);
-	LEAVE_XLIB();
+        Display *dpy = myDpy;
+
+
+        ENTER_XLIB();
+        newBitmap = XCreatePixmap(dpy, RootWindow(dpy, screen),
+                                       __intVal(w), __intVal(h), 1);
+        LEAVE_XLIB();
 #ifdef COUNT_RESOURCES
-	if (newBitmap)
-	    __cnt_bitmap++;
-#endif
-
-	RETURN ( (newBitmap != (Pixmap)0) ? __MKEXTERNALADDRESS(newBitmap) : nil );
+        if (newBitmap)
+            __cnt_bitmap++;
+#endif
+
+        RETURN ( (newBitmap != (Pixmap)0) ? __MKEXTERNALADDRESS(newBitmap) : nil );
     }
 %}.
     self primitiveFailedOrClosedConnection.
@@ -2586,7 +2612,6 @@
 !
 
 primCreateBitmapFromArray:anArray width:w height:h
-
     <context: #return>
 
 %{  /* UNLIMITEDSTACK */
@@ -2602,93 +2627,93 @@
     REGISTER int col;
     unsigned bits;
     static char reverseBitTable[256];
-    static firstCall = 1;
+    static int firstCall = 1;
     int nBytes;
     unsigned char fastBits[10000];
     OBJ num, *op;
     int bytesPerRow;
 
     if (! ISCONNECTED) {
-	RETURN (nil);
+        RETURN (nil);
     }
 
     dpy = myDpy;
     if (firstCall) {
-	for (index=0; index < 256; index++) {
-	    int t = 0;
-
-	    if (index & 128) t |=   1;
-	    if (index &  64) t |=   2;
-	    if (index &  32) t |=   4;
-	    if (index &  16) t |=   8;
-	    if (index &   8) t |=  16;
-	    if (index &   4) t |=  32;
-	    if (index &   2) t |=  64;
-	    if (index &   1) t |= 128;
-
-	    reverseBitTable[index] = t;
-	}
-	firstCall = 0;
+        for (index=0; index < 256; index++) {
+            int t = 0;
+
+            if (index & 128) t |=   1;
+            if (index &  64) t |=   2;
+            if (index &  32) t |=   4;
+            if (index &  16) t |=   8;
+            if (index &   8) t |=  16;
+            if (index &   4) t |=  32;
+            if (index &   2) t |=  64;
+            if (index &   1) t |= 128;
+
+            reverseBitTable[index] = t;
+        }
+        firstCall = 0;
     }
 
     if (__bothSmallInteger(w, h) && _isNonNilObject(anArray)) {
-	newBitmap = (Pixmap)0;
-	b_width = __intVal(w);
-	b_height = __intVal(h);
-	bytesPerRow = (b_width + 7) / 8;
-	nBytes = b_height * bytesPerRow;
-	if (nBytes < sizeof(fastBits)) {
-	    cp = b_bits = fastBits;
-	    allocatedBits = 0;
-	} else {
-	    cp = b_bits = allocatedBits = (unsigned char *) malloc(nBytes);
-	    if (! cp) goto fail;
-	}
-
-	if (__isArrayLike(anArray)) {
-	    index = 1;
-	    op = &(__ArrayInstPtr(anArray)->a_element[index - 1]);
-	    for (row = b_height; row; row--) {
-		for (col = bytesPerRow; col; col--) {
-		    num = *op++;
-		    if (__isSmallInteger(num)) {
-			bits = __intVal(num);
-		    } else {
-			bits = __longIntVal(num);
-			if (bits == 0) {
-			    goto fail;
-			}
-		    }
-		    *cp++ = reverseBitTable[bits & 0xFF];
-		}
-	    }
-	} else {
-	    if (__isByteArrayLike(anArray)) {
-		pBits = __ByteArrayInstPtr(anArray)->ba_element;
-		for (col = b_height*bytesPerRow; col; col--) {
-		    *cp++ = reverseBitTable[*pBits++];
-		}
-	    } else {
-		goto fail;
-	    }
-	}
-
-
-	ENTER_XLIB();
-	newBitmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
-					       (char *)b_bits,
-					       b_width, b_height);
-	LEAVE_XLIB();
+        newBitmap = (Pixmap)0;
+        b_width = __intVal(w);
+        b_height = __intVal(h);
+        bytesPerRow = (b_width + 7) / 8;
+        nBytes = b_height * bytesPerRow;
+        if (nBytes < sizeof(fastBits)) {
+            cp = b_bits = fastBits;
+            allocatedBits = 0;
+        } else {
+            cp = b_bits = allocatedBits = (unsigned char *) malloc(nBytes);
+            if (! cp) goto fail;
+        }
+
+        if (__isArrayLike(anArray)) {
+            index = 1;
+            op = &(__ArrayInstPtr(anArray)->a_element[index - 1]);
+            for (row = b_height; row; row--) {
+                for (col = bytesPerRow; col; col--) {
+                    num = *op++;
+                    if (__isSmallInteger(num)) {
+                        bits = __intVal(num);
+                    } else {
+                        bits = __longIntVal(num);
+                        if (bits == 0) {
+                            goto fail;
+                        }
+                    }
+                    *cp++ = reverseBitTable[bits & 0xFF];
+                }
+            }
+        } else {
+            if (__isByteArrayLike(anArray)) {
+                pBits = __ByteArrayInstPtr(anArray)->ba_element;
+                for (col = b_height*bytesPerRow; col; col--) {
+                    *cp++ = reverseBitTable[*pBits++];
+                }
+            } else {
+                goto fail;
+            }
+        }
+
+
+        ENTER_XLIB();
+        newBitmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
+                                               (char *)b_bits,
+                                               b_width, b_height);
+        LEAVE_XLIB();
 #ifdef COUNT_RESOURCES
-	if (newBitmap)
-	    __cnt_bitmap++;
+        if (newBitmap)
+            __cnt_bitmap++;
 #endif
 
 
 fail: ;
-	if (allocatedBits)
-	    free(allocatedBits);
-	RETURN ( newBitmap ? __MKEXTERNALADDRESS(newBitmap) : nil );
+        if (allocatedBits)
+            free(allocatedBits);
+        RETURN ( newBitmap ? __MKEXTERNALADDRESS(newBitmap) : nil );
     }
 %}.
     ^ nil
@@ -3564,6 +3589,45 @@
 
 !XWorkstation methodsFor:'drawing'!
 
+clearRectangleX:x y:y width:width height:height in:aDrawableId with:aGCId
+    "clear (fill with background) a rectangle. If any coordinate is not integer, an error is triggered."
+
+    <context: #return>
+
+    operationsUntilFlush notNil ifTrue:[
+        operationsUntilFlush <= 0 ifTrue:[
+            self flush.
+        ] ifFalse:[
+            operationsUntilFlush := operationsUntilFlush - 1.
+        ].
+    ].
+%{
+
+    int w, h;
+
+    if (ISCONNECTED
+     && __isExternalAddress(aDrawableId)
+     && __bothSmallInteger(x, y)
+     && __bothSmallInteger(width, height)) {
+        w = __intVal(width);
+        h = __intVal(height);
+        /*
+         * need this check here: some servers simply dump core with bad args
+         */
+        if ((w >= 0) && (h >= 0)) {
+            ENTER_XLIB();
+            XClearArea(myDpy,
+                           __DrawableVal(aDrawableId),
+                           __intVal(x), __intVal(y), w, h, 0);
+            LEAVE_XLIB();
+        }
+        RETURN ( self );
+    }
+%}.
+    "badGC, badDrawable or coordinates not integer"
+    self primitiveFailedOrClosedConnection
+!
+
 copyFromId:sourceId x:srcX y:srcY gc:srcGCId to:destId x:dstX y:dstY gc:dstGCId width:w height:h
     "do a bit-blt; copy bits from the rectangle defined by
      srcX/srcY and w/h from the sourceId drawable to the rectangle
@@ -7805,7 +7869,7 @@
 	    ).
 
       Screen current
-	heightOf:'hello World gggÖÜ' from:1 to:15
+	heightOf:'hello World gggÖÜ' from:1 to:15
 	inFont:(Screen current getDefaultFontWithEncoding:#'iso10646-1')
     "
 !
@@ -13731,10 +13795,47 @@
     ^ true
 ! !
 
+!XWorkstation::X11GraphicsContext methodsFor:'accessing'!
+
+depth
+    ^ depth
+!
+
+xftDrawId
+    ^ xftDrawId
+! !
+
+!XWorkstation::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
+%}.
+! !
+
 !XWorkstation::X11GraphicsContext methodsFor:'displaying'!
 
-displayString:aString x:x y:y opaque:opaque
-    "draw a string - if opaque is false, draw foreground only; otherwise, draw both
+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."
 
@@ -13742,121 +13843,469 @@
 
     |displayId|
 
+    font isXftFont ifTrue:[
+        self displayDeviceXftString:aString from:index1 to:index2 x:x y:y opaque:opaque.
+        ^ self.
+    ].
+
     device flushIfAppropriate.
     displayId := device displayIdOrErrorIfBroken.
 
 %{
-#if 0
     GC gc;
     Window win;
     char *cp;
-    int n;
-    OBJ cls;
+    int  i1, i2, l, n;
 #   define NLOCALBUFFER 200
     XChar2b xlatebuffer[NLOCALBUFFER];
     int nInstBytes;
 
-    if (displayId != nil
+    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));
-
-	cp = (char *) __stringVal(aString);
-
-	if (__isStringLike(aString)) {
-	    n = __stringSize(aString);
-	    if (n > lMax) n = lMax;
-	    ENTER_XLIB();
-	    if (opaque == true)
-		XDrawImageString(dpy, win, gc, __intVal(x), __intVal(y), cp, n);
-	    else
-		XDrawString(dpy, win, gc, __intVal(x), __intVal(y), cp, n);
-	    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 (n > lMax) n = lMax;
-	    ENTER_XLIB();
-	    if (opaque == true)
-		XDrawImageString(dpy, win, gc, __intVal(x), __intVal(y), cp, n);
-	    else
-		XDrawString(dpy, win, gc, __intVal(x), __intVal(y), cp, n);
-	    LEAVE_XLIB();
-	    RETURN ( self );
-	}
-
-	/* TWOBYTESTRINGS */
-	if (__isWords(aString)) {
-	    union {
-		char b[2];
-		unsigned short s;
-	    } u;
-	    int i;
-	    XChar2b *cp2;
-	    int mustFree = 0;
-
-	    n = (__byteArraySize(aString) - nInstBytes) / 2;
-	    if (n > lMax) n = lMax;
+        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
-	     */
+                    /*
+                     * 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
-	    {
-		if (n <= NLOCALBUFFER) {
-		    cp2 = xlatebuffer;
-		} else {
-		    cp2 = (XChar2b *)(malloc(n * 2));
-		    mustFree = 1;
-		}
-
-		for (i=0; i<n; i++) {
-		    cp2[i].byte1 = (((XChar2b *)cp)[i]).byte2;
-		    cp2[i].byte2 = (((XChar2b *)cp)[i]).byte1;
-		}
-		cp = (char *) cp2;
-	    }
-#endif
-	    ENTER_XLIB();
-	    if (opaque == true)
-		XDrawImageString16(dpy, win, gc, __intVal(x), __intVal(y), (XChar2b *)cp, n);
-	    else
-		XDrawString16(dpy, win, gc, __intVal(x), __intVal(y), (XChar2b *)cp, n);
-	    LEAVE_XLIB();
-
-	    if (mustFree) {
-		free(cp2);
-	    }
-
-	    RETURN ( self );
-	}
+                    /*
+                     * 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
-#endif
-%}.
-    ^ super displayString:aString x:x y:y opaque:opaque
+%}.
+
+    "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 getFontId.
+
+%{ /* 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.
+    ].
+! !
+
+!XWorkstation::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
+! !
+
+!XWorkstation::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
 ! !
 
 !XWorkstation class methodsFor:'documentation'!