XWorkstat.st
author Claus Gittinger <cg@exept.de>
Wed, 06 Dec 1995 15:12:16 +0100
changeset 277 eb67c44da084
parent 268 070f61898aab
child 288 5d49b00f2bad
permissions -rw-r--r--
testing new inline-expression feature of stc - no real change

"
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.
"

DeviceWorkstation subclass:#XWorkstation
       instanceVariableNames:'screen
			      hasShapeExtension hasFaxExtension hasShmExtension
			      hasDPSExtension hasMbufExtension hasXVideoExtension
			      hasSaveUnder hasPEXExtension hasImageExtension
			      hasInputExtension ignoreBackingStore
			      blackpixel whitepixel 
			      protocolsAtom deleteWindowAtom saveYourselfAtom
			      quitAppAtom
			      primaryAtom secondaryAtom cutBuffer0Atom
			      stringAtom lengthAtom
			      listOfXFonts buttonsPressed
			      eventRootX eventRootY
			      displayName eventTrace
			      dispatchingExpose
			      rgbVisual virtualRootId rootId
			      eventBuffer
			      altModifierMask metaModifierMask'
       classVariableNames:   'RawKeysymTranslation'
       poolDictionaries:''
       category:'Interface-Graphics'
!

!XWorkstation class methodsFor:'documentation'!

copyright
"
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.
"
!

version
    ^ '$Header: /cvs/stx/stx/libview/Attic/XWorkstat.st,v 1.84 1995-12-06 14:12:16 cg Exp $'
!

documentation
"
    this class provides the interface to X11. It redefines all required methods
    from DeviceWorkstation. Notice, that in Smalltalk/X you are not technically
    limited to one display - in theory, you can create Views on many displays
    simultanously. However, the default setup is for one display only.
    To support multiple displays, you will have to start another event dispatcher
    process for the other display(s) and create the other views with a slightly
    different protocol. However, 'normal' applications do not have to care for
    all of this ...

    See more documentation in my superclass, DeviceWorkstation.
"
! !

!XWorkstation primitiveDefinitions!

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

#ifdef memset
# undef memset
#endif

#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>

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

#include <X11/cursorfont.h>

/*
 * this define adds support for two-byte-strings.
 * leaving it undefined does not really save you much
 * (the define will vanish)
 */
#define TWOBYTESTRINGS

/*
 * 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

/*
 * this is a non-standard fax-image decompression extension
 * (only found in megascan servers ported by myself)
 */
#ifdef FAX
# include <X11/extensions/XFAXImage.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

/*
 * 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(IRIX5) || (XlibSpecificationRelease == 6)
  /*
   * accessing private data in Display ... sorry
   */
# define DISPLAYACCESS(d) ((_XPrivDisplay)d)
#else
# define DISPLAYACCESS(d) d
#endif

/*
 * some defines - tired of typing ...
 */
#define _DisplayVal(o)       (Display *)(__MKCP(o))
#define _WindowVal(o)        (Window)(__MKCP(o))
#define _PixmapVal(o)        (Pixmap)(__MKCP(o))
#define _GCVal(o)            (GC)(__MKCP(o))
#define _CursorVal(o)        (Cursor)(__MKCP(o))
#define _FontVal(o)          (XFontStruct *)(__MKCP(o))
#define _DPSContextVal(o)    (DPSContext)(__MKCP(o))

#define __MKATOMOBJ(a)       __MKSMALLINT(a)
#define _AtomVal(o)          __intVal(o)
#define __isAtomID(o)        __isSmallInteger(o)

#define myDpy                _DisplayVal(_INST(displayId))
#define ISCONNECTED          (_INST(displayId) != nil)

#ifndef THISCONTEXT_IN_REGISTER
# define BEGIN_INTERRUPTSBLOCKED /* */
# define END_INTERRUPTSBLOCKED /* */
#else
extern int __interruptsBlocked;
# define BEGIN_INTERRUPTSBLOCKED        \
    {                                   \
	int needUnblock = 0;            \
	extern OBJ __thisContext__;     \
					\
	__thisContext__ = __thisContext;\
	if (!__interruptsBlocked) {     \
	    __BLOCKINTERRUPTS();        \
	    needUnblock = 1;            \
	}

# define END_INTERRUPTSBLOCKED          \
	__thisContext = __thisContext;  \
	__thisContext__ = 0;            \
	if (needUnblock) {              \
	    __UNBLOCKINTERRUPTS();      \
	}                               \
    }

#endif
%}
! !

!XWorkstation primitiveVariables!

%{
/*
 * remembered info from private error handler
 */
static char lastErrorMsg[80] = "";
static unsigned lastRequestCode = 0;
static unsigned lastMinorCode = 0;
static unsigned lastResource = 0;

static int __debug__ = 0;
#define DPRINTF(x)      if (__debug__) { printf x; }
%}
! !

!XWorkstation primitiveFunctions!

%{
/*
 * catch X-errors and forward as errorInterrupt:#DisplayError,
 * (which itself invokes my handler and optionally raises an exceptionSignal)
 * the implementation below is somewhat wrong: it will
 * report all errors for Display, even though there could be
 * more than one display connection. (being fixed, new errorInterrupt mechanism
 * allows passing an additional argument, which is the displayID ...)
 */
static
__XErrorHandler__(dpy, event)
    Display *dpy;
    XErrorEvent *event;
{
#ifdef _AIX
printf("XError\n"); fflush(stdout);
#endif
    XGetErrorText(dpy, event->error_code, lastErrorMsg, 80);
    if (lastErrorMsg[0] == '\0') {
	sprintf(lastErrorMsg, "code: %d", event->error_code);
    }
    lastRequestCode = event->request_code;
    lastMinorCode = event->minor_code;
    lastResource = event->resourceid;

    if (@global(ErrorPrinting) == true) {
	fprintf(stderr, "XWORKSTAT: x-error cought maj=%d (0x%x) min=%d (0x%x) resource=%x\n",
			event->request_code, event->request_code, 
			event->minor_code, event->minor_code, event->resourceid);
	fprintf(stderr, "XWORKSTAT: x-error message is '%s'\n", lastErrorMsg);
    }

    __errorInterruptWithIDAndParameter__(@symbol(DisplayError), __MKOBJ(dpy));
    return 0;
}

#ifdef VIRTUAL_ROOT
/*
 * added since RootWindow-macro is not suficient
 * when virtual root-windows are involved (i.e. tvtwm)
 */
static Window
getRootWindow(dpy, screen)
    Display *dpy;
{
    Window root;
    Atom vRootAtom = None;
    int i;
    Window rootReturn, parentReturn;
    Window* children;
    unsigned int numChildren;

    root = RootWindow(dpy, screen);
    /*
     * on IRIS, this creates a badwindow error - why ?
     * children contains a funny window (000034)
     */
# if !defined(IRIS) || defined(IRIX5)
    if (XQueryTree(dpy, root, &rootReturn, &parentReturn, &children, &numChildren)) {
	vRootAtom = XInternAtom(dpy, "__SWM_VROOT", True );
	if (vRootAtom != None) {
	    for (i=0; i < numChildren; i++) {
		Atom actual_type;
		int actual_format;
		unsigned long nitems, bytesafter;
		Window* newRoot = (Window*) 0;

		if (children[i]) {
		    if (XGetWindowProperty(dpy, children[i], vRootAtom,
					   0L, 1L, False, XA_WINDOW,
					   &actual_type, &actual_format, &nitems, &bytesafter,
					   (unsigned char**) &newRoot) == Success && newRoot) {
			root = *newRoot;
			break;
		    }
		}
	    }
	    if (children) XFree( children );
	}
    }
# endif
    return root;
}
#endif
%}
! !

!XWorkstation class methodsFor:'initialization'!

initialize
    |d|

    super initialize.

    "/ the following table maps X-keyevents to ST/X
    "/ device independed events. 
    "/ It is NOT meant as a keyboardMap replacement.

    RawKeysymTranslation := d := Dictionary new.
    d at:'Delete_line' put:#DeleteLine.
    d at:'Delete_word' put:#DeleteWord.
    d at:'Down' put:#CursorDown.
    d at:'Up' put:#CursorUp.
    d at:'Left' put:#CursorLeft.
    d at:'Right' put:#CursorRight.
! !

!XWorkstation class methodsFor:'error handling'!

debug:aBoolean
%{  /* NOCONTEXT */

    __debug__ = (aBoolean == true) ? 1 : 0;
%}
!

requestCodeOfLastError
%{  /* NOCONTEXT */

    RETURN ( _MKSMALLINT(lastRequestCode) );
%}
!

minorCodeOfLastError
%{  /* NOCONTEXT */

    RETURN ( _MKSMALLINT(lastMinorCode) );
%}
!

resourceIdOfLastError
%{  /* NOCONTEXT */

    RETURN ( __MKOBJ(lastResource) );
%}
!

errorStringOfLastError
%{
    RETURN ( __MKSTRING(lastErrorMsg COMMA_CON) );
%}
!

lastErrorString
    "return the last X-error string - 
     when buffering is on, this may be
     an error for a long-ago operation"

    |string requestCode s match line|

    string := self errorStringOfLastError.
    requestCode := self requestCodeOfLastError.
    "
     X specific: search the requestCode in '/usr/lib/X11/XErrorDB',
     and append the name of the corresponding X-request
    "
    s := '/usr/lib/X11/XErrorDB' asFilename readStream.
    s notNil ifTrue:[
	match := 'XRequest.' , requestCode printString.
	line := s peekForLineStartingWith:match.
	line notNil ifTrue:[
	    string := string , ' in ' , (line copyFrom:(line indexOf:$:)+1)
	].
	s close.
    ].
    ^ string
! !

!XWorkstation methodsFor:'initialize / release'!

initializeFor:aDisplayName
    "initialize the receiver for a connection to an X-Server;
     the argument, aDisplayName may be nil (for the default server from
     DISPLAY-variable or command line argument) or the name of the server 
     as hostname:number"

    |dpyName index|

    dpyName := aDisplayName.
    dpyName isNil ifTrue:[
	"look for a '-display xxx' argument"
	Arguments notNil ifTrue:[
	    index := Arguments indexOf:'-display'.
	    (index between:1 and:(Arguments size - 1)) ifTrue:[
		dpyName := Arguments at:index+1
	    ]
	]
    ].
%{
    int scr;
    Display *dpy;
    Visual *visual;
    XVisualInfo viproto;
    XVisualInfo *vip;                   /* retured info */
    int maxRGBDepth;
    int rgbRedMask, rgbGreenMask, rgbBlueMask;
    int rgbVisualID;
    int nvi, i;
    int shapeEventBase, shapeErrorBase;
    int shmEventBase, shmErrorBase;
    int faxEventBase, faxErrorBase;
    char *type, *nm;
    int dummy;
    OBJ dpyID;

    if (_INST(displayId) != nil) {
	/*
	 * already connected - you bad guy try to
	 * trick me manually ?
	 */
	RETURN ( self );
    }

    BEGIN_INTERRUPTSBLOCKED

    if (__isString(dpyName))
	nm = (char *)_stringVal(dpyName);
    else {
	dpyName = __MKSTRING((char *)getenv("DISPLAY") COMMA_CON);
	nm = NULL;
    }
    dpy = XOpenDisplay(nm);

    if (dpy) {
	_INST(displayId) = dpyID = __MKOBJ(dpy); __STORE(self, dpyID);

#ifdef SUPERDEBUG
	XSynchronize(dpy, 1);
#endif

	XSetErrorHandler(__XErrorHandler__);
    }

    END_INTERRUPTSBLOCKED
%}.
    displayId isNil ifTrue:[
	'XWORKSTATION: cannot connect to Display.' errorPrintNL.
	^ nil
    ].

    self initializeScreenProperties.

    dispatching := false.
    dispatchingExpose := false.
    isSlow := false.
    shiftDown := false.
    ctrlDown := false.
    metaDown := false.
    altDown := false.
    motionEventCompression := true.
    buttonsPressed := 0.
    displayName := dpyName.

    protocolsAtom := nil.
    deleteWindowAtom := nil.
    saveYourselfAtom := nil.
    quitAppAtom := nil.

    self initializeDefaultValues.
    self initializeEventBuffer.
    self initializeSpecialFlags.
    self initializeKeyboardMap.

    ObjectMemory registerErrorInterruptHandler:self class forID:#DisplayError.
!

initializeDefaultValues
    buttonTranslation := ButtonTranslation.
    multiClickTimeDelta := MultiClickTimeDelta.

    "/ these should be queried from the server
    "/ (this will soon be done) - for now, take standard values

    altModifiers := #(Alt_L Alt_R).
    metaModifiers := #(Meta_L Meta_R).
    ctrlModifiers := #(Control_L Control_R).
    shiftModifiers := #(Shift_L Shift_R).
!

initializeEventBuffer
    |sz|

%{
    sz = _MKSMALLINT(sizeof(XEvent) + 100);
%}.
    eventBuffer isNil ifTrue:[
	eventBuffer := ByteArray new:sz.
    ].
!

initializeScreenProperties
%{  /* NOCONTEXT */

    Display *dpy = myDpy;
    int scr;
    Visual *visual;
    XVisualInfo viproto;
    XVisualInfo *vip;                   /* retured info */
    int maxRGBDepth;
    int rgbRedMask, rgbGreenMask, rgbBlueMask;
    int rgbVisualID;
    int nvi, i;
    int shapeEventBase, shapeErrorBase;
    int shmEventBase, shmErrorBase;
    int faxEventBase, faxErrorBase;
    char *type, *nm;
    int dummy;
    int mask, shift, nBits;

    if (ISCONNECTED) {
	_INST(altModifierMask) = __MKSMALLINT(Mod2Mask);
	_INST(metaModifierMask) = __MKSMALLINT(Mod1Mask);

	BEGIN_INTERRUPTSBLOCKED

	_INST(screen) = _MKSMALLINT(scr = DefaultScreen(dpy));
	_INST(depth) = _MKSMALLINT(DisplayPlanes(dpy, scr));
	_INST(ncells) = _MKSMALLINT(DisplayCells(dpy, scr));
	_INST(width) = _MKSMALLINT(DisplayWidth(dpy, scr));
	_INST(height) = _MKSMALLINT(DisplayHeight(dpy, scr));
	_INST(widthMM) = _MKSMALLINT(DisplayWidthMM(dpy, scr));
	_INST(heightMM) = _MKSMALLINT(DisplayHeightMM(dpy, scr));
	_INST(blackpixel) = _MKSMALLINT(BlackPixel(dpy, scr));
	_INST(whitepixel) = _MKSMALLINT(WhitePixel(dpy, scr));

#ifdef SHAPE
	if (XShapeQueryExtension(dpy, &shapeEventBase, &shapeErrorBase))
	    _INST(hasShapeExtension) = true;
	else
#endif
	  _INST(hasShapeExtension) = false;

#ifdef SHM
	if (XShmQueryExtension(dpy, &shmEventBase, &shmErrorBase))
	    _INST(hasShmExtension) = true;
	else
#endif
	  _INST(hasShmExtension) = false;

#ifdef FAX
	if (XFAXImageQueryExtension(dpy, &faxEventBase, &faxErrorBase))
	    _INST(hasFaxExtension) = true;
	else
#endif
	  _INST(hasFaxExtension) = false;

#ifdef DPS
	if (XQueryExtension(dpy, "DPSExtension", &dummy, &dummy, &dummy))
	    _INST(hasDPSExtension) = true;
	else
#endif
	  _INST(hasDPSExtension) = false;

#ifdef XVIDEO
	if (XQueryExtension(dpy, "XVideo", &dummy, &dummy, &dummy))
	    _INST(hasXVideoExtension) = true;
	else
#endif
	  _INST(hasXVideoExtension) = false;

#ifdef MBUF
	if (XQueryExtension(dpy, "Multi-Buffering", &dummy, &dummy, &dummy))
	    _INST(hasMbufExtension) = true;
	else
#endif
	  _INST(hasMbufExtension) = false;

#ifdef PEX5
	if (XQueryExtension(dpy, PEX_NAME_STRING, &dummy, &dummy, &dummy))
	    _INST(hasPEXExtension) = true;
	else
#endif
	  _INST(hasPEXExtension) = false;

#ifdef XIE
	if (XQueryExtension(dpy, xieExtName, &dummy, &dummy, &dummy))
	    _INST(hasImageExtension) = true;
	else
#endif
	  _INST(hasImageExtension) = false;

#ifdef XI
	if (XQueryExtension(dpy, "XInputExtension", &dummy, &dummy, &dummy))
	    _INST(hasInputExtension) = true;
	else
#endif
	  _INST(hasInputExtension) = false;

	/*
	 * look for RGB visual
	 */
	nvi = 0;
	viproto.screen = scr;
	vip = XGetVisualInfo (dpy, VisualScreenMask, &viproto, &nvi);
	maxRGBDepth = 0;
	for (i = 0; i < nvi; i++) {
	    switch (vip[i].class) {
		case TrueColor:
		    if (vip[i].depth > maxRGBDepth) {
			maxRGBDepth = vip[i].depth;
			rgbRedMask = vip[i].red_mask;
			rgbGreenMask = vip[i].green_mask;
			rgbBlueMask = vip[i].blue_mask;
			rgbVisualID = vip[i].visualid;
		    }
		    break;
	    }
	}
	if (vip) XFree ((char *) vip);

	if (maxRGBDepth) {
	    _INST(rgbVisual) = __MKOBJ(rgbVisualID); __STORESELF(rgbVisual);
	}

	visual = DefaultVisualOfScreen(DefaultScreenOfDisplay(dpy));
	_INST(monitorType) = @symbol(unknown);
	_INST(hasColors) = true;
	_INST(hasGreyscales) = true;
	switch (visual->class) {
	    case StaticGray:
		_INST(visualType) = @symbol(StaticGray);
		_INST(hasColors) = false;
		_INST(monitorType) = @symbol(monochrome);
		break;
	    case GrayScale:
		_INST(visualType) = @symbol(GrayScale);
		_INST(hasColors) = false;
		_INST(monitorType) = @symbol(monochrome);
		break;
	    case StaticColor:
		_INST(visualType) = @symbol(StaticColor);
		break;
	    case PseudoColor:
		_INST(visualType) = @symbol(PseudoColor);
		break;
	    case TrueColor:
		_INST(visualType) = @symbol(TrueColor);
		break;
	    case DirectColor:
		_INST(visualType) = @symbol(DirectColor);
		break;
	}
	if (DisplayCells(dpy, scr) == 2) {
	    _INST(hasColors) = false;
	    _INST(hasGreyscales) = false;
	    _INST(monitorType) = @symbol(monochrome);
	}
	_INST(bitsPerRGB) = _MKSMALLINT(visual->bits_per_rgb);
	_INST(redMask)   = _MKSMALLINT(visual->red_mask);
	_INST(greenMask) = _MKSMALLINT(visual->green_mask);
	_INST(blueMask)  = _MKSMALLINT(visual->blue_mask);
	switch (visual->class) {
	    case TrueColor:
		/* extract number of bits and shift counts */
		mask = visual->red_mask;
		shift = 0;
		while (mask && ((mask & 1) == 0)) {
		    mask >>= 1;
		    shift++;
		}
		_INST(redShift) = __MKSMALLINT(shift);
		nBits = 0;
		while (mask) {
		    mask >>= 1;
		    nBits++;
		}
		_INST(bitsRed) = __MKSMALLINT(nBits);

		mask = visual->green_mask;
		shift = 0;
		while (mask && ((mask & 1) == 0)) {
		    mask >>= 1;
		    shift++;
		}
		_INST(greenShift) = __MKSMALLINT(shift);
		nBits = 0;
		while (mask) {
		    mask >>= 1;
		    nBits++;
		}
		_INST(bitsGreen) = __MKSMALLINT(nBits);

		mask = visual->blue_mask;
		shift = 0;
		while (mask && ((mask & 1) == 0)) {
		    mask >>= 1;
		    shift++;
		}
		_INST(blueShift) = __MKSMALLINT(shift);
		nBits = 0;
		while (mask) {
		    mask >>= 1;
		    nBits++;
		}
		_INST(bitsBlue) = __MKSMALLINT(nBits);
		break;
	}

#ifndef XA_PRIMARY
	_INST(primaryAtom) = __MKATOMOBJ( XInternAtom(dpy, "PRIMARY", True) );
#else
	_INST(primaryAtom) = __MKATOMOBJ( XA_PRIMARY );
#endif
#ifndef XA_SECONDARY
	_INST(secondaryAtom) = __MKATOMOBJ( XInternAtom(dpy, "SECONDARY", True) );
#else
	_INST(secondaryAtom) = __MKATOMOBJ( XA_SECONDARY );
#endif
#ifndef XA_CUT_BUFFER0
	_INST(cutBuffer0Atom) = __MKATOMOBJ( XInternAtom(dpy, "CUT_BUFFER0", True) );
#else
	_INST(cutBuffer0Atom) = __MKATOMOBJ( XA_CUT_BUFFER0 );
#endif
#ifndef XA_STRING
	_INST(stringAtom) = __MKATOMOBJ( XInternAtom(dpy, "STRING", True) );
#else
	_INST(stringAtom) = __MKATOMOBJ( XA_STRING );
#endif
#ifndef XA_LENGTH
	_INST(lengthAtom) = __MKATOMOBJ( XInternAtom(dpy, "LENGTH", True) );
#else
	_INST(lengthAtom) = __MKATOMOBJ( XA_LENGTH );
#endif

	END_INTERRUPTSBLOCKED
    }
%}
!

initializeSpecialFlags
    "perform additional special server implementation flags"

    "/
    "/ assume we have it ... (should check)
    "/
    hasSaveUnder := true.
    ignoreBackingStore := false.

    (self serverVendor = 'X11/NeWS') ifTrue:[
	"/
	"/ this is a kludge around a bug in the X11/NeWS server,
	"/ which does not correctly handle saveUnder
	"/
	hasSaveUnder := false.
    ].
!

close
    "close down the connection to the X-server"

%{  /* NOCONTEXT */

    if (ISCONNECTED) {
	BEGIN_INTERRUPTSBLOCKED
	XCloseDisplay(myDpy);
	_INST(displayId) = nil;
	END_INTERRUPTSBLOCKED
    }
%}
!

reinitialize
    virtualRootId := rootId := nil.
    super reinitialize.
    dispatchingExpose := nil
! !

!XWorkstation methodsFor:'misc'!

setInputFocusTo:aWindowId
"/    self setInputFocusTo:aWindowId revertTo:#parent
    self setInputFocusTo:aWindowId revertTo:#root
!

setInputFocusTo:aWindowId revertTo:revertSymbol
    "set the focus to the view as defined by aWindowId.
     Passing nil set the focus to no window and lets the display discard all
     input until a new focus is set.
     RevertSymbol specifies what should happen if the view becomes invisible;
     passing one of #parent, #root or nil specifies that the focus should be
     given to the parent view, the root view or no view."

%{  /* NOCONTEXT */
    int arg;
    Window focusWindow;

    if (ISCONNECTED) {
        if (__isExternalAddress(aWindowId)) {
	    focusWindow = _WindowVal(aWindowId);
	} else {
	    focusWindow = None;
	}
	if (revertSymbol == @symbol(parent))
	    arg = RevertToParent;
	else if (revertSymbol == @symbol(root))
	    arg = RevertToPointerRoot;
	else 
	    arg = RevertToNone;

	BEGIN_INTERRUPTSBLOCKED
	XSetInputFocus(myDpy, focusWindow, arg, CurrentTime);
	END_INTERRUPTSBLOCKED
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

unBuffered
    "make all drawing be sent immediately to the display"

%{  /* NOCONTEXT */

    if (ISCONNECTED) {
	BEGIN_INTERRUPTSBLOCKED
	XSynchronize(myDpy, 1);
	END_INTERRUPTSBLOCKED
    }
%}
    "Display unbuffered"
!

buffered
    "buffer drawing - do not send it immediately to the display.
     This is the default anyway."

%{  /* NOCONTEXT */

    if (ISCONNECTED) {
	BEGIN_INTERRUPTSBLOCKED
	XSynchronize(myDpy, 0);
	END_INTERRUPTSBLOCKED
    }
%}
    "Display buffered"
!

flush
    "send all buffered drawing to the display.
     This may be required to make certain, that all previous operations
     are really sent to the display before continuing. For example,
     after a cursor-change with a followup long computation.
     (otherwise, the cursor change request may still be in the output
      buffer)"

%{  /* NOCONTEXT */

    if (ISCONNECTED) {
	BEGIN_INTERRUPTSBLOCKED
	XSync(myDpy, 0);
	END_INTERRUPTSBLOCKED
    }
%}
!

flushDpsContext:aDPSContext

%{  /* NOCONTEXT */
#ifdef DPS
    if (__isExternalAddress(aDPSContext)) {
	BEGIN_INTERRUPTSBLOCKED
	DPSFlushContext(MKDPSCONTEXT(aDPSContext));
	END_INTERRUPTSBLOCKED
	RETURN ( self );
    }
#endif
%}
.
    self primitiveFailed
!

beep:volumeInPercent
    "output an audible beep"
%{
    int volume;

    if (__isSmallInteger(volumeInPercent) && ISCONNECTED) {
	/* stupid: X wants -100 .. 100 and calls this percent */
	volume = _intVal(volumeInPercent) * 2 - 100;
	if (volume < -100) volume = -100;
	else if (volume > 100) volume = 100;
	BEGIN_INTERRUPTSBLOCKED
	XBell(myDpy, volume);
	END_INTERRUPTSBLOCKED
    }
%}
!

beep
    "output an audible beep or bell"

    self beep:50
!

ignoreBackingStore:aBoolean
    "if the argument is true, the views backingStore setting will be ignored, and
     no backing store used - this can be used on servers where backing store is
     very slow or is broken (can be put into display-rc-file)"

    ignoreBackingStore := aBoolean
! !

!XWorkstation class methodsFor:'queries'!

platformName
    "ST-80 compatibility.
     Return a string describing the display systems platform."

    ^ 'X'  "I don't know what ST-80 returns for X ..."
! !

!XWorkstation methodsFor:'keyboard mapping'!

translateKey:untranslatedKey
    "Return the key translated via the translation table.
     Here, we preTranslate the key into a common ST/X symbolic name, 
     which gets further processed in the superclasses translation method."

    |key|

    (key := untranslatedKey) isString ifTrue:[
	key := RawKeysymTranslation at:key ifAbsent:key.
	key := key asSymbol.
    ].
    ^ super translateKey:key 
! !

!XWorkstation methodsFor:'accessing & queries'!

displayFileDescriptor
    "return the displays fileNumber - for select"

%{  /* NOCONTEXT */

    if (ISCONNECTED) {
	RETURN ( __MKSMALLINT(ConnectionNumber(myDpy)) );
    }
    RETURN (nil);
%}
!

displayName
    "return the X-connections display name.
     This is (currently) nil for the default display, 
     something like foo:0 for any other remote display.
     Future versions may return non-nil strings for the default display as well."

    ^ displayName
!

serverVendor
    "return the X-server vendor string - this should normally not be of
     any interrest, but can be for special cases
     (to avoid bugs in certain implementations)"
%{
    if (ISCONNECTED) {
	RETURN ( __MKSTRING(XServerVendor(myDpy) COMMA_CON) );
    }
    RETURN (nil);
%}

    "
     Display serverVendor
    "
!

vendorRelease
    "return the X-servers vendor release - should normally not be of
     any interrest, but can be for special cases.
     (to avoid bugs in certain implementations)"

%{  /* NOCONTEXT */
    if (ISCONNECTED) {
	RETURN ( _MKSMALLINT(XVendorRelease(myDpy)) );
    }
    RETURN (nil);
%}

    "
     Display vendorRelease
    "
!

protocolVersion
    "return the X-servers protocol version - should normally not be of
     any interrest"

%{  /* NOCONTEXT */
    if (ISCONNECTED) {
	RETURN ( _MKSMALLINT(XProtocolVersion(myDpy)) );
    }
    RETURN (nil);
%}

    "
     Display protocolVersion
    "
!

hasShape
    "return true, if this workstation supports non-rectangular windows.
     Both the server must support it, and the feature must have been
     enabled in the smalltalk system, for true to be returned."

    ^ hasShapeExtension

    "
     Display hasShape   
    "
!

hasShm
    "return true, if this workstation supports the shared pixmap extension.
     Both the server must support it, and the feature must have been
     enabled in the smalltalk system, for true to be returned."

    ^ hasShmExtension

    "
     Display hasShm 
    "
!

hasFax
    "return true, if this workstation supports decompression of fax images.
     Both the server must support it, and the feature must have been
     enabled in the smalltalk system, for true to be returned."

    ^ hasFaxExtension

    "
     Display hasFaxExtension
    "
!

hasDPS
    "return true, if this workstation supports display postscript.
     Both the server must support it, and the feature must have been
     enabled in the smalltalk system, for true to be returned."

    ^ hasDPSExtension

    "
     Display hasDPS 
    "
!

hasPEX
    "return true, if this workstation supports PEX 3D graphics.
     Both the server must support it, and the feature must have been
     enabled in the smalltalk system, for true to be returned."

    ^ hasPEXExtension

    "
     Display hasPEX 
    "
!

hasMultibuffer
    "return true, if this workstation supports the multibuffer extension.
     Both the server must support it, and the feature must have been
     enabled in the smalltalk system, for true to be returned."

    ^ hasMbufExtension

    "
     Display hasMultibuffer 
    "
!

hasInputExtension
    "return true, if this workstation supports the X input extension.
     Both the server must support it, and the feature must have been
     enabled in the smalltalk system, for true to be returned."

    ^ hasInputExtension

    "
     Display hasInputExtension 
    "
!

hasImageExtension
    "return true, if this workstation supports the X image extension.
     Both the server must support it, and the feature must have been
     enabled in the smalltalk system, for true to be returned."

    ^ hasImageExtension

    "
     Display hasImageExtension 
    "
!

hasXVideo
    "return true, if this workstation supports the XVideo extension.
     Both the server must support it, and the feature must have been
     enabled in the smalltalk system, for true to be returned."

    ^ hasXVideoExtension

    "
     Display hasXVideo 
    "
!

hasExtension:extensionString
    "query for an X extension. The argument, extensionString
     should be the name of the extension (i.e. 'SHAPE', 'XInputExtension' etc).
     Return true, if that extension is available in the server.
     (which does not imply, that there is support in smalltalk for it."

%{
    int dummy;

    if (__isString(extensionString) && ISCONNECTED) {
	if (XQueryExtension(myDpy, __stringVal(extensionString), &dummy, &dummy, &dummy)) {
	    RETURN ( true );
	}
    }
%}.
    ^ false

    "
     Display hasExtension:'XVideo' 
     Display hasExtension:'Input' 
     Display hasExtension:'GLX' 
     Display hasExtension:'X3D-PEX' 
     Display hasExtension:'XInputExtension' 
     Display hasExtension:'SHAPE' 
     Display hasExtension:'MIT-SHM' 
     Display hasExtension:'SGIFullScreenStereo' 
    "
!

supportedImageFormats
    "return an array with supported image formats; 
     each array entry is an attribute dictionary, consisting of 
     depth, bitsPerPixel and padding values."

    |nFormats "{ Class: SmallInteger }"
     formatArray|
%{
    Display *dpy = myDpy;

    if (! ISCONNECTED) {
	RETURN (nil);
    }
    nFormats = _MKSMALLINT(DISPLAYACCESS(dpy)->nformats);
%}.
    formatArray := Array new:nFormats.
    1 to:nFormats do:[:index |
	|info bitsPerPixelInfo depthInfo paddingInfo i|

	i := index.
%{
	ScreenFormat *format;
	Display *dpy = myDpy;

	format = DISPLAYACCESS(dpy)->pixmap_format;
	format += (_intVal(i)-1);
	bitsPerPixelInfo = __MKSMALLINT(format->bits_per_pixel);
	depthInfo = __MKSMALLINT(format->depth);
	paddingInfo = __MKSMALLINT(format->scanline_pad);
%}.
	info := IdentityDictionary new.
	info at:#depth put:depthInfo.
	info at:#bitsPerPixel put:bitsPerPixelInfo.
	info at:#padding put:paddingInfo.
	formatArray at:index put:info.
    ].
    ^ formatArray

    "
     Display supportedImageFormats 
    "
!

supportsDeepIcons
    "return true, if this device supports non b&w (i.e. greyScale
     or colored icons). Many Xservers (and/or windowManagers) crash,
     if you pass them a deep form as icon; therefore, we return false.
     It may be a good idea to check for the server vendor/release and
     return trie sometimes."

    ^ false
!

supportsViewGravity
    "return true, if this device supports gravity attributes.
     We do not depend on it being implemented, but some resizing operations
     are faster, it is is."

    ^ true
!

blackpixel
    "return the colornumber of black"

    ^ blackpixel
!

whitepixel
    "return the colornumber of white"

    ^ whitepixel
!

buttonMotionMask:aButton
    "return the state-mask for button1 in motion events state-field.
     This is the devices mask."

%{  /* NOCONTEXT */
    if (aButton == _MKSMALLINT(1)) {
	RETURN (_MKSMALLINT(Button1MotionMask));
    }
    if (aButton == _MKSMALLINT(2)) {
	RETURN (_MKSMALLINT(Button2MotionMask));
    }
    if (aButton == _MKSMALLINT(3)) {
	RETURN (_MKSMALLINT(Button3MotionMask));
    }
%}.
    ^ nil
!

button1MotionMask
    "return the state-mask for button1 in motion events state-field.
     For backward compatibility."

%{  /* NOCONTEXT */
    RETURN (_MKSMALLINT(Button1MotionMask));
%}
!

button2MotionMask
    "return the state-mask for button2 in motion events state-field
     For backward compatibility."

%{  /* NOCONTEXT */
    RETURN (_MKSMALLINT(Button2MotionMask));
%}
!

button3MotionMask
    "return the state-mask for button3 in motion events state-field
     For backward compatibility."

%{  /* NOCONTEXT */
    RETURN (_MKSMALLINT(Button3MotionMask));
%}
!

modifier1Mask
    "return the Xlib mask bit for the 1st modifier key.
     See comment in altModifierMask: / metaModifierMask: for what
     this could be used."

%{  /* NOCONTEXT */
    RETURN (_MKSMALLINT(Mod1Mask));
%}
!

modifier2Mask
    "return the Xlib mask bit for the 2nd modifier key.
     See comment in altModifierMask: / metaModifierMask: for what
     this could be used."

%{  /* NOCONTEXT */
    RETURN (_MKSMALLINT(Mod2Mask));
%}
!

altModifierMask:aSmallInteger
    "define which key takes the role of an alt-key.
     By default, this is X's modifier1, which is the ALT key on
     most keyboards. However, there may be exceptions to this,
     and the setting can be changed with:
	Display altModifierMask:(Display modifier2Mask)
     Setting the mask to 0 disables the ALT key (in ST/X) altogether.
    "

    altModifierMask := aSmallInteger
!

metaModifierMask:aSmallInteger
    "define which key takes the role of a meta key.
     By default, this is X's modifier2, which is the 2nd ALT key on
     most keyboards (if present at all).
     However, there may be exceptions to this, and the setting can
     be changed with:
	Display metaModifierMask:(Display modifier1Mask)
     Setting the mask to 0 disables the META key (in ST/X) altogether.
     As reported, some Xservers place the Meta-key onto NumLock,
     and having NumLock enabled makes ST/X think, that meta is pressed
     all the time. On those, you should disable the meta key by setting
     the mask to 0.
    "

    metaModifierMask := aSmallInteger
!

defaultEventMask
    "return a mask to enable some events by default."

%{  /* NOCONTEXT */
    RETURN (_MKSMALLINT( ExposureMask | StructureNotifyMask |
			 KeyPressMask | KeyReleaseMask |
			 EnterWindowMask | LeaveWindowMask |
			 ButtonPressMask | ButtonMotionMask | ButtonReleaseMask ));
%}
!

viewIdFromPoint:aPoint in:windowId
    "given a point in rootWindow, return the viewId of the subview of windowId
     hit by this coordinate. Return nil if no view was hit.
     The returned id may be the id of a non ST view.
     - used to find the window to drop objects after a cross-view drag."

%{  /* NOCONTEXT */

    Display *dpy = myDpy;
    int screen = _intVal(_INST(screen));
    OBJ xp, yp;
    int xpos, ypos;
    Window child_return;

    if (__isExternalAddress(windowId)
     && __isPoint(aPoint)) {
	xp = _point_X(aPoint);
	yp = _point_Y(aPoint);
	if (__bothSmallInteger(xp, yp)) {
	    BEGIN_INTERRUPTSBLOCKED
	    XTranslateCoordinates(dpy,
				  RootWindow(dpy, screen),
				  _WindowVal(windowId),
				  _intVal(xp), _intVal(yp), 
				  &xpos, &ypos, &child_return);
	    END_INTERRUPTSBLOCKED
	    if (child_return) {
		RETURN ( __MKOBJ(child_return) );
	    }
	    RETURN ( nil );
	}
    }
%}.
    windowId notNil ifTrue:[
	aPoint isPoint ifTrue:[
	    ^ self viewIdFromPoint:aPoint asPoint truncated in:windowId
	]
    ].

    ^ nil
!

translatePoint:aPoint from:windowId1 to:windowId2
    "given a point in window1, return the coordinate in window2.
     This expects a device coordinate (relative to the first views origin)
     in aPoint and returns a device coordinate relative to the 2nd views origin.
     - use to xlate points from a window to rootwindow"

    |x1 y1 x2 y2|

    x1 := x2 := aPoint x truncated.
    y1 := y2 := aPoint y truncated.
%{
    int xpos, ypos;
    Window w1, w2, child_return;
    int screen = _intVal(_INST(screen));
    Display *dpy = myDpy;

    if (__isExternalAddress(windowId1)
     && __isExternalAddress(windowId2)
     && __bothSmallInteger(x1, y1)) {
	w1 = _WindowVal(windowId1);
	w2 = _WindowVal(windowId2);
#ifdef VIRTUAL_ROOT
	if ((w1 == RootWindow(dpy, screen))
	 || (w2 == RootWindow(dpy, screen))) {
	    if (w1 == RootWindow(dpy, screen)) {
		w1 = getRootWindow(dpy, screen);
	    }
	    if (w2 == RootWindow(dpy, screen)) {
		w2 = getRootWindow(dpy, screen);
	    }
	}
#endif
	BEGIN_INTERRUPTSBLOCKED
	XTranslateCoordinates(dpy, w1, w2,
			      _intVal(x1), _intVal(y1), 
			      &xpos, &ypos, &child_return);
	END_INTERRUPTSBLOCKED
	x2 = _MKSMALLINT(xpos);
	y2 = _MKSMALLINT(ypos);
    }
%}.

    ^ (x2 @ y2)
!

rootView
    rootView isNil ifTrue:[
	rootView := DisplayRootView on:self
    ].
    ^ rootView

    "
     |v|
     v := Display rootView.
     v paint:Color red.
     v noClipByChildren.
     v fillRectangleX:10 y:10 width:100 height:100.  
    "
!

virtualExtent
    "return the virtual extent of the display (in pixels).
     On most systems, this is the same as the physical width;
     except, if a window manager with a virtual desktop like olvwm
     (simulating a bigger screen) is running."

%{
    if ((_INST(rootId) != _INST(virtualRootId)) 
     && __isExternalAddress(_INST(virtualRootId))) {
	Window vRootWin;
	Window root;
	int x, y;
	unsigned int width, height;
	unsigned int dummy;
	extern OBJ __MKPOINT_INT();

	vRootWin = _WindowVal(_INST(virtualRootId));
	if (XGetGeometry(myDpy, vRootWin, &root, &x, &y, &width, &height,
					  &dummy, &dummy)) {
	    RETURN ( __MKPOINT_INT(width, height) );
	}
    }
%}.
    ^ width @ height
! !

!XWorkstation methodsFor:'bitmap/window creation'!

createFaxImageFromArray:data width:w height:h type:type k:k msbFirst:msbFirst
    "create a new faxImage in the workstation
     type: 0 -> uncompressed
	   1 -> group3 1D (k is void)
	   2 -> group3 2D
	   3 -> group4 2D (k is void)"

    |nBytes|

    hasFaxExtension ifFalse:[^ nil].
    nBytes := data size.
%{
#ifdef FAX
    Display *dpy = myDpy;
    int screen = _intVal(_INST(screen));
    FAXImage newImage;
    int _type, _msb, _k = 0;
    unsigned char *bits;

    if (__bothSmallInteger(w, h)
     && __bothSmallInteger(type, k)
     && __isSmallInteger(nBytes)
     && __isByteArray(data)) {
	if (msbFirst == true)
	    _msb = 1;
	else
	    _msb = 0;
	_type = _intVal(type);
	if ((_type < 0) || (_type > 3)) {
	    RETURN ( nil );
	}
	if (_type == 2) {
	    if (! __isSmallInteger(k)) {
		RETURN ( nil );
	    }
	    _k = _intVal(k);
	}
	bits =  _ByteArrayInstPtr(data)->ba_element;
	BEGIN_INTERRUPTSBLOCKED
	newImage = XFAXImageCreateImage(dpy, _intVal(w), _intVal(h),
					_type, _k, _msb,
					_intVal(nBytes), bits);
	END_INTERRUPTSBLOCKED
	RETURN ( (newImage != (FAXImage)0) ? __MKOBJ(newImage) : nil );
    }
#else
    RETURN ( nil );
#endif
%}
.
    self primitiveFailed.
    ^ nil
!

createBitmapWidth:w height:h
    "allocate a bitmap on the Xserver, the contents is undefined
     (i.e. random). Return a bitmap id or nil"

%{  /* NOCONTEXT */

    Display *dpy = myDpy;
    int screen = _intVal(_INST(screen));
    Pixmap newBitmap;

    if (__bothSmallInteger(w, h) && ISCONNECTED) {
	BEGIN_INTERRUPTSBLOCKED
	newBitmap = XCreatePixmap(dpy, RootWindow(dpy, screen),
				       _intVal(w), _intVal(h), 1);
	END_INTERRUPTSBLOCKED
	RETURN ( (newBitmap != (Pixmap)0) ? __MKOBJ(newBitmap) : nil );
    }
%}
.
    self primitiveFailed.
    ^ nil
!

createPixmapWidth:w height:h depth:d
    "allocate a pixmap on the Xserver, the contents is undefined
     (i.e. random). Return a bitmap id or nil"

%{  /* NOCONTEXT */

    Display *dpy = myDpy;
    int screen = _intVal(_INST(screen));
    Pixmap newBitmap;

    if (__bothSmallInteger(w, h) && ISCONNECTED) {
	BEGIN_INTERRUPTSBLOCKED
	newBitmap = XCreatePixmap(dpy, RootWindow(dpy, screen),
				       _intVal(w), _intVal(h), _intVal(d));
	END_INTERRUPTSBLOCKED
	RETURN ( (newBitmap != (Pixmap)0) ? __MKOBJ(newBitmap) : nil );
    }
%}
.
    self primitiveFailed.
    ^ nil
!

createBitmapFromFile:aString for:aForm
    |id w h|

%{
    Display *dpy = myDpy;
    int screen = _intVal(_INST(screen));
    Pixmap newBitmap;
    char *filename;
    unsigned b_width, b_height;
    int b_x_hot, b_y_hot;
    int status;

    if (ISCONNECTED) {
	if (__isString(aString) || __isSymbol(aString)) {
	    filename = (char *)_stringVal(aString);

	    BEGIN_INTERRUPTSBLOCKED
	    status = XReadBitmapFile(dpy, RootWindow(dpy, screen),
				     filename, &b_width, &b_height, &newBitmap,
				     &b_x_hot, &b_y_hot);
	    END_INTERRUPTSBLOCKED

	    if (status == BitmapSuccess) {
		w = _MKSMALLINT(b_width);
		h = _MKSMALLINT(b_height);
		id = __MKOBJ(newBitmap);
	    }
	}
    }
%}.
    id notNil ifTrue:[
	aForm setWidth:w height:h
    ].
    ^ id
!

primCreateBitmapFromArray:anArray width:w height:h

%{  /* UNLIMITEDSTACK */

    Display *dpy = myDpy;
    int screen = _intVal(_INST(screen));
    Pixmap newBitmap;
    unsigned int b_width, b_height;
    REGISTER unsigned char *cp;
    REGISTER unsigned char *pBits;
    unsigned char *b_bits, *allocatedBits;
    int index, row;
    REGISTER int col;
    unsigned bits;
    static char reverseBitTable[256];
    static firstCall = 1;
    int nBytes;
    unsigned char fastBits[10000];
    OBJ num, *op;
    int bytesPerRow;

    if (firstCall) {
	for (index=0; index < 256; index++) {
	    reverseBitTable[index] = 0;
	    if (index & 128) reverseBitTable[index] |=   1;
	    if (index &  64) reverseBitTable[index] |=   2;
	    if (index &  32) reverseBitTable[index] |=   4;
	    if (index &  16) reverseBitTable[index] |=   8;
	    if (index &   8) reverseBitTable[index] |=  16;
	    if (index &   4) reverseBitTable[index] |=  32;
	    if (index &   2) reverseBitTable[index] |=  64;
	    if (index &   1) reverseBitTable[index] |= 128;
	}
	firstCall = 0;
    }

    if (__bothSmallInteger(w, h) && _isNonNilObject(anArray)) {
	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 (__qClass(anArray) == Array) {
	    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)) goto fail;
		    bits = _intVal(num);
		    *cp++ = reverseBitTable[bits];
		}
	    }
	} else {
	    if (__qClass(anArray) == ByteArray) {
		pBits = _ByteArrayInstPtr(anArray)->ba_element;
		for (col = b_height*bytesPerRow; col; col--) {
		    *cp++ = reverseBitTable[*pBits++];
		}
	    } else {
		goto fail;
	    }
	}

	BEGIN_INTERRUPTSBLOCKED
	newBitmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
					       (char *)b_bits, 
					       b_width, b_height);
	END_INTERRUPTSBLOCKED
fail: ;
	if (allocatedBits)
	    free(allocatedBits);
	RETURN ( newBitmap ? __MKOBJ(newBitmap) : nil );
    }
%}
!

createBitmapFromArray:anArray width:w height:h
    |bitmapId|

    bitmapId := self primCreateBitmapFromArray:anArray width:w height:h.
    bitmapId isNil ifTrue:[
	self primitiveFailed
    ].
    ^ bitmapId
!

destroyPixmap:aDrawableId

%{  /* NOCONTEXT */

    if (__isExternalAddress(aDrawableId) && ISCONNECTED) {
	BEGIN_INTERRUPTSBLOCKED
	XFreePixmap(myDpy, _PixmapVal(aDrawableId));
	END_INTERRUPTSBLOCKED
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

destroyFaxImage:aFaxImageId

%{  /* NOCONTEXT */

#ifdef FAX
    if (__isExternalAddress(aFaxImageId)) {
	BEGIN_INTERRUPTSBLOCKED
	XFAXImageFreeImage(myDpy, (FAXImage)_WindowVal(aFaxImageId));
	END_INTERRUPTSBLOCKED
	RETURN ( self );
    }
#endif
%}.
    self primitiveFailed
!

realRootWindowId
    "return the id of the real root window.
     This may not be the window you see as background,
     since some window managers install a virtual root window on top
     of it. Except for very special cases, use #rootWindowId, which takes
     care of any virtual root."

%{  /* NOCONTEXT */

    int screen = _intVal(_INST(screen));
    Window root;
    OBJ id;

    if (_INST(rootId) != nil) {
	RETURN (_INST(rootId));
    }

    if (ISCONNECTED) {
	root = RootWindow(myDpy, screen);
	if (! root) {
	    id = nil;
	} else {
	    _INST(rootId) = id = __MKOBJ(root); __STORE(self, id);
	}
	RETURN (id);
    }
%}.
    self primitiveFailed
!

rootWindowId
    "return the id of the root window.
     This is the window you see as background, 
     however, it may or may not be the real physical root window,
     since some window managers install a virtual root window on top
     of the real one. If this is the case, that views id is returned here."

%{  /* NOCONTEXT */
    int screen = _intVal(_INST(screen));
    Window rootWin, vRootWin;
    OBJ id;

    if (_INST(virtualRootId) != nil) {
	RETURN (_INST(virtualRootId));
    }

    if (ISCONNECTED) {
	vRootWin = rootWin = RootWindow(myDpy, screen);
#ifndef IRIS
	BEGIN_INTERRUPTSBLOCKED
	/*
	 * on IRIS, this creates a badwindow error - why ?
	 * children contains a funny window (000034)
	 */

	/*
	 * care for virtual root windows (tvtwm & friends)
	 */
	{
	    Atom vRootAtom = None;
	    int i;
	    Window rootReturn, parentReturn;
	    Window* children;
	    unsigned int numChildren;

	    if (XQueryTree(myDpy, rootWin, 
			   &rootReturn, &parentReturn, 
			   &children, &numChildren)) {
		vRootAtom = XInternAtom(myDpy, "__SWM_VROOT", True );
		if (vRootAtom != None) {
		    for (i=0; i < numChildren; i++) {
			Atom actual_type;
			int actual_format;
			unsigned long nitems, bytesafter;
			Window* newRoot = (Window*) 0;

			if (children[i]) {
			    if (XGetWindowProperty(myDpy, children[i], vRootAtom, 
						     0L, 1L, False, XA_WINDOW,
						     &actual_type, &actual_format, 
						     &nitems, &bytesafter,
						     (unsigned char**) &newRoot
						   ) == Success && newRoot) {
				vRootWin = *newRoot;
				break;
			    }
			}
		    }
		    if (children) XFree( children );
		}
	    }
	}
	END_INTERRUPTSBLOCKED
#endif
    }

    /* cannot happen */
    if (! vRootWin) {
	vRootWin = rootWin;
	if (! rootWin) {
	    RETURN ( nil );
	}
    }
    _INST(rootId) = id = __MKOBJ(rootWin); __STORE(self, id);
    _INST(virtualRootId) = id = __MKOBJ(vRootWin); __STORE(self, id);
    RETURN ( id );
%}
!

realRootWindowFor:aView
    "the name of this method is historic;
     - it will vanish"

    |id|

    id := self realRootWindowId.
    self addKnownView:aView withId:id.
    ^ id
!

rootWindowFor:aView
    |id|

    id := self rootWindowId.
    self addKnownView:aView withId:id.
    ^ id
!

createWindowFor:aView left:xpos top:ypos width:wwidth height:wheight
    "will vanish - for compatibility with previous versions"

    ^ self 
	  createWindowFor:aView 
	  origin:(xpos @ ypos)
	  extent:(wwidth @ wheight)
	  minExtent:(aView minExtent)
	  maxExtent:(aView maxExtent)
	  borderWidth:(aView borderWidth)
	  subViewOf:(aView superView)
	  onTop:(aView isPopUpView)
	  inputOnly:(aView inputOnly)
	  label:(aView label)
	  cursor:(aView cursor)
	  icon:(aView icon)
	  iconView:(aView iconView)
!

createWindowFor:aView
		 origin:origin
		 extent:extent
		 minExtent:minExt 
		 maxExtent:maxExt
		 borderWidth:bWidth
		 subViewOf:wsuperView
		 onTop:wisPopUpView
		 inputOnly:winputOnly
		 label:wlabel
		 cursor:wcursor
		 icon:wicon
		 iconView:wiconView

    |xpos ypos wwidth wheight minWidth minHeight maxWidth maxHeight 
     bColorId wsuperViewId wcursorId wiconId windowId
     weventMask wiconViewId bitGravity viewGravity vBgColor
     vBgForm deepForm preferredVisual preferredDepth|

    displayId isNil ifTrue:[
	self primitiveFailed.
	^ nil
    ].

    origin notNil ifTrue:[
	xpos := origin x.
	ypos := origin y.
    ] ifFalse:[
	xpos := ypos := 0.
    ].
    extent notNil ifTrue:[
	wwidth := extent x.
	wheight := extent y.
    ] ifFalse:[
	wwidth := wheight := 100.
    ].
    minExt notNil ifTrue:[
	minWidth := minExt x.
	minHeight := minExt y
    ].
    maxExt notNil ifTrue:[
	maxWidth := maxExt x.
	maxHeight := maxExt y
    ].

    wsuperView notNil ifTrue:[
	wsuperViewId := wsuperView id
    ].
    wcursor isNil ifTrue:[
	'XWORKSTATION: cursor nil - defaulted' errorPrintNL
    ] ifFalse:[
	wcursorId := wcursor id
    ].

    wicon notNil ifTrue:[
	wiconId := wicon id
    ].
    wiconView notNil ifTrue:[
	wiconViewId := wiconView id
    ].
    weventMask := aView eventMask.

    preferredVisual := aView preferredVisual.
    preferredDepth := aView preferredDepth.

%{  /* STACK:16000 */
    Display *dpy = myDpy;
    int screen = _intVal(_INST(screen));
    Visual visual;
    XGCValues xgcv;
    XSetWindowAttributes xswa;
    XSizeHints sizehints;
    XWMHints wmhints;
    int bw, bd, bg;
    Window newWindow, parentWindow;
    char *windowName;
    XFontStruct *f;
    Pixmap backPixmap = (Pixmap)0, iconBitmap = (Pixmap)0;
    int flags = 0, depth, ioClass;
    extern OBJ Rectangle, Form;
    Window iconWindow;
    Atom WmDeleteWindowAtom, WmSaveYourselfAtom, WmProtocolsAtom;
    Atom WmQuitAppAtom;
    Atom atoms[3];
    int atomCount = 0, isTopWindow = 0;

    sizehints.flags = 0;
    sizehints.width = 100;
    sizehints.height = 100;
    sizehints.x = 0;
    sizehints.y = 0;

    if (__bothSmallInteger(wwidth, wheight)) {
	sizehints.flags |= PSize;
	sizehints.width = _intVal(wwidth);
	sizehints.height = _intVal(wheight);
    }
    if (__bothSmallInteger(xpos, ypos)) {
	sizehints.flags |= PPosition;
	sizehints.x = _intVal(xpos);
	sizehints.y = _intVal(ypos);
    }
    if (__bothSmallInteger(minWidth, minHeight)) {
	sizehints.flags |= PMinSize;
	sizehints.min_width = _intVal(minWidth);
	sizehints.min_height = _intVal(minHeight);
    }
    if (__bothSmallInteger(maxWidth, maxHeight)) {
	sizehints.flags |= PMaxSize;
	sizehints.max_width = _intVal(maxWidth);
	sizehints.max_height = _intVal(maxHeight);
    }

    bg = WhitePixel(dpy, screen);

    if (__isSmallInteger(bWidth)) {
	bw = _intVal(bWidth);
    } else {
	bw = 0;
    }

    bd = BlackPixel(dpy, screen);

    if (__isExternalAddress(wsuperViewId)) {
	parentWindow = _WindowVal(wsuperViewId);
    } else {
	parentWindow = RootWindow(dpy, screen);
	isTopWindow = 1;
    }

    if (wisPopUpView == true)
	xswa.override_redirect = 1;
    else 
	xswa.override_redirect = 0;

    if (winputOnly == true) 
	ioClass = InputOnly;
    else 
	ioClass = InputOutput;

    if (__isSmallInteger(weventMask)) {
	xswa.event_mask = _intVal(weventMask);
    } else {
	xswa.event_mask = 0;
    }

    if (ioClass == InputOnly) {
	bw = 0;
	depth = 0;
	flags |= CWEventMask;
    } else {
	depth = DefaultDepth(dpy,screen);
	flags |= CWEventMask | CWBorderPixel | CWOverrideRedirect;

	if (backPixmap != (Pixmap)0) {
	    xswa.background_pixmap = backPixmap;
	    flags |= CWBackPixmap;
	} else {
	    xswa.background_pixel = bg;
	    flags |= CWBackPixel;
	}
	xswa.border_pixel = bd;
    }

    visual.visualid = CopyFromParent;
    if (__isSmallInteger(preferredDepth)) {
	depth = _intVal(preferredDepth);
    }

    BEGIN_INTERRUPTSBLOCKED
    if (preferredVisual != nil) {
	XVisualInfo vi;
	int cls;

	if (preferredVisual == @symbol(StaticGray))
	    cls = StaticGray;
	else if (preferredVisual == @symbol(GrayScale)) 
	    cls = StaticGray;
	else if (preferredVisual == @symbol(StaticColor)) 
	    cls = StaticColor;
	else if (preferredVisual == @symbol(PseudoColor)) 
	    cls = PseudoColor;
	else if (preferredVisual == @symbol(TrueColor)) 
	    cls = TrueColor;
	else if (preferredVisual == @symbol(DirectColor)) 
	    cls = DirectColor;
	else
	    cls = PseudoColor;

	if (XMatchVisualInfo(dpy, screen, depth, cls, &vi)) {
	    visual.visualid = vi.visualid;
/*
	    printf("visualId=%x\n", vi.visualid);
*/
	}
    }

    newWindow = XCreateWindow(dpy, parentWindow,
			   sizehints.x, sizehints.y,
			   sizehints.width, sizehints.height,
			   bw, depth, ioClass, &visual,
			   flags, &xswa);
    END_INTERRUPTSBLOCKED

    if (! newWindow) {
	RETURN ( nil );
    }

    BEGIN_INTERRUPTSBLOCKED
    /*
     * define its cursor
     */
    if (__isExternalAddress(wcursorId)) {
	XDefineCursor(dpy, newWindow, _CursorVal(wcursorId));
    }

    /*
     * define its icon and name
     * (only makes sense for topWindows)
     */
    if (isTopWindow) {
	if (__isExternalAddress(wiconId))
	    iconBitmap = _PixmapVal(wiconId);
	else
	    iconBitmap = (Pixmap)0;

	if (__isExternalAddress(wiconViewId))
	    iconWindow = _WindowVal(wiconViewId);
	else
	    iconWindow = (Window)0;

	if (__isString(wlabel) || __isSymbol(wlabel))
	    windowName = (char *)_stringVal(wlabel);
	else
	    windowName = "";

	if (iconBitmap || windowName) {
	    XSetStandardProperties(dpy, newWindow,
					windowName, windowName,
					iconBitmap,
					0, 0, &sizehints);

	}

	wmhints.flags = 0;
	if (iconBitmap) {
	    wmhints.flags |= IconPixmapHint;
	    wmhints.icon_pixmap = iconBitmap;
	}
	if (iconWindow) {
	    wmhints.flags |= IconWindowHint;
	    wmhints.icon_window = iconWindow;
	}
/*
	wmhints.flags |= InputHint;
	wmhints.input = True;
*/
	XSetWMHints(dpy, newWindow, &wmhints);

	/*
	 * tell window manager to not kill us but send an event instead
	 */
	/*
	 * get atoms first (if not already known)
	 */
	if (_INST(protocolsAtom) == nil) {
	    WmProtocolsAtom = XInternAtom(dpy, "WM_PROTOCOLS", False);
	    _INST(protocolsAtom) = __MKATOMOBJ(WmProtocolsAtom);
#ifdef USE_SAVEYOURSELF_ATOM
	    WmSaveYourselfAtom = XInternAtom(dpy, "WM_SAVE_YOURSELF", False);
	    _INST(saveYourselfAtom) = __MKATOMOBJ(WmSaveYourselfAtom);
#endif
#ifdef USE_QUIT_APP_ATOM
	    WmQuitAppAtom = XInternAtom(dpy, "_WM_QUIT_APP", False);
	    _INST(quitAppAtom) = __MKATOMOBJ(WmQuitAppAtom);
#endif
	    WmDeleteWindowAtom = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
	    _INST(deleteWindowAtom) = __MKATOMOBJ(WmDeleteWindowAtom);
	} else {
#ifdef USE_QUIT_APP_ATOM
	    WmQuitAppAtom = _AtomVal(_INST(quitAppAtom));
#else
	    WmQuitAppAtom = 0;
#endif
	    WmProtocolsAtom = _AtomVal(_INST(protocolsAtom));
	    WmDeleteWindowAtom = _AtomVal(_INST(deleteWindowAtom));
#ifdef USE_SAVEYOURSELF_ATOM
	    WmSaveYourselfAtom = _AtomVal(_INST(saveYourselfAtom));
#else
	    WmSaveYourselfAtom = 0;
#endif
	}

	atoms[0] = WmDeleteWindowAtom; atomCount++;
#ifdef USE_SAVEYOURSELF_ATOM
	atoms[atomCount] = WmSaveYourselfAtom; atomCount++;
#endif
#ifdef USE_QUIT_APP_ATOM
	atoms[atomCount] = WmQuitAppAtom; atomCount++;
#endif
	XChangeProperty(dpy, newWindow, WmProtocolsAtom, XA_ATOM,
			32, PropModeReplace, (unsigned char *)atoms, atomCount);
    }

    END_INTERRUPTSBLOCKED

    windowId = __MKOBJ(newWindow);
%}.
    self addKnownView:aView withId:windowId.
    ^ windowId
!

destroyView:aView withId:aWindowId
%{
    if (__isExternalAddress(aWindowId) && ISCONNECTED) {
	BEGIN_INTERRUPTSBLOCKED
	XDestroyWindow(myDpy, _WindowVal(aWindowId));
	END_INTERRUPTSBLOCKED
    }
%}.
    self removeKnownView:aView
!

destroyGC:aGCId

%{  /* NOCONTEXT */
    if (__isExternalAddress(aGCId) && ISCONNECTED) {
	BEGIN_INTERRUPTSBLOCKED
	XFreeGC(myDpy, _GCVal(aGCId));
	END_INTERRUPTSBLOCKED
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

gcFor:aDrawableId

%{  /* NOCONTEXT */
    int screen = _intVal(_INST(screen));
    GC gc;

    if (__isExternalAddress(aDrawableId) && ISCONNECTED) {
	BEGIN_INTERRUPTSBLOCKED
	gc = XCreateGC(myDpy, (Drawable)_WindowVal(aDrawableId),
			      0L, (XGCValues *)0);
	END_INTERRUPTSBLOCKED
	RETURN ( gc ? __MKOBJ(gc) : nil );
    }
%}.
    self primitiveFailed.
    ^ nil
!

dpsContextFor:aDrawableId and:aGCId

%{  /* NOCONTEXT */
#ifdef XXDPS
    int screen = _intVal(_INST(screen));
    DPSContext dps;
    int height;

    if (__isExternalAddress(aDrawableId)
     && __isExternalAddress(aGCId)
     && ISCONNECTED) {
	BEGIN_INTERRUPTSBLOCKED
	dps = XDPSCreateContext(myDpy, (Drawable)_WindowVal(aDrawableId),
				       _GCVal(aGCId),
				       0, height, 0, colormap, NULL, 0,
				       XDPSDefaultTextBackstop,
				       XDPSDefaultErrorProc,
				       NULL);
	END_INTERRUPTSBLOCKED
	RETURN ( dps ? __MKOBJ(dps) : nil );
    }
#endif
%}
.
    self primitiveFailed.
    ^ nil
! !

!XWorkstation methodsFor:'resources'!

getResource:name class:cls
%{
    char *rslt;

    if ((__isString(name) || __isSymbol(name))
     && (__isString(cls) || __isSymbol(cls))
     && ISCONNECTED) {
	BEGIN_INTERRUPTSBLOCKED
	rslt = XGetDefault(myDpy, (char *)_stringVal(cls),
				  (char *)_stringVal(name));
	END_INTERRUPTSBLOCKED
	RETURN (rslt ? __MKSTRING(rslt COMMA_CON) : nil );
    }
%}
.
    self primitiveFailed.
    ^ nil
! !

!XWorkstation methodsFor:'selections'!

setTextProperty:propertyID value:aString for:aWindowID
    ^ self setProperty:propertyID type:(self atomIDOfSTRING) value:aString for:aWindowID
!

setLengthProperty:propertyID value:aNumber for:aWindowID
    ^ self setProperty:propertyID type:(self atomIDOfLENGTH) value:aNumber for:aWindowID
!

setObjectProperty:propertyID value:anObject for:aWindowID
    |s|

    (anObject isMemberOf:String) ifTrue:[
	^ self setTextProperty:propertyID value:anObject for:aWindowID
    ].
    s := WriteStream on:(ByteArray new:200).
    anObject storeBinaryOn:s.
    ^ self 
	setProperty:propertyID 
	type:(self atomIDOf:'ST_OBJECT' create:true) 
	value:(s contents) 
	for:aWindowID
!

setProperty:propertyID type:typeID value:anObject for:aWindowID

%{  /* UNLIMITEDSTACK */

    Display *dpy = myDpy;
    Atom prop, type;
    Window window;
    unsigned int value;

    if (__isAtomID(propertyID)
     && __isAtomID(typeID) 
     && ISCONNECTED
     && (__isString(anObject) 
	 || __isSmallInteger(anObject) 
	 || __isSymbol(anObject) 
	 || __isByteArray(anObject))) {

	prop = _AtomVal(propertyID);
	type = _AtomVal(typeID);
	if (__isExternalAddress(aWindowID)) {
	    window = _WindowVal(aWindowID);
	} else {
	    window = DefaultRootWindow(dpy);
	}
	if (__isSmallInteger(anObject)) {
	    value = _intVal(anObject);
	    XChangeProperty(dpy, window, prop, type, 32,
			    PropModeReplace,
			    (unsigned char *)(&value), sizeof(unsigned int));
	} else {
	    if (__isByteArray(anObject)) {
		XChangeProperty(dpy, window, prop, type, 8,
				PropModeReplace,
				_ByteArrayInstPtr(anObject)->ba_element,
				_byteArraySize(anObject));
	    } else {
		/* string or symbol */
		XChangeProperty(dpy, window, prop, XA_STRING, 8,
				PropModeReplace,
				_stringVal(anObject),
				strlen(_stringVal(anObject)));
	    }
	}
	RETURN (true);
    }
%}.
    ^ false
!

getTextProperty:propertyID from:aWindowID
    "get a text property; return string or nil"

    self getProperty:propertyID from:aWindowID into:[:type :value |
	type == stringAtom ifTrue:[
	    ^ value
	]
    ].
    ^ nil
!

getObjectProperty:propertyID from:aWindowID
    "get an object property; return object or nil"

    self getProperty:propertyID from:aWindowID into:[:type :value |
	type == stringAtom ifTrue:[
	    ^ value
	].
	(value isMemberOf:ByteArray) ifTrue:[
	    ^ (Object readBinaryFrom:(ReadStream on:value) onError:[nil])
	]
    ].
    ^ nil
!

getProperty:propertyID from:aWindowID into:aTwoArgBlock
    "get a property, evaluate aTwoArgBlock with typeID and value"

    |val typeID cls|

    cls := ByteArray.
%{
    Display *dpy = myDpy;
    Window window;
    Atom property;
    char *cp, *cp2;
    Atom actual_type;
    int actual_format,i;
    unsigned long nitems, bytes_after, nread;
    unsigned char *data;
    int ok = 1;
    OBJ __new(), __MKSTRING_L();
#   define PROP_SIZE    2048

    if (__isAtomID(propertyID)) {
	property = _AtomVal(propertyID);
	if (__isExternalAddress(aWindowID)) {
	    window = _WindowVal(aWindowID);
	} else {
	    window = DefaultRootWindow(dpy);
	}

	nread = 0;
	cp = 0;
/*
	fprintf(stderr, "getProperty: ");
 */
	do {
	    if (XGetWindowProperty(dpy,window,property,nread/4,PROP_SIZE,False,
				   AnyPropertyType,&actual_type,&actual_format,
				   &nitems,&bytes_after,(unsigned char **)&data)
		!= Success) {
		    ok = 0;
		    break;
	    }
	    typeID = __MKATOMOBJ(actual_type);
	    if (! cp) {
		cp = cp2 = (char *)malloc(nitems+1);
	    } else {
		cp = (char *)realloc(cp, nread + nitems + 1);
		cp2 = cp + nread;
	    }
	    if (! cp) goto fail;

	    nread += nitems;
	    bcopy(data, cp2, nitems);
	    XFree(data);
/*
	    fprintf(stderr, "<nitems:%d bytes_after:%d>", nitems, bytes_after);
 */
	} while (bytes_after > 0);
/*
	fprintf(stderr, "\n");
 */

	if (ok) {
	    if (actual_type == XA_STRING) {
		cp[nread] = '\0';
		val = __MKSTRING_L(cp, nread COMMA_CON);
	    } else {
		val = __new(nread + OHDR_SIZE);
		val->o_class = cls;
		bcopy(cp, _ByteArrayInstPtr(val)->ba_element, nread);
	    }
	}
	if (cp)
	    free(cp);
    }
fail: ;
%}.
    typeID isNil ifTrue:[
	^ false
    ].
    aTwoArgBlock value:typeID value:val.
    ^ true
!

getSelectionOwnerOf:selectionAtomID
    "get the owner of a selection"

%{  /* NOCONTEXT */
    Display *dpy = myDpy;
    Atom selection;
    Window window;

    if (__isAtomID(selectionAtomID) && ISCONNECTED) {
	window = XGetSelectionOwner(dpy, _AtomVal(selectionAtomID));
	RETURN ((window == None) ? nil : __MKOBJ(window));
    }
%}.
     self primitiveFailed.
    ^ nil
!

setSelectionOwner:aWindowId of:selectionID
    "set the owner of a selection; return false if failed"

%{  /* NOCONTEXT */
    Display *dpy = myDpy;
    Window win;

    if (__isExternalAddress(aWindowId)
     && __isAtomID(selectionID)
     && ISCONNECTED) {
	win = _WindowVal(aWindowId);
	XSetSelectionOwner(dpy, _AtomVal(selectionID), win, CurrentTime);
	if (XGetSelectionOwner(dpy, _AtomVal(selectionID)) != win) {
	    RETURN (false);
	}
	RETURN (true);
    }
%}
.
    self primitiveFailed.
    ^ nil
!

requestObjectSelection:selectionID property:propertyID for:aWindowId
    "ask the server to send us the selection - the view with ID aWindowID
     will later receive a SelectionNotify event for it."

    ^ self requestSelection:selectionID 
		   property:propertyID 
		   type:(self atomIDOf:'ST_OBJECT' create:true) 
		   for:aWindowId
!

requestTextSelection:selectionID property:propertyID for:aWindowId
    "ask the server to send us the selection - the view with ID aWindowID
     will later receive a SelectionNotify event for it."

    ^ self requestSelection:selectionID 
		   property:propertyID 
		       type:stringAtom 
			for:aWindowId
!

requestSelection:selectionID property:propertyID type:typeID for:aWindowId
    "ask the server to send us the selection - the view with id aWindowID
     will later receive a SelectionNotify event for it (once the Xserver replies
     with the selections value)."

%{  /* NOCONTEXT */
    Display *dpy = myDpy;
    Atom sel_prop;
    char *cp;

    if (__isExternalAddress(aWindowId)
     && ISCONNECTED
     && __isSmallInteger(typeID)
     && __isAtomID(selectionID)) {
	if (XGetSelectionOwner(dpy, _AtomVal(selectionID)) == None) {
	    /*
	     * no owner of primary selection
	     */
	    RETURN (false);
	}
	/*
	 * PRIMARY selection
	 */
	XConvertSelection(dpy, _AtomVal(selectionID), _AtomVal(typeID), 
			       _AtomVal(propertyID), _WindowVal(aWindowId), CurrentTime);
	RETURN (true);
    }
%}.
    self primitiveFailed.
    ^ false

    "
     Display requestSelection:(Display atomIDOf:'PRIMARY')
		     property:(Display atomIDOf:'VT_SELECTION')
			  for:0
    "
!

atomIDOfPRIMARY
    ^ primaryAtom
!

atomIDOfSECONDARY
    ^ secondaryAtom
!

atomIDOfSTRING
    ^ stringAtom
!

atomIDOfLENGTH
    ^ lengthAtom
!

atomIDOfCUTBUFFER0
    ^ cutBuffer0Atom
!

atomIDOf:aStringOrSymbol
    "return an Atoms ID; dont create if not already present"

    ^ self atomIDOf:aStringOrSymbol create:false
!

atomIDOf:aStringOrSymbol create:create
    "return an Atoms ID; if create is true, create it if not already present"

%{  /* NOCONTEXT */
    Atom prop;

    if (ISCONNECTED) {
	if (__isString(aStringOrSymbol)
	 || __isSymbol(aStringOrSymbol)) {
	    prop = XInternAtom(myDpy, _stringVal(aStringOrSymbol), 
				      (create == true) ? False : True);
	    if (prop == None) {
		RETURN (nil);
	    }
	    RETURN ( __MKATOMOBJ(prop) );
	}
    }
%}.
    self primitiveFailed.
    ^ nil

    "
     Display atomIDOf:'VT_SELECTION' create:false
     Display atomIDOf:'CUT_BUFFER0' create:false
     Display atomIDOf:'STRING' create:false
     Display atomIDOf:'PRIMARY' create:false
     Display atomIDOfPRIMARY
    "
!

atomName:anAtomID
%{  /* NOCONTEXT */ 
    OBJ str;
    char *name;

    if (ISCONNECTED) {
	if (__isAtomID(anAtomID)) {
	    name = XGetAtomName(myDpy, _AtomVal(anAtomID));
	    if (name == 0) {
		RETURN (nil);
	    }
	    str = __MKSTRING(name COMMA_CON);
	    XFree(name);
	    RETURN ( str );
	}
    }
%}.
    self primitiveFailed.
    ^ nil

    "
     Display atomName:1
    "
!

sendSelection:something property:propertyID target:targetID from:windowID to:requestorID
    "send aString back from a SelectionRequest"

    self 
	sendSelection:something 
	selection:primaryAtom
	property:propertyID 
	target:targetID 
	from:windowID 
	to:requestorID
!

sendSelection:something selection:selectionID property:propertyID target:targetID from:windowID to:requestorID
    "send aString back from a SelectionRequest"

    self 
	setProperty:propertyID 
	type:targetID 
	value:something 
	for:requestorID.
    self 
	sendSelectionNotifySelection:selectionID 
	property:propertyID 
	target:targetID 
	from:requestorID 
	to:requestorID.
!

sendSelectionNotifySelection:selectionID property:propertyID target:targetID from:windowID to:requestorID
    "send a selectionNotify back from a SelectionRequest"

%{  /* NOCONTEXT */
    Display *dpy = myDpy;

    if (__isAtomID(propertyID)
     && __isExternalAddress(requestorID)
     && ISCONNECTED
     && __isAtomID(targetID)
     && __isAtomID(selectionID)) {
	XEvent ev;
	Window requestor = _WindowVal(requestorID);
	Atom property = _AtomVal(propertyID);
	Atom target = _AtomVal(targetID);
	Atom selection = _AtomVal(selectionID);
	Status result;

	ev.xselection.type = SelectionNotify;
	ev.xselection.selection = selection;
	ev.xselection.target = target;
	if (__isExternalAddress(windowID))
	    ev.xselection.requestor = _WindowVal(windowID);
	else
	    ev.xselection.requestor = DefaultRootWindow(dpy);
	ev.xselection.time = CurrentTime;
	if (property == None)
	    ev.xselection.property = target;
	else
	    ev.xselection.property = property;

	DPRINTF(("sending SelectionNotify sel=%x prop=%x target=%x requestor=%x to %x\n",
		ev.xselection.selection,
		ev.xselection.property,
		ev.xselection.target,
		ev.xselection.requestor,
		requestor));

	result = XSendEvent(dpy, requestor, False, 0 , &ev);
	if ((result == BadValue) || (result == BadWindow)) {
	    DPRINTF(("bad status\n"));
	}
	RETURN (self )
    }
%}
.
    self primitiveFailed
!

getTextSelectionFor:drawableId
    "get the text selection -  either immediate, or asynchronous.
     Returns nil, if async request is on its way"

    |selProp sel|

    (self getSelectionOwnerOf:primaryAtom) isNil ifTrue:[
	"no primary selection - use cut buffer"
	sel := self getTextProperty:cutBuffer0Atom from:nil.
	^ sel
    ].
    selProp := self atomIDOf:'VT_SELECTION' create:true.
    self requestTextSelection:primaryAtom property:selProp for:drawableId.
    ^ nil
!

getSelectionFor:drawableId
    "get the object selection -  either immediate, or asynchronous.
     Returns nil, if async request is on its way"

    |selProp sel|

    (self getSelectionOwnerOf:primaryAtom) isNil ifTrue:[
	"no primary selection - use cut buffer"
	sel := self getObjectProperty:cutBuffer0Atom from:nil.
	^ sel
    ].
    selProp := self atomIDOf:'ST_SELECTION' create:true.
    self requestObjectSelection:primaryAtom property:selProp for:drawableId.
    ^ nil
!

setTextSelection:aString owner:aWindowId
    "set the text selection, and make aWindowId be the owner.
     This can be used by any other X application."

    (self setSelectionOwner:aWindowId of:primaryAtom) ifFalse:[
	'ownerchange failed' errorPrintNL.
    ].
    ^ self setTextProperty:cutBuffer0Atom value:aString for:nil
!

setSelection:anObject owner:aWindowId
    "set the object selection, and make aWindowId be the owner.
     This can be used by other Smalltalk(X) applications only."

    (self setSelectionOwner:aWindowId of:primaryAtom) ifFalse:[
	^ false
    ].
"/    ^ self setObjectProperty:cutBuffer0Atom value:anObject for:nil
    ^ true
! !

!XWorkstation methodsFor:'font stuff'!

decomposeXFontName:aString into:aBlock
    "extract family, face, style and size from an
     X-font name 
     (-brand-family-face-style-moreStyle--height-size-res-res-?-??-coding); 
     evaluate aBlock with these"

    |origin family face style moreStyle skip fheight size
     resX resY x1 x2 coding start end |

    aString isNil ifTrue:[^ false].
    (aString startsWith:'-') ifFalse:[
	"
	 take care for ill-named fonts (i.e. pre Rel4 fonts)
	"
	('*-*-[0-9]*' match:aString) ifTrue:[
	    end := aString indexOf:$- startingAt:1.
	    family := aString copyFrom:1 to:(end - 1).
	    start := end + 1.
	    end := aString indexOf:$- startingAt:start.
	    style := aString copyFrom:start to:(end - 1).
	    start := end + 1.
	    size := aString copyFrom:start.
	    size := (Number readFromString:size onError:[^false]).
	    aBlock value:family value:nil value:style value:size value:nil.
	    ^ true.
	].
	('*-[0-9]*' match:aString) ifTrue:[
	    "
	     something like lucidasans-24
	    "
	    end := aString indexOf:$- startingAt:1.

	    family := aString copyFrom:1 to:(end - 1).
	    start := end + 1.
	    size := aString copyFrom:start.
	    size := (Number readFromString:size onError:[^false]).
	    aBlock value:family value:nil value:nil value:size value:nil.
	    ^ true.
	].
	aBlock value:aString value:nil value:nil value:nil value:nil.
	^ true.
    ].

    end := aString indexOf:$- startingAt:2.
    (end == 0) ifTrue:[^ false].
    origin := aString copyFrom:2 to:(end - 1).

    start := end + 1.
    end := aString indexOf:$- startingAt:start.
    (end == 0) ifTrue:[^ false].
    family := aString copyFrom:start to:(end - 1).

    start := end + 1.
    end := aString indexOf:$- startingAt:start.
    (end == 0) ifTrue:[^ false].
    face := aString copyFrom:start to:(end - 1).

    start := end + 1.
    end := aString indexOf:$- startingAt:start.
    (end == 0) ifTrue:[^ false].
    style := aString copyFrom:start to:(end - 1).
    (style = 'o') ifTrue:[
	style := 'oblique'
    ] ifFalse:[
	(style = 'i') ifTrue:[
	    style := 'italic'
	] ifFalse:[
	    (style = 'r') ifTrue:[
		style := 'roman'
	    ]
	]
    ].

    start := end + 1.
    end := aString indexOf:$- startingAt:start.
    (end == 0) ifTrue:[^ false].
    moreStyle := aString copyFrom:start to:(end - 1).

    start := end + 1.
    end := aString indexOf:$- startingAt:start.
    (end == 0) ifTrue:[^ false].
    skip := aString copyFrom:start to:(end - 1).

    start := end + 1.
    end := aString indexOf:$- startingAt:start.
    (end == 0) ifTrue:[^ false].
    fheight := aString copyFrom:start to:(end - 1).

    start := end + 1.
    end := aString indexOf:$- startingAt:start.
    (end == 0) ifTrue:[^ false].
    size := aString copyFrom:start to:(end - 1).
    size := (Number readFromString:size) / 10.

    start := end + 1.
    end := aString indexOf:$- startingAt:start.
    (end == 0) ifTrue:[^ false].
    resX := aString copyFrom:start to:(end - 1).

    start := end + 1.
    end := aString indexOf:$- startingAt:start.
    (end == 0) ifTrue:[^ false].
    resY := aString copyFrom:start to:(end - 1).

    start := end + 1.
    end := aString indexOf:$- startingAt:start.
    (end == 0) ifTrue:[^ false].
    x1 := aString copyFrom:start to:(end - 1).

    start := end + 1.
    end := aString indexOf:$- startingAt:start.
    (end == 0) ifTrue:[^ false].
    x2 := aString copyFrom:start to:(end - 1).

    start := end + 1.
    end := aString indexOf:$- startingAt:start.
    (end == 0) ifTrue:[^ false].
    coding := aString copyFrom:start to:(end - 1).

    aBlock value:family value:face value:style value:size value:coding.
    ^ true

    "Modified: 27.9.1995 / 10:46:52 / stefan"
!

listOfAvailableFonts
    "return a list with all available fonts on this display.
     Since this takes a long time, keep the result of the query for the
     next time. The elements of the returned collection are instances of
     FontDescription."

    |stream names aName fntDescr|

    listOfXFonts isNil ifTrue:[
"/
"/ old code; using a pipe to xlsfonts
"/
"/      stream := PipeStream readingFrom:'xlsfonts ''*'''.
"/      stream isNil ifTrue:[^ nil].
"/      listOfXFonts := OrderedCollection new.
"/      [stream atEnd] whileFalse:[
"/          aName := stream nextLine.
"/          aName notNil ifTrue:[
"/          self decomposeXFontName:aName into:
"/                  [:family :face :style :size :coding |
"/                      family notNil ifTrue:[
"/                          fntDescr := FontDescription
"/                                          family:family
"/                                          face:face
"/                                          style:style
"/                                          size:size
"/                                          encoding:coding.
"/                          listOfXFonts add:fntDescr
"/                      ]
"/                  ]
"/          ]
"/      ].
"/      stream close.
"/      "if xlsfont is broken ... (hey sco)"
"/      (listOfXFonts size == 0) ifTrue:[
"/          listOfXFonts := nil
"/      ] ifFalse:[
"/          listOfXFonts sort:[:a :b | a family < b family].
"/      ].

	"/
	"/ new code:
	"/ use new primitive to get font names;
	"/ this is much faster, and also works on systems where
	"/      a) xlsfonts is broken (sco)
	"/      b) xlsfonts is not available (aix)
	"/
	names := self getAvailableFontsMatching:'*'.
	names isNil ifTrue:[
	    "no names returned ..."
	    ^ nil
	].
	listOfXFonts := names collect:[:aName |
				    |fntDescr|

				    (self decomposeXFontName:aName into:
					[:family :face :style :size :coding |
					   family notNil ifTrue:[
					       fntDescr := FontDescription
							       family:family
							       face:face
							       style:style
							       size:size
							       encoding:coding.
					   ] ifFalse:[
					       fntDescr := FontDescription
							       name:aName
					   ]
					]
				    ) ifFalse:[
					fntDescr := FontDescription name:aName.
				    ].  
				    fntDescr
			    ].

    ].
    ^ listOfXFonts

    "
     Display listOfAvailableFonts
    "

    "Modified: 27.9.1995 / 10:54:47 / stefan"
!

getAvailableFontsMatching:pattern
    "return an Array filled with font names matching aPattern"

%{  /* UNLIMITEDSTACK */

    int nnames = 1500;
    int available = nnames + 1;
    char **fonts;
    OBJ arr, str;
    int i;

    if (ISCONNECTED) {
	if (__isString(pattern)) {
	    for (;;) {
		fonts = XListFonts(myDpy, __stringVal(pattern), nnames, &available);
		if ((fonts == NULL) || (available < nnames)) break;
		XFreeFontNames(fonts);
		nnames = available * 2;
	    }
	    if (fonts == NULL) {
		RETURN ( nil );
	    }
	    /*
	     * now, that we know the number of font names,
	     * create the array ...
	     */
	    arr = __ARRAY_NEW_INT(available);
	    if (! arr) {
		RETURN (nil);
	    }
	    /*
	     * ... and fill it
	     */
	    for (i=0; i<available; i++) {
		PROTECT(arr);
		str = __MKSTRING(fonts[i] COMMA_CON);
		UNPROTECT(arr);
		__ArrayInstPtr(arr)->a_element[i] = str; __STORE(arr, str);
	    }
	    RETURN (arr);
	}
    }
%}.
    ^ nil
!

getFontWithFamily:familyString face:faceString
	    style:styleString size:sizeArg encoding:encodingSym

    "try to get the specified font, if not available, try next smaller
     font. Access to X-fonts by name is possible, by passing the X font name
     as family and the other parameters as nil. For example, the cursor font
     can be aquired that way."

    |theSize theName theId xlatedStyle enc|

    "special: if face is nil, allow access to X-fonts"
    faceString isNil ifTrue:[
	sizeArg notNil ifTrue:[
	    theName := familyString , '-' , sizeArg printString
	] ifFalse:[
	    theName := familyString
	].
	theName isNil ifTrue:[
	    "
	     mhmh - fall back to the default font
	    "
	    theName := 'fixed'
	].
	theId := self createFontFor:theName.
	theId isNil ifTrue:[
	    theId := self getDefaultFont
	].
	^ theId
    ].

"/ new:
    xlatedStyle := styleString.
    xlatedStyle notNil ifTrue:[
	xlatedStyle := xlatedStyle first asString
    ].

    ^ self 
	getFontWithFoundry:'*'
	family:familyString asLowercase
	weight:faceString
	slant:xlatedStyle
	spacing:'normal'
	pixelSize:nil
	size:sizeArg 
	registry:'*'
	encoding:encodingSym.


"/ old:
"/    xlatedStyle := styleString.
"/    "oblique is named italic in times font"
"/    ((familyString = 'Times') or:[familyString = 'times']) ifTrue:[
"/        ((styleString = 'Oblique') or:[styleString = 'oblique']) ifTrue:[
"/            xlatedStyle := 'italic'
"/        ]
"/    ].
"/    (xlatedStyle = 'italic') ifTrue:[
"/        xlatedStyle := 'i'
"/    ] ifFalse:[
"/        (xlatedStyle = 'roman') ifTrue:[
"/            xlatedStyle := 'r'
"/        ] ifFalse:[
"/            (xlatedStyle = 'oblique') ifTrue:[
"/                xlatedStyle := 'o'
"/            ]
"/        ]
"/    ].
"/
"/    theId := nil.
"/    theSize := sizeArg.
"/    [theId isNil] whileTrue:[
"/        "this works only on Release >= 3 - X-servers"
"/        enc := encodingSym.
"/        enc isNil ifTrue:[
"/            enc := '*'
"/        ].
"/        theName := ('-*-' , familyString ,
"/                     '-' , faceString ,
"/                     '-' , xlatedStyle , '-*-*-*-'
"/                     , theSize printString , '0-*-*-*-*-'
"/                     , enc , '-*').
"/"
"/Transcript showCr:theName; endEntry.
"/"
"/        theId := self createFontFor:theName.
"/        theId isNil ifTrue:[
"/            "could not get the font - try next smaller one"
"/            theSize := theSize - 1.
"/            (theSize < (sizeArg // 2)) ifTrue:[
"/                "thats too much - give up"
"/                ^ self getDefaultFont
"/                "^ nil"
"/            ]
"/        ]
"/    ].
"/    (theSize ~~ sizeArg) ifTrue:[
"/        Transcript show:'next smaller font: '.
"/        Transcript showCr:theName
"/    ].
"/    ^ theId
!

getFontWithFoundry:foundry family:family weight:weight
	      slant:slant spacing:spc pixelSize:pSize size:size 
	      registry:registry encoding:encoding

    "get the specified font, if not available, return nil.
     This is the new font creation method - all others will be changed to
     use this entry.
     Individual attributes can be left empty (i.e. '') or nil to match any.

     foundry: 'adobe', 'misc', 'dec', 'schumacher' ... usually '*'
     family:  'helvetica' 'courier' 'times' ...
     weight:  'bold' 'medium' 'demi' ...
     slant:   'r(oman)' 'i(talic)' 'o(blique)'
     spacing: 'narrow' 'normal' semicondensed' ... usually '*'
     pixelSize: 16,18 ... usually left empty
     size:      size in point (1/72th of an inch)
     registry:  iso8859, sgi ... '*'
    "

    |theName sMatch|

    "this works only on 'Release >= 3' - X-servers"
    "name is:
	-foundry-family    -weight -slant-
	 sony    helvetica bold     r
	 adobe   courier   medium   i
	 msic    fixed              o
	 ...     ...
    "

    size isNil ifTrue:[sMatch := '*'] ifFalse:[sMatch := size printString , '0'].

    theName := ('-' , (foundry isNil ifTrue:['*'] ifFalse:[foundry]),
		'-' , (family isNil ifTrue:['*'] ifFalse:[family]),
		'-' , (weight isNil ifTrue:['*'] ifFalse:[weight]) ,
		'-' , (slant isNil ifTrue:['*'] ifFalse:[slant]) , 
		'-' , (spc isNil ifTrue:['*'] ifFalse:[spc]) ,
		'-*' ,
		'-' , (pSize isNil ifTrue:['*'] ifFalse:[pSize printString]),
		'-' , sMatch ,
		'-*-*-*-*' ,
		'-' , (registry isNil ifTrue:['*'] ifFalse:[registry]) ,
		'-' , (encoding isNil ifTrue:['*'] ifFalse:[encoding])).
"/  Transcript showCr:theName; endEntry.

    ^ self createFontFor:theName.

    "
     Display getFontWithFoundry:'*'
			 family:'courier'
			 weight:'medium'
			  slant:'r'
			spacing:nil
		      pixelSize:nil
			   size:13
		       registry:'iso8859'
		       encoding:'*'
    "
!

createFontFor:aFontName
    "a basic method for X-font allocation; this method allows
     any font to be aquired (even those not conforming to
     standard naming conventions, such as cursor, fixed or k14)"

%{  /* UNLIMITEDSTACK */
    /* UNLIMITEDSTACK STACK:100000 xxNOCONTEXT */

    XFontStruct *newFont;

    if (ISCONNECTED) {
	if (__isString(aFontName) || __isSymbol(aFontName)) {
	    BEGIN_INTERRUPTSBLOCKED
	    newFont = XLoadQueryFont(myDpy, (char *)__stringVal(aFontName));
	    END_INTERRUPTSBLOCKED
	    RETURN ( newFont ? __MKOBJ(newFont) : nil );
	}
    }
%}.
    ^ nil
!

getDefaultFont
    "return a default font id - used when class Font cannot
     find anything usable"

     ^ self createFontFor:'fixed'
!

releaseFont:aFontId

%{  /* NOCONTEXT */

    XFontStruct *f;

    if (ISCONNECTED) {
	if (__isExternalAddress(aFontId)) {
	    f = _FontVal(aFontId);
	    BEGIN_INTERRUPTSBLOCKED
	    XFreeFont(myDpy, f);
	    END_INTERRUPTSBLOCKED
	    RETURN ( self );
	}
    }
%}
.
    self primitiveFailed
!

ascentOf:aFontId
    "the normal ascent"

%{  /* NOCONTEXT */

    XFontStruct *f;

    if (__isExternalAddress(aFontId)) {
	f = _FontVal(aFontId);
	RETURN ( _MKSMALLINT(f->ascent) );
    }
%}
.
    self primitiveFailed.
    ^ nil
!

descentOf:aFontId
    "the normal descent"

%{  /* NOCONTEXT */

    XFontStruct *f;

    if (__isExternalAddress(aFontId)) {
	f = _FontVal(aFontId);
	RETURN ( _MKSMALLINT(f->descent) );
    }
%}
.
    self primitiveFailed.
    ^ nil
!

minWidthOfFont:aFontId

%{  /* NOCONTEXT */

    XFontStruct *f;

    if (__isExternalAddress(aFontId)) {
	f = _FontVal(aFontId);
	RETURN ( _MKSMALLINT(f->min_bounds.width) );
    }
%}
.
    self primitiveFailed.
    ^ nil
!

maxAscentOf:aFontId
    "the max ascent"

%{  /* NOCONTEXT */

    XFontStruct *f;

    if (__isExternalAddress(aFontId)) {
	f = _FontVal(aFontId);
	RETURN ( _MKSMALLINT(f->max_bounds.ascent) );
    }
%}
.
    self primitiveFailed.
    ^ nil
!

maxDescentOf:aFontId
    "the max descent"

%{  /* NOCONTEXT */

    XFontStruct *f;

    if (__isExternalAddress(aFontId)) {
	f = _FontVal(aFontId);
	RETURN ( _MKSMALLINT(f->max_bounds.descent) );
    }
%}
.
    self primitiveFailed.
    ^ nil
!

maxWidthOfFont:aFontId
    "the width of the widest character"

%{  /* NOCONTEXT */

    XFontStruct *f;

    if (__isExternalAddress(aFontId)) {
	f = _FontVal(aFontId);
	RETURN ( _MKSMALLINT(f->max_bounds.width) );
    }
%}
.
    self primitiveFailed.
    ^ nil
!

widthOf:aString inFont:aFontId

%{  /* NOCONTEXT */

    XFontStruct *f;
    char *cp;
    int len, n;

    if (__isExternalAddress(aFontId)) {
	f = _FontVal(aFontId);
	if (__isString(aString) || __isSymbol(aString)) {
	    n = _stringSize(aString);
	    cp = (char *)_stringVal(aString);
	    BEGIN_INTERRUPTSBLOCKED
	    len = XTextWidth(f, cp, n);
	    END_INTERRUPTSBLOCKED
	    RETURN ( _MKSMALLINT(len) );
	}
#ifdef TWOBYTESTRINGS
	if (__Class(aString) == @global(TwoByteString)) {
	    n = _byteArraySize(aString) / 2;
	    cp = (char *) _stringVal(aString);
	    BEGIN_INTERRUPTSBLOCKED
	    len = XTextWidth16(f, (XChar2b *)cp, n);
	    END_INTERRUPTSBLOCKED
	    RETURN ( _MKSMALLINT(len) );
	}
#endif
    }
%}
.
    self primitiveFailed.
    ^ nil
!

widthOf:aString from:index1 to:index2 inFont:aFontId

%{  /* NOCONTEXT */

    XFontStruct *f;
    char *cp;
    int len, n, i1, i2;

    if (__bothSmallInteger(index1, index2)
     && __isExternalAddress(aFontId)) {
	f = _FontVal(aFontId);
	i1 = _intVal(index1) - 1;
	i2 = _intVal(index2) - 1;
	if (__isString(aString) || __isSymbol(aString)) {
	    cp = (char *) _stringVal(aString);
	    n = _stringSize(aString);
	    if ((i1 >= 0) && (i2 >= i1) && (i2 < n)) {
		cp += i1;
		BEGIN_INTERRUPTSBLOCKED
		len = XTextWidth(f, cp, i2 - i1 + 1);
		END_INTERRUPTSBLOCKED
		RETURN ( _MKSMALLINT(len) );
	    }
	}
#ifdef TWOBYTESTRINGS
	if (__Class(aString) == @global(TwoByteString)) {
	    cp = (char *) _stringVal(aString);
	    n = _byteArraySize(aString) / 2;
	    if ((i1 >= 0) && (i2 >= i1) && (i2 < n)) {
		cp += (i1 * 2);
		BEGIN_INTERRUPTSBLOCKED
		len = XTextWidth16(f, (XChar2b *)cp, i2 - i1 + 1);
		END_INTERRUPTSBLOCKED
		RETURN ( _MKSMALLINT(len) );
	    }
	}
#endif
    }
%}
.
    self primitiveFailed.
    ^ nil
!

sizesInFamily:aFamilyName face:aFaceName style:aStyleName
    "return a set of all available font sizes in aFamily/aFace/aStyle
     on this display.
     Redefined to handle X's special case of 0-size (which stands for any)"

    |sizes|

    sizes := super sizesInFamily:aFamilyName face:aFaceName style:aStyleName.
    (sizes notNil and:[sizes includes:0]) ifTrue:[
	"special: in X11R5 and above, size 0 means:
	 there are scaled versions in all sizes available"

	^ #(4 5 6 7 8 9 10 11 12 14 16 18 20 22 24 28 32 48 64)
    ].
    ^ sizes

    "
     Display sizesInFamily:'courier' face:'bold' style:'roman'
    "
! !

!XWorkstation methodsFor:'cursor stuff'!

destroyCursor:aCursorId

%{  /* NOCONTEXT */

    if (ISCONNECTED) {
	if (__isExternalAddress(aCursorId)) {
	    BEGIN_INTERRUPTSBLOCKED
	    XFreeCursor(myDpy, _CursorVal(aCursorId));
	    END_INTERRUPTSBLOCKED
	    RETURN ( self );
	}
    }
%}
.
    self primitiveFailed
!

createCursorSourceForm:sourceForm maskForm:maskForm hotX:hx hotY:hy
    "create a cursor given 2 bitmaps (source, mask) and a hotspot"

    |id sourceId maskId|

    displayId isNil ifTrue:[
	self primitiveFailed.
	^ nil
    ].
    sourceId := sourceForm id.
    maskId := maskForm id.
%{
    Cursor newCursor;
    XColor fgColor, bgColor;

    if (__isExternalAddress(sourceId)
     && __isExternalAddress(maskId)
     && __bothSmallInteger(hx, hy)) {
	fgColor.red = 0;        /* fg is black */
	fgColor.green = 0;
	fgColor.blue = 0;
	bgColor.red = 0xFFFF;   /* bg is white */
	bgColor.green = 0xFFFF;
	bgColor.blue = 0xFFFF;

	BEGIN_INTERRUPTSBLOCKED
	newCursor = XCreatePixmapCursor(myDpy,
				_PixmapVal(sourceId),
				_PixmapVal(maskId),
				&fgColor, &bgColor, _intVal(hx), _intVal(hy));
	END_INTERRUPTSBLOCKED
	if (newCursor != (Cursor)0) {
	    id = __MKOBJ(newCursor);
	}
    }
%}.
    ^ id
!

shapeNumberFromSymbol:shape
    "given a shape-symbol, return the corresponding cursor-number"

    "this is pure X-knowlegde - but you may easily add more"

    (shape == #upLeftArrow)     ifTrue:[ ^ %{ __MKSMALLINT(XC_top_left_arrow)    %} "132" ].
    (shape == #upRightHand)     ifTrue:[ ^ %{ __MKSMALLINT(XC_hand1)             %} "58" ].
    (shape == #upDownArrow)     ifTrue:[ ^ %{ __MKSMALLINT(XC_sb_v_double_arrow) %} "116" ].
    (shape == #leftRightArrow)  ifTrue:[ ^ %{ __MKSMALLINT(XC_sb_h_double_arrow) %} "108" ].
    (shape == #upLimitArrow)    ifTrue:[ ^ %{ __MKSMALLINT(XC_top_side)          %} "138" ].
    (shape == #downLimitArrow)  ifTrue:[ ^ %{ __MKSMALLINT(XC_bottom_side)       %} "16" ].
    (shape == #leftLimitArrow)  ifTrue:[ ^ %{ __MKSMALLINT(XC_left_side)         %} "70" ].
    (shape == #rightLimitArrow) ifTrue:[ ^ %{ __MKSMALLINT(XC_right_side)        %} "96" ].
    (shape == #text)            ifTrue:[ ^ %{ __MKSMALLINT(XC_xterm)             %} "152" ].
    (shape == #upRightArrow)    ifTrue:[ ^ %{ __MKSMALLINT(XC_draft_large)       %} "44" ].
    (shape == #leftHand)        ifTrue:[ ^ %{ __MKSMALLINT(XC_hand2)             %} "60" ].
    (shape == #questionMark)    ifTrue:[ ^ %{ __MKSMALLINT(XC_question_arrow)    %} "92" ].
    (shape == #cross)           ifTrue:[ ^ %{ __MKSMALLINT(XC_X_cursor)          %} "0" ].
    (shape == #wait)            ifTrue:[ ^ %{ __MKSMALLINT(XC_watch)             %} "150" ].
    (shape == #crossHair)       ifTrue:[ ^ %{ __MKSMALLINT(XC_tcross)            %} "130" ].
    ((shape == #origin)
    or:[shape == #topLeft])     ifTrue:[ ^ %{ __MKSMALLINT(XC_ul_angle)          %} "144" ].
    ((shape == #corner)
    or:[shape == #bottomRight]) ifTrue:[ ^ %{ __MKSMALLINT(XC_lr_angle)          %} "78" ].
    (shape == #topRight)        ifTrue:[ ^ %{ __MKSMALLINT(XC_ur_angle)          %} "148" ].
    (shape == #bottomLeft)      ifTrue:[ ^ %{ __MKSMALLINT(XC_ll_angle)          %} "76" ].
    (shape == #square)          ifTrue:[ ^ %{ __MKSMALLINT(XC_dotbox)            %} "40" ].
    (shape == #fourWay)         ifTrue:[ ^ %{ __MKSMALLINT(XC_fleur)             %} "52" ].
    (shape == #crossCursor)     ifTrue:[ ^ %{ __MKSMALLINT(XC_X_cursor)          %} "0" ].
    ('XWORKSTATION: invalid cursorShape:' , shape printString) errorPrintNL.
    ^  0
!

createCursorShape:aShape
    "create a cursor given a shape-symbol"

    |number id|

    displayId isNil ifTrue:[
	self primitiveFailed.
	^ nil
    ].
    number := self shapeNumberFromSymbol:aShape.
%{
    Cursor newCursor;

    if (__isSmallInteger(number)) {
	BEGIN_INTERRUPTSBLOCKED
	newCursor = XCreateFontCursor(myDpy, _intVal(number));
	END_INTERRUPTSBLOCKED
	if (newCursor != (Cursor)0) {
	    id = __MKOBJ(newCursor);
	}
    }
%}.
    ^ id
!

colorCursor:aCursorId foreground:fgColor background:bgColor
    "change a cursors colors"

    |fgR fgG fgB bgR bgG bgB|

    fgR := fgColor red.
    fgG := fgColor green.
    fgB := fgColor blue.
    bgR := bgColor red.
    bgG := bgColor green.
    bgB := bgColor blue.

    fgR := self percentToXColorValue:fgR.
    fgG := self percentToXColorValue:fgG.
    fgB := self percentToXColorValue:fgB.
    bgR := self percentToXColorValue:bgR.
    bgG := self percentToXColorValue:bgG.
    bgB := self percentToXColorValue:bgB.

%{
    XColor fgcolor, bgcolor;

    if (__isExternalAddress(aCursorId)
     && __bothSmallInteger(fgG, fgB)
     && __bothSmallInteger(bgR, bgG) 
     && __bothSmallInteger(bgB, fgR)) {

	fgcolor.red = _intVal(fgR);
	fgcolor.green= _intVal(fgG);
	fgcolor.blue = _intVal(fgB);
	bgcolor.red = _intVal(bgR);
	bgcolor.green= _intVal(bgG);
	bgcolor.blue = _intVal(bgB);
	BEGIN_INTERRUPTSBLOCKED
	XRecolorCursor(myDpy, _CursorVal(aCursorId), &fgcolor, &bgcolor);
	END_INTERRUPTSBLOCKED
	RETURN ( self );
    }
%}
.
    self primitiveFailed
! !

!XWorkstation methodsFor:'grabbing '!

grabKeyboardIn:aWindowId
    "grab the keyboard"

%{  /* NOCONTEXT */
    int result, ok;

    if (__isExternalAddress(aWindowId)) {
	BEGIN_INTERRUPTSBLOCKED
	result = XGrabKeyboard(myDpy,
			       _WindowVal(aWindowId),
			       True /* False */,
			       GrabModeAsync,
			       GrabModeAsync,
			       CurrentTime);
	END_INTERRUPTSBLOCKED
	ok = 0;
	switch(result) {
	    case AlreadyGrabbed: 
		printf("XWORKSTAT: grab keyboard: AlreadyGrabbed\n");
		break;
	    case GrabNotViewable: 
		printf("XWORKSTAT: grab keyboard: GrabNotViewable\n");
		break;
	    case GrabInvalidTime: 
		printf("XWORKSTAT: grab keyboard: InvalidTime\n");
		break;
	    case GrabFrozen: 
		printf("XWORKSTAT: grab keyboard: Frozen\n");
		break;
	    default:
		ok = 1;
		break;
	}
	if (! ok) {
	    XUngrabKeyboard(myDpy, CurrentTime);
	    RETURN (false);
	}

	RETURN ( true );
    }
%}
.
    self primitiveFailed
!

ungrabKeyboard
    "release the keyboard"

%{  /* NOCONTEXT */

    if (ISCONNECTED) {
	BEGIN_INTERRUPTSBLOCKED
	XUngrabKeyboard(myDpy, CurrentTime);
	XSync(myDpy, 0);
	END_INTERRUPTSBLOCKED
    }
%}.
    activeKeyboardGrab := nil
!

grabPointerIn:aWindowId withCursor:aCursorId pointerMode:pMode keyboardMode:kMode confineTo:confineId
    "grap the pointer - return true if ok"

%{  /* NOCONTEXT */

    int result, ok;
    Window confineWin;
    Cursor curs;
    int pointer_mode, keyboard_mode;

    if (__isExternalAddress(aWindowId)) {
	if (__isExternalAddress(confineId)) 
	    confineWin = _WindowVal(confineId);
	else
	    confineWin = (Window) None;

	if (__isExternalAddress(aCursorId)) 
	    curs = _CursorVal(aCursorId);
	else
	    curs = (Cursor) None;

	if (pMode == @symbol(sync))
	    pointer_mode = GrabModeSync;
	else
	    pointer_mode = GrabModeAsync;

	if (kMode == @symbol(sync))
	    keyboard_mode = GrabModeSync;
	else
	    keyboard_mode = GrabModeAsync;

	BEGIN_INTERRUPTSBLOCKED
	result = XGrabPointer(myDpy,
			      _WindowVal(aWindowId), 
			      False, 
			      ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
			      pointer_mode, keyboard_mode,
			      confineWin,
			      curs,
			      CurrentTime);
	END_INTERRUPTSBLOCKED

	ok = 0;
	switch (result) {
	    case AlreadyGrabbed: 
		printf("XWORKSTAT: grab pointer: AlreadyGrabbed\n");
		break;
	    case GrabNotViewable: 
		printf("XWORKSTAT: grab pointer: GrabNotViewable\n");
		break;
	    case GrabInvalidTime: 
		printf("XWORKSTAT: grab pointer: InvalidTime\n");
		break;
	    case GrabFrozen: 
		printf("XWORKSTAT: grab pointer: Frozen\n");
		break;
	    default:
		ok = 1;
		break;
	}

	if (! ok) {
	    XUngrabPointer(myDpy, CurrentTime);
	    RETURN (false);
	}
	RETURN ( true );
    }
%}
.
    self primitiveFailed
!

ungrabPointer
    "release the pointer"

%{  /* NOCONTEXT */

    if (ISCONNECTED) {
	BEGIN_INTERRUPTSBLOCKED
	XUngrabPointer(myDpy, CurrentTime);
	XSync(myDpy, 0);
	END_INTERRUPTSBLOCKED
    }
%}.
    activePointerGrab := nil
!

allowEvents:mode
%{  /* NOCONTEXT */

    int _mode, ok = 1;

    if (mode == @symbol(asyncPointer))
	_mode = AsyncPointer;
    else if (mode == @symbol(syncPointer))
	_mode = SyncPointer;
    else if (mode == @symbol(asyncKeyboard))
	_mode = AsyncKeyboard;
    else if (mode == @symbol(syncKeyboard))
	_mode = SyncKeyboard;
    else if (mode == @symbol(syncBoth))
	_mode = SyncBoth;
    else if (mode == @symbol(asyncBoth))
	_mode = AsyncBoth;
    else if (mode == @symbol(replayPointer))
	_mode = ReplayPointer;
    else if (mode == @symbol(replayKeyboard))
	_mode = ReplayKeyboard;
    else
	ok = 0;

    if (ok) {
	BEGIN_INTERRUPTSBLOCKED
	XAllowEvents(myDpy, _mode, CurrentTime);
	END_INTERRUPTSBLOCKED
	RETURN (self);
    }
%}
.
    self primitiveFailed
! !

!XWorkstation methodsFor:'pointer queries '!

rootPositionOfLastEvent
    "return the position in root-window coordinates
     of the last button, key or pointer event"

    ^ eventRootX @ eventRootY
!

pointerPosition
    "return the current pointer position in root-window coordinates"

    |xpos ypos|

%{
    Display *dpy = myDpy;
    Window w;
    int screen = _intVal(_INST(screen));
    Window rootRet, childRet;
    int rootX, rootY, winX, winY;
    unsigned int mask;

    BEGIN_INTERRUPTSBLOCKED
#ifdef VIRTUAL_ROOT
    w = getRootWindow(myDpy, screen);
#else
    w = RootWindow(dpy, screen);
#endif
    XQueryPointer(dpy, w, &rootRet, &childRet,
			  &rootX, &rootY,
			  &winX, &winY,
			  &mask);
    xpos = _MKSMALLINT(rootX);
    ypos = _MKSMALLINT(rootY);
    END_INTERRUPTSBLOCKED
%}
.
    ^ xpos @ ypos
!

buttonStates
    "return an integer representing the state of the pointer buttons;
     a one-bit in positions 0.. represent a pressed button"

%{  /* NOCONTEXT*/
    Display *dpy = myDpy;
    Window w;
    int screen = _intVal(_INST(screen));
    Window rootRet, childRet;
    int rootX, rootY, winX, winY;
    unsigned int mask;

    BEGIN_INTERRUPTSBLOCKED
#ifdef VIRTUAL_ROOT
    w = getRootWindow(myDpy, screen);
#else
    w = RootWindow(dpy, screen);
#endif
    XQueryPointer(dpy, w, &rootRet, &childRet,
			  &rootX, &rootY,
			  &winX, &winY,
			  &mask);
    END_INTERRUPTSBLOCKED
    RETURN (_MKSMALLINT(mask));
%}
!

leftButtonStateMask
    "return an integer for masking out the left button from a
     buttonStates value"

    ^ 256
!

middleButtonStateMask
    "return an integer for masking out the middle button from a
     buttonStates value"

    ^ 512
!

rightButtonStateMask
    "return an integer for masking out the right button from a
     buttonStates value"

    ^ 1024
! !

!XWorkstation methodsFor:'color stuff'!

listOfAvailableColors
    "return a list of all available colornames.
     This should not be used, since colornames are very
     display-specific (here X-specific)."

    |aStream list line index colorName|

    aStream := FileStream readonlyFileNamed:'/usr/lib/X11/rgb.txt'.
    aStream isNil ifTrue:[^ nil].
    list := OrderedCollection new.
    [aStream atEnd] whileFalse:[
	line := aStream nextLine.
	line notNil ifTrue:[
	    "skip the r/g/b numbers"
	    index := 1.
	    [(line at:index) isDigit] whileTrue:[index := index + 1].
	    [(line at:index) isSeparator] whileTrue:[index := index + 1].
	    [(line at:index) isDigit] whileTrue:[index := index + 1].
	    [(line at:index) isSeparator] whileTrue:[index := index + 1].
	    [(line at:index) isDigit] whileTrue:[index := index + 1].
	    [(line at:index) isSeparator] whileTrue:[index := index + 1].
	    colorName := line copyFrom:index.
	    ((colorName occurrencesOf:(Character space)) == 0) ifTrue:[
		list add:colorName
	    ]
	]
    ].
    aStream close.
    ^ list sort
!

freeColor:colorIndex
    "free a display color when its no longer needed"

%{  /* NOCONTEXT */

    Display *dpy = myDpy;
    unsigned long color;
    int screen = _intVal(_INST(screen));

#ifdef LATER
    if (_INST(visualType) == @symbol(TrueColor)) {
	/* no need to do anything on TrueColor displays ... */
	RETURN (self);
    }
#endif
    if (__isSmallInteger(colorIndex) && ISCONNECTED) {
	color = (long) _intVal(colorIndex);
	BEGIN_INTERRUPTSBLOCKED
	XFreeColors(dpy, DefaultColormap(dpy, screen), &color, 1, 0L);
	END_INTERRUPTSBLOCKED
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

percentToXColorValue:aPercentage
    "given a color-component value in percent (0..100), return the corresponding
     x-component value (0..65k) as an integer"

%{  /* NOCONTEXT */

    if (__isSmallInteger(aPercentage)) {
	RETURN ( _MKSMALLINT(0xFFFF * _intVal(aPercentage) / 100) );
    }
    if (__isFloat(aPercentage)) {
	RETURN ( _MKSMALLINT(0xFFFF * (int)(_floatVal(aPercentage)) / 100) );
    }
%}
.
    ^ (16rFFFF * aPercentage / 100) rounded
!

colorRed:redVal green:greenVal blue:blueVal
    "allocate a color with rgb values (0..100) - return index"

    |r g b|

    r := self percentToXColorValue:redVal.
    g := self percentToXColorValue:greenVal.
    b := self percentToXColorValue:blueVal.
%{
    Display *dpy = myDpy;
    XColor ecolor;
    int screen = _intVal(_INST(screen));
    Status ok;

    if (__bothSmallInteger(r, g) 
     && __isSmallInteger(b)
     && ISCONNECTED) {
	ecolor.red = _intVal(r);
	ecolor.green= _intVal(g);
	ecolor.blue = _intVal(b);
	BEGIN_INTERRUPTSBLOCKED
	ok = XAllocColor(dpy, DefaultColormap(dpy, screen), &ecolor);
	END_INTERRUPTSBLOCKED
	if (! ok) {
	    RETURN ( nil );
	}
	RETURN ( _MKSMALLINT(ecolor.pixel) );
    }
%}
.
    self primitiveFailed.
    ^ nil
!

colorNamed:aString
    "allocate a color with color name - return index.
     Dont use this method, colornames are mostly X specific"

%{  /* NOCONTEXT */

    char *colorname;
    Display *dpy = myDpy;
    XColor scolor, ecolor;
    int screen =_intVal(_INST(screen));
    Status ok;

    if (ISCONNECTED) {
	if (__isString(aString) || __isSymbol(aString)) {
	    colorname = (char *)_stringVal(aString);

	    BEGIN_INTERRUPTSBLOCKED
	    ok = XParseColor(dpy, DefaultColormap(dpy, screen), colorname, &ecolor);
	    if (ok) {
		ok = XAllocColor(dpy, DefaultColormap(dpy, screen), &ecolor);
	    }
	    END_INTERRUPTSBLOCKED
	    if (! ok) {
		RETURN ( nil );
	    }
	    RETURN ( _MKSMALLINT(ecolor.pixel) );
	}
    }
%}
.
    self primitiveFailed.
    ^ nil
!

colorCell
    "allocate a color cell - return index.
     This method will return nil for StaticGrey and StaticGrey displays."

%{  /* NOCONTEXT */

    Display *dpy = myDpy;
    int screen = _intVal(_INST(screen));
    XColor color;
    unsigned long dummy;
    Status ok;

    BEGIN_INTERRUPTSBLOCKED
    ok = XAllocColorCells(dpy, DefaultColormap(dpy, screen), (Bool)0,
			       &dummy, 0, &color.pixel, 1);
    END_INTERRUPTSBLOCKED
    if (ok) {
	RETURN ( _MKSMALLINT(color.pixel) );
    }
%}
.
    ^ nil
!

setColor:index red:redVal green:greenVal blue:blueVal
    "change color in map at:index to rgb (0..100).
     This method is a noop for StaticGrey and StaticGrey displays."

%{  /* NOCONTEXT */

    char *colorname;
    Display *dpy = myDpy;
    XColor color;
    int screen = _intVal(_INST(screen));
    int r, g, b;
    int ok = 1;

    if (__isSmallInteger(redVal))
	r = 0xFFFF * _intVal(redVal) / 100;
    else if (__isFloat(redVal))
	r = 0xFFFF * (int)(_floatVal(redVal)) / 100;
    else ok = 0;

    if (__isSmallInteger(greenVal))
	g = 0xFFFF * _intVal(greenVal) / 100;
    else if (__isFloat(greenVal))
	g = 0xFFFF * (int)(_floatVal(greenVal)) / 100;
    else ok = 0;

    if (__isSmallInteger(blueVal))
	b = 0xFFFF * _intVal(blueVal) / 100;
    else if (__isFloat(blueVal))
	b = 0xFFFF * (int)(_floatVal(blueVal)) / 100;
    else ok = 0;

    if (__isSmallInteger(index) && ok) {
	color.pixel = _intVal(index);
	color.red = r;
	color.green = g;
	color.blue = b;
	color.flags = DoRed | DoGreen | DoBlue;

	BEGIN_INTERRUPTSBLOCKED
	XStoreColor(dpy, DefaultColormap(dpy, screen), &color);
	END_INTERRUPTSBLOCKED
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

getRGBFromName:colorName into:aBlock
    "get rgb components (0..100) of color named colorName,
     and evaluate the 3-arg block, aBlock with them"

    |r g b|

    displayId isNil ifTrue:[
	self pimitiveFailed.
	^ nil
    ].
%{
    Display *dpy = myDpy;
    int screen = _intVal(_INST(screen));
    XColor color;
    double fr, fg, fb;
    double floor();

    if (__isString(colorName) || __isSymbol(colorName)) {
	BEGIN_INTERRUPTSBLOCKED
	if (XParseColor(dpy, DefaultColormap(dpy, screen), 
			     (char *)_stringVal(colorName), &color)) {
	    /* 
	     * scale to 0..100 and round to the first decimal
	     */
	    fr = floor( ((((double)color.red) * 1000.0) / 0xFFFF) + 0.5) / 10.0;
	    fg = floor( ((((double)color.green) * 1000.0) / 0xFFFF) + 0.5) / 10.0;
	    fb = floor( ((((double)color.blue) * 1000.0) / 0xFFFF) + 0.5) / 10.0;

	    r = _MKFLOAT(fr COMMA_CON);
	    g = _MKFLOAT(fg COMMA_CON);
	    b = _MKFLOAT(fb COMMA_CON);
	}
	END_INTERRUPTSBLOCKED
    }
%}
.
    aBlock value:r value:g value:b
!

getRGBFrom:index into:aBlock
    "get rgb components (0..100) of color in map at:index,
     and evaluate the 3-arg block, aBlock with them"

    |r g b|
%{
    Display *dpy = myDpy;
    int screen = _intVal(_INST(screen));
    XColor color;
    double fr, fg, fb;
    double floor();
    int bits, scale, shift;

    if (__isSmallInteger(index)) {
	color.pixel = _intVal(index);
	BEGIN_INTERRUPTSBLOCKED
	XQueryColor(dpy, DefaultColormap(dpy, screen), &color);
	END_INTERRUPTSBLOCKED

	/* scale to 0..100 and round to the first decimal */

	/* 
	 * have to compensate for an error in X ?, which does not scale
	 * colors correctly if lesser than 16bits are valid in a color,
	 * (for example, color white on a 4bitsPerRGB server will return
	 * (16rF000 16rF000 16rF000) instead of (16rFFFF 16rFFFF 16rFFFF)
	 */
	bits = _intVal(_INST(bitsPerRGB));
	scale = (1<<bits) - 1;
	shift = 16 - bits;

	fr = floor( ( ((double)(color.red>>shift) * 1000.0) / scale) + 0.5) / 10.0;
	fg = floor( ( ((double)(color.green>>shift) * 1000.0) / scale) + 0.5) / 10.0;
	fb = floor( ( ((double)(color.blue>>shift) * 1000.0) / scale) + 0.5) / 10.0;

	r = _MKFLOAT(fr COMMA_CON);
	g = _MKFLOAT(fg COMMA_CON);
	b = _MKFLOAT(fb COMMA_CON);
    }
%}.
    aBlock value:r value:g value:b
! !

!XWorkstation methodsFor:'window stuff'!

setBackingStore:how in:aWindowId
    "turn on/off backing-store for a window"

%{  /* NOCONTEXT */

    XSetWindowAttributes wa;

    if (__isExternalAddress(aWindowId)) {
	if (_INST(ignoreBackingStore) != true) {
	    if (how == @symbol(always)) wa.backing_store = Always;
	    else if (how == @symbol(whenMapped)) wa.backing_store = WhenMapped;
	    else if (how == true) wa.backing_store = Always;
	    else wa.backing_store = 0;
	    BEGIN_INTERRUPTSBLOCKED
	    XChangeWindowAttributes(myDpy, _WindowVal(aWindowId), CWBackingStore, &wa);
	    END_INTERRUPTSBLOCKED
	}
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

setBitGravity:how in:aWindowId
    "set bit gravity for a window"

%{  /* NOCONTEXT */

    XSetWindowAttributes wa;

    if (__isExternalAddress(aWindowId)) {
	if (how == @symbol(NorthWest)) {
	    wa.bit_gravity = NorthWestGravity;
	} else if (how == @symbol(NorthEast)) {
	    wa.bit_gravity = NorthEastGravity;
	} else if (how == @symbol(SouthWest)) {
	    wa.bit_gravity = SouthWestGravity;
	} else if (how == @symbol(SouthEast)) {
	    wa.bit_gravity = SouthEastGravity;
	} else if (how == @symbol(Center)) {
	    wa.bit_gravity = CenterGravity;
	} else if (how == @symbol(North)) {
	    wa.bit_gravity = NorthGravity;
	} else if (how == @symbol(South)) {
	    wa.bit_gravity = SouthGravity;
	} else if (how == @symbol(West)) {
	    wa.bit_gravity = WestGravity;
	} else if (how == @symbol(East)) {
	    wa.bit_gravity = EastGravity;
	} else {
	    wa.bit_gravity = NorthWestGravity;
	}

	BEGIN_INTERRUPTSBLOCKED
	XChangeWindowAttributes(myDpy, _WindowVal(aWindowId), CWBitGravity, &wa);
	END_INTERRUPTSBLOCKED
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

setWindowGravity:how in:aWindowId
    "set window gravity for a window"

%{  /* NOCONTEXT */

    XSetWindowAttributes wa;

    if (__isExternalAddress(aWindowId)) {
	if (how == @symbol(NorthWest)) {
	    wa.win_gravity = NorthWestGravity;
	} else if (how == @symbol(NorthEast)) {
	    wa.win_gravity = NorthEastGravity;
	} else if (how == @symbol(SouthWest)) {
	    wa.win_gravity = SouthWestGravity;
	} else if (how == @symbol(SouthEast)) {
	    wa.win_gravity = SouthEastGravity;
	} else if (how == @symbol(Center)) {
	    wa.win_gravity = CenterGravity;
	} else if (how == @symbol(North)) {
	    wa.win_gravity = NorthGravity;
	} else if (how == @symbol(South)) {
	    wa.win_gravity = SouthGravity;
	} else if (how == @symbol(West)) {
	    wa.win_gravity = WestGravity;
	} else if (how == @symbol(East)) {
	    wa.win_gravity = EastGravity;
	} else {
	    wa.win_gravity = NorthWestGravity;
	}

	BEGIN_INTERRUPTSBLOCKED
	XChangeWindowAttributes(myDpy, _WindowVal(aWindowId), CWWinGravity, &wa);
	END_INTERRUPTSBLOCKED
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

setSaveUnder:yesOrNo in:aWindowId
    "turn on/off save-under for a window"

%{  /* NOCONTEXT */

    XSetWindowAttributes wa;

    if (__isExternalAddress(aWindowId)) {
	if (_INST(hasSaveUnder) == true) {
	    wa.save_under = (yesOrNo == true) ? 1 : 0;
	    XChangeWindowAttributes(myDpy, _WindowVal(aWindowId), CWSaveUnder, &wa);
	}
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

setWindowBackground:aColorIndex in:aWindowId
    "set the windows background color. This is the color with which
     the view is filled whenever exposed. Do not confuse this with
     the background drawing color, which is used with opaque drawing."

%{  /* NOCONTEXT */

    if (__isExternalAddress(aWindowId)
     && __isSmallInteger(aColorIndex)) {
	XSetWindowBackground(myDpy, _WindowVal(aWindowId), _intVal(aColorIndex));
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

setWindowBackgroundPixmap:aPixmapId in:aWindowId
    "set the windows background pattern to be a form.
     This is the pattern with which the view is filled whenever exposed. 
     Do not confuse this with the background drawing color, which is used 
     with opaque drawing."

%{  /* NOCONTEXT */

    if (__isExternalAddress(aWindowId)
     && __isExternalAddress(aPixmapId)) {
	XSetWindowBackgroundPixmap(myDpy, _WindowVal(aWindowId), _PixmapVal(aPixmapId));
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

setWindowBorderColor:aColorIndex in:aWindowId
    "set the windows border color"

%{  /* NOCONTEXT */

    if (__isExternalAddress(aWindowId)
     && __isSmallInteger(aColorIndex)) {
	XSetWindowBorder(myDpy, _WindowVal(aWindowId), _intVal(aColorIndex));
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

setWindowBorderPixmap:aPixmapId in:aWindowId
    "set the windows border pattern"

%{  /* NOCONTEXT */

    if (__isExternalAddress(aWindowId)
     && __isExternalAddress(aPixmapId)) {
	XSetWindowBorderPixmap(myDpy, _WindowVal(aWindowId), _PixmapVal(aPixmapId));
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

setWindowBorderWidth:aNumber in:aWindowId
    "set the windows border width"

%{  /* NOCONTEXT */

    if (__isExternalAddress(aWindowId)
     && __isSmallInteger(aNumber)) {
	XSetWindowBorderWidth(myDpy, _WindowVal(aWindowId), _intVal(aNumber));
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

setWindowBorderShape:aPixmapId in:aWindowId
    "set the windows border shape"

    hasShapeExtension ifFalse:[^ self].

%{  /* NOCONTEXT */

#ifdef SHAPE
    if (__isExternalAddress(aWindowId)
     && __isExternalAddress(aPixmapId)) {
	XShapeCombineMask(myDpy, _WindowVal(aWindowId), ShapeBounding,
			  0, 0, _PixmapVal(aPixmapId), ShapeSet);
	RETURN ( self );
    }
#endif
%}.
    self primitiveFailed
!

setWindowShape:aPixmapId in:aWindowId
    "set the windows shape"

    hasShapeExtension ifFalse:[^ self].

%{  /* NOCONTEXT */

#ifdef SHAPE
    if (__isExternalAddress(aWindowId)
     && __isExternalAddress(aPixmapId)) {
	XShapeCombineMask(myDpy, _WindowVal(aWindowId), ShapeClip,
			  0, 0,
			  _PixmapVal(aPixmapId), ShapeSet);
	RETURN ( self );
    }
#endif
%}.
    self primitiveFailed
!

setCursor:aCursorId in:aWindowId
    "define a windows cursor"

%{  /* NOCONTEXT */

    Display *dpy = myDpy;

    if (__isExternalAddress(aWindowId)
     && __isExternalAddress(aCursorId)) {
	XDefineCursor(dpy, _WindowVal(aWindowId), _CursorVal(aCursorId));
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

setWindowName:aString in:aWindowId
    "define a windows name"

%{  /* NOCONTEXT */

    if (__isExternalAddress(aWindowId)
     && (__isString(aString) || __isSymbol(aString))) {
	XStoreName(myDpy, _WindowVal(aWindowId), (char *)_stringVal(aString));
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

setIconName:aString in:aWindowId
    "define a windows iconname"

%{  /* NOCONTEXT */

    if (__isExternalAddress(aWindowId)
     && (__isString(aString) || __isSymbol(aString))) {
	XSetIconName(myDpy, _WindowVal(aWindowId), (char *)_stringVal(aString));
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

setWindowIcon:aForm in:aWindowId
    "define a bitmap to be used as icon"

    |iconId|

    aForm notNil ifTrue:[
	iconId := aForm id
    ].
%{
    if (__isExternalAddress(iconId)
     && __isExternalAddress(aWindowId)) {
	XWMHints hints;

	hints.icon_pixmap = _PixmapVal(iconId);
	hints.flags = IconPixmapHint;
	XSetWMHints(myDpy, _WindowVal(aWindowId), &hints);
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

setWindowIconWindow:aView in:aWindowId
    "define a window to be used as icon"

    |iconWindowId|

    aView notNil ifTrue:[
	iconWindowId := aView id
    ].
%{
    if (__isExternalAddress(iconWindowId)
     && __isExternalAddress(aWindowId)) {
	XWMHints wmhints;

	wmhints.icon_window = _WindowVal(iconWindowId);
	wmhints.flags = IconWindowHint;
	XSetWMHints(myDpy, _WindowVal(aWindowId), &wmhints);
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

setTransient:aWindowId for:aMainWindowId
    "set aWindowId to be a transient of aMainWindow"

%{  /* NOCONTEXT */

    if (__isExternalAddress(aWindowId)
     && __isExternalAddress(aMainWindowId)) {
	XSetTransientForHint(myDpy, _WindowVal(aWindowId),
				    _WindowVal(aMainWindowId));
	RETURN ( self );
    }
%}.
    self primitiveFailed
!

clearWindow:aWindowId
    "clear a window to viewbackground"

%{  /* NOCONTEXT */

    if (__isExternalAddress(aWindowId)) {
	XClearWindow(myDpy, _WindowVal(aWindowId));
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

clearRectangleX:x y:y width:width height:height in:aWindowId
    "clear a rectangular area to viewbackground"

%{  /* NOCONTEXT */

    int w, h;

    if (__isExternalAddress(aWindowId)
     && __bothSmallInteger(x, y)
     && __bothSmallInteger(width, height)) {
	w = _intVal(width);
	h = _intVal(height);
	if (w < 0) w = 0;
	if (h < 0) h = 0;
	XClearArea(myDpy, _WindowVal(aWindowId), _intVal(x), _intVal(y), w, h, 0);
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

mapView:aView id:aWindowId iconified:aBoolean atX:xPos y:yPos width:w height:h
    "make a window visible - either as icon or as a real view - needed for restart"

    |wicon wiconId wiconView wiconViewId wlabel|

    aBoolean ifTrue:[
	wicon := aView icon.
	wicon notNil ifTrue:[
	    wiconId := wicon id
	].
	wiconView := aView iconView.
	wiconView notNil ifTrue:[
	    wiconViewId := wiconView id
	].
	wlabel := aView label.
    ].
%{  

    XWMHints wmhints;
    XSizeHints szhints;
    Display *dpy = myDpy;
    Window win;

    if (__isExternalAddress(aWindowId)) {
	win = _WindowVal(aWindowId);

	szhints.flags = 0;
	if (__bothSmallInteger(xPos, yPos)) {
	    szhints.x = _intVal(xPos);
	    szhints.y = _intVal(yPos);
	    szhints.flags |= USPosition;
	}
	if (__bothSmallInteger(w, h)) {
	    szhints.width = _intVal(w);
	    szhints.height = _intVal(h);
	    szhints.flags |= USSize;
	}

	if (aBoolean == true) {
	    char *windowName;
	    Pixmap iconBitmap = (Pixmap)0;
	    Window iconWindow;

	    if (__isExternalAddress(wiconId))
		iconBitmap = _PixmapVal(wiconId);
	    else
		iconBitmap = (Pixmap)0;

	    if (__isExternalAddress(wiconViewId))
		iconWindow = _WindowVal(wiconViewId);
	    else
		iconWindow = (Window)0;

	    if (__isString(wlabel) || __isSymbol(wlabel))
		windowName = (char *)_stringVal(wlabel);
	    else
		windowName = "";

	    if (iconBitmap || windowName) {
		XSetStandardProperties(dpy, win,
					windowName, windowName,
					iconBitmap,
					0, 0, &szhints);
	    }

	    wmhints.flags = 0;
	    if (iconBitmap) {
		wmhints.flags |= IconPixmapHint;
		wmhints.icon_pixmap = iconBitmap;
	    }
	    if (iconWindow) {
		wmhints.flags |= IconWindowHint;
		wmhints.icon_window = iconWindow;
	    }

	    wmhints.initial_state = IconicState;
	    wmhints.flags |= StateHint;
	    XSetWMHints(dpy, win, &wmhints);
	}

	if (szhints.flags) {
	    XSetNormalHints(dpy, win, &szhints);
	}

	XMapWindow(dpy, win);
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

mapWindow:aWindowId
    "make a window visible"

%{  /* NOCONTEXT */

    if (__isExternalAddress(aWindowId)) {
	XMapWindow(myDpy, _WindowVal(aWindowId));
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

unmapWindow:aWindowId
    "make a window invisible"

%{  /* NOCONTEXT */

    if (__isExternalAddress(aWindowId)) {
	XUnmapWindow(myDpy, _WindowVal(aWindowId));
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

raiseWindow:aWindowId
    "bring a window to front"

%{  /* NOCONTEXT */

    if (__isExternalAddress(aWindowId)) {
	XRaiseWindow(myDpy, _WindowVal(aWindowId));
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

lowerWindow:aWindowId
    "bring a window to back"

%{  /* NOCONTEXT */

    if (__isExternalAddress(aWindowId)) {
	XLowerWindow(myDpy, _WindowVal(aWindowId));
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

moveWindow:aWindowId x:x y:y
    "move a window"

%{  /* NOCONTEXT */

    if (__isExternalAddress(aWindowId) && __bothSmallInteger(x, y)) {
	XMoveWindow(myDpy, _WindowVal(aWindowId), _intVal(x), _intVal(y));
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

resizeWindow:aWindowId width:w height:h
    "resize a window"

%{  /* NOCONTEXT */

    int newWidth, newHeight;

    if (__isExternalAddress(aWindowId) && __bothSmallInteger(w, h)) {
	newWidth = _intVal(w);
	newHeight = _intVal(h);
	if (newWidth < 1) newWidth = 1;
	if (newHeight < 1) newHeight = 1;
	XResizeWindow(myDpy, _WindowVal(aWindowId), newWidth, newHeight);
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

moveResizeWindow:aWindowId x:x y:y width:w height:h
    "move and resize a window"

%{  /* NOCONTEXT */

    int newWidth, newHeight;

    if (__isExternalAddress(aWindowId)
     && __bothSmallInteger(w, h)
     && __bothSmallInteger(x, y)) {
	newWidth = _intVal(w);
	newHeight = _intVal(h);
	if (newWidth < 1) newWidth = 1;
	if (newHeight < 1) newHeight = 1;
	XMoveResizeWindow(myDpy, _WindowVal(aWindowId),
			      _intVal(x), _intVal(y),
			      newWidth, newHeight);
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

configureWindow:aWindowId sibling:siblingId stackMode:modeSymbol
    "configure stacking operation of aWindowId w.r.t siblingId"

%{  /* NOCONTEXT */

    XWindowChanges chg;
    int mask = CWSibling | CWStackMode;

    if (__isExternalAddress(aWindowId)
     && __isExternalAddress(siblingId)) {
	if (modeSymbol == @symbol(above)) {
	    chg.stack_mode = Above;
	} else if (modeSymbol == @symbol(below)) {
	    chg.stack_mode = Below;
	} else if (modeSymbol == @symbol(topIf)) {
	    chg.stack_mode = TopIf;
	} else if (modeSymbol == @symbol(bottomIf)) {
	    chg.stack_mode = BottomIf;
	} else if (modeSymbol == @symbol(opposite)) {
	    chg.stack_mode = Opposite;
	} else {
	    mask = CWSibling;
	}

	chg.sibling = _WindowVal(siblingId);
	XConfigureWindow(myDpy, _WindowVal(aWindowId),
				mask, &chg);
	RETURN ( self );
    }
bad: ;
%}
.
    self primitiveFailed
! !

!XWorkstation ignoredMethodsFor:'window stuff'!

iconifyWindow:aWindowId
    "iconify a topView"

%{  /* NOCONTEXT */
    if (__isExternalAddress(aWindowId)) {
	XWMHints wmhints;

	wmhints.initial_state = IconicState;
	wmhints.flags |= StateHint;
	XSetWMHints(myDpy, _WindowVal(aWindowId), &wmhints);
	RETURN ( self );
    }
%}.
    self primitiveFailed
! !

!XWorkstation methodsFor:'graphic context stuff'!

setForeground:fgColorIndex in:aGCId
    "set foreground color to be drawn with"

%{  /* NOCONTEXT */

    if (__isExternalAddress(aGCId)
     && __isSmallInteger(fgColorIndex)) {
	XSetForeground(myDpy, _GCVal(aGCId), _intVal(fgColorIndex));
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

setBackground:bgColorIndex in:aGCId
    "set background color to be drawn with"

%{  /* NOCONTEXT */

    if (__isExternalAddress(aGCId)
     && __isSmallInteger(bgColorIndex)) {
	XSetBackground(myDpy, _GCVal(aGCId), _intVal(bgColorIndex));
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

setForeground:fgColorIndex background:bgColorIndex in:aGCId
    "set foreground and background colors to be drawn with"

%{  /* NOCONTEXT */

    Display *dpy = myDpy;
    GC gc = _GCVal(aGCId);

    if (__bothSmallInteger(fgColorIndex, bgColorIndex)
     && __isExternalAddress(aGCId)) {
	XSetForeground(dpy, gc, _intVal(fgColorIndex));
	XSetBackground(dpy, gc, _intVal(bgColorIndex));
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

setForeground:fgColor background:bgColor mask:aBitmapId in:aGCId
    "set foreground and background colors to be drawn with using mask or
     solid (if aBitmapId is nil)"

%{  /* NOCONTEXT */

    Display *dpy = myDpy;
    GC gc = _GCVal(aGCId);

    if (__isExternalAddress(aGCId)) {
	if (__isSmallInteger(fgColor))
	    XSetForeground(dpy, gc, _intVal(fgColor));
	if (__isSmallInteger(bgColor))
	    XSetBackground(dpy, gc, _intVal(bgColor));

	if (__isExternalAddress(aBitmapId)) {
	    XSetStipple(dpy, gc, _PixmapVal(aBitmapId));
	    XSetFillStyle(dpy, gc, FillOpaqueStippled);
	    RETURN ( self );
	}
	if (aBitmapId == nil) {
	    XSetFillStyle(dpy, gc, FillSolid);
	    RETURN ( self );
	}
    }
%}
.
    self primitiveFailed
!

setLineWidth:aNumber style:lineStyle cap:capStyle join:joinStyle in:aGCId
    "set line attributes"

%{  /* NOCONTEXT */

    int x_style, x_cap, x_join;

    if (__isExternalAddress(aGCId)
     && __isSmallInteger(aNumber)) {
	if (lineStyle == @symbol(solid)) x_style = LineSolid;
	else if (lineStyle == @symbol(dashed)) x_style = LineOnOffDash;
	else if (lineStyle == @symbol(doubleDashed)) x_style = LineDoubleDash;
	else  goto bad;

	if (capStyle == @symbol(notLast)) x_cap = CapNotLast;
	else if (capStyle == @symbol(butt)) x_cap = CapButt;
	else if (capStyle == @symbol(round)) x_cap  = CapRound;
	else if (capStyle == @symbol(projecting)) x_cap  = CapProjecting;
	else  goto bad;

	if (joinStyle == @symbol(miter)) x_join = JoinMiter;
	else if (joinStyle == @symbol(bevel)) x_join = JoinBevel;
	else if (joinStyle == @symbol(round)) x_join  = JoinRound;
	else  goto bad;

	XSetLineAttributes(myDpy,
			   _GCVal(aGCId), _intVal(aNumber),
			   x_style, x_cap, x_join);
	RETURN ( self );
    }
bad: ;
%}
.
    "
     either aGCId is invalid,
     and/or lineStyle is none of #solid, #dashed, #doubleDashed
     and/or capStyle is none of #notLast, #butt, #round, #projecting
     and/or joinStyle is none of #miter, #bevel, #round
    "
    self primitiveFailed
!

setForeground:fgColor background:bgColor mask:aBitmapId lineWidth:lw in:aGCId
    "set foreground and background colors to be drawn with using mask or
     solid (if aBitmapId is nil); also set lineWidth"

%{  /* NOCONTEXT */

    Display *dpy = myDpy;
    GC gc = _GCVal(aGCId);

    if (__isExternalAddress(aGCId)) {
	if (__isSmallInteger(lw)) {
	    XSetLineAttributes(dpy, gc, _intVal(lw),
				    LineSolid, CapNotLast, JoinMiter);
	}
	if (__isSmallInteger(fgColor))
	    XSetForeground(dpy, gc, _intVal(fgColor));
	if (__isSmallInteger(bgColor))
	    XSetBackground(dpy, gc, _intVal(bgColor));

	if (__isExternalAddress(aBitmapId)) {
	    XSetStipple(dpy, gc, _PixmapVal(aBitmapId));
	    XSetFillStyle(dpy, gc, FillOpaqueStippled);
	    RETURN ( self );
	}
	if (aBitmapId == nil) {
	    XSetFillStyle(dpy, gc, FillSolid);
	    RETURN ( self );
	}
    }
%}
.
    self primitiveFailed
!

setFunction:aFunctionSymbol in:aGCId
    "set alu function to be drawn with"

%{  /* NOCONTEXT */

    GC gc = _GCVal(aGCId);
    int fun = -1;

    if (__isExternalAddress(aGCId)) {
	if (aFunctionSymbol == @symbol(copy)) fun = GXcopy;
	else if (aFunctionSymbol == @symbol(copyInverted)) fun = GXcopyInverted;
	else if (aFunctionSymbol == @symbol(xor)) fun = GXxor;
	else if (aFunctionSymbol == @symbol(and)) fun = GXand;
	else if (aFunctionSymbol == @symbol(andReverse)) fun = GXandReverse;
	else if (aFunctionSymbol == @symbol(andInverted)) fun = GXandInverted;
	else if (aFunctionSymbol == @symbol(or)) fun = GXor;
	else if (aFunctionSymbol == @symbol(orReverse)) fun = GXorReverse;
	else if (aFunctionSymbol == @symbol(orInverted)) fun = GXorInverted;
	if (fun != -1) {
	    XSetFunction(myDpy, gc, fun);
	    RETURN ( self );
	}
    }
%}
.
    "
     either aGCId is not an integer, or an invalid symbol
     was passed ... valid functions are #copy, #copyInverted, #xor, #and, #andReverse,
     #andInverted, #or, #orReverse, #orInverted. See Xlib documentation for more details.
    "
    self primitiveFailed
!

setFont:aFontId in:aGCId
    "set font to be drawn in"

%{  /* NOCONTEXT */

    XFontStruct *f;

    if (__isExternalAddress(aFontId)
     && __isExternalAddress(aGCId)) {
	f = (XFontStruct *) _FontVal(aFontId);
	XSetFont(myDpy, _GCVal(aGCId), f->fid);
	RETURN ( self );
    }
%}
.
    "
     aGCId and/or aFontId are invalid
    "
    self primitiveFailed
!

setPixmapMask:aPixmapId in:aGCId
    "set or clear the drawing mask - a pixmap mask providing full color"

%{  /* NOCONTEXT */

    Display *dpy = myDpy;
    GC gc = _GCVal(aGCId);
    Pixmap pixmap;

    if (__isExternalAddress(aGCId)) {
	if (__isExternalAddress(aPixmapId)) {
	    pixmap = _PixmapVal(aPixmapId);
	    XSetTile(dpy, gc, pixmap);
	    XSetFillStyle(dpy, gc, FillTiled);
	    RETURN ( self );
	}
	if (aPixmapId == nil) {
	    XSetFillStyle(dpy, gc, FillSolid);
	    RETURN ( self );
	}
    }
%}
.
    self primitiveFailed
!

setBitmapMask:aBitmapId in:aGCId
    "set or clear the drawing mask - a bitmap mask using current fg/bg"

%{  /* NOCONTEXT */

    Display *dpy = myDpy;
    GC gc = _GCVal(aGCId);
    Pixmap bitmap;

    if (__isExternalAddress(aGCId)) {
	if (__isExternalAddress(aBitmapId)) {
	    bitmap = _PixmapVal(aBitmapId);
	    XSetStipple(dpy, gc, bitmap);
	    XSetFillStyle(dpy, gc, FillOpaqueStippled);
	    RETURN ( self );
	}
	if (aBitmapId == nil) {
	    XSetFillStyle(dpy, gc, FillSolid);
	    RETURN ( self );
	}
    }
%}
.
    self primitiveFailed
!

setMaskOriginX:orgX y:orgY in:aGCid
    "set the mask origin"

%{  /* NOCONTEXT */

    if (__bothSmallInteger(orgX, orgY) && __isExternalAddress(aGCid)) {
	XSetTSOrigin(myDpy, _GCVal(aGCid), _intVal(orgX), _intVal(orgY));
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

setClipByChildren:aBool in:aGCId
    "enable/disable drawing into child views"

%{  /* NOCONTEXT */

    XGCValues gcv;
    GC gc = _GCVal(aGCId);

    if (__isExternalAddress(aGCId)) {
	if (aBool == true)
	    gcv.subwindow_mode = ClipByChildren;
	else
	    gcv.subwindow_mode = IncludeInferiors;

	XChangeGC(myDpy, gc, GCSubwindowMode, &gcv);
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

noClipIn:aGCId
    "disable clipping rectangle"

%{  /* NOCONTEXT */

    XGCValues gcv;
    GC gc = _GCVal(aGCId);

    if (__isExternalAddress(aGCId)) {
	gcv.clip_mask = None;
	XChangeGC(myDpy, gc, GCClipMask, &gcv);
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

setClipX:clipX y:clipY width:clipWidth height:clipHeight in:aGCId
    "clip to a rectangle"

%{  /* NOCONTEXT */

    XRectangle r;

    if (__isExternalAddress(aGCId)
     && __bothSmallInteger(clipX, clipY)
     && __bothSmallInteger(clipWidth, clipHeight)) {
	r.x = _intVal(clipX);
	r.y = _intVal(clipY);
	r.width = _intVal(clipWidth);
	r.height = _intVal(clipHeight);
	XSetClipRectangles(myDpy, _GCVal(aGCId), 0, 0, &r, 1, Unsorted);
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

setGraphicsExposures:aBoolean in:aGCId
    "set or clear the graphics exposures flag"

%{  /* NOCONTEXT */

    if (__isExternalAddress(aGCId)) {
	XSetGraphicsExposures(myDpy, _GCVal(aGCId), (aBoolean==true)?1:0);
	RETURN ( self );
    }
%}
.
    self primitiveFailed
! !

!XWorkstation methodsFor:'retrieving pixels'!

getPixelX:x y:y from:aDrawableId
    "return the pixel value at x/y; coordinates start at 0/0 for the upper left."

%{  /* UNLIMITEDSTACK NOCONTEXT */

    Window win = _WindowVal(aDrawableId);
    XImage *img;
    int ret;
    int xpos, ypos;

    if (__isExternalAddress(aDrawableId) && __bothSmallInteger(x, y)) {
	xpos = _intVal(x);
	ypos = _intVal(y);
	if ((xpos < 0) || (ypos < 0)) {
	    RETURN ( _MKSMALLINT(0) );
	}
	img = XGetImage(myDpy, win, xpos, ypos, 1, 1, (unsigned)~0, ZPixmap);
	ret = XGetPixel(img, 0, 0);
	XDestroyImage(img);
	RETURN (  _MKSMALLINT(ret) );
    }
%}.
    ^ nil
!

getBitsFrom:aDrawableId x:srcx y:srcy width:w height:h into:imageBits
    "get bits from a drawable into the imageBits. The storage for the bits
     must be big enough for the data to fit. If ok, returns an array with some
     info and the bits in imageBits. The info contains the depth, bitOrder and
     number of bytes per scanline. The number of bytes per scanline is not known
     in advance, since the X-server is free to return whatever it thinks is a good padding."

    |info|

    ((w <= 0) or:[h <= 0]) ifTrue:[
	self primitiveFailed.
	^ nil
    ].

    info := Array with:nil "depth"
		  with:nil "bit order"
		  with:nil "bytes_per_line"
		  with:nil "byte_order".

    "/ had to extract the getPixel call into a separate method, to specify
    "/ unlimitedStack (some implementations use alloca and require huge amounts
    "/ of temporary stack space

    (self primGetBitsFrom:aDrawableId x:srcx y:srcy width:w height:h into:imageBits infoInfo:info) ifTrue:[
	^ info
    ].
    "
     some error occured - either args are not smallintegers, imageBits is not a ByteArray
     or is too small to hold the bits
    "
    ^ self primitiveFailed
!

primGetBitsFrom:aDrawableId x:srcx y:srcy width:w height:h into:imageBits infoInfo:info
    "since XGetImage may allocate huge amount of stack space 
     (some implementations use alloca), this must run with unlimited stack."

%{  /* UNLIMITEDSTACK */

    Display *dpy = myDpy;
    Window win = _WindowVal(aDrawableId);
    XImage *image = (XImage *)0;
    int pad, bytes_per_line, numBytes;

    if (__isExternalAddress(aDrawableId)
     && __bothSmallInteger(srcx, srcy)
     && __bothSmallInteger(w, h)
     && __isArray(info)
     && __isByteArray(imageBits)) {
	image = XGetImage(dpy, win, _intVal(srcx), _intVal(srcy),
				    _intVal(w), _intVal(h),
				    (unsigned)AllPlanes, ZPixmap);

	pad = image->bitmap_pad;
#ifdef SUPERDEBUG
	printf("pad:%d depth:%d\n", image->bitmap_pad, image->depth);
#endif
	switch (image->depth) {
	    case 1:
	    case 2:
	    case 4:
	    case 8:
	    case 16:
	    case 24:
	    case 32:
		numBytes = image->bytes_per_line * image->height;
		break;
	    default:
		/* unsupported depth */
		printf("unsupported depth:%d in primGetBits\n", image->depth);
		goto fail;
	}

#ifdef SUPERDEBUG
	printf("bytes need:%d bytes given:%d\n", numBytes, _byteArraySize(imageBits));
#endif

	if (numBytes > _byteArraySize(imageBits)) {
	    /* imageBits too small */
	    goto fail;
	}
	if (image->bitmap_bit_order == MSBFirst)
	    _ArrayInstPtr(info)->a_element[0] = @symbol(msbFirst);
	else
	    _ArrayInstPtr(info)->a_element[0] = @symbol(lsbFirst);
	_ArrayInstPtr(info)->a_element[1] = _MKSMALLINT(image->depth);
	_ArrayInstPtr(info)->a_element[2] = _MKSMALLINT(image->bytes_per_line);
	if (image->byte_order == MSBFirst)
	    _ArrayInstPtr(info)->a_element[3] = @symbol(msbFirst);
	else
	    _ArrayInstPtr(info)->a_element[3] = @symbol(lsbFirst);
	bcopy(image->data, _ByteArrayInstPtr(imageBits)->ba_element, numBytes);
	XDestroyImage(image);
	RETURN ( true );
    }
fail: 
    if (image) {
	XDestroyImage(image);
    }
%}.
    ^ false
! !

!XWorkstation methodsFor:'drawing'!

displayString:aString x:x y:y in:aDrawableId with:aGCId opaque:opaque 
    "draw a 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."

%{  /* NOCONTEXT */

    GC gc = _GCVal(aGCId);
    Window win = _WindowVal(aDrawableId);
    unsigned char *cp;
    int n;
    OBJ cls;

    if (__isExternalAddress(aGCId)
     && __isExternalAddress(aDrawableId)
     && __isNonNilObject(aString)
     && __bothSmallInteger(x, y)) {
	cls = __qClass(aString);
	if ((cls == String) || (cls == Symbol)) {
	    cp = _stringVal(aString);
	    n = _stringSize(aString);
	    if (n > 1000) n = 1000;
	    if (opaque == true)
		XDrawImageString(myDpy, win, gc, _intVal(x), _intVal(y), (char *)cp, n);
	    else
		XDrawString(myDpy, win, gc, _intVal(x), _intVal(y), (char *)cp, n);
	    RETURN ( self );
	}
#ifdef TWOBYTESTRINGS
	if (cls == @global(TwoByteString)) {
	    cp = _stringVal(aString);
	    n = _byteArraySize(aString) / 2;
	    if (n > 1000) n = 1000;
	    if (opaque == true)
		XDrawImageString16(myDpy, win, gc, _intVal(x), _intVal(y), (XChar2b *)cp, n);
	    else
		XDrawString16(myDpy, win, gc, _intVal(x), _intVal(y), (XChar2b *)cp, n);
	    RETURN ( self );
	}
#endif
    }
%}.
    "x/y not integer, badGC or drawable, or not a string"
    self primitiveFailed
!

displayString:aString from:index1 to:index2 x:x y:y in:aDrawableId with:aGCId 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."

%{  /* NOCONTEXT */

    GC gc = _GCVal(aGCId);
    Window win = _WindowVal(aDrawableId);
    unsigned char *cp;
    OBJ cls;
    int  i1, i2, l, n;

    if (__isExternalAddress(aGCId)
     && __isExternalAddress(aDrawableId)
     && __isNonNilObject(aString)
     && __bothSmallInteger(index1, index2)
     && __bothSmallInteger(x, y)) {
	cls = __qClass(aString);
	if ((cls == String) || (cls == Symbol)) {
	    i1 = _intVal(index1) - 1;
	    i2 = _intVal(index2) - 1;
	    n = _stringSize(aString);
	    cp = _stringVal(aString);
	    if ((i1 >= 0) && (i2 < n)) {
		if (i2 >= i1) {
		    cp += i1;
		    l = i2 - i1 + 1;
		    if (l > 1000) l = 1000;
		    if (opaque == true)
			XDrawImageString(myDpy, win, gc, _intVal(x), _intVal(y), (char *)cp, l);
		    else
			XDrawString(myDpy, win, gc, _intVal(x), _intVal(y), (char *)cp, l);
		}
		RETURN ( self );
	    }
	}
#ifdef TWOBYTESTRINGS
	if (cls == @global(TwoByteString)) {
	    i1 = _intVal(index1) - 1;
	    i2 = _intVal(index2) - 1;
	    n = _byteArraySize(aString) / 2;
	    cp = _stringVal(aString);
	    if ((i1 >= 0) && (i2 < n)) {
		if (i2 >= i1) {
		    cp += (i1 * 2);
		    l = i2 - i1 + 1;
		    if (l > 1000) l = 1000;
		    if (opaque == true)
			XDrawImageString16(myDpy, win, gc, _intVal(x), _intVal(y), (XChar2b *)cp, l);
		    else
			XDrawString16(myDpy, win, gc, _intVal(x), _intVal(y), (XChar2b *)cp, l);
		    RETURN ( self );
		}
	    }
	}
#endif
    }
%}.
    "x/y not integer, badGC or drawable, or not a string"
    self primitiveFailed
!

displayPointX:x y:y in:aDrawableId with:aGCId
    "draw a point. If x/y are not integers, an error is triggered." 

%{  /* NOCONTEXT */

    GC gc = _GCVal(aGCId);
    Window win = _WindowVal(aDrawableId);

    if (__isExternalAddress(aGCId)
     && __isExternalAddress(aDrawableId)
     && __bothSmallInteger(x, y)) {
	XDrawPoint(myDpy, win, gc, _intVal(x), _intVal(y));
	RETURN ( self );
    }
%}.
    "badGC, badDrawable or x/y not integer"
    self primitiveFailed
!

displayLineFromX:x0 y:y0 toX:x1 y:y1 in:aDrawableId with:aGCId
    "draw a line. If the coordinates are not integers, an error is triggered." 

%{  /* NOCONTEXT */

    GC gc = _GCVal(aGCId);
    Window win = _WindowVal(aDrawableId);

    if (__isExternalAddress(aGCId)
     && __isExternalAddress(aDrawableId)
     && __bothSmallInteger(x0, y0)
     && __bothSmallInteger(x1, y1)) {
	XDrawLine(myDpy, win, gc, _intVal(x0), _intVal(y0),
				  _intVal(x1), _intVal(y1));
	RETURN ( self );
    }
%}.
    "badGC, badDrawable or coordinates not integer"
    self primitiveFailed
!

displayRectangleX:x y:y width:width height:height in:aDrawableId with:aGCId
    "draw a rectangle. If the coordinates are not integers, an error is triggered." 

%{  /* NOCONTEXT */

    GC gc = _GCVal(aGCId);
    Window win = _WindowVal(aDrawableId);
    int w, h;

    if (__isExternalAddress(aGCId)
     && __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)) {
	    XDrawRectangle(myDpy, win, gc, _intVal(x), _intVal(y), w, h);
	}
	RETURN ( self );
    }
%}.
    "badGC, badDrawable or coordinates not integer"
    self primitiveFailed
!

displayPolygon:aPolygon in:aDrawableId with:aGCId
    "draw a polygon, the argument aPolygon is a Collection of individual points, which
     define the polygon.
     If any coordinate is not integer, an error is triggered."

    |numberOfPoints newPoints|

    numberOfPoints := aPolygon size.
%{
    GC gc = _GCVal(aGCId);
    Window win = _WindowVal(aDrawableId);
    extern OBJ Point, __AT_();
    OBJ point, x, y;
    int i, num;
    XPoint *points;
    XPoint qPoints[100];

    if (__isExternalAddress(aGCId)
     && __isExternalAddress(aDrawableId)
     && __isSmallInteger(numberOfPoints)) {
	num = _intVal(numberOfPoints);
	/*
	 * avoid a (slow) malloc, if the number of points is small
	 */
	if (num > 100) {
	    points = (XPoint *)malloc(sizeof(XPoint) * num);
	    if (! points) goto fail;
	} else
	    points = qPoints;

	for (i=0; i<num; i++) {
	    point = __AT_(aPolygon COMMA_CON, _MKSMALLINT(i+1));
	    if (! __isPoint(point)) goto fail;
	    x = _point_X(point);
	    y = _point_Y(point);
	    if (! __bothSmallInteger(x, y))
		goto fail;
	    points[i].x = _intVal(x);
	    points[i].y = _intVal(y);
	}
	XDrawLines(myDpy, win, gc, points, num, CoordModeOrigin);
	if (num > 100)
	    free(points);
	RETURN ( self );
    }
fail: ;
%}.
    "badGC, badDrawable or coordinates not integer"
    self primitiveFailed
!

copyFromFaxImage:sourceId x:srcX y:srcY to:destId x:dstX y:dstY 
		      width:w height:h with:aGCId scaleX:scaleX scaleY:scaleY

    "do a bit-blt of a compressed FAX image 
     - this needs my private FAX extension"

%{  /* NOCONTEXT */
#ifdef FAX
    GC gc = _GCVal(aGCId);
    FAXImage source;
    Drawable dest;

    if (__isExternalAddress(aGCId)
     && __isExternalAddress(sourceId)
     && __isExternalAddress(destId)
     && __bothSmallInteger(scaleX, scaleY)
     && __bothSmallInteger(w, h)
     && __bothSmallInteger(srcX, srcY)
     && __bothSmallInteger(dstX, dstY)) {
	source = (FAXImage) _WindowVal(sourceId);
	dest = (Drawable) _WindowVal(destId);
	XFAXImageCopyImage(myDpy, source, dest, gc,
				_intVal(srcX), _intVal(srcY),
				_intVal(w), _intVal(h),
				_intVal(dstX), _intVal(dstY),
				_intVal(scaleX), _intVal(scaleY));
	RETURN ( self );
    }
#endif
%}.
    self primitiveFailed
!

copyFromId:sourceId x:srcX y:srcY to:destId x:dstX y:dstY 
		width:w height:h with:aGCId
    "do a bit-blt; copy bits from the rectangle defined by
     srcX/srcY and w/h from the sourceId drawable to the rectangle
     below dstX/dstY in the destId drawable. Trigger an error if any
     argument is not integer."

%{  /* NOCONTEXT */

    GC gc = _GCVal(aGCId);
    Drawable source, dest;

    if (__isExternalAddress(aGCId)
     && __isExternalAddress(sourceId)
     && __isExternalAddress(destId)
     && __bothSmallInteger(w, h)
     && __bothSmallInteger(srcX, srcY)
     && __bothSmallInteger(dstX, dstY)) {
	source = (Drawable) _WindowVal(sourceId);
	dest = (Drawable) _WindowVal(destId);
	XCopyArea(myDpy, source, dest, gc,
				 _intVal(srcX), _intVal(srcY),
				_intVal(w), _intVal(h),
				_intVal(dstX), _intVal(dstY));
	RETURN ( self );
    }
%}.
    "badGC, bad sourceDrawableId or destDrawableID
     or any non integer coordinate"

    self primitiveFailed
!

copyPlaneFromId:sourceId x:srcX y:srcY to:destId x:dstX y:dstY 
		width:w height:h with:aGCId
    "do a bit-blt, but only copy the low-bit plane; 
     copy bits from the rectangle defined by
     srcX/srcY and w/h from the sourceId drawable to the rectangle
     below dstX/dstY in the destId drawable. Trigger an error if any
     argument is not integer."

%{  /* NOCONTEXT */

    GC gc = _GCVal(aGCId);
    Drawable source, dest;

    if (__isExternalAddress(aGCId)
     && __isExternalAddress(sourceId)
     && __isExternalAddress(destId)
     && __bothSmallInteger(w, h)
     && __bothSmallInteger(srcX, srcY)
     && __bothSmallInteger(dstX, dstY)) {
	source = (Drawable) _WindowVal(sourceId);
	dest = (Drawable) _WindowVal(destId);
	XCopyPlane(myDpy, source, dest, gc,
				 _intVal(srcX), _intVal(srcY),
				 _intVal(w), _intVal(h),
				 _intVal(dstX), _intVal(dstY), 1);
	RETURN ( self );
    }
%}.
    "badGC, bad sourceDrawableId or destDrawableID
     or any non integer coordinate"

    self primitiveFailed
!

displayArcX:x y:y w:width h:height from:startAngle angle:angle in:aDrawableId with:aGCId
    "draw an arc. If any of x,y, w or h is not an integer, an error is triggered.
     The angles may be floats or integer - they are given in degrees."

%{  /* NOCONTEXT */

    GC gc = _GCVal(aGCId);
    Window win = _WindowVal(aDrawableId);
    int w, h, angle1, angle2;
    double f;

    if (__isSmallInteger(startAngle))
	angle1 = _intVal(startAngle) * 64;
    else if (__isFloat(startAngle)) {
	f = _floatVal(startAngle);
	angle1 = f * 64;
    }
    if (__isSmallInteger(angle))
	angle2 = _intVal(angle) * 64;
    else if (__isFloat(angle)) {
	f = _floatVal(angle);
	angle2 = f * 64;
    }
    if (__isExternalAddress(aGCId)
     && __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) && (angle1 >= 0) && (angle2 >= 0)) {
	    XDrawArc(myDpy, win, gc, _intVal(x), _intVal(y),
				   w, h, angle1, angle2);
	}
	RETURN ( self );
    }
%}.
    "badGC, badDrawable or coordinates not integer"
    self primitiveFailed
!

fillArcX:x y:y w:width h:height from:startAngle angle:angle
	       in:aDrawableId with:aGCId
    "fill an arc. If any coordinate is not integer, an error is triggered.
     The angles may be floats or integer - they are given in degrees."

%{  /* NOCONTEXT */

    GC gc = _GCVal(aGCId);
    Window win = _WindowVal(aDrawableId);
    int w, h, angle1, angle2;
    double f;

    if (__isSmallInteger(startAngle))
	angle1 = _intVal(startAngle) * 64;
    else if (__isFloat(startAngle)) {
	f = _floatVal(startAngle);
	angle1 = f * 64;
    }
    if (__isSmallInteger(angle))
	angle2 = _intVal(angle) * 64;
    else if (__isFloat(angle)) {
	f = _floatVal(angle);
	angle2 = f * 64;
    }
    if (__isExternalAddress(aGCId)
     && __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) && (angle1 >= 0) && (angle2 >= 0)) {
	    XFillArc(myDpy, win, gc, _intVal(x), _intVal(y),
				   w, h, angle1, angle2);
	}
	RETURN ( self );
    }
%}.
    "badGC, badDrawable or coordinates not integer"
    self primitiveFailed
!

fillRectangleX:x y:y width:width height:height in:aDrawableId with:aGCId
    "fill a rectangle. If any coordinate is not integer, an error is triggered."

%{  /* NOCONTEXT */

    int w, h;

    if (__isExternalAddress(aGCId)
     && __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)) {
	    XFillRectangle(myDpy,
			   (Drawable)_WindowVal(aDrawableId), _GCVal(aGCId),
			   _intVal(x), _intVal(y), w, h);
	}
	RETURN ( self );
    }
%}.
    "badGC, badDrawable or coordinates not integer"
    self primitiveFailed
!

fillPolygon:aPolygon in:aDrawableId with:aGCId
    "fill a polygon given by its points. 
     If any coordinate is not integer, an error is triggered."

    |numberOfPoints|

    numberOfPoints := aPolygon size.
%{
    GC gc = _GCVal(aGCId);
    Window win = _WindowVal(aDrawableId);
    OBJ point, x, y;
    extern OBJ Point, __AT_();
    int i, num;
    XPoint *points;
    XPoint qPoints[100];

    if (__isExternalAddress(aGCId)
     && __isExternalAddress(aDrawableId)
     && __isSmallInteger(numberOfPoints)) {
	num = _intVal(numberOfPoints);
	if (num < 3) {
	    RETURN ( self );
	}
	/*
	 * avoid (slow) malloc, if not many points
	 */
	if (num > 100) {
	    points = (XPoint *) malloc(sizeof(XPoint) * num);
	    if (! points) goto fail;
	} else
	    points = qPoints;
	for (i=0; i<num; i++) {
	    point = __AT_(aPolygon COMMA_CON, _MKSMALLINT(i+1));
	    if (! __isPoint(point)) goto fail;
	    x = _point_X(point);
	    y = _point_Y(point);
	    if (! __bothSmallInteger(x, y))
		goto fail;
	    points[i].x = _intVal(x);
	    points[i].y = _intVal(y);
	}
	XFillPolygon(myDpy, win, gc, points, num, Complex, CoordModeOrigin);
	if (num > 100)
	    free(points);
	RETURN ( self );
fail: ;
    }
%}.
    "badGC, badDrawable or coordinates not integer"
    self primitiveFailed
!

drawBits:imageBits depth:imageDepth 
		   width:imageWidth height:imageHeight 
		       x:srcx y:srcy
		    into:aDrawableId 
		       x:dstx y:dsty 
		   width:w height:h 
		    with:aGCId

    "draw a bitImage which has depth id, width iw and height ih into
     the drawable. draw a region of w/h pixels from srcx/srcy to dstx/dsty.
     Individual source pixels must have imageDepth bits.
     It has to be checked elsewhere, that the server can do it with the given
     depth - otherwise, primitive failure will be signalled.
     Also it is assumed, that the colormap is setup correctly and the
     colors are allocated - otherwise the colors may be wrong."

    ^ self drawBits:imageBits bitsPerPixel:imageDepth depth:imageDepth 
				     width:imageWidth height:imageHeight 
					 x:srcx y:srcy
				      into:aDrawableId 
					 x:dstx y:dsty 
				     width:w height:h 
				      with:aGCId

!

drawBits:imageBits bitsPerPixel:bitsPerPixel depth:imageDepth 
			  width:imageWidth height:imageHeight 
			      x:srcx y:srcy
			   into:aDrawableId 
			      x:dstx y:dsty 
			  width:w height:h 
			   with:aGCId

    "draw a bitImage which has depth id, width iw and height ih into
     the drawable. draw a region of w/h pixels from srcx/srcy to dstx/dsty.
     Individual source pixels have bitsPerPixel bits, allowing to draw
     depth and pixel-units to be different.
     It has to be checked elsewhere, that the server can do it with the given
     depth - otherwise, primitive failure will be signalled.
     Also it is assumed, that the colormap is setup correctly and the
     colors are allocated - otherwise the colors may be wrong."

    "
     sorry; I had to separate it into 2 methods, since XPutImage needs
     an unlimited stack, and thus cannot send primitiveFailed
    "
    (self primDrawBits:imageBits bitsPerPixel:bitsPerPixel depth:imageDepth 
					width:imageWidth height:imageHeight 
					     x:srcx y:srcy
					  into:aDrawableId 
					     x:dstx y:dsty 
					 width:w height:h 
					  with:aGCId)
    ifFalse:[
	"
	 also happens, if a segmentation violation occurs in the 
	 XPutImage ...
	"
	self primitiveFailed
    ].
!

primDrawBits:imageBits bitsPerPixel:bitsPerPixel depth:imageDepth 
			      width:imageWidth height:imageHeight 
				  x:srcx y:srcy
			       into:aDrawableId 
				  x:dstx y:dsty 
			      width:w height:h 
			       with:aGCId

    "since XPutImage may allocate huge amount of stack space 
     (some implementations use alloca), this must run with unlimited stack."

%{  /* UNLIMITEDSTACK */

    /*
     * need unlimited stack, since some Xlibs do a huge alloca in
     * XPutImage
     */
    Display *dpy = myDpy;
    GC gc = _GCVal(aGCId);
    Window win = _WindowVal(aDrawableId);
    XImage image;

    if (__isExternalAddress(aGCId)
     && __isExternalAddress(aDrawableId)
     && __bothSmallInteger(srcx, srcy)
     && __bothSmallInteger(dstx, dsty)
     && __bothSmallInteger(w, h)
     && __bothSmallInteger(imageWidth, imageHeight)
     && __bothSmallInteger(imageDepth, bitsPerPixel)
     && __isByteArray(imageBits)) {
#ifdef ARGDEBUG
	printf("args ok\n");
#endif
	image.data = (char *)_ByteArrayInstPtr(imageBits)->ba_element;
	image.width = _intVal(imageWidth);
	image.height = _intVal(imageHeight);
	image.xoffset = 0;
	image.format = ZPixmap;
	image.byte_order = MSBFirst;
	image.bitmap_unit = 8;
	image.bitmap_bit_order = MSBFirst;
	image.bitmap_pad = 8;
	image.depth = _intVal(imageDepth);
	image.bits_per_pixel = _intVal(bitsPerPixel);
	switch (image.bits_per_pixel) {
	    case 1:
		image.bytes_per_line = (_intVal(imageWidth) + 7) / 8;
		break;
	    case 2:
		image.bytes_per_line = (_intVal(imageWidth)*2 + 7) / 8;
		break;
	    case 4:
		image.bytes_per_line = (_intVal(imageWidth)*4 + 7) / 8;
		break;
	    case 8:
		image.bytes_per_line = _intVal(imageWidth);
		break;
	    case 16:
		image.bytes_per_line = _intVal(imageWidth)*2;
		break;
	    case 24:
		image.bytes_per_line = _intVal(imageWidth)*3;
		break;
	    case 32:
		image.bytes_per_line = _intVal(imageWidth)*4;
		break;
	    default:
#ifdef ARGDEBUG
		printf("bits_per_pixel=%d\n",image.bits_per_pixel);
#endif
		goto fail;
	}
	image.red_mask = 0xFFFF;
	image.green_mask = 0xFFFF;
	image.blue_mask = 0xFFFF;
	XPutImage(dpy, win, gc, &image, _intVal(srcx), _intVal(srcy),
					_intVal(dstx), _intVal(dsty),
					_intVal(w), _intVal(h));
	RETURN ( true );
    }
#ifdef ARGDEBUG
    if (!! __isExternalAddress(aGCId)) printf("GC\n");
    if (!! __isExternalAddress(aDrawableId)) printf("aDrawableId\n");
    if (!! __isSmallInteger(srcx)) printf("srcx\n");
    if (!! __isSmallInteger(srcy)) printf("srcy\n");
    if (!! __isSmallInteger(dstx)) printf("dstx\n");
    if (!! __isSmallInteger(dsty)) printf("dsty\n");
    if (!! __isSmallInteger(w)) printf("w\n");
    if (!! __isSmallInteger(h)) printf("h\n");
    if (!! __isSmallInteger(imageWidth)) printf("imageWidth\n");
    if (!! __isSmallInteger(imageHeight)) printf("imageHeight\n");
    if (!! __isSmallInteger(imageDepth)) printf("imageDepth\n");
    if (!! __isSmallInteger(bitsPerPixel)) printf("bitsPerPixel\n");
    if (!! __isByteArray(imageBits)) printf("imageBits\n");
#endif

fail: ;
%}
.
    ^ false
! !

!XWorkstation methodsFor:'event handling'!

eventMaskFor:anEventSymbol
    "return the eventMask bit-constant corresponding to an event symbol"

%{  /* NOCONTEXT */

    int m = 0;

    if (anEventSymbol == @symbol(keyPress)) m = KeyPressMask;
    else if (anEventSymbol == @symbol(keyRelease)) m = KeyReleaseMask;
    else if (anEventSymbol == @symbol(buttonPress)) m = ButtonPressMask;
    else if (anEventSymbol == @symbol(buttonRelease)) m = ButtonReleaseMask;
    else if (anEventSymbol == @symbol(buttonMotion)) m = ButtonMotionMask;
    else if (anEventSymbol == @symbol(pointerMotion)) m = PointerMotionMask;
    else if (anEventSymbol == @symbol(expose)) m = ExposureMask;
    else if (anEventSymbol == @symbol(focusChange)) m = FocusChangeMask;
    else if (anEventSymbol == @symbol(enter)) m = EnterWindowMask;
    else if (anEventSymbol == @symbol(leave)) m = LeaveWindowMask;
    else if (anEventSymbol == @symbol(keymapState)) m = KeymapStateMask;
    else if (anEventSymbol == @symbol(visibilityChange)) m = VisibilityChangeMask;
    else if (anEventSymbol == @symbol(structureNotify)) m = StructureNotifyMask;
    else if (anEventSymbol == @symbol(resizeRedirect)) m = ResizeRedirectMask;
    else if (anEventSymbol == @symbol(propertyChange)) m = PropertyChangeMask;
    else if (anEventSymbol == @symbol(colormapChange)) m = ColormapChangeMask;
    RETURN (_MKSMALLINT(m));
%}
!

setEventMask:aMask in:aWindowId
    "tell X that we are only interrested in events from aMask, which
     is the bitwise or of the eventMask bits (see 'eventMaskFor:')"

%{  /* NOCONTEXT */

    int mask;

    if (__isExternalAddress(aWindowId)
     && __isSmallInteger(aMask)) {
	mask = _intVal(aMask);

#ifdef OLD
	/* these may not be disabled */
	mask |= ExposureMask | StructureNotifyMask |
		KeyPressMask | KeyReleaseMask |
		EnterWindowMask | LeaveWindowMask |
		ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
#endif

	XSelectInput(myDpy, _WindowVal(aWindowId), mask);
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

startDispatch
    "redefined to clear dispatchingExpose, which is a special X feature"

    dispatching ifTrue:[^ self].
    dispatchingExpose := nil.
    super startDispatch
!

XXcheckForEndOfDispatch
    "return true, if there are still any views of interrest - if not,
     stop dispatch"

"/    idToViewMapping isEmpty ifTrue:[
"/      dispatching := false.
"/    ] ifFalse:[
"/       ((idToViewMapping size == 1) and:[idToViewMapping includesValue:RootView]) ifTrue:[
"/         dispatching := false.
"/      ]
"/    ]

    knownViews isEmpty ifTrue:[
	dispatching := false.
	^ self
    ].
    ((knownViews size == 1) and:[(knownViews at:1) == rootView]) ifTrue:[
	dispatching := false.
    ]
!

dispatchPendingEvents
    "central event handling method:
     this code is somewhat special, since X has a concept of graphic
     expose events (which are sent after a bitblt). After such a bitblt,
     we only handle exposes until the graphicsExpose arrives.
     Other systems may not need such a kludge"

    "interrested in exposes only ?"
    dispatchingExpose notNil ifTrue:[
	[self exposeEventPendingFor:dispatchingExpose] whileTrue:[
	    self dispatchExposeEventFor:dispatchingExpose
	].
	^ self
    ].

    "no, general dispatch"
    [self eventPendingWithoutSync] whileTrue:[
	self dispatchEventFor:nil withMask:nil
    ]
!

handleExposeOnlyFor:aView
    "from now on, handle expose events only"

    dispatchingExpose := aView id
!

handleAllEvents
    "from now on, handle any kind of event"

    dispatchingExpose := nil
!

dispatchExposeEventFor:aViewIdOrNil
    "get next expose event and send appropriate message to the sensor or view.
     If the argument aViewIdOrNil is nil, events for any view are processed,
     otherwise only events for the view with given id are processed."

    self dispatchEventFor:aViewIdOrNil withMask:(self eventMaskFor:#expose)
!

dispatchEventFor:aViewIdOrNil withMask:eventMask
    "central event handling method:
     get next event and send appropriate message to the sensor or view.
     If the argument aViewIdOrNil is nil, events for any view are processed,
     otherwise only events for the view with given id are processed.
     If the argument aMask is nonNil, only events for this eventMask are
     handled."

    (self getEventFor:aViewIdOrNil withMask:eventMask) ifTrue:[
	Object abortSignal catch:[
	    self dispatchLastEvent.
	]
    ].
!

getEventFor:aViewIdOrNil withMask:eventMask
    "read next event - put into local eventBuffer. 
     If aViewIdOrNil is nil, events for any view are fetched; 
     otherwise only events for that specific view will be fetched.
     Returns true, if there was an event, false otherwise.
     This method may block - so you better check for pending events
     before calling for it.

     Sorry I had to split dispatch into this fetch method and an extra
     handle method to allow unlimitedstack here.
     (some Xlibs do a big alloca there ...) which cannot be done in 
     dispatchLastEvent, since it dispatches out into ST-methods.
     BUG: uses a static buffer - has to be rewritten, to support multiple
     display connections.
    "

%{  /* UNLIMITEDSTACK */

    Display *dpy = myDpy;
    Window win, wWanted;
    int evMask;
    OBJ eB;
    XEvent *ev;

    if (! ISCONNECTED) {
	RETURN (false);
    }

    eB = _INST(eventBuffer);
    if (__isByteArray(eB)) {
	ev = (XEvent *)(_ByteArrayInstPtr(eB)->ba_element);
    } else {
	printf("DISPLAY: no eventBuffer\n");
	RETURN (false);
    }
    ev->type = 0;

    if (__isSmallInteger(eventMask)) {
	evMask = _intVal(eventMask);
    } else {
	evMask = ~0;
    }

    if (__isExternalAddress(aViewIdOrNil)) {
	wWanted = _WindowVal(aViewIdOrNil);
	if (XCheckWindowEvent(dpy, wWanted, evMask, ev)) {
	    RETURN ( true );
	}
    } else {
	if (evMask == ~0) {
	    XNextEvent(dpy, ev);
	    RETURN (true);
	}
	if (XCheckMaskEvent(dpy, evMask, ev)) {
	   RETURN (true);
	}
    }
%}.
    ^ false
!

dispatchLastEvent
    |theView symS arg butt sibling windowID siblingID propertyID selectionID targetID requestorID
     eventType|

%{  /* STACK: 8000 */
#   define ANYBUTTON   (Button1MotionMask | Button2MotionMask | Button3MotionMask)

    Display *dpy = myDpy;
    OBJ eB;
    XEvent *ev;

#   define ae ((XAnyEvent *)ev)
#   define ee ((XExposeEvent *)ev)
#   define ke ((XKeyPressedEvent *)ev)
#   define be ((XButtonPressedEvent *)ev)
#   define ce ((XConfigureEvent *)ev)
#   define me ((XMotionEvent *)ev)
#   define ewe ((XEnterWindowEvent *)ev)
#   define lwe ((XLeaveWindowEvent *)ev)
#   define de ((XDestroyWindowEvent *)ev)
#   define ve ((XVisibilityEvent *)ev)

    KeySym keySym;
    unsigned char buffer[10];
    int i, nchars;
    char *keySymString;
    char keySymStringBuffer[32];
    static unsigned multiClickTime = 0;
    unsigned nextMultiClickTime;
    OBJ upDown;
    extern OBJ __AT_();

    struct inlineCache *ipS;
    static struct inlineCache vid = _ILC1;

    static struct inlineCache expS = _ILC5;
    static struct inlineCache gexpS = _ILC5;
    static struct inlineCache nexpS = _ILC1;
    static struct inlineCache motS = _ILC4;
    static struct inlineCache bpS = _ILC4;
    static struct inlineCache bmpS = _ILC4;
    static struct inlineCache bspS = _ILC4;
    static struct inlineCache brS = _ILC4;
    static struct inlineCache focInS = _ILC1;
    static struct inlineCache focOutS = _ILC1;
    static struct inlineCache peS = _ILC4;
    static struct inlineCache plS = _ILC2;
    static struct inlineCache termS = _ILC1;
    static struct inlineCache savtermS = _ILC1;
    static struct inlineCache destrS = _ILC1;
    static struct inlineCache unmapS = _ILC1;
    static struct inlineCache mapS = _ILC1;
    static struct inlineCache confS = _ILC5;
    static struct inlineCache coveredS = _ILC2;

    static struct inlineCache keymap = _ILC0;
    static struct inlineCache created = _ILC0;
    static struct inlineCache mapReq = _ILC0;
    static struct inlineCache repar = _ILC0;
    static struct inlineCache confReq = _ILC0;
    static struct inlineCache resReq = _ILC0;
    static struct inlineCache prop = _ILC0;
    static struct inlineCache selClear = _ILC1;
    static struct inlineCache selReq = _ILC4;
    static struct inlineCache selNotify = _ILC4;
    static struct inlineCache colormap = _ILC0;
    static struct inlineCache vis = _ILC1;

    static struct inlineCache skpS = _ILC4;
    static struct inlineCache skrS = _ILC4;

    eB = _INST(eventBuffer);
    if (__isByteArray(eB)) {
	ev = (XEvent *)(_ByteArrayInstPtr(eB)->ba_element);
    } else {
	printf("DISPLAY: no eventBuffer\n");
	RETURN (false);
    }

    windowID = __MKOBJ(ae->window);
    theView = (*vid.ilc_func)(self, @symbol(viewFromId:) COMMA_CON, nil, &vid, windowID);

    if (theView == nil) {
	RETURN (nil);
    }

    /*
     * key, button and pointer events are sent to the sensor,
     * or (if there is none) to the delegate.
     * or (if there is none) to the view.
     *
     * expose events are sent to the sensor,
     * or (if there is none) to the view
     *
     * sensor and delegate get view as additional argument
     * all of this has been taken out of here to corresponding methods
     * in DeviceWorkstation.
     */

#ifdef DEBUG
    eventType = __MKSMALLINT(ev->type);
#endif
    switch (ev->type) {
	case KeyRelease:
	    symS = @symbol(keyRelease:x:y:view:);
	    ipS = &skrS;
	    upDown = false;
	    goto keyPressAndRelease;

	case KeyPress:
	    symS = @symbol(keyPress:x:y:view:);
	    ipS = &skpS;
	    upDown = true;
	    /* FALL INTO */

	keyPressAndRelease:
	    _INST(eventRootX) = _MKSMALLINT(ke->x_root);
	    _INST(eventRootY) = _MKSMALLINT(ke->y_root);
#ifdef OLD
	    _INST(altDown) = (ke->state & Mod2Mask) ? true : false;
	    _INST(metaDown) = (ke->state & Mod1Mask) ? true : false;
#else
	    _INST(altDown) = (ke->state & __intVal(_INST(altModifierMask))) ? true : false;
	    _INST(metaDown) = (ke->state & __intVal(_INST(metaModifierMask))) ? true : false;
#endif
	    _INST(shiftDown) = (ke->state & ShiftMask) ? true : false;
	    _INST(ctrlDown) = (ke->state & ControlMask) ? true : false;

	    arg = nil;
	    nchars = XLookupString(ke, (char *)buffer, sizeof(buffer), &keySym, NULL);
	    if (nchars 
	     && (((buffer[0] >= ' ') && (buffer[0] <= '~'))
		 || (buffer[0] >= 0x80))) {
		arg = _MKCHARACTER(buffer[0])/* *_CharacterTable[buffer[0]] */;
		keySymString = NULL;
	    } else {
#ifdef OLD
		switch (keySym) {
		    case XK_Control_L:
		    case XK_Control_R:
			_INST(ctrlDown) = upDown;
			break;
		    case XK_Shift_L:
		    case XK_Shift_R:
			_INST(shiftDown) = upDown;
			break;
		    case XK_Meta_L:
		    case XK_Meta_R:
			_INST(metaDown) = upDown;
			break;
		    case XK_Alt_L:
		    case XK_Alt_R:
			_INST(altDown) = upDown;
			break;
		}
#endif

		keySymString = XKeysymToString(keySym);
		if (keySymString) {
#ifdef OLD
		    if (keySymString[0] == 'D') {
			/*
			 * remove underscore, dont want it in symbols
			 */
			if (strcmp(keySymString, "Delete_line") == 0) {
			    keySymString = "DeleteLine";
			} else if (strcmp(keySymString, "Delete_word") == 0) {
			    keySymString = "DeleteWord";
			}
		    }
		    /*
		     * make names compatible
		     */
		    if (strcmp(keySymString, "Down") == 0) {
			keySymString = "CursorDown";
		    } else if (strcmp(keySymString, "Up") == 0) {
			keySymString = "CursorUp";
		    } else if (strcmp(keySymString, "Left") == 0) {
			keySymString = "CursorLeft";
		    } else if (strcmp(keySymString, "Right") == 0) {
			keySymString = "CursorRight";
		    }
		    arg = _MKSYMBOL(keySymString, (OBJ *)0, __context);
#else
		    PROTECT(theView);
		    arg = __MKSTRING(keySymString COMMA_CON);
		    UNPROTECT(theView);
#endif
		}
	    }

	    if (arg == nil) {
		/* happens sometimes (alt-graph on sun has no keysym) */
		break;
	    }

	    (*(*ipS).ilc_func)(self, symS COMMA_CON, nil, ipS,
			       arg, 
			       _MKSMALLINT(ke->x), 
			       _MKSMALLINT(ke->y),
			       theView);
	    break;

	case ButtonPress:
	    _INST(buttonsPressed) = _MKSMALLINT(_intVal(_INST(buttonsPressed)) | (1 << be->button));
	    _INST(eventRootX) = _MKSMALLINT(be->x_root);
	    _INST(eventRootY) = _MKSMALLINT(be->y_root);

	    if (__isSmallInteger(_INST(multiClickTimeDelta)))
		nextMultiClickTime = be->time + _intVal(_INST(multiClickTimeDelta));
	    else
		nextMultiClickTime = 0;

	    if (multiClickTime) {
		if (be->time < multiClickTime) {
		    multiClickTime = nextMultiClickTime;
		    ipS = &bmpS;
		    symS = @symbol(buttonMultiPress:x:y:view:);
		    goto sendButtonEvent;
		    break;
		}
	    }
	    multiClickTime = nextMultiClickTime;
	    if (be->state & ShiftMask) {
		ipS = &bspS;
		symS = @symbol(buttonShiftPress:x:y:view:);
		goto sendButtonEvent;
	    }
	    ipS = &bpS;
	    symS = @symbol(buttonPress:x:y:view:);
	    goto sendButtonEvent;

	    /* NOT REACHED */

	case ButtonRelease:
	    _INST(buttonsPressed) = _MKSMALLINT(_intVal(_INST(buttonsPressed)) & ~(1 << be->button));
	    _INST(eventRootX) = _MKSMALLINT(be->x_root);
	    _INST(eventRootY) = _MKSMALLINT(be->y_root);
	    ipS = &brS;
	    symS = @symbol(buttonRelease:x:y:view:);
	    /* fall into */

	sendButtonEvent:
	    butt = _MKSMALLINT(be->button);
#ifdef NOTDEF
	    /*
	     * this allows operation with single button mouses: meta-click is always Button 2
	     */
	    if (_INST(metaDown) == true)
		butt = _MKSMALLINT(2);
	    else 
#endif
		butt = __AT_(_INST(buttonTranslation), butt);


	    (*(*ipS).ilc_func)(self, 
			       symS
			       COMMA_CON, nil, ipS,
			       butt, 
			       _MKSMALLINT(ke->x), 
			       _MKSMALLINT(ke->y),
			       theView);
	    break;

	case MotionNotify:
	    if (_INST(motionEventCompression) != false) {
		while (XCheckWindowEvent(dpy, me->window, ANYBUTTON, ev)) ;;
	    }

	    _INST(eventRootX) = _MKSMALLINT(me->x_root);
	    _INST(eventRootY) = _MKSMALLINT(me->y_root);

#ifdef OLD
	    _INST(altDown) = (me->state & Mod2Mask) ? true : false;
	    _INST(metaDown) = (me->state & Mod1Mask) ? true : false;
#else
	    _INST(altDown) = (ke->state & __intVal(_INST(altModifierMask))) ? true : false;
	    _INST(metaDown) = (ke->state & __intVal(_INST(metaModifierMask))) ? true : false;
#endif
	    _INST(shiftDown) = (me->state & ShiftMask) ? true : false;
	    _INST(ctrlDown) = (me->state & ControlMask) ? true : false;

	    (*motS.ilc_func)(self, 
			     @symbol(buttonMotion:x:y:view:)
			     COMMA_CON, nil, &motS,
			     _MKSMALLINT(me->state),
			     _MKSMALLINT(me->x),
			     _MKSMALLINT(me->y),
			     theView);
	    break;

	case FocusIn:
	    (*focInS.ilc_func)(self, 
			       @symbol(focusInView:)
			       COMMA_CON, nil, &focInS, 
			       theView);
	    break;

	case FocusOut:
	    (*focOutS.ilc_func)(self, 
				@symbol(focusOutView:)
				COMMA_CON, nil, &focOutS, 
				theView);
	    break;

	case EnterNotify:
#ifdef OLD
	    _INST(altDown) = (ewe->state & Mod2Mask) ? true : false;
	    _INST(metaDown) = (ewe->state & Mod1Mask) ? true : false;
#else
	    _INST(altDown) = (ke->state & __intVal(_INST(altModifierMask))) ? true : false;
	    _INST(metaDown) = (ke->state & __intVal(_INST(metaModifierMask))) ? true : false;
#endif
	    _INST(shiftDown) = (ewe->state & ShiftMask) ? true : false;
	    _INST(ctrlDown) = (ewe->state & ControlMask) ? true : false;

	    (*peS.ilc_func)(self, 
			    @symbol(pointerEnter:x:y:view:)
			    COMMA_CON, nil, &peS,
			    _MKSMALLINT(ewe->state),
			    _MKSMALLINT(ewe->x), 
			    _MKSMALLINT(ewe->y),
			    theView);
	    break;

	case LeaveNotify:
	    (*plS.ilc_func)(self, 
			    @symbol(pointerLeave:view:)
			    COMMA_CON, nil, &plS,
			    _MKSMALLINT(lwe->state), 
			    theView);
	    break;

	case GraphicsExpose:
	    (*gexpS.ilc_func)(self, 
			      @symbol(graphicExposeX:y:width:height:view:)
			      COMMA_CON, nil, &gexpS,
			      _MKSMALLINT(ee->x),
			      _MKSMALLINT(ee->y),
			      _MKSMALLINT(ee->width),
			      _MKSMALLINT(ee->height),
			      theView);

	    if (ee->count != 0) {
		break;
	    }
	    /* fall into */

	case NoExpose:
	    (*nexpS.ilc_func)(self, 
			      @symbol(noExposeView:)
			      COMMA_CON, nil, &nexpS, 
			      theView);
	    break;

	case Expose:
	    (*expS.ilc_func)(self, 
			     @symbol(exposeX:y:width:height:view:)
			     COMMA_CON, nil, &expS,
			     _MKSMALLINT(ee->x),
			     _MKSMALLINT(ee->y),
			     _MKSMALLINT(ee->width),
			     _MKSMALLINT(ee->height),
			     theView);
	    break;

	case ConfigureNotify:
	    if (ce->above != None) {
		siblingID = __MKOBJ(ce->above);
		sibling = (*vid.ilc_func)(self, @symbol(viewFromId:) 
					  COMMA_CON, nil, &vid, siblingID);
	    }

	    (*confS.ilc_func)(self, 
			     @symbol(configureX:y:width:height:view:)
			     COMMA_CON, nil, &confS,
			     _MKSMALLINT(ce->x),
			     _MKSMALLINT(ce->y),
			     _MKSMALLINT(ce->width),
			     _MKSMALLINT(ce->height),
			     theView);
	    if (sibling != nil) {
		(*coveredS.ilc_func)(self,
				    @symbol(coveredBy:view:)
				    COMMA_CON, nil, &coveredS,
				    theView,
				    sibling);
	    }
	    break;

	case ClientMessage:
	    if (ev->xclient.message_type == (int) _AtomVal(_INST(protocolsAtom))) {
		if ((ev->xclient.data.l[0] == (int) _AtomVal(_INST(quitAppAtom)))
		 || (ev->xclient.data.l[0] == (int) _AtomVal(_INST(deleteWindowAtom)))) {
		    (*termS.ilc_func)(self, 
				      @symbol(terminateView:)
				      COMMA_CON, nil, &termS, theView);
		    break;
		}
		if (ev->xclient.data.l[0] == (int) _AtomVal(_INST(saveYourselfAtom))) {
		    (*savtermS.ilc_func)(self, 
					 @symbol(saveAndTerminateView:)
					 COMMA_CON, nil, &savtermS, theView);
		    break;
		}
	    }
	    break;

	case DestroyNotify:
	    (*destrS.ilc_func)(self, @symbol(destroyedView:)
			       COMMA_CON, nil, &destrS, theView);
	    break;

	case UnmapNotify:
	    (*unmapS.ilc_func)(self, @symbol(unmappedView:) 
			       COMMA_CON, nil, &unmapS, theView);
	    break;

	case MapNotify:
	    (*mapS.ilc_func)(self, 
			     @symbol(mappedView:) 
			     COMMA_CON, nil, &mapS, theView);
	    break;

	case KeymapNotify:
	    (*keymap.ilc_func)(theView, 
			       @symbol(keyMapChange) 
			       COMMA_CON, nil, &keymap);
	    break;

	case VisibilityNotify:
	    switch (ve->state) {
		case VisibilityUnobscured:
		    arg = @symbol(unobscured);
		    break;
		case VisibilityPartiallyObscured:
		    arg = @symbol(partiallyObscured);
		    break;
		case VisibilityFullyObscured:
		    arg = @symbol(fullyObscured);
		    break;
	    }
	    (*vis.ilc_func)(theView, @symbol(visibilityChange:) COMMA_CON, nil, &vis, arg);
	    break;

	case CreateNotify:
	    (*created.ilc_func)(theView, @symbol(created) COMMA_CON, nil, &created);
	    break;

	case MapRequest:
	    (*mapReq.ilc_func)(theView, @symbol(mapRequest) COMMA_CON, nil, &mapReq);
	    break;

	case ReparentNotify:
	    (*repar.ilc_func)(theView, @symbol(reparented) COMMA_CON, nil, &repar);
	    break;

	case ConfigureRequest:
	    (*confReq.ilc_func)(theView, @symbol(configRequest) COMMA_CON, nil, &confReq);
	    break;

	case GravityNotify:
	case ResizeRequest:
	    (*resReq.ilc_func)(theView, @symbol(resizeRequest) COMMA_CON, nil, &resReq);
	    break;

	case CirculateNotify:
	case CirculateRequest:
	    break;

	case PropertyNotify:
	    (*prop.ilc_func)(theView, 
			     @symbol(propertyChange) 
			     COMMA_CON, nil, &prop);
	    break;

	case SelectionClear:
	    selectionID = __MKATOMOBJ(ev->xselectionclear.selection);
	    (*selClear.ilc_func)(theView, 
				 @symbol(selectionClear:) 
				 COMMA_CON, nil, &selClear,
				 selectionID);
	    break;

	case SelectionNotify:
	    /*
	     * returned selection value (answer from SelectionRequest)
	     */
	    DPRINTF(("SelectionNotify prop=%x target=%x selection= %x requestor=%x\n", 
			ev->xselection.property, ev->xselection.target,
			ev->xselection.selection, ev->xselection.requestor));

	    propertyID = __MKATOMOBJ(ev->xselection.property);
	    targetID = __MKATOMOBJ(ev->xselection.target);
	    selectionID = __MKATOMOBJ(ev->xselection.selection);
	    requestorID = __MKOBJ(ev->xselection.requestor);
	    (*selNotify.ilc_func)(theView, 
				  @symbol(selectionNotify:target:selection:from:) 
				  COMMA_CON, nil, &selNotify,
				  propertyID, targetID, selectionID, requestorID);
	    break;

	case SelectionRequest:
	    /*
	     * someone wants the selection
	     */
	    DPRINTF(("SelectionRequest prop=%x target=%x selection=%x requestor=%x\n", 
			ev->xselectionrequest.property,
			ev->xselectionrequest.target,
			ev->xselectionrequest.selection,
			ev->xselectionrequest.requestor));

	    propertyID = __MKATOMOBJ(ev->xselectionrequest.property);
	    targetID = __MKATOMOBJ(ev->xselectionrequest.target);
	    selectionID = __MKATOMOBJ(ev->xselectionrequest.selection);
	    requestorID = __MKOBJ(ev->xselectionrequest.requestor);
	    (*selReq.ilc_func)(theView, 
			       @symbol(selectionRequest:target:selection:from:) 
			       COMMA_CON, nil, &selReq,
			       propertyID, targetID, selectionID, requestorID);
	    break;

	case ColormapNotify:
	    (*colormap.ilc_func)(theView, 
				 @symbol(colorMapChange) 
				 COMMA_CON, nil, &colormap);
	    break;

	case MappingNotify:
/*
printf("mapping\n");
*/
/*
	    (*mapping.ilc_func)(theView, 
				@symbol(mapping) 
				COMMA_CON, nil, &mapping);
*/
	    break;
    }
#undef ae
#undef ee
#undef ke
#undef be
#undef ce
#undef me
#undef ewe
#undef lwe
#undef de
%}
.
    ^ true
!

disposeEventsWithMask:aMask for:aWindowIdOrNil
    "dispose (throw away) specific events. If aWindowId is nil,
     events matching the mask are thrown away regardless of which
     view they are for. Otherwise, only matching events for that 
     view are flushed."

%{  /* NOCONTEXT */

    Display *dpy = myDpy;
    XEvent ev;
    Window win;

    if (__isSmallInteger(aMask)) {
	if (__isExternalAddress(aWindowIdOrNil)) {
	    win = _WindowVal(aWindowIdOrNil);
	    while (XCheckWindowEvent(dpy, win, _intVal(aMask), &ev)) ;;
	} else {
	    while (XCheckMaskEvent(dpy, _intVal(aMask), &ev)) ;;
	}
	RETURN ( self );
    }
%}
.
    self primitiveFailed
!

eventPending
    "return true, if any event is pending"

    dispatchingExpose notNil ifTrue:[
	^ self exposeEventPendingFor:dispatchingExpose
    ].
"/    ^ self eventPendingWithSync
    ^ self eventPendingWithoutSync
!

eventPendingWithSync
    "return true, if any event is pending. 
     Do a flush output buffer before."

%{  /* UNLIMITEDSTACK */

    Display *dpy = myDpy;

    if (ISCONNECTED) {
	XSync(dpy, 0);      /* make certain everything is flushed */
	if (XPending(dpy)) {
	    RETURN (true);
	}
    }
    RETURN ( false );
%}
!

eventPendingWithoutSync
    "return true, if any event is pending."

%{  /* UNLIMITEDSTACK */

    if (ISCONNECTED) {
	if (XPending(myDpy)) {
	    RETURN (true);
	}
    }
    RETURN ( false );
%}
!

exposeEventPendingFor:aWindowIdOrNil
    "return true, if any expose event is pending"

%{  /* UNLIMITEDSTACK */

    Display *dpy = myDpy;
    XEvent ev;
    Window win;
    int thereIsOne;

    if (ISCONNECTED) {
	XSync(dpy, 0);      /* make certain everything is flushed */
	if (__isExternalAddress(aWindowIdOrNil)) {
	    win = _WindowVal(aWindowIdOrNil);
	    thereIsOne = XCheckWindowEvent(dpy, win, ExposureMask, &ev);
	} else {
	    thereIsOne = XCheckMaskEvent(dpy, ExposureMask, &ev);
	}
	if (thereIsOne) {
	    XPutBackEvent(dpy, &ev);
	    RETURN ( true );
	}
    }
    RETURN ( false );
%}
!

eventsPending:anEventMask for:aWindowIdOrNil
    "return true, if any of the masked events is pending"

%{  /* UNLIMITEDSTACK */

    Display *dpy = myDpy;
    XEvent ev;
    Window win;
    int thereIsOne;

    if (ISCONNECTED && __isSmallInteger(anEventMask)) {
	XSync(dpy, 0);      /* make certain everything is flushed */
	if (__isExternalAddress(aWindowIdOrNil)) {
	    win = _WindowVal(aWindowIdOrNil);
	    thereIsOne = XCheckWindowEvent(dpy, win, _intVal(anEventMask), &ev);
	} else {
	    thereIsOne = XCheckMaskEvent(dpy, _intVal(anEventMask), &ev);
	}
	if (thereIsOne) {
	    XPutBackEvent(dpy, &ev);
	    RETURN ( true );
	}
    }
    RETURN ( false );
%}
!

eventPending:anEventSymbol for:aWindowIdOrNil
    "return true, if a specific event is pending"

    ^ self eventsPending:(self eventMaskFor:anEventSymbol) for:aWindowIdOrNil
! !