XWorkstation.st
branchjv
changeset 7541 39940e2446a5
parent 7491 b8d53ade8f6f
parent 7486 c3a1433996ec
child 7542 9e125aa140f9
--- a/XWorkstation.st	Thu Sep 01 23:27:10 2016 +0100
+++ b/XWorkstation.st	Mon Aug 01 23:30:02 2016 +0100
@@ -55,7 +55,7 @@
 !
 
 DeviceGraphicsContext subclass:#X11GraphicsContext
-	instanceVariableNames:'useXftFont xftDrawId'
+	instanceVariableNames:'depth xftDrawId'
 	classVariableNames:''
 	poolDictionaries:''
 	privateIn:XWorkstation
@@ -125,6 +125,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
@@ -200,7 +213,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
@@ -233,6 +252,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 ...
  */
@@ -270,20 +297,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
@@ -379,30 +406,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
@@ -526,6 +549,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)
@@ -535,50 +563,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
@@ -595,14 +621,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
     /*
@@ -630,16 +655,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;
 
@@ -651,16 +675,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__
 
 %}
 ! !
@@ -1819,10 +1844,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
@@ -2016,19 +2038,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.
@@ -2669,7 +2691,6 @@
 !
 
 primCreateBitmapFromArray:anArray width:w height:h
-
     <context: #return>
 
 %{  /* UNLIMITEDSTACK */
@@ -2685,93 +2706,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
@@ -3460,7 +3481,7 @@
     if (shape == @symbol(fourWay)) RETURN (  __MKSMALLINT(XC_fleur) );
     if (shape == @symbol(crossCursor)) RETURN (  __MKSMALLINT(XC_X_cursor) );
 %}.
-"/    ('XWorkstation [info]: invalid cursorShape:' , shape printString) infoPrintNL.
+"/    Logger info:'invalid cursorShape: %1' with:shape.
     ^  nil
 ! !
 
@@ -3475,128 +3496,128 @@
 
     (msgType := self atomIDOf:#DndProtocol) notNil ifTrue:[
 
-	"/ DND can drop files, file, dir, links, dirLink and text
-	"/ check for this.
-
-	dropObjects isCollection ifFalse:[
-	    dropColl := Array with:dropObjects
-	] ifTrue:[
-	    dropColl := dropObjects
-	].
-	anyFile := anyDir := anyText := anyOther := false.
-	dropColl do:[:aDropObject |
-	    aDropObject isFileObject ifTrue:[
-		aDropObject theObject isDirectory ifTrue:[
-		    anyDir := true
-		] ifFalse:[
-		    anyFile := true
-		]
-	    ] ifFalse:[
-		aDropObject isTextObject ifTrue:[
-		    anyText := true
-		] ifFalse:[
-		    anyOther := true
-		]
-	    ]
-	].
-
-	anyOther ifTrue:[
-	    "/ DND does not support this ...
-	    'XWorkstation [info]: DND can only drop files or text' infoPrintCR.
-	    ^ false
-	].
-	anyText ifTrue:[
-	    (anyFile or:[anyDir]) ifTrue:[
-		"/ DND does not support mixed types
-		'XWorkstation [info]: DND cannot drop both files and text' infoPrintCR.
-		^ false
-	    ]
-	].
-
-	dropCollSize := dropColl size.
-	anyFile ifTrue:[
-	    dropType := #DndFiles.
-	    dropCollSize == 1 ifTrue:[
-		dropType := #DndFile
-	    ]
-	] ifFalse:[
-	    anyDir ifTrue:[
-		dropType := #DndFiles.
-		dropCollSize == 1 ifTrue:[
-		    dropType := #DndDir
-		]
-	    ] ifFalse:[
-		anyText ifTrue:[
-		    dropCollSize == 1 ifTrue:[
-			dropType := #DndText
-		    ] ifFalse:[
-			"/ can only drop a single text object
-			'XWorkstation [info]: DND can only drop a single text' infoPrintCR.
-			^ false
-		    ]
-		] ifFalse:[
-		    "/ mhmh ...
-		    'XWorkstation [info]: DND cannot drop this' infoPrintCR.
-		    ^ false
-		]
-	    ]
-	].
-
-	dropTypeCode := self dndDropTypes indexOf:dropType.
-	dropTypeCode == 0 ifTrue:[
-	    'XWorkstation [info]: DND cannot drop this' infoPrintCR.
-	    ^ false
-	].
-	dropTypeCode := dropTypeCode - 1.
-
-
-	"/ place the selection inTo the DndSelection property
-	"/ of the rootView ...
-	"/ ... need a single string, with 0-terminated parts.
-
-	strings := OrderedCollection new.
-	sz := 0.
-	dropColl do:[:anObject |
-	    |s o|
-
-	    o := anObject theObject.
-	    anObject isFileObject ifTrue:[
-		o := o pathName
-	    ].
-	    s := o asString.
-	    strings add:s.
-	    sz := sz + (s size) + 1.
-	].
-	val := String new:sz.
-	idx := 1.
-	strings do:[:aString |
-	    |sz|
-
-	    sz := aString size.
-	    val replaceFrom:idx to:(idx + sz - 1) with:aString startingAt:1.
-	    idx := idx + sz.
-	    val at:idx put:(Character value:0).
-	    idx := idx + 1
-	].
-
-	self
-	    setProperty:(self atomIDOf:#DndSelection)
-	    type:(self atomIDOf:#STRING)
-	    value:val
-	    for:rootId.
-
-	^ self
-	    sendClientEvent:msgType
-	    format:32
-	    to:destinationId
-	    propagate:true
-	    eventMask:nil
-	    window:destinationId
-	    data1:dropTypeCode
-	    data2:0
-	    data3:destinationId
-	    data4:nil
-	    data5:nil.
+        "/ DND can drop files, file, dir, links, dirLink and text
+        "/ check for this.
+
+        dropObjects isCollection ifFalse:[
+            dropColl := Array with:dropObjects
+        ] ifTrue:[
+            dropColl := dropObjects
+        ].
+        anyFile := anyDir := anyText := anyOther := false.
+        dropColl do:[:aDropObject |
+            aDropObject isFileObject ifTrue:[
+                aDropObject theObject isDirectory ifTrue:[
+                    anyDir := true
+                ] ifFalse:[
+                    anyFile := true
+                ]
+            ] ifFalse:[
+                aDropObject isTextObject ifTrue:[
+                    anyText := true
+                ] ifFalse:[
+                    anyOther := true
+                ]
+            ]
+        ].
+
+        anyOther ifTrue:[
+            "/ DND does not support this ...
+            Logger info:'DND can only drop files or text'.
+            ^ false
+        ].
+        anyText ifTrue:[
+            (anyFile or:[anyDir]) ifTrue:[
+                "/ DND does not support mixed types
+                Logger info:'DND cannot drop both files and text'.
+                ^ false
+            ]
+        ].
+
+        dropCollSize := dropColl size.
+        anyFile ifTrue:[
+            dropType := #DndFiles.
+            dropCollSize == 1 ifTrue:[
+                dropType := #DndFile
+            ]
+        ] ifFalse:[
+            anyDir ifTrue:[
+                dropType := #DndFiles.
+                dropCollSize == 1 ifTrue:[
+                    dropType := #DndDir
+                ]
+            ] ifFalse:[
+                anyText ifTrue:[
+                    dropCollSize == 1 ifTrue:[
+                        dropType := #DndText
+                    ] ifFalse:[
+                        "/ can only drop a single text object
+                        Logger info:'DND can only drop a single text'.
+                        ^ false
+                    ]
+                ] ifFalse:[
+                    "/ mhmh ...
+                    Logger info:'DND cannot drop this'.
+                    ^ false
+                ]
+            ]
+        ].
+
+        dropTypeCode := self dndDropTypes indexOf:dropType.
+        dropTypeCode == 0 ifTrue:[
+            Logger info:'DND cannot drop this'.
+            ^ false
+        ].
+        dropTypeCode := dropTypeCode - 1.
+
+
+        "/ place the selection inTo the DndSelection property
+        "/ of the rootView ...
+        "/ ... need a single string, with 0-terminated parts.
+
+        strings := OrderedCollection new.
+        sz := 0.
+        dropColl do:[:anObject |
+            |s o|
+
+            o := anObject theObject.
+            anObject isFileObject ifTrue:[
+                o := o pathName
+            ].
+            s := o asString.
+            strings add:s.
+            sz := sz + (s size) + 1.
+        ].
+        val := String new:sz.
+        idx := 1.
+        strings do:[:aString |
+            |sz|
+
+            sz := aString size.
+            val replaceFrom:idx to:(idx + sz - 1) with:aString startingAt:1.
+            idx := idx + sz.
+            val at:idx put:(Character value:0).
+            idx := idx + 1
+        ].
+
+        self
+            setProperty:(self atomIDOf:#DndSelection)
+            type:(self atomIDOf:#STRING)
+            value:val
+            for:rootId.
+
+        ^ self
+            sendClientEvent:msgType
+            format:32
+            to:destinationId
+            propagate:true
+            eventMask:nil
+            window:destinationId
+            data1:dropTypeCode
+            data2:0
+            data3:destinationId
+            data4:nil
+            data5:nil.
     ].
 
     ^ false
@@ -3647,6 +3668,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
@@ -5266,9 +5326,9 @@
     dropType := (self dndDropTypes) at:dropType+1 ifAbsent:#DndNotDnd.
 
     property := self
-	getProperty:(self atomIDOf:#DndSelection)
-	from:rootId
-	delete:false.
+        getProperty:(self atomIDOf:#DndSelection)
+        from:rootId
+        delete:false.
 
     propertyType := property key.
     dropValue := property value.
@@ -5282,70 +5342,69 @@
     "/ in the default dropMessage handling of SimpleView.
 
     dropType == #DndFiles ifTrue:[
-	"/ actually, a list of fileNames
-	propertyType ~~ stringAtom ifTrue:[
-	    'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
-	    ^ self
-	].
-
-	names := OrderedCollection new.
-	i1 := 1.
-	[i1 ~~ 0] whileTrue:[
-	    i2 := dropValue indexOf:(Character value:0) startingAt:i1.
-	    i2 ~~ 0 ifTrue:[
-		names add:(dropValue copyFrom:i1 to:(i2-1)).
-		i1 := i2 + 1.
-	    ] ifFalse:[
-		i1 := i2
-	    ].
-	].
-	dropValue := names.
-	dropValue := dropValue collect:[:nm | nm asFilename].
-	dropType := #files.
+        "/ actually, a list of fileNames
+        propertyType ~~ stringAtom ifTrue:[
+            Logger info:'expected a string propertyValue in drop'.
+            ^ self
+        ].
+
+        names := OrderedCollection new.
+        i1 := 1.
+        [i1 ~~ 0] whileTrue:[
+            i2 := dropValue indexOf:(Character value:0) startingAt:i1.
+            i2 ~~ 0 ifTrue:[
+                names add:(dropValue copyFrom:i1 to:(i2-1)).
+                i1 := i2 + 1.
+            ] ifFalse:[
+                i1 := i2
+            ].
+        ].
+        dropValue := names.
+        dropValue := dropValue collect:[:nm | nm asFilename].
+        dropType := #files.
     ] ifFalse:[ (dropType == #DndFile) ifTrue:[
-	propertyType ~~ stringAtom ifTrue:[
-	    'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
-	    ^ self
-	].
-	dropValue := dropValue asFilename.
-	dropType := #file.
+        propertyType ~~ stringAtom ifTrue:[
+            Logger info:'expected a string propertyValue in drop'.
+            ^ self
+        ].
+        dropValue := dropValue asFilename.
+        dropType := #file.
     ] ifFalse:[ (dropType == #DndDir) ifTrue:[
-	propertyType ~~ stringAtom ifTrue:[
-	    'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
-	    ^ self
-	].
-	dropValue := dropValue asFilename.
-	dropType := #directory.
+        propertyType ~~ stringAtom ifTrue:[
+            Logger info:'expected a string propertyValue in drop'.
+            ^ self
+        ].
+        dropValue := dropValue asFilename.
+        dropType := #directory.
     ] ifFalse:[ (dropType == #DndText) ifTrue:[
-	propertyType ~~ stringAtom ifTrue:[
-	    'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
-	    ^ self
-	].
-	dropType := #text.
+        propertyType ~~ stringAtom ifTrue:[
+            Logger info:'expected a string propertyValue in drop'.
+            ^ self
+        ].
+        dropType := #text.
     ] ifFalse:[ (dropType == #DndExe) ifTrue:[
-	propertyType ~~ stringAtom ifTrue:[
-	    'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
-	    ^ self
-	].
-	dropType := #executable.
+        propertyType ~~ stringAtom ifTrue:[
+            Logger info:'expected a string propertyValue in drop'.
+            ^ self
+        ].
+        dropType := #executable.
     ] ifFalse:[ (dropType == #DndLink) ifTrue:[
-	propertyType ~~ stringAtom ifTrue:[
-	    'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
-	    ^ self
-	].
-	dropType := #link.
+        propertyType ~~ stringAtom ifTrue:[
+            Logger info:'expected a string propertyValue in drop'.
+            ^ self
+        ].
+        dropType := #link.
     ] ifFalse:[ (dropType == #DndRawData) ifTrue:[
-	dropType := #rawData.
+        dropType := #rawData.
     ] ifFalse:[
-	'XWorkstation [info]: unsupported dropType: ' infoPrint. dropType infoPrintCR.
-	'XWorkstation [info]: data: ' infoPrint. dropValue infoPrintCR.
-	dropType := #unknown.
+        Logger info:'unsupported dropType: %1 data: %2 ' with:dropType with:dropValue.
+        dropType := #unknown.
     ]]]]]]].
 
     sensor := targetView sensor.
     "not posted, if there is no sensor ..."
     sensor notNil ifTrue:[
-	sensor dropMessage:dropType data:dropValue view:targetView position:nil handle:nil
+        sensor dropMessage:dropType data:dropValue view:targetView position:nil handle:nil
     ].
 
     "Created: 4.4.1997 / 17:59:37 / cg"
@@ -9198,7 +9257,7 @@
     This remapping kludge is here to have all the widget's code backward/windows
     compatible while still having X11's middle button behavior.
 
-    Also note, that buttonTranslation is overwritten in display.rc,
+    Also note that buttonTranslation is overwritten in display.rc,
     the code is here just for a case display.rc is not read/available
     and for documentation (symbol references does not search .rc files).
     "
@@ -11660,21 +11719,20 @@
     buffer := self perform:bufferGetSelector.
 
     (aTargetAtomID == (self atomIDOf:#'ST_OBJECT')) ifTrue:[
-	"/ 'st-object' printCR.
-	"send the selection in binaryStore format"
-	"require libboss to be loaded"
-	(Smalltalk isClassLibraryLoaded:'libstx_libboss') ifFalse:[
-	    'XWorkstation: cannot use binary store for copy buffer (libboss missing)' errorPrintCR.
-	    ^ nil -> nil.
-	].
-
-	[
-	    ^ aTargetAtomID -> (buffer binaryStoreBytes).
-	] on:Error do:[:ex|
-	    'XWorkstation: error on binary store of copy buffer: ' infoPrint.
-	    ex description infoPrintCR.
-	    ^ nil -> nil.
-	].
+        "/ 'st-object' printCR.
+        "send the selection in binaryStore format"
+        "require libboss to be loaded"
+        (Smalltalk isClassLibraryLoaded:'libstx_libboss') ifFalse:[
+            Logger error:'cannot use binary store for copy buffer (libboss missing)'.
+            ^ nil -> nil.
+        ].
+
+        [
+            ^ aTargetAtomID -> (buffer binaryStoreBytes).
+        ] on:Error do:[:ex|
+            Logger info:'error on binary store of copy buffer: %1' with: ex description.
+            ^ nil -> nil.
+        ].
     ].
 
     bufferAsString := self class bufferAsString:buffer.
@@ -11682,25 +11740,25 @@
     (aTargetAtomID == (self atomIDOf:#STRING)
      or:[aTargetAtomID == (self atomIDOf:#'text/plain')]
     ) ifTrue:[
-	"/ 'string' printCR.
-	"the other view wants the selection as string"
-	^ aTargetAtomID -> (bufferAsString asSingleByteStringReplaceInvalidWith:$#).
+        "/ 'string' printCR.
+        "the other view wants the selection as string"
+        ^ aTargetAtomID -> (bufferAsString asSingleByteStringReplaceInvalidWith:$#).
     ].
 
     (aTargetAtomID == (self atomIDOf:#UTF8_STRING)
      or:[aTargetAtomID == (self atomIDOf:#'text/plain;codeset=utf-8')]
     ) ifTrue:[
-	"/ 'utf string' printCR.
-	"the other view wants the selection as utf8 string"
-	^ aTargetAtomID -> (bufferAsString utf8Encoded).
+        "/ 'utf string' printCR.
+        "the other view wants the selection as utf8 string"
+        ^ aTargetAtomID -> (bufferAsString utf8Encoded).
     ].
 
     aTargetAtomID == (self atomIDOf:#LENGTH) ifTrue:[
-	"the other one wants to know the size of our selection.
-	 LENGTH is deprecated, since we do not know how the selection is
-	 going to be converted. The client must not rely on the length returned"
-
-	^ (self atomIDOf:#INTEGER) -> (bufferAsString size).
+        "the other one wants to know the size of our selection.
+         LENGTH is deprecated, since we do not know how the selection is
+         going to be converted. The client must not rely on the length returned"
+
+        ^ (self atomIDOf:#INTEGER) -> (bufferAsString size).
     ].
 
     "we do not support the requestet target type"
@@ -13852,10 +13910,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."
 
@@ -13863,121 +13958,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 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.
+    ].
+! !
+
+!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'!