XWorkstation.st
changeset 4252 9dca820cd786
parent 4245 d28b613dfc06
child 4258 a4b5ac616c69
--- a/XWorkstation.st	Wed Sep 15 01:03:38 2004 +0200
+++ b/XWorkstation.st	Wed Sep 15 01:06:05 2004 +0200
@@ -21,14 +21,24 @@
 		motifWMHintsAtom listOfXFonts buttonsPressed eventRootX
 		eventRootY displayName eventTrace dispatchingExpose rgbVisual
 		virtualRootId rootId altModifierMask metaModifierMask
-		multiClickTime deviceIOTimeoutErrorSignal activateOnClick
-		rawKeySymTranslation selectionOwner xlibTimeout xlibTimeoutForWindowCreation'
+		lastEventTime lastButtonPressTime deviceIOTimeoutErrorSignal
+		activateOnClick rawKeySymTranslation selectionOwner selectionTime
+		selectionFetchers preWaitAction xlibTimeout
+		xlibTimeoutForWindowCreation'
 	classVariableNames:'RawKeySymTranslation ConservativeSync MaxStringLength
-		SelectionHandlers DefaultXLibTimeout DefaultXLibTimeoutForWindowCreation'
+		DefaultXLibTimeout DefaultXLibTimeoutForWindowCreation'
 	poolDictionaries:''
 	category:'Interface-Graphics'
 !
 
+Object subclass:#SelectionFetcher
+	instanceVariableNames:'sema message display drawableID propertyID targetID buffer done
+		incremental'
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:XWorkstation
+!
+
 !XWorkstation primitiveDefinitions!
 %{
 
@@ -204,14 +214,14 @@
  */
 #define __ENTER_XLIB(whichTimeout)   \
     { \
-	__blockingPrimitiveTimoutHandler__ = (VOIDFUNC)__XTimeoutErrorHandler; \
-	__blockingPrimitiveTimeoutArg__ = (INT)self; \
-	__blockingPrimitiveTimeout__ = __intVal(__INST(whichTimeout)) * 50; \
+        __blockingPrimitiveTimoutHandler__ = (VOIDFUNC)__XTimeoutErrorHandler; \
+        __blockingPrimitiveTimeoutArg__ = (INT)self; \
+        __blockingPrimitiveTimeout__ = __intVal(__INST(whichTimeout)) * 50; \
     } {
 
 #define LEAVE_XLIB()   \
     { \
-	__blockingPrimitiveTimeout__ = 0; \
+        __blockingPrimitiveTimeout__ = 0; \
     } }
 
 #define ENTER_XLIB()   __ENTER_XLIB(xlibTimeout)
@@ -305,22 +315,25 @@
 # endif
 static
 dummyToForceLoading() {
-	XCreateSimpleWindow(0, 0, 0, 0, 0, 0, 0, 0, 0);
-	XCloseDisplay(0);
-	XCreateImage(0, 0, 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0);
-	XSetWindowColormap(0, 0, 0);
-	XQueryColors(0,0,0,0);
+        XCreateSimpleWindow(0, 0, 0, 0, 0, 0, 0, 0, 0);
+        XCloseDisplay(0);
+        XCreateImage(0, 0, 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0);
+        XSetWindowColormap(0, 0, 0);
+        XQueryColors(0,0,0,0);
 # ifdef SHM
-	XShmAttach(0, 0);
-	XShmCreateImage(0, 0, 0, 0, 0, 0, 0 ,0);
-	XShmDetach(0, 0);
-	XShmPutImage(0, 0, 0, 0 , 0,0,0,0,0,0,0);
-	shmctl(0,0,0);
-	fgetc(0);
+        XShmAttach(0, 0);
+        XShmCreateImage(0, 0, 0, 0, 0, 0, 0 ,0);
+        XShmDetach(0, 0);
+        XShmPutImage(0, 0, 0, 0 , 0,0,0,0,0,0,0);
+        shmctl(0,0,0);
+        fgetc(0);
 # endif
 }
 #endif
 
+#undef __myInstPtr
+#define __myInstPtr(obj) ((struct __XWorkstation_struct *)(obj))
+
 /*
  * catch X-errors and forward as errorInterrupt:#DisplayError,
  * (which itself invokes my handler and optionally raises an exceptionSignal)
@@ -338,26 +351,26 @@
     lastErrorMsg[127] = '\0';
 
     if (lastErrorMsg[0] == '\0') {
-	sprintf(lastErrorMsg, "code: %d", event->error_code);
+        sprintf(lastErrorMsg, "code: %d", event->error_code);
     }
     lastRequestCode = event->request_code;
     lastMinorCode = event->minor_code;
     lastResource = event->resourceid;
     if ((event->error_code == BadWindow) && (lastRequestCode == 4) && (lastMinorCode == 0)) {
-	/*
-	 * this is a BadWindow error for X_DestroyWindow.
-	 * ignore it here, since it results from the GC freeing windows
-	 * in non bottom-up window order.
-	 */
-	return 0;
+        /*
+         * this is a BadWindow error for X_DestroyWindow.
+         * ignore it here, since it results from the GC freeing windows
+         * in non bottom-up window order.
+         */
+        return 0;
     }
 
     if (@global(ErrorPrinting) == true) {
-	fprintf(stderr, "XWorkstation [error]: x-error caught 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, "XWorkstation [error]: x-error message is [%d] '%s'\n",
-			event->error_code, lastErrorMsg);
+        fprintf(stderr, "XWorkstation [error]: x-error caught 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, "XWorkstation [error]: x-error message is [%d] '%s'\n",
+                        event->error_code, lastErrorMsg);
     }
 
     __errorInterruptWithIDAndParameter__(@symbol(DisplayError), __MKEXTERNALADDRESS(dpy));
@@ -377,10 +390,10 @@
     Display *dpy;
 {
     if (@global(ErrorPrinting) == true) {
-	fprintf(stderr, "XWorkstation [error]: I/O error\n");
+        fprintf(stderr, "XWorkstation [error]: I/O error\n");
     }
     __immediateErrorInterruptWithIDAndParameter__(@symbol(DisplayIOError),
-						  __MKEXTERNALADDRESS(dpy));
+                                                  __MKEXTERNALADDRESS(dpy));
 
 #if 0
     /*
@@ -414,12 +427,12 @@
     extern OBJ __GLOBAL_GET_BY_NAME();
 
     if (@global(ErrorPrinting) == true) {
-	fprintf(stderr, "XWorkstation [error]: I/O request timeout dpy=%x\n", displayDeviceInst);
+        fprintf(stderr, "XWorkstation [error]: I/O request timeout dpy=%x\n", displayDeviceInst);
     }
     if ((displayDeviceInst == @global(MainDisplay))
      || (displayDeviceInst == __GLOBAL_GET_BY_NAME("Display"))) {  /* cannot use global(Display), because Display is a typedef in Xlib */
-	fprintf(stderr, "XWorkstation [error]: keep display connection for master display (no shutdown)\n");
-	return;
+        fprintf(stderr, "XWorkstation [error]: keep display connection for master display (no shutdown)\n");
+        return;
     }
 
 #if 0
@@ -446,10 +459,10 @@
      * if we return from the error interrupt ...
      */
     if (__OINST(displayDeviceInst, displayId) != nil) {
-	__internalError("unhandled display Timeout error");
-
-	__terminateProcess(0);      /* soft terminate */
-	__terminateProcess(1);      /* hard terminate */
+        __internalError("unhandled display Timeout error");
+
+        __terminateProcess(0);      /* soft terminate */
+        __terminateProcess(1);      /* hard terminate */
     }
 }
 
@@ -476,29 +489,29 @@
      */
 # if !defined(IRIS) || defined(IRIX5)
     if (root) {
-	vRootAtom = XInternAtom(dpy, "__SWM_VROOT", True);
-	if (vRootAtom != None) {
-	    if (XQueryTree(dpy, root, &rootReturn, &parentReturn, &children, &numChildren)) {
-		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;
-			    XFree(newRoot); /* XXX */
-			    break;
-			}
-		    }
-		}
-	    }
-	    if (children) XFree( children );
-	}
+        vRootAtom = XInternAtom(dpy, "__SWM_VROOT", True);
+        if (vRootAtom != None) {
+            if (XQueryTree(dpy, root, &rootReturn, &parentReturn, &children, &numChildren)) {
+                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;
+                            XFree(newRoot); /* XXX */
+                            break;
+                        }
+                    }
+                }
+            }
+            if (children) XFree( children );
+        }
     }
 # endif
     return root;
@@ -634,22 +647,23 @@
      when buffering is on, this may be
      an error for a long-ago operation"
 
-    |string requestCode s match line|
+    |string 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
     "
+    match := 'XRequest.' , self requestCodeOfLastError printString.
     s := '/usr/lib/X11/XErrorDB' asFilename readStreamOrNil.
     s notNil ifTrue:[
-	match := 'XRequest.' , requestCode printString.
-	line := s peekForLineStartingWith:match.
-	line notNil ifTrue:[
-	    string := string , ' in ' , (line copyFrom:(line indexOf:$:)+1)
-	].
-	s close.
+        line := s peekForLineStartingWith:match.
+        s close.
+    ].
+    line isNil ifTrue:[
+        string := string, ' in ', match
+    ] ifFalse:[
+        string := string , ' in ' , (line copyFrom:(line indexOf:$:)+1)
     ].
     ^ string
 !
@@ -669,19 +683,19 @@
 !
 
 resourceIdOfLastError
-    %{  /* NOCONTEXT */
-
-	if (lastResource != 0) {
-	    RETURN ( __MKEXTERNALADDRESS(lastResource) );
-	}
-    %}.
-
-    ^ nil
-
-
-    "
-	Screen resourceIdOfLastError
-    "
+%{  /* NOCONTEXT */
+
+      if (lastResource != 0) {
+         RETURN ( __MKEXTERNALADDRESS(lastResource) );
+      }
+%}.
+
+     ^ nil
+
+
+     "
+         Screen resourceIdOfLastError
+     "
 !
 
 setConnectionTimeOut:seconds
@@ -4417,14 +4431,16 @@
 buttonMotion:view state:state x:x y:y rootX:rX rootY:rY time:time
     "forward a buttonMotion event for some view"
 
+    lastEventTime := time.
     self buttonMotion:state x:x y:y view:view
 !
 
 buttonPress:view button:button state:state x:x y:y rootX:rX rootY:rY time:time
     "forward a buttonPress event for some view"
 
-    |logicalButton nextMultiClickTime|
-
+    |logicalButton|
+
+    lastEventTime := time.
     altDown := state bitTest:altModifierMask.
     metaDown := state bitTest:metaModifierMask.
     shiftDown := state bitTest:(self shiftModifierMask).
@@ -4443,32 +4459,29 @@
     ].
 
     logicalButton isInteger ifTrue:[
-	buttonsPressed := buttonsPressed bitOr:(1 bitShift:logicalButton-1).
-    ].
-
-    multiClickTimeDelta notNil ifTrue:[
-	nextMultiClickTime := time + multiClickTimeDelta.
-	multiClickTime notNil ifTrue:[
-	    time < multiClickTime ifTrue:[
-		multiClickTime := nextMultiClickTime.
-		self buttonMultiPress:logicalButton x:x y:y view:view.
-		^ self.
-	    ]
-	].
-	multiClickTime := nextMultiClickTime.
-    ].
+        buttonsPressed := buttonsPressed bitOr:(1 bitShift:logicalButton-1).
+    ].
+
+    (multiClickTimeDelta notNil and:[lastButtonPressTime notNil]) ifTrue:[
+        time < (lastButtonPressTime + multiClickTimeDelta) ifTrue:[
+            lastButtonPressTime := time.
+            self buttonMultiPress:logicalButton x:x y:y view:view.
+            ^ self.
+        ].
+    ].
+    lastButtonPressTime := time.
 
     view isNil ifTrue:[
-	"/ event arrived, after I destroyed it myself
-	^ self
+        "/ event arrived, after I destroyed it myself
+        ^ self
     ].
     logicalButton == 1 ifTrue:[
-	activateOnClick == true ifTrue:[
-	    "/ dont raise above an active popup view.
-	    (activeKeyboardGrab isNil and:[activePointerGrab isNil]) ifTrue:[
-		view topView raise.
-	    ]
-	].
+        activateOnClick == true ifTrue:[
+            "/ dont raise above an active popup view.
+            (activeKeyboardGrab isNil and:[activePointerGrab isNil]) ifTrue:[
+                view topView raise.
+            ]
+        ].
     ].
     super buttonPress:logicalButton x:x y:y view:view
 !
@@ -4478,6 +4491,7 @@
 
     |logicalButton|
 
+    lastEventTime := time.
     altDown := state bitTest:altModifierMask.
     metaDown := state bitTest:metaModifierMask.
     shiftDown := state bitTest:(self shiftModifierMask).
@@ -4495,7 +4509,7 @@
     ].
 
     logicalButton isInteger ifTrue:[
-	buttonsPressed := buttonsPressed bitClear:(1 bitShift:logicalButton-1).
+        buttonsPressed := buttonsPressed bitClear:(1 bitShift:logicalButton-1).
     ].
     self buttonRelease:logicalButton x:x y:y view:view
 !
@@ -4539,21 +4553,20 @@
 dndMessage:event data:data view:targetView
     "handle a DND drag&drop protocol message"
 
-    |sensor dropType dropValue names i1 i2 t|
+    |sensor property dropType dropValue names i1 i2 propertyType|
 
     dropType := data doubleWordAt:1.
 
     "/ see def's in DragAndDropTypes.h
     dropType := (self dndDropTypes) at:dropType+1 ifAbsent:#DndNotDnd.
 
-    self
-	getProperty:(self atomIDOf:#DndSelection)
-	from:rootId
-	delete:false
-	into:[:type :value |
-	    t := type.
-	    dropValue := value
-	].
+    property := self
+        getProperty:(self atomIDOf:#DndSelection)
+        from:rootId
+        delete:false.
+
+    propertyType := property key.
+    dropValue := property value.
 
     "/ preconvert into a collection
     "/ of fileNames, string or byteArray
@@ -4564,83 +4577,72 @@
     "/ in the default dropMessage handling of SimpleView.
 
     dropType == #DndFiles ifTrue:[
-	"/ actually, a list of fileNames
-	t ~~ stringAtom ifTrue:[
-	    'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
-	    ^ self
-	].
-
-	names := OrderedCollection new.
-	i1 := 1.
-	[i1 ~~ 0] whileTrue:[
-	    i2 := dropValue indexOf:(Character value:0) startingAt:i1.
-	    i2 ~~ 0 ifTrue:[
-		names add:(dropValue copyFrom:i1 to:(i2-1)).
-		i1 := i2 + 1.
-	    ] ifFalse:[
-		i1 := i2
-	    ].
-	].
-	dropValue := names.
-	dropValue := dropValue collect:[:nm | nm asFilename].
-	dropType := #files.
+        "/ actually, a list of fileNames
+        propertyType ~~ stringAtom ifTrue:[
+            'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
+            ^ self
+        ].
+
+        names := OrderedCollection new.
+        i1 := 1.
+        [i1 ~~ 0] whileTrue:[
+            i2 := dropValue indexOf:(Character value:0) startingAt:i1.
+            i2 ~~ 0 ifTrue:[
+                names add:(dropValue copyFrom:i1 to:(i2-1)).
+                i1 := i2 + 1.
+            ] ifFalse:[
+                i1 := i2
+            ].
+        ].
+        dropValue := names.
+        dropValue := dropValue collect:[:nm | nm asFilename].
+        dropType := #files.
     ] ifFalse:[ (dropType == #DndFile) ifTrue:[
-	t ~~ stringAtom ifTrue:[
-	    'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
-	    ^ self
-	].
-
-	dropValue := dropValue asFilename.
-	dropType := #file.
+        propertyType ~~ stringAtom ifTrue:[
+            'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
+            ^ self
+        ].
+        dropValue := dropValue asFilename.
+        dropType := #file.
     ] ifFalse:[ (dropType == #DndDir) ifTrue:[
-	t ~~ stringAtom ifTrue:[
-	    'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
-	    ^ self
-	].
-
-	dropValue := dropValue asFilename.
-	dropType := #directory.
+        propertyType ~~ stringAtom ifTrue:[
+            'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
+            ^ self
+        ].
+        dropValue := dropValue asFilename.
+        dropType := #directory.
     ] ifFalse:[ (dropType == #DndText) ifTrue:[
-	t ~~ stringAtom ifTrue:[
-	    'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
-	    ^ self
-	].
-
-	dropValue := dropValue.
-	dropType := #text.
+        propertyType ~~ stringAtom ifTrue:[
+            'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
+            ^ self
+        ].
+        dropType := #text.
     ] ifFalse:[ (dropType == #DndExe) ifTrue:[
-	t ~~ stringAtom ifTrue:[
-	    'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
-	    ^ self
-	].
-
-	dropValue := dropValue.
-	dropType := #executable.
+        propertyType ~~ stringAtom ifTrue:[
+            'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
+            ^ self
+        ].
+        dropType := #executable.
     ] ifFalse:[ (dropType == #DndLink) ifTrue:[
-	t ~~ stringAtom ifTrue:[
-	    'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
-	    ^ self
-	].
-
-	dropValue := dropValue.
-	dropType := #link.
+        propertyType ~~ stringAtom ifTrue:[
+            'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
+            ^ self
+        ].
+        dropType := #link.
     ] ifFalse:[ (dropType == #DndRawData) ifTrue:[
-	dropValue := dropValue.
-	dropType := #rawData.
+        dropType := #rawData.
     ] ifFalse:[
-	'XWorkstation [info]: unsupported dropType: ' infoPrint. dropType infoPrintCR.
-	'XWorkstation [info]: data: ' infoPrint. dropValue infoPrintCR.
-
-	dropValue := dropValue.
-	dropType := #unknown.
+        'XWorkstation [info]: unsupported dropType: ' infoPrint. dropType infoPrintCR.
+        'XWorkstation [info]: data: ' infoPrint. dropValue infoPrintCR.
+        dropType := #unknown.
     ]]]]]]].
 
     (sensor := targetView sensor) notNil ifTrue:[
-	sensor dropMessage:dropType data:dropValue view:targetView
+        sensor dropMessage:dropType data:dropValue view:targetView
     ] ifFalse:[
-	"
-	 not posted, if there is no sensor ...
-	"
+        "
+         not posted, if there is no sensor ...
+        "
     ]
 
     "Created: 4.4.1997 / 17:59:37 / cg"
@@ -4682,43 +4684,39 @@
 keyPress:view key:key code:keyCode state:state x:x y:y rootX:rX rootY:rY time:time
     "forward a key-press event for some view"
 
+    lastEventTime := time.
     altDown := state bitTest:altModifierMask.
     metaDown := state bitTest:metaModifierMask.
     shiftDown := state bitTest:(self shiftModifierMask).
     ctrlDown := state bitTest:(self ctrlModifierMask).
 
     key isNil ifTrue:[
-	"/ happens sometimes on some systems
-	"/ (alt-graph on sun has no keysym)
-	^ self
+        "/ happens sometimes on some systems
+        "/ (alt-graph on sun has no keysym)
+        ^ self
     ].
     eventRootX := rX.
     eventRootY := rY.
     self keyPress:key x:x y:y view:view.
-
-
 !
 
 keyRelease:view key:key code:keyCode state:state x:x y:y rootX:rX rootY:rY time:time
     "forward a key-release event for some view"
 
+    lastEventTime := time.
     altDown := state bitTest:altModifierMask.
     metaDown := state bitTest:metaModifierMask.
     shiftDown := state bitTest:(self shiftModifierMask).
     ctrlDown := state bitTest:(self ctrlModifierMask).
 
     key isNil ifTrue:[
-	"/ happens sometimes on some systems
-	"/ (alt-graph on sun has no keysym)
-	^ self
+        "/ happens sometimes on some systems
+        "/ (alt-graph on sun has no keysym)
+        ^ self
     ].
     eventRootX := rX.
     eventRootY := rY.
     self keyRelease:key x:x y:y view:view.
-
-
-
-
 !
 
 mappingNotify:view request:what event:eB
@@ -4736,6 +4734,7 @@
 pointerEnter:view x:x y:y rootX:rX rootY:rY state:state mode:mode detail:detail time:time
     "forward a pointer enter event for some view"
 
+    lastEventTime := time.
     altDown := state bitTest:altModifierMask.
     metaDown := state bitTest:metaModifierMask.
     shiftDown := state bitTest:(self shiftModifierMask).
@@ -4749,6 +4748,7 @@
 pointerLeave:view x:x y:y rootX:rX rootY:rY state:state mode:mode detail:detail time:time
     "forward a pointer leave event for some view"
 
+    lastEventTime := time.
     altDown := state bitTest:altModifierMask.
     metaDown := state bitTest:metaModifierMask.
     shiftDown := state bitTest:(self shiftModifierMask).
@@ -4759,29 +4759,34 @@
     self pointerLeave:state view:view
 !
 
-propertyChange:aView atom:atom state:aSymbol time:time
+propertyChange:aView property:propertyId state:aSymbol time:time
     "sent when an X property changes.
      This is a very X-specific mechanism."
 
+    |selectionFetcher|
+
+    lastEventTime := time.
     aView isNil ifTrue:[
-	"/ event arrived, after I destroyed it myself
-	^ self
-    ].
+        "event arrived, after aView has been destroyed"
+        ^ self
+    ].
+
+"/    'propertyChange ' infoPrint. (self atomName:propertyId) print. ': ' print. aSymbol printCR.
 "/    aView propertyChange:atom state:aSymbol.
-!
-
-selectionClear:aView atom:selectionID time:time
+
+    selectionFetcher := self findSelectionFetcher:aView id.
+    selectionFetcher notNil ifTrue:[
+        selectionFetcher message:thisContext message.
+    ].
+!
+
+selectionClear:aView selection:selectionID time:time
     "sent when another X-client has created a selection.
      This is a very X-specific mechanism."
 
+    lastEventTime := time.
     self setCopyBuffer:nil.
 
-    SelectionHandlers notNil ifTrue:[
-	SelectionHandlers do:[:eachHandler |
-	    eachHandler selectionClear:selectionID
-	]
-    ].
-
     "/ noone is interested in that ...
     "/ aView selectionClear:selectionID
 !
@@ -4790,7 +4795,7 @@
     "sent when the server returns an answer from a request for a selection.
      This is a very X-specific mechanism."
 
-    |clipBoardContents|
+    |selectionFetcher|
 
 "/    Transcript show:'seletionNotify selID:'.
 "/    Transcript show:selectionID; show:' ('; show:(self atomName:selectionID); show:') '.
@@ -4801,51 +4806,56 @@
 "/    Transcript showCR:''.
 "/    Transcript endEntry.
 
-    clipBoardContents := self getProperty:propertyID type:targetID from:requestorID.
-    clipBoardContents notNil ifTrue:[
-	aView sensor pasteFromClipBoard:clipBoardContents view:aView
-    ]
+    lastEventTime := time.
+
+    aView isNil ifTrue:[
+        "event arrived, after aView has been destroyed"
+        ^ self
+    ].
+    selectionFetcher := self findSelectionFetcher:aView id.
+    selectionFetcher notNil ifTrue:[
+        selectionFetcher message:thisContext message.
+    ].
 !
 
 selectionRequest:aView requestor:requestorID selection:selectionID target:targetID property:propertyID time:time
     "sent by some other X-client to ask for the selection.
      This is a very X-specific mechanism."
 
-    |selection targetIdOut|
+    |selection property|
 
 "/'Selection: ' print. (self atomName:selectionID) print. ' TargetId: ' print. (self atomName:targetID) print.
 "/' Property: ' print. (self atomName:propertyID) print. ' Requestor: ' print. requestorID printCR.
 
+    lastEventTime := time.
     selection := self selectionAs:targetID.
+
+"/'Send selection: ' print. selection printCR.
+
+    property := propertyID.
+
     selection isNil ifTrue:[
+        "sending property None tells the client, 
+         that I could not convert"
 "/        ('XWorkstation: unsupported selection target ', (self atomName:targetID)) errorPrintCR.
-
-	"sending property None tells client, that i cannot convert"
-	self
-	    sendSelectionNotifySelection:selectionID
-	    property:nil
-	    target:targetID
-	    time:time
-"/            from:aView id  BAD: nobody understands this
-	    from:requestorID
-	    to:requestorID.
-	^ self
-    ].
-"/'Send selection: ' print. selection printCR.
-
-    targetIdOut := targetID.
-    selection isString ifTrue:[
-	targetIdOut := self atomIDOf:#STRING.
-    ].
-
-    self sendSelection:selection
-	 selection:selectionID
-	 property:propertyID
-	 target:targetIdOut
-	 time:time
-"/         from:aView id    BAD: nobody understands this
-	 from:requestorID
-	 to:requestorID.
+        property := nil.
+    ] ifFalse:[
+        property == 0 ifTrue:[
+            "Support old (obsolete) clients requesting a None property.
+             Set the propertyID to the targetID"
+            property := targetID.
+        ].
+        self setProperty:property
+             type:targetID
+             value:selection
+             for:requestorID.
+    ].
+
+    self sendSelectionNotifySelection:selectionID
+         property:property
+         target:targetID
+         time:time
+         to:requestorID.
 !
 
 visibilityNotify:aView state:how
@@ -4978,7 +4988,7 @@
     eventArray := Array new:13.
 
     (self getEventFor:aViewIdOrNil withMask:eventMask into:eventArray) ifTrue:[
-	AbortSignal handle:[:ex |
+	AbortOperationRequest handle:[:ex |
 	    ex return
 	] do:[
 	    self dispatchEvent:eventArray.
@@ -5001,16 +5011,13 @@
 !
 
 dispatchLoop
-    |flushBlock|
-
-    flushBlock := [self flush].
-
-    Processor addPreWaitAction:flushBlock.
-
+    preWaitAction := [self flush].
+    Processor addPreWaitAction:preWaitAction.
     [
 	super dispatchLoop
     ] ensure:[
-	Processor removePreWaitAction:flushBlock.
+	Processor removePreWaitAction:preWaitAction.
+	preWaitAction := nil.
     ].
 !
 
@@ -5037,7 +5044,7 @@
     eventArray := Array new:13.
     [self eventPendingWithSync:false] whileTrue:[
 	(self getEventFor:nil withMask:nil into:eventArray) ifTrue:[
-	    AbortSignal handle:[:ex |
+	    AbortOperationRequest handle:[:ex |
 		ex return
 	    ] do:[
 		self dispatchEvent:eventArray.
@@ -5271,11 +5278,11 @@
 
      The event fields are placed them into anEventArray (must be at least size 13):
      the fields are:
-	1:      windowID
-	2:      eventType-ID
-	3:      eventTypeSymbol
-
-	4..     args
+        1:      windowID
+        2:      eventType-ID
+        3:      eventTypeSymbol
+
+        4..     args
 
      Sorry I had to split dispatch into this fetch method and a separate
      handler method to allow UNLIMITEDSTACK here.
@@ -5295,11 +5302,10 @@
     int i, nchars;
     char *keySymString;
     char keySymStringBuffer[32];
-    unsigned INT nextMultiClickTime;
     OBJ arg, sym, t, windowID;
 
     if (! ISCONNECTED) {
-	RETURN (false);
+        RETURN (false);
     }
 
     dpy = myDpy;
@@ -5307,39 +5313,39 @@
     ev.type = 0;
 
     if (__isSmallInteger(eventMask)) {
-	evMask = __intVal(eventMask);
+        evMask = __intVal(eventMask);
     } else {
-	evMask = ~0;
+        evMask = ~0;
     }
 
     if (__isExternalAddress(aViewIdOrNil)) {
-	wWanted = __WindowVal(aViewIdOrNil);
-	returnValue = XCheckWindowEvent(dpy, wWanted, evMask, &ev);
+        wWanted = __WindowVal(aViewIdOrNil);
+        returnValue = XCheckWindowEvent(dpy, wWanted, evMask, &ev);
     } else {
-	if (evMask == ~0) {
-	    XNextEvent(dpy, &ev);
-	    returnValue = 1;
-	} else {
-	    returnValue = XCheckMaskEvent(dpy, evMask, &ev);
-	}
+        if (evMask == ~0) {
+            XNextEvent(dpy, &ev);
+            returnValue = 1;
+        } else {
+            returnValue = XCheckMaskEvent(dpy, evMask, &ev);
+        }
     }
     if (!returnValue) {
-	/* there is no event */
-	RETURN (false);
+        /* there is no event */
+        RETURN (false);
     }
 
     if (anEventArray == nil) {
-	/* sender is not interested in the event */
-	RETURN(true);
+        /* sender is not interested in the event */
+        RETURN(true);
     }
 
     if (!__isArray(anEventArray)) {
-	fprintf(stderr, "XWorkstation: bad argument [%d]\n", __LINE__);
-	RETURN (false);
+        fprintf(stderr, "XWorkstation: bad argument [%d]\n", __LINE__);
+        RETURN (false);
     }
     if (__arraySize(anEventArray) < 11) {
-	fprintf(stderr, "XWorkstation: bad argument [%d]\n", __LINE__);
-	RETURN (false);
+        fprintf(stderr, "XWorkstation: bad argument [%d]\n", __LINE__);
+        RETURN (false);
     }
 
 #   define ANYBUTTON   (Button1MotionMask | Button2MotionMask | Button3MotionMask)
@@ -5365,367 +5371,367 @@
 #   define cme ((XColormapEvent *)&ev)
 
     if (((t = __INST(lastId)) != nil)
-	 && __isExternalAddress(t)
-	 && (__WindowVal(t) == ae->window)) {
-	windowID = t;
+         && __isExternalAddress(t)
+         && (__WindowVal(t) == ae->window)) {
+        windowID = t;
     } else {
-	windowID = __MKEXTERNALADDRESS(ae->window);
+        windowID = __MKEXTERNALADDRESS(ae->window);
     }
 
     __ArrayInstPtr(anEventArray)->a_element[0] = windowID; __STORE(anEventArray, windowID);
     __ArrayInstPtr(anEventArray)->a_element[1] = __MKSMALLINT(ev.type);
 
     switch (ev.type) {
-	case KeyRelease:
-	    sym = @symbol(keyRelease:key:code:state:x:y:rootX:rootY:time:);
-	    goto keyPressAndRelease;
-
-	case KeyPress:
-	    sym = @symbol(keyPress:key:code:state:x:y:rootX:rootY:time:);
-	    /* FALL INTO */
-
-	keyPressAndRelease:
-	    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 {
-		keySymString = XKeysymToString(keySym);
-		if (keySymString) {
-		    arg = __MKSYMBOL(keySymString, 0);
-		} else {
-		    arg = nil;
-		}
-	    }
+        case KeyRelease:
+            sym = @symbol(keyRelease:key:code:state:x:y:rootX:rootY:time:);
+            goto keyPressAndRelease;
+
+        case KeyPress:
+            sym = @symbol(keyPress:key:code:state:x:y:rootX:rootY:time:);
+            /* FALL INTO */
+
+        keyPressAndRelease:
+            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 {
+                keySymString = XKeysymToString(keySym);
+                if (keySymString) {
+                    arg = __MKSYMBOL(keySymString, 0);
+                } else {
+                    arg = nil;
+                }
+            }
 
 #ifdef IGNORE_UNKNOWN_KEYCODES
-	    if (arg == nil) {
-		/* happens sometimes (alt-graph on sun has no keysym) */
-		RETURN (false);
-	    }
-#endif
-	    __ArrayInstPtr(anEventArray)->a_element[2] = sym;
-
-	    __ArrayInstPtr(anEventArray)->a_element[3] = arg; __STORE(anEventArray, arg);
-	    __ArrayInstPtr(anEventArray)->a_element[4] = t = __MKUINT(ke->keycode); __STORE(anEventArray, t);
-	    __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(ke->state);
-	    __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(ke->x);
-	    __ArrayInstPtr(anEventArray)->a_element[7] = __mkSmallInteger(ke->y);
-	    __ArrayInstPtr(anEventArray)->a_element[8] = __mkSmallInteger(ke->x_root);
-	    __ArrayInstPtr(anEventArray)->a_element[9] = __mkSmallInteger(ke->y_root);
-	    __ArrayInstPtr(anEventArray)->a_element[10] = t = __MKUINT(ke->time); __STORE(anEventArray, t);
-	    break;
-
-	case ButtonPress:
-	    sym = @symbol(buttonPress:button:state:x:y:rootX:rootY:time:);
-	    goto buttonPressAndRelease;
-
-	case ButtonRelease:
-	    sym = @symbol(buttonRelease:button:state:x:y:rootX:rootY:time:);
-	    /* fall into */
-
-	buttonPressAndRelease:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = sym;
-	    __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(be->button);
-	    __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(ke->state);
-	    __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(be->x);
-	    __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(be->y);
-	    __ArrayInstPtr(anEventArray)->a_element[7] = __mkSmallInteger(be->x_root);
-	    __ArrayInstPtr(anEventArray)->a_element[8] = __mkSmallInteger(be->y_root);
-	    __ArrayInstPtr(anEventArray)->a_element[9] = t = __MKUINT(be->time); __STORE(anEventArray, t);
-	    break;
-
-	case MotionNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(buttonMotion:state:x:y:rootX:rootY:time:);
-
-	    __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(me->state);
-	    __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(me->x);
-	    __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(me->y);
-	    __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(me->x_root);
-	    __ArrayInstPtr(anEventArray)->a_element[7] = __mkSmallInteger(me->y_root);
-	    __ArrayInstPtr(anEventArray)->a_element[8] = t = __MKUINT(me->time); __STORE(anEventArray, t);
-	    break;
-
-	case FocusIn:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(focusIn:mode:detail:);
-	    goto focusInOut;
-
-	case FocusOut:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(focusOut:mode:detail:);
-	    /* fall into */
-
-	focusInOut:
-	    __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(fe->mode);
-	    __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(fe->detail);
-	    break;
-
-	case EnterNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(pointerEnter:x:y:rootX:rootY:state:mode:detail:time:);
-	    goto enterLeave;
-
-	case LeaveNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(pointerLeave:x:y:rootX:rootY:state:mode:detail:time:);
-	    /* fall into */
-
-	enterLeave:
-	    __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(ele->x);
-	    __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(ele->y);
-	    __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(ele->x_root);
-	    __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(ele->y_root);
-	    __ArrayInstPtr(anEventArray)->a_element[7] = __mkSmallInteger(ele->state);
-	    __ArrayInstPtr(anEventArray)->a_element[8] = __mkSmallInteger(ele->mode);
-	    __ArrayInstPtr(anEventArray)->a_element[9] = __mkSmallInteger(ele->detail);
-	    __ArrayInstPtr(anEventArray)->a_element[10] = t = __MKUINT(ele->time); __STORE(anEventArray, t);
-	    break;
-
-	case Expose:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(expose:x:y:width:height:count:);
-	    goto expose;
-
-	case GraphicsExpose:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(graphicsExpose:x:y:width:height:count:);
-	    /* fall into */
-
-	expose:
-	    __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(ee->x);
-	    __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(ee->y);
-	    __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(ee->width);
-	    __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(ee->height);
-	    __ArrayInstPtr(anEventArray)->a_element[7] = __mkSmallInteger(ee->count);
-	    break;
-
-	case NoExpose:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(noExposeView:);
-	    break;
-
-	case VisibilityNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(visibilityNotify:state:);
-	    switch (ve->state) {
-		case VisibilityUnobscured:
-		    __ArrayInstPtr(anEventArray)->a_element[3] = @symbol(unobscured);
-		    break;
-		case VisibilityPartiallyObscured:
-		    __ArrayInstPtr(anEventArray)->a_element[3] = @symbol(partiallyObscured);
-		    break;
-		case VisibilityFullyObscured:
-		    __ArrayInstPtr(anEventArray)->a_element[3] = @symbol(fullyObscured);
-		    break;
-		default:
-		    __ArrayInstPtr(anEventArray)->a_element[3] = __MKSMALLINT(ve->state);
-		    break;
-	    }
-	    break;
-
-	case CreateNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(createWindow:x:y:width:height:);
-	    __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(cre->x);
-	    __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(cre->y);
-	    __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(cre->width);
-	    __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(cre->height);
-	    break;
-
-	case DestroyNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(destroyedView:);
-	    break;
-
-	case UnmapNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(unmappedView:);
-	    break;
-
-	case MapNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(mappedView:);
-	    break;
-
-	case ConfigureNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(configure:x:y:width:height:above:);
-	    __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(ce->x);
-	    __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(ce->y);
-	    __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(ce->width);
-	    __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(ce->height);
-	    __ArrayInstPtr(anEventArray)->a_element[7] = nil;
-	    if (ce->above != None) {
-		__ArrayInstPtr(anEventArray)->a_element[7] = t = __MKEXTERNALADDRESS(ce->above); __STORE(anEventArray, t);
-	    }
-	    break;
-
-	case GravityNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(gravityNotify:x:y:);
-	    __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(gre->x);
-	    __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(gre->y);
-	    break;
-
-	case ResizeRequest:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(resizeRequest:width:height:);
-	    __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(rr->width);
-	    __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(rr->height);
-	    break;
-
-	case ConfigureRequest:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(configureRequest:x:y:width:height:above:detail:);
-	    __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(cr->x);
-	    __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(cr->y);
-	    __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(cr->width);
-	    __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(cr->height);
-	    __ArrayInstPtr(anEventArray)->a_element[7] = nil;
-	    if (cr->above != None) {
-		__ArrayInstPtr(anEventArray)->a_element[7] = t = __MKEXTERNALADDRESS(cr->above); __STORE(anEventArray, t);
-	    }
-	    switch (cr->detail) {
-		case Above:
-		    __ArrayInstPtr(anEventArray)->a_element[8] = @symbol(above);
-		    break;
-		case Below:
-		    __ArrayInstPtr(anEventArray)->a_element[8] = @symbol(below);
-		    break;
-		case TopIf:
-		    __ArrayInstPtr(anEventArray)->a_element[8] = @symbol(topIf);
-		    break;
-		case BottomIf:
-		    __ArrayInstPtr(anEventArray)->a_element[8] = @symbol(bottomIf);
-		    break;
-		case Opposite:
-		    __ArrayInstPtr(anEventArray)->a_element[8] = @symbol(opposite);
-		    break;
-		default:
-		    __ArrayInstPtr(anEventArray)->a_element[8] = __MKSMALLINT(cr->detail);
-		    break;
-	    }
-	    break;
-
-	case CirculateNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(circulateNotify:place:);
-	    goto circulate;
-
-	case CirculateRequest:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(circulateRequest:place:);
-	    /* fall into */
-	circulate:
-	    switch (cie->place) {
-		case PlaceOnTop:
-		    __ArrayInstPtr(anEventArray)->a_element[3] = @symbol(placeOnTop);
-		    break;
-		case PlaceOnBottom:
-		    __ArrayInstPtr(anEventArray)->a_element[3] = @symbol(placeOnBottom);
-		    break;
-		default:
-		    __ArrayInstPtr(anEventArray)->a_element[3] = __MKSMALLINT(cie->place);
-		    break;
-	    }
-	    break;
-
-	case PropertyNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(propertyChange:atom:state:time:);
-	    __ArrayInstPtr(anEventArray)->a_element[3] = __MKATOMOBJ(pe->atom);
-	    switch (pe->state) {
-		case PropertyNewValue:
-		    __ArrayInstPtr(anEventArray)->a_element[4] = @symbol(newValue);
-		    break;
-		case PropertyDelete:
-		    __ArrayInstPtr(anEventArray)->a_element[4] = @symbol(deleted);
-		    break;
-		default:
-		    __ArrayInstPtr(anEventArray)->a_element[4] = __MKSMALLINT(pe->state);
-		    break;
-	    }
-	    __ArrayInstPtr(anEventArray)->a_element[5] = t = __MKUINT(pe->time); __STORE(anEventArray, t);
-	    break;
-
-	case SelectionClear:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(selectionClear:atom:time:);
-	    __ArrayInstPtr(anEventArray)->a_element[3] = __MKATOMOBJ(sce->selection);
-	    __ArrayInstPtr(anEventArray)->a_element[4] = t = __MKUINT(sce->time);         __STORE(anEventArray, t);
-	    break;
-
-	case SelectionRequest:
-	    /*
-	     * someone wants the selection
-	     */
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(selectionRequest:requestor:selection:target:property:time:);
-	    __ArrayInstPtr(anEventArray)->a_element[3] = t = __MKEXTERNALADDRESS(ev.xselectionrequest.requestor); __STORE(anEventArray, t);
-	    __ArrayInstPtr(anEventArray)->a_element[4] = __MKATOMOBJ(ev.xselectionrequest.selection);
-	    __ArrayInstPtr(anEventArray)->a_element[5] = __MKATOMOBJ(ev.xselectionrequest.target);
-	    __ArrayInstPtr(anEventArray)->a_element[6] = __MKATOMOBJ(ev.xselectionrequest.property);
-	    __ArrayInstPtr(anEventArray)->a_element[7] = t = __MKUINT(ev.xselectionrequest.time);         __STORE(anEventArray, t);
-	    break;
-
-	case SelectionNotify:
-	    /*
-	     * returned selection value (answer from SelectionRequest)
-	     */
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(selectionNotify:selection:target:property:requestor:time:);
-	    __ArrayInstPtr(anEventArray)->a_element[3] = __MKATOMOBJ(ev.xselection.selection);
-	    __ArrayInstPtr(anEventArray)->a_element[4] = __MKATOMOBJ(ev.xselection.target);
-	    __ArrayInstPtr(anEventArray)->a_element[5] = __MKATOMOBJ(ev.xselection.property);
-	    __ArrayInstPtr(anEventArray)->a_element[6] = t = __MKEXTERNALADDRESS(ev.xselection.requestor); __STORE(anEventArray, t);
-	    __ArrayInstPtr(anEventArray)->a_element[7] = t = __MKUINT(ev.xselection.time); __STORE(anEventArray, t);
-	    break;
-
-	case ColormapNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(colormapNotify:state:);
-	    __ArrayInstPtr(anEventArray)->a_element[3] = cme->state == ColormapInstalled ? true : false;
-	    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)))) {
-		    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(terminateView:);
-		    break;
-		}
-		if (ev.xclient.data.l[0] == (int) __AtomVal(__INST(saveYourselfAtom))) {
-		    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(saveAndTerminateView:);
-		    break;
-		}
-	    }
-	    /*
-	     * any other client message
-	     */
+            if (arg == nil) {
+                /* happens sometimes (alt-graph on sun has no keysym) */
+                RETURN (false);
+            }
+#endif
+            __ArrayInstPtr(anEventArray)->a_element[2] = sym;
+
+            __ArrayInstPtr(anEventArray)->a_element[3] = arg; __STORE(anEventArray, arg);
+            __ArrayInstPtr(anEventArray)->a_element[4] = t = __MKUINT(ke->keycode); __STORE(anEventArray, t);
+            __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(ke->state);
+            __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(ke->x);
+            __ArrayInstPtr(anEventArray)->a_element[7] = __mkSmallInteger(ke->y);
+            __ArrayInstPtr(anEventArray)->a_element[8] = __mkSmallInteger(ke->x_root);
+            __ArrayInstPtr(anEventArray)->a_element[9] = __mkSmallInteger(ke->y_root);
+            __ArrayInstPtr(anEventArray)->a_element[10] = t = __MKUINT(ke->time); __STORE(anEventArray, t);
+            break;
+
+        case ButtonPress:
+            sym = @symbol(buttonPress:button:state:x:y:rootX:rootY:time:);
+            goto buttonPressAndRelease;
+
+        case ButtonRelease:
+            sym = @symbol(buttonRelease:button:state:x:y:rootX:rootY:time:);
+            /* fall into */
+
+        buttonPressAndRelease:
+            __ArrayInstPtr(anEventArray)->a_element[2] = sym;
+            __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(be->button);
+            __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(ke->state);
+            __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(be->x);
+            __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(be->y);
+            __ArrayInstPtr(anEventArray)->a_element[7] = __mkSmallInteger(be->x_root);
+            __ArrayInstPtr(anEventArray)->a_element[8] = __mkSmallInteger(be->y_root);
+            __ArrayInstPtr(anEventArray)->a_element[9] = t = __MKUINT(be->time); __STORE(anEventArray, t);
+            break;
+
+        case MotionNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(buttonMotion:state:x:y:rootX:rootY:time:);
+
+            __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(me->state);
+            __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(me->x);
+            __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(me->y);
+            __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(me->x_root);
+            __ArrayInstPtr(anEventArray)->a_element[7] = __mkSmallInteger(me->y_root);
+            __ArrayInstPtr(anEventArray)->a_element[8] = t = __MKUINT(me->time); __STORE(anEventArray, t);
+            break;
+
+        case FocusIn:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(focusIn:mode:detail:);
+            goto focusInOut;
+
+        case FocusOut:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(focusOut:mode:detail:);
+            /* fall into */
+
+        focusInOut:
+            __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(fe->mode);
+            __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(fe->detail);
+            break;
+
+        case EnterNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(pointerEnter:x:y:rootX:rootY:state:mode:detail:time:);
+            goto enterLeave;
+
+        case LeaveNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(pointerLeave:x:y:rootX:rootY:state:mode:detail:time:);
+            /* fall into */
+
+        enterLeave:
+            __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(ele->x);
+            __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(ele->y);
+            __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(ele->x_root);
+            __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(ele->y_root);
+            __ArrayInstPtr(anEventArray)->a_element[7] = __mkSmallInteger(ele->state);
+            __ArrayInstPtr(anEventArray)->a_element[8] = __mkSmallInteger(ele->mode);
+            __ArrayInstPtr(anEventArray)->a_element[9] = __mkSmallInteger(ele->detail);
+            __ArrayInstPtr(anEventArray)->a_element[10] = t = __MKUINT(ele->time); __STORE(anEventArray, t);
+            break;
+
+        case Expose:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(expose:x:y:width:height:count:);
+            goto expose;
+
+        case GraphicsExpose:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(graphicsExpose:x:y:width:height:count:);
+            /* fall into */
+
+        expose:
+            __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(ee->x);
+            __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(ee->y);
+            __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(ee->width);
+            __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(ee->height);
+            __ArrayInstPtr(anEventArray)->a_element[7] = __mkSmallInteger(ee->count);
+            break;
+
+        case NoExpose:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(noExposeView:);
+            break;
+
+        case VisibilityNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(visibilityNotify:state:);
+            switch (ve->state) {
+                case VisibilityUnobscured:
+                    __ArrayInstPtr(anEventArray)->a_element[3] = @symbol(unobscured);
+                    break;
+                case VisibilityPartiallyObscured:
+                    __ArrayInstPtr(anEventArray)->a_element[3] = @symbol(partiallyObscured);
+                    break;
+                case VisibilityFullyObscured:
+                    __ArrayInstPtr(anEventArray)->a_element[3] = @symbol(fullyObscured);
+                    break;
+                default:
+                    __ArrayInstPtr(anEventArray)->a_element[3] = __MKSMALLINT(ve->state);
+                    break;
+            }
+            break;
+
+        case CreateNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(createWindow:x:y:width:height:);
+            __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(cre->x);
+            __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(cre->y);
+            __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(cre->width);
+            __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(cre->height);
+            break;
+
+        case DestroyNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(destroyedView:);
+            break;
+
+        case UnmapNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(unmappedView:);
+            break;
+
+        case MapNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(mappedView:);
+            break;
+
+        case ConfigureNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(configure:x:y:width:height:above:);
+            __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(ce->x);
+            __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(ce->y);
+            __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(ce->width);
+            __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(ce->height);
+            __ArrayInstPtr(anEventArray)->a_element[7] = nil;
+            if (ce->above != None) {
+                __ArrayInstPtr(anEventArray)->a_element[7] = t = __MKEXTERNALADDRESS(ce->above); __STORE(anEventArray, t);
+            }
+            break;
+
+        case GravityNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(gravityNotify:x:y:);
+            __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(gre->x);
+            __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(gre->y);
+            break;
+
+        case ResizeRequest:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(resizeRequest:width:height:);
+            __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(rr->width);
+            __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(rr->height);
+            break;
+
+        case ConfigureRequest:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(configureRequest:x:y:width:height:above:detail:);
+            __ArrayInstPtr(anEventArray)->a_element[3] = __mkSmallInteger(cr->x);
+            __ArrayInstPtr(anEventArray)->a_element[4] = __mkSmallInteger(cr->y);
+            __ArrayInstPtr(anEventArray)->a_element[5] = __mkSmallInteger(cr->width);
+            __ArrayInstPtr(anEventArray)->a_element[6] = __mkSmallInteger(cr->height);
+            __ArrayInstPtr(anEventArray)->a_element[7] = nil;
+            if (cr->above != None) {
+                __ArrayInstPtr(anEventArray)->a_element[7] = t = __MKEXTERNALADDRESS(cr->above); __STORE(anEventArray, t);
+            }
+            switch (cr->detail) {
+                case Above:
+                    __ArrayInstPtr(anEventArray)->a_element[8] = @symbol(above);
+                    break;
+                case Below:
+                    __ArrayInstPtr(anEventArray)->a_element[8] = @symbol(below);
+                    break;
+                case TopIf:
+                    __ArrayInstPtr(anEventArray)->a_element[8] = @symbol(topIf);
+                    break;
+                case BottomIf:
+                    __ArrayInstPtr(anEventArray)->a_element[8] = @symbol(bottomIf);
+                    break;
+                case Opposite:
+                    __ArrayInstPtr(anEventArray)->a_element[8] = @symbol(opposite);
+                    break;
+                default:
+                    __ArrayInstPtr(anEventArray)->a_element[8] = __MKSMALLINT(cr->detail);
+                    break;
+            }
+            break;
+
+        case CirculateNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(circulateNotify:place:);
+            goto circulate;
+
+        case CirculateRequest:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(circulateRequest:place:);
+            /* fall into */
+        circulate:
+            switch (cie->place) {
+                case PlaceOnTop:
+                    __ArrayInstPtr(anEventArray)->a_element[3] = @symbol(placeOnTop);
+                    break;
+                case PlaceOnBottom:
+                    __ArrayInstPtr(anEventArray)->a_element[3] = @symbol(placeOnBottom);
+                    break;
+                default:
+                    __ArrayInstPtr(anEventArray)->a_element[3] = __MKSMALLINT(cie->place);
+                    break;
+            }
+            break;
+
+        case PropertyNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(propertyChange:property:state:time:);
+            __ArrayInstPtr(anEventArray)->a_element[3] = __MKATOMOBJ(pe->atom);
+            switch (pe->state) {
+                case PropertyNewValue:
+                    __ArrayInstPtr(anEventArray)->a_element[4] = @symbol(newValue);
+                    break;
+                case PropertyDelete:
+                    __ArrayInstPtr(anEventArray)->a_element[4] = @symbol(deleted);
+                    break;
+                default:
+                    __ArrayInstPtr(anEventArray)->a_element[4] = __MKSMALLINT(pe->state);
+                    break;
+            }
+            __ArrayInstPtr(anEventArray)->a_element[5] = t = __MKUINT(pe->time); __STORE(anEventArray, t);
+            break;
+
+        case SelectionClear:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(selectionClear:selection:time:);
+            __ArrayInstPtr(anEventArray)->a_element[3] = __MKATOMOBJ(sce->selection);
+            __ArrayInstPtr(anEventArray)->a_element[4] = t = __MKUINT(sce->time);         __STORE(anEventArray, t);
+            break;
+
+        case SelectionRequest:
+            /*
+             * someone wants the selection
+             */
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(selectionRequest:requestor:selection:target:property:time:);
+            __ArrayInstPtr(anEventArray)->a_element[3] = t = __MKEXTERNALADDRESS(ev.xselectionrequest.requestor); __STORE(anEventArray, t);
+            __ArrayInstPtr(anEventArray)->a_element[4] = __MKATOMOBJ(ev.xselectionrequest.selection);
+            __ArrayInstPtr(anEventArray)->a_element[5] = __MKATOMOBJ(ev.xselectionrequest.target);
+            __ArrayInstPtr(anEventArray)->a_element[6] = __MKATOMOBJ(ev.xselectionrequest.property);
+            __ArrayInstPtr(anEventArray)->a_element[7] = t = __MKUINT(ev.xselectionrequest.time);         __STORE(anEventArray, t);
+            break;
+
+        case SelectionNotify:
+            /*
+             * returned selection value (answer from SelectionRequest)
+             */
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(selectionNotify:selection:target:property:requestor:time:);
+            __ArrayInstPtr(anEventArray)->a_element[3] = __MKATOMOBJ(ev.xselection.selection);
+            __ArrayInstPtr(anEventArray)->a_element[4] = __MKATOMOBJ(ev.xselection.target);
+            __ArrayInstPtr(anEventArray)->a_element[5] = __MKATOMOBJ(ev.xselection.property);
+            __ArrayInstPtr(anEventArray)->a_element[6] = t = __MKEXTERNALADDRESS(ev.xselection.requestor); __STORE(anEventArray, t);
+            __ArrayInstPtr(anEventArray)->a_element[7] = t = __MKUINT(ev.xselection.time); __STORE(anEventArray, t);
+            break;
+
+        case ColormapNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(colormapNotify:state:);
+            __ArrayInstPtr(anEventArray)->a_element[3] = cme->state == ColormapInstalled ? true : false;
+            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)))) {
+                    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(terminateView:);
+                    break;
+                }
+                if (ev.xclient.data.l[0] == (int) __AtomVal(__INST(saveYourselfAtom))) {
+                    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(saveAndTerminateView:);
+                    break;
+                }
+            }
+            /*
+             * any other client message
+             */
 printf("clientMessage type:%d format:%d\n", ev.xclient.message_type, ev.xclient.format);
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(clientMessage:type:format:data:);
-	    __ArrayInstPtr(anEventArray)->a_element[3] = __MKATOMOBJ(ev.xclient.message_type);
-	    __ArrayInstPtr(anEventArray)->a_element[4] = __MKSMALLINT(ev.xclient.format);
-	    __ArrayInstPtr(anEventArray)->a_element[5] = t = __MKBYTEARRAY(ev.xclient.data, sizeof(ev.xclient.data)); __STORE(anEventArray, t);
-	    break;
-
-	case MappingNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(mappingNotify:request:event:);
-	    switch(mape->request) {
-		case MappingModifier:
-		    arg = @symbol(mappingModifier);
-		    break;
-		case MappingKeyboard:
-		    arg = @symbol(mappingKeyboard);
-		    break;
-		case MappingPointer:
-		    arg = @symbol(mappingPointer);
-		    break;
-		default:
-		    arg = __MKSMALLINT(mape->request);
-		    break;
-	    }
-	    __ArrayInstPtr(anEventArray)->a_element[3] = arg;
-	    __ArrayInstPtr(anEventArray)->a_element[4] = t = __MKBYTEARRAY(&ev, sizeof(*mape));
-	    __STORE(anEventArray, t);
-	    break;
-
-	case KeymapNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(keymapNotify:);
-	    break;
-
-	case MapRequest:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(mapRequest:);
-	    break;
-
-	case ReparentNotify:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(reparentedView:);
-	    break;
-
-	default:
-	    __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(unknownX11Event);
-	    break;
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(clientMessage:type:format:data:);
+            __ArrayInstPtr(anEventArray)->a_element[3] = __MKATOMOBJ(ev.xclient.message_type);
+            __ArrayInstPtr(anEventArray)->a_element[4] = __MKSMALLINT(ev.xclient.format);
+            __ArrayInstPtr(anEventArray)->a_element[5] = t = __MKBYTEARRAY(ev.xclient.data, sizeof(ev.xclient.data)); __STORE(anEventArray, t);
+            break;
+
+        case MappingNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(mappingNotify:request:event:);
+            switch(mape->request) {
+                case MappingModifier:
+                    arg = @symbol(mappingModifier);
+                    break;
+                case MappingKeyboard:
+                    arg = @symbol(mappingKeyboard);
+                    break;
+                case MappingPointer:
+                    arg = @symbol(mappingPointer);
+                    break;
+                default:
+                    arg = __MKSMALLINT(mape->request);
+                    break;
+            }
+            __ArrayInstPtr(anEventArray)->a_element[3] = arg;
+            __ArrayInstPtr(anEventArray)->a_element[4] = t = __MKBYTEARRAY(&ev, sizeof(*mape));
+            __STORE(anEventArray, t);
+            break;
+
+        case KeymapNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(keymapNotify:);
+            break;
+
+        case MapRequest:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(mapRequest:);
+            break;
+
+        case ReparentNotify:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(reparentedView:);
+            break;
+
+        default:
+            __ArrayInstPtr(anEventArray)->a_element[2] = @symbol(unknownX11Event);
+            break;
     }
 #undef ae
 #undef ee
@@ -8577,10 +8583,23 @@
 !
 
 reinitialize
-
+    preWaitAction notNil ifTrue:[
+        Processor removePreWaitAction:preWaitAction.
+        preWaitAction := nil.
+    ].
     virtualRootId := rootId := nil.
+    selectionFetchers := nil.
     super reinitialize.
     dispatchingExpose := nil
+!
+
+releaseDeviceResources
+    preWaitAction notNil ifTrue:[
+        Processor removePreWaitAction:preWaitAction.
+        preWaitAction := nil.
+    ].
+    selectionFetchers := nil.
+    super releaseDeviceResources.
 ! !
 
 !XWorkstation methodsFor:'keyboard mapping'!
@@ -9256,6 +9275,33 @@
     "
 ! !
 
+!XWorkstation methodsFor:'private'!
+
+findSelectionFetcher:aDrawableId
+
+    selectionFetchers isNil ifTrue:[
+        ^ nil.
+    ].
+
+    ^ selectionFetchers detect:[:eachFetcher| 
+            eachFetcher matchesDrawableId:aDrawableId
+    ] ifNone:[].
+!
+
+registerSelectionFetcher:aSelectionFetcher
+
+    selectionFetchers isNil ifTrue:[
+        selectionFetchers := OrderedCollection new.
+    ].
+
+    selectionFetchers add:aSelectionFetcher.
+!
+
+unregisterSelectionFetcher:aSelectionFetcher
+
+    selectionFetchers remove:aSelectionFetcher.
+! !
+
 !XWorkstation methodsFor:'properties'!
 
 deleteProperty:propertyID for:aWindowID
@@ -9291,44 +9337,23 @@
     self primitiveFailedOrClosedConnection.
 !
 
-getObjectProperty:propertyID from:aWindowID
-    "get an object property from the server; return object or nil"
-
-    self
-	getProperty:propertyID
-	from:aWindowID
-	delete:true
-	into:
-	    [:type :value |
-		type == stringAtom ifTrue:[
-		    ^ value
-		].
-		(value isMemberOf:ByteArray) ifTrue:[
-		    ^ (Object readBinaryFrom:(ReadStream on:value) onError:[nil])
-		]
-	    ].
-    ^ nil
-
-    "Modified: 6.4.1997 / 13:27:07 / cg"
-!
-
-getProperty:propertySymbolOrAtomID from:aWindowOrWindowIDOrNil delete:doDelete into:aTwoArgBlock
-    "get a property, evaluate aTwoArgBlock with typeID and value"
+getProperty:propertySymbolOrAtomID from:aWindowOrWindowIDOrNil delete:doDelete
+    "get a property as an association propertyType->propertyValue"
 
     <context: #return>
 
     |val typeID propertyID windowID|
 
     propertySymbolOrAtomID isString ifTrue:[
-	propertyID := self atomIDOf:propertySymbolOrAtomID create:false.
-	propertyID isNil ifTrue:[^ false].
+        propertyID := self atomIDOf:propertySymbolOrAtomID create:false.
+        propertyID isNil ifTrue:[^ nil].
     ] ifFalse:[
-	propertyID := propertySymbolOrAtomID.
+        propertyID := propertySymbolOrAtomID.
     ].
     aWindowOrWindowIDOrNil isView ifTrue:[
-	windowID := aWindowOrWindowIDOrNil id.
+        windowID := aWindowOrWindowIDOrNil id.
     ] ifFalse:[
-	windowID := aWindowOrWindowIDOrNil.
+        windowID := aWindowOrWindowIDOrNil.
     ].
 
 %{
@@ -9343,170 +9368,87 @@
 #   define PROP_SIZE    2048
 
     if (ISCONNECTED) {
-	Display *dpy = myDpy;
-
-	if (__isAtomID(propertyID)) {
-	    property = __AtomVal(propertyID);
-
-	    if (__isExternalAddress(windowID)) {
-		window = __WindowVal(windowID);
-	    } else if (windowID == nil) {
-		window = DefaultRootWindow(dpy);
-	    } else
-		goto fail;
-
-	    nread = 0;
-	    cp = 0;
+        Display *dpy = myDpy;
+
+        if (__isAtomID(propertyID)) {
+            property = __AtomVal(propertyID);
+
+            if (__isExternalAddress(windowID)) {
+                window = __WindowVal(windowID);
+            } else if (windowID == nil) {
+                window = DefaultRootWindow(dpy);
+            } else
+                goto fail;
+
+            nread = 0;
+            cp = 0;
 #ifdef PROPERTY_DEBUG
-	    fprintf(stderr, "getProperty %x\n", property);
-#endif
-
-	    do {
-		int retVal;
-
-		ENTER_XLIB();
-		retVal = XGetWindowProperty(dpy, window, property, nread/4, PROP_SIZE,
-					    doDelete == true,
-					    AnyPropertyType, &actual_type, &actual_format,
-					    &nitems, &bytes_after, (unsigned char **)&data);
-		LEAVE_XLIB();
-		if (retVal != Success) {
+            fprintf(stderr, "getProperty %x\n", property);
+#endif
+
+            do {
+                int retVal;
+
+                ENTER_XLIB();
+                retVal = XGetWindowProperty(dpy, window, property, nread/4, PROP_SIZE,
+                                            doDelete == true,
+                                            AnyPropertyType, &actual_type, &actual_format,
+                                            &nitems, &bytes_after, (unsigned char **)&data);
+                LEAVE_XLIB();
+                if (retVal != Success) {
 #ifdef PROPERTY_DEBUG
-		    fprintf(stderr, "- no success\n");
-#endif
-		    ok = 0;
-		    break;
-		}
+                    fprintf(stderr, "- no success\n");
+#endif
+                    ok = 0;
+                    break;
+                }
 #ifdef PROPERTY_DEBUG
-		fprintf(stderr, "- type:%x\n", actual_type);
-#endif
-		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) {
-		    XFree(data);
-		    goto fail;
-		}
-
-		nread += nitems;
-		bcopy(data, cp2, nitems);
-		XFree(data);
+                fprintf(stderr, "- type:%x\n", actual_type);
+#endif
+                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) {
+                    XFree(data);
+                    goto fail;
+                }
+
+                nread += nitems;
+                bcopy(data, cp2, nitems);
+                XFree(data);
 #ifdef PROPERTY_DEBUG
-		fprintf(stderr, "- <nitems:%d bytes_after:%d>\n", nitems, bytes_after);
-#endif
-	    } while (bytes_after > 0);
-
-	    if (ok) {
-		if (actual_type == XA_STRING) {
-		    cp[nread] = '\0';
-		    val = __MKSTRING_L(cp, nread);
-		} else {
-		    val = __MKBYTEARRAY(cp, nread);
-		}
-	    }
-	    if (cp)
-		free(cp);
-	}
+                fprintf(stderr, "- <nitems:%d bytes_after:%d>\n", nitems, bytes_after);
+#endif
+            } while (bytes_after > 0);
+
+            if (ok) {
+                if (actual_type == XA_STRING) {
+                    cp[nread] = '\0';
+                    val = __MKSTRING_L(cp, nread);
+                } else {
+                    val = __MKBYTEARRAY(cp, nread);
+                }
+            }
+            if (cp)
+                free(cp);
+        }
     }
 fail: ;
 %}.
     typeID isNil ifTrue:[
-	^ false
-    ].
-    aTwoArgBlock value:typeID value:val.
-    ^ true
+        ^ nil
+    ].
+    ^ typeID->val
 
     "
      Display
-	getProperty:#'_DESKTOP_COLORS'
-	from:nil
-	delete:false
-	into:[:a :b | self halt]
-    "
-!
-
-getProperty:propertyID type:targetID from:aWindowID
-    | value |
-
-    targetID == (self atomIDOf:#'ST_OBJECT') ifTrue:[
-	"an object"
-	^ self getObjectProperty:propertyID from:aWindowID.
-    ].
-
-    (targetID == stringAtom
-    or:[ targetID == (self atomIDOf:#'UTF8_STRING')
-    or:[ targetID == (self atomIDOf:#'COMPOUND_TEXT')
-    or:[ targetID == (self atomIDOf:#'TEXT') ]]]) ifTrue:[
-	"some kind of string"
-	value := self getTextProperty:propertyID from:aWindowID.
-	value notNil ifTrue:[
-	    (value endsWith:Character cr) ifTrue:[
-		value := value asStringCollection copyWith:''
-	    ]
-	].
-	^ value.
-    ].
-
-    'XWorkstation [info]: unhandled targetType: ' infoPrint.
-    (self atomName:targetID) infoPrintCR.
-    ^ nil.
-!
-
-getTextProperty:propertyID from:aWindowID
-    "get a text property; return string or nil"
-
-    self
-	getProperty:propertyID
-	from:aWindowID
-	delete:true
-	into:
-	    [:type :value |
-		|stringClass|
-
-		type == stringAtom ifTrue:[
-		    clipBoardEncoding notNil ifTrue:[
-			^ value decodeFrom:clipBoardEncoding
-		    ].
-		    ^ value
-		].
-
-		type == (self atomIDOf:#'UTF8_STRING') ifTrue:[
-"/ Transcript show:'UTF8: '; showCR:value storeString.
-		    ^ CharacterArray fromUTF8Bytes:value
-		].
-
-		type == (self atomIDOf:#'TEXT') ifTrue:[
-"/ Transcript show:'TEXT: '; showCR:value storeString.
-		    ^ value asString
-		].
-
-		type == (self atomIDOf:#'COMPOUND_TEXT') ifTrue:[
-"/ Transcript show:'COMPOUND_TEXT: '; showCR:value storeString.
-		    ^ value asString
-		].
-
-		type == (self atomIDOf:#INCR) ifTrue:[
-		    'XWorkstation: unimplemented property type: INCR value: ' infoPrint.
-		    value storeString infoPrintCR.
-		    ^ nil
-		].
-
-		'XWorkstation: unimplemented property type: ' infoPrint. type infoPrint.
-		' ' infoPrint. (self atomName:type) infoPrint.
-		' value:' infoPrint. value infoPrintCR.
-		^ nil
-	    ].
-    ^ nil
-
-    "Modified: 30.6.1997 / 20:54:59 / cg"
-
-    "
-     Display getTextProperty:#'_KDE_GENERAL' from:nil.
-     Display getTextProperty:#'_DESKTOP_FONTS' from:nil.
+        getProperty:#'_NET_WM_ICON_GEOMETRY'
+        from:nil
+        delete:false
     "
 !
 
@@ -9519,9 +9461,9 @@
     |windowID atoms|
 
     aWindowOrWindowIDOrNil isView ifTrue:[
-	windowID := aWindowOrWindowIDOrNil id.
+        windowID := aWindowOrWindowIDOrNil id.
     ] ifFalse:[
-	windowID := aWindowOrWindowIDOrNil.
+        windowID := aWindowOrWindowIDOrNil.
     ].
 
 %{
@@ -9530,41 +9472,41 @@
     int i;
 
     if (ISCONNECTED) {
-	Display *dpy = myDpy;
-	int numProps = 0;
-
-	if (__isExternalAddress(windowID)) {
-	    window = __WindowVal(windowID);
-	} else if (windowID == nil) {
-	    window = DefaultRootWindow(dpy);
-	} else if (__isInteger(windowID)) {
-	    window = (Window)__unsignedLongIntVal(windowID);
-	} else {
-	    goto fail;
-	}
-
-	ENTER_XLIB();
-	atomListPtr = XListProperties(dpy, window, &numProps);
-	LEAVE_XLIB();
-
-	if (atomListPtr == NULL) {
-	    RETURN (nil);
-	}
-
-	atoms = __ARRAY_NEW_INT(numProps);
-
-	if (atoms == nil) {
-	    goto fail;
-	}
-
-	for (i=0; i<numProps; i++) {
-	    OBJ atm;
-
-	    atm = __MKATOMOBJ(atomListPtr[i]);
-	    __ArrayInstPtr(atoms)->a_element[i] = atm; __STORE(atoms, atm);
-	}
-	XFree(atomListPtr);
-	RETURN (atoms);
+        Display *dpy = myDpy;
+        int numProps = 0;
+
+        if (__isExternalAddress(windowID)) {
+            window = __WindowVal(windowID);
+        } else if (windowID == nil) {
+            window = DefaultRootWindow(dpy);
+        } else if (__isInteger(windowID)) {
+            window = (Window)__unsignedLongIntVal(windowID);
+        } else {
+            goto fail;
+        }
+
+        ENTER_XLIB();
+        atomListPtr = XListProperties(dpy, window, &numProps);
+        LEAVE_XLIB();
+
+        if (atomListPtr == NULL) {
+            RETURN (nil);
+        }
+
+        atoms = __ARRAY_NEW_INT(numProps);
+
+        if (atoms == nil) {
+            goto fail;
+        }
+
+        for (i=0; i<numProps; i++) {
+            OBJ atm;
+
+            atm = __MKATOMOBJ(atomListPtr[i]);
+            __ArrayInstPtr(atoms)->a_element[i] = atm; __STORE(atoms, atm);
+        }
+        XFree(atomListPtr);
+        RETURN (atoms);
     }
 fail: ;
 %}.
@@ -9572,15 +9514,16 @@
 
     "
      Display propertiesOf:nil
+     Display propertiesOf:Transcript view id
     "
     "
      (Display propertiesOf:nil) do:[:atm |
-	|v|
-
-	Transcript show:(atm printStringLeftPaddedTo:5).
-	Transcript show:' '.
-	Display getProperty:atm from:nil delete:false into:[:type :val | v := type->val].
-	Transcript showCR:v.
+        |v|
+
+        Transcript show:((Display atomName:atm) printStringLeftPaddedTo:5).
+        Transcript show:': '.
+        Display getProperty:atm from:nil delete:false into:[:type :val | v := (Display atomName:type)->val].
+        Transcript showCR:v.
      ]
     "
 !
@@ -9596,61 +9539,59 @@
 
 %{  /* UNLIMITEDSTACK */
     if (ISCONNECTED && __isAtomID(propertyID) && __isAtomID(typeID)) {
-	Display *dpy = myDpy;
-	Atom prop, type;
-	Window window;
-
-	prop = __AtomVal(propertyID);
-	type = __AtomVal(typeID);
-
-	if (__isExternalAddress(aWindowID)) {
-	    window = __WindowVal(aWindowID);
-	} else if (aWindowID == nil) {
-	    window = DefaultRootWindow(dpy);
-	} else if (__isInteger(aWindowID)) {
-	    window = (Window)__unsignedLongIntVal(aWindowID);
-	} else {
-	    RETURN(false);
-	}
-
-	retval = true;
-
-	ENTER_XLIB();
-	if (__isSmallInteger(anObject)) {
-	    unsigned INT value = __intVal(anObject);
-	    XChangeProperty(dpy, window, prop, type, 32,
-			    PropModeReplace,
-			    (unsigned char *)&value, 1);
-	} else if (__isByteArray(anObject)) {
-	    XChangeProperty(dpy, window, prop, type, 8,
-			    PropModeReplace,
-			    __byteArrayVal(anObject),
-			    __byteArraySize(anObject));
-	} else if (__isWords(anObject)) {
-	    /* wordArray-like (16bit-string) object */
-	    XChangeProperty(dpy, window, prop, type, 16,
-			    PropModeReplace,
-			    __stringVal(anObject),
-			    __wordArraySize(anObject));
-#ifdef __integerArrayVal
-	} else if (__isIntegerArray(anObject)) {
-	    /* array of atoms */
-	    XChangeProperty(dpy, window, prop, type, 32,
-			    PropModeReplace,
-			    (char *)__integerArrayVal(anObject),
-			    __integerArraySize(anObject));
-#endif
-	} else if (__isString(anObject) || __isSymbol(anObject)) {
-	    XChangeProperty(dpy, window, prop, type, 8,
-			    PropModeReplace,
-			    __stringVal(anObject),
-			    __stringSize(anObject));
-	} else {
-	    retval = false;
-	}
-	LEAVE_XLIB();
-
-	DPRINTF(("changeProp win=%x prop=%x type=%x\n", window, prop, type));
+        Display *dpy = myDpy;
+        Atom prop, type;
+        Window window;
+
+        prop = __AtomVal(propertyID);
+        type = __AtomVal(typeID);
+
+        if (__isExternalAddress(aWindowID)) {
+            window = __WindowVal(aWindowID);
+        } else if (aWindowID == nil) {
+            window = DefaultRootWindow(dpy);
+        } else if (__isInteger(aWindowID)) {
+            window = (Window)__unsignedLongIntVal(aWindowID);
+        } else {
+            RETURN(false);
+        }
+
+        retval = true;
+
+        ENTER_XLIB();
+        if (__isInteger(anObject)) {
+            unsigned INT value = __longIntVal(anObject);
+            XChangeProperty(dpy, window, prop, type, 32,
+                            PropModeReplace,
+                            (unsigned char *)&value, 1);
+        } else if (__isByteArray(anObject)) {
+            XChangeProperty(dpy, window, prop, type, 8,
+                            PropModeReplace,
+                            __byteArrayVal(anObject),
+                            __byteArraySize(anObject));
+        } else if (__isWords(anObject)) {
+            /* wordArray-like (16bit-string) object */
+            XChangeProperty(dpy, window, prop, type, 16,
+                            PropModeReplace,
+                            __stringVal(anObject),
+                            __wordArraySize(anObject));
+        } else if (__isIntegerArray(anObject)) {
+            /* array of atoms */
+            XChangeProperty(dpy, window, prop, type, 32,
+                            PropModeReplace,
+                            (char *)__integerArrayVal(anObject),
+                            __integerArraySize(anObject));
+        } else if (__isStringLike(anObject)) {
+            XChangeProperty(dpy, window, prop, type, 8,
+                            PropModeReplace,
+                            __stringVal(anObject),
+                            __stringSize(anObject));
+        } else {
+            retval = false;
+        }
+        LEAVE_XLIB();
+
+        DPRINTF(("changeProp win=%x prop=%x type=%x\n", window, prop, type));
     }
 %}.
     ^ retval
@@ -10026,18 +9967,11 @@
     ^ false
 ! !
 
-!XWorkstation methodsFor:'selections'!
-
-addSelectionHandler:aHandler
-    SelectionHandlers isNil ifTrue:[
-	SelectionHandlers := IdentitySet new.
-    ].
-    SelectionHandlers add:aHandler
-!
+!XWorkstation methodsFor:'selection fetching'!
 
 getSelectionFor:drawableId
-    "get the object selection - either immediate, or asynchronous.
-     Returns nil, if async request is on its way.
+    "get the object selection.
+     Returns nil, if no selection is available.
 
      Smalltalk puts ST_OBJECT only into the CLIPBOARD"
 
@@ -10045,69 +9979,58 @@
 
     selectionOwnerWindowId := self getSelectionOwnerOf:clipboardAtom.
     selectionOwnerWindowId isNil ifTrue:[
-	^ nil       "no selection"
+        ^ nil       "no selection"
     ].
     selectionOwnerWindowId == selectionOwner ifTrue:[
-	"I still hold the selection, so return my locally buffered data"
-	^ copyBuffer
-    ].
-
-    self
-	requestSelection:clipboardAtom
-	property:(self atomIDOf:#'ST_SELECTION')
-	type:(self atomIDOf:#'ST_OBJECT')
-	for:drawableId.
-    ^ nil
-
-    "Modified: / 17.6.1998 / 17:11:15 / cg"
+        "I still hold the selection, so return my locally buffered data"
+        ^ copyBuffer
+    ].
+
+    ^ SelectionFetcher 
+        requestSelection:clipboardAtom 
+        type:(self atomIDOf:#'ST_OBJECT') 
+        onDevice:self for:drawableId.
+
+
+     "
+       Display getSelectionFor:Transcript id
+     "
 !
 
 getTextSelection:selectionBufferSymbol for:drawableId
-    "get the text selection -  either immediate, or asynchronous.
-     Returns nil, if async request is on its way
-     or if no selection is available"
+    "get the text selection.
+     Returns nil, if no selection is available"
 
     |selectionId selectionOwnerWindowId|
 
     selectionBufferSymbol == #selection ifTrue:[
-	selectionId := primaryAtom.
+        selectionId := primaryAtom.
     ] ifFalse:[
-	selectionId := clipboardAtom.
+        selectionId := clipboardAtom.
     ].
 
     selectionOwnerWindowId := self getSelectionOwnerOf:selectionId.
     selectionOwnerWindowId isNil ifTrue:[
-	^ nil       "no selection"
+        ^ nil       "no selection"
     ].
 
     selectionOwnerWindowId == selectionOwner ifTrue:[
-	"I still hold the selection, so return my locally buffered data"
-	^ self selectionAsString.
-    ].
-
-    self
-	requestSelection:selectionId
-	property:(self atomIDOf:#'VT_SELECTION')
-	type:(self atomIDOf:#'UTF8_STRING')
-	for:drawableId.
-
-"/    self
-"/        requestSelection:selectionId
-"/        property:(self atomIDOf:#'VT_SELECTION')
-"/        type:stringAtom
-"/        for:drawableId.
-
-    ^ nil.
-!
-
-removeSelectionHandler:aHandler
-    SelectionHandlers notNil ifTrue:[
-	SelectionHandlers remove:aHandler ifAbsent:nil.
-	SelectionHandlers isEmpty ifTrue:[
-	    SelectionHandlers := nil
-	]
-    ].
-!
+        "I still hold the selection, so return my locally buffered data"
+        ^ self selectionAsString.
+    ].
+
+    ^ SelectionFetcher 
+        requestSelection:selectionId 
+        type:(self atomIDOf:#'UTF8_STRING') 
+        onDevice:self for:drawableId.
+
+     "
+       Display getTextSelection:#clipboard for:Transcript id
+       Display getTextSelection:#selection for:Transcript id
+     "
+! !
+
+!XWorkstation methodsFor:'selection sending'!
 
 selectionAs:aTargetAtom
     "convert the current selection to the format defined by aTargetAtom.
@@ -10116,66 +10039,51 @@
     |stream|
 
     (aTargetAtom == (self atomIDOf:#STRING)) ifTrue:[
-	"the other view wants the selection as string"
-	^ self selectionAsString.
+        "the other view wants the selection as string"
+        ^ self selectionAsString.
+    ].
+
+    (aTargetAtom == (self atomIDOf:#UTF8_STRING)) ifTrue:[
+        "the other view wants the selection as utf8 string"
+        ^ self selectionAsString utf8Encoded.
+    ].
+
+    (aTargetAtom == (self atomIDOf:#TIMESTAMP)) ifTrue:[
+        "the other view wants to know when we acquired ownership of the selection"
+        ^ selectionTime.
     ].
 
     (aTargetAtom == (self atomIDOf:#TARGETS)) ifTrue:[
-	"the other view wants to know which targets we support"
-	^ self supportedTargetAtoms.
+        "the other view wants to know which targets we support"
+        ^ self supportedTargetAtoms.
     ].
 
     (aTargetAtom == (self atomIDOf:#'ST_OBJECT')) ifTrue:[
-	"send the selection in binaryStore format"
-	stream := WriteStream on:(ByteArray new:200).
-	self getCopyBuffer storeBinaryOn:stream.
-	^ stream contents.
+        "send the selection in binaryStore format"
+        stream := WriteStream on:(ByteArray new:200).
+        self getCopyBuffer storeBinaryOn:stream.
+        ^ stream contents.
     ].
 
     aTargetAtom == (self atomIDOf:#LENGTH) ifTrue:[
-	"the other one wants to know the size of our selection.
-	 LENGTH is deprecated, since we do not know how the selection is
-	 going to be converted. The client must not rely on the length returned"
-
-	^ self selectionAsString size
+        "the other one wants to know the size of our selection.
+         LENGTH is deprecated, since we do not know how the selection is
+         going to be converted. The client must not rely on the length returned"
+
+        ^ self selectionAsString size
     ].
 
     "we do not support the requestet target"
     ^ nil.
 !
 
-sendSelection:something selection:selectionID property:propertyID target:targetID time:t from:windowID to:requestorID
-    "send the selection back from a SelectionRequest"
-
-    |property|
-
-    property := propertyID.
-    property == 0 ifTrue:[
-	"Support old (obsolete) clients requesting a None property.
-	 Set the propertyID to the targetID"
-
-	property := targetID.
-    ].
-
-    self setProperty:property
-	 type:targetID
-	 value:something
-	 for:requestorID.
-
-    self sendSelectionNotifySelection:selectionID
-	 property:property
-	 target:targetID
-	 time:t
-	 from:windowID
-	 to:requestorID.
-!
-
 setSelection:anObject owner:aWindowId
     "set the object selection, and make aWindowId be the owner.
      This can be used by other Smalltalk(X) applications only.
      We set only the CLIPBOARD selection"
 
-    ^ self setSelectionOwner:aWindowId of:clipboardAtom
+    selectionTime := lastEventTime.
+    ^ self setSelectionOwner:aWindowId of:clipboardAtom time:selectionTime
 !
 
 setTextSelection:aString owner:aWindowId
@@ -10185,10 +10093,12 @@
      We set both the PRIMARY and CLIPBOARD, so that you can paste
      into xterm."
 
-    (self setSelectionOwner:aWindowId of:clipboardAtom) ifFalse:[
-	'XWorkstation [warning]: selection ownerchange failed' errorPrintCR.
-    ].
-    self setSelectionOwner:aWindowId of:primaryAtom.
+    selectionTime := lastEventTime.
+
+    (self setSelectionOwner:aWindowId of:clipboardAtom time:selectionTime) ifFalse:[
+        'XWorkstation [warning]: selection ownerchange failed' errorPrintCR.
+    ].
+    self setSelectionOwner:aWindowId of:primaryAtom time:selectionTime.
     ^ true
 
     "Modified: / 17.6.1998 / 19:48:54 / cg"
@@ -10200,11 +10110,11 @@
 
     |supportedTargets numericTargetArray|
 
-    supportedTargets := #(ST_OBJECT STRING TARGETS LENGTH).
+    supportedTargets := #(ST_OBJECT STRING UTF8_STRING TARGETS TIMESTAMP LENGTH).
 
     numericTargetArray := IntegerArray new:supportedTargets size.
     supportedTargets keysAndValuesDo:[:index :targetSymbol|
-	numericTargetArray at:index put:(self atomIDOf:targetSymbol)
+        numericTargetArray at:index put:(self atomIDOf:targetSymbol)
     ].
 
     ^ numericTargetArray
@@ -10248,31 +10158,45 @@
 
     <context:#return>
 
-%{
-    Atom sel_prop;
-    char *cp;
-
-    if ((__isExternalAddress(aWindowId) || (aWindowId == nil))
-     && ISCONNECTED
+    |anIntegerTimestamp|
+
+    anIntegerTimestamp := lastEventTime.
+
+%{
+
+    if (ISCONNECTED
      && __isAtomID(typeID)
      && __isAtomID(propertyID)
      && __isAtomID(selectionID)) {
-	Display *dpy = myDpy;
-	Window w;
-	Window selectionOwner;
-
-	if (__isExternalAddress(aWindowId)) {
-	    w = __WindowVal(aWindowId);
-	} else {
-	    w = (Window)0;
-	}
-
-	ENTER_XLIB();
-	XConvertSelection(dpy, __AtomVal(selectionID), __AtomVal(typeID),
-			       __AtomVal(propertyID), w, CurrentTime);
-	LEAVE_XLIB();
-
-	RETURN (true);
+        Display *dpy = myDpy;
+        Window w;
+        Time time;
+
+        if (__isExternalAddress(aWindowId)) {
+            w = __WindowVal(aWindowId);
+        } else if (aWindowId == nil) {
+            w = (Window)0;
+        } else
+            goto err;
+
+        if (anIntegerTimestamp == nil) {
+            /* 
+             * the ICCCM convention says: you should set the time to the time when
+             * the selection was requested and not to CurrentTime
+             */
+            time = CurrentTime;
+        } else if (__isInteger(anIntegerTimestamp)) {
+            time = __unsignedLongIntVal(anIntegerTimestamp);
+        } else 
+            goto err;
+
+        ENTER_XLIB();
+        XConvertSelection(dpy, __AtomVal(selectionID), __AtomVal(typeID),
+                               __AtomVal(propertyID), w, time);
+        LEAVE_XLIB();
+
+        RETURN (true);
+err:;
     }
 %}.
     self primitiveFailedOrClosedConnection.
@@ -10280,101 +10204,92 @@
 
     "
      Display
-	requestSelection:(Display atomIDOf:'PRIMARY')
-	property:(Display atomIDOf:'VT_SELECTION')
-	type:(Display atomIDOf:'STRING')
-	for:Transcript id
+        requestSelection:(Display atomIDOf:'PRIMARY')
+        property:(Display atomIDOf:'VT_SELECTION')
+        type:(Display atomIDOf:'STRING')
+        for:Transcript id
     "
     "
      Display
-	requestSelection:(Display atomIDOf:'PRIMARY')
-	property:(Display atomIDOf:'VT_SELECTION')
-	type:(Display atomIDOf:'C_STRING')
-	for:Transcript id
-    "
-!
-
-sendSelectionNotifySelection:selectionID property:propertyID target:targetID time:t from:windowID to:requestorID
+        requestSelection:(Display atomIDOf:'PRIMARY')
+        property:(Display atomIDOf:'VT_SELECTION')
+        type:(Display atomIDOf:'C_STRING')
+        for:Transcript id
+    "
+!
+
+sendSelectionNotifySelection:selectionID property:propertyID target:targetID time:t to:requestorID
     "send a selectionNotify back from a SelectionRequest"
 
     <context: #return>
 %{
     if (ISCONNECTED
-	&& (__isAtomID(propertyID) || propertyID == nil)
-	&& __isAtomID(targetID) && __isAtomID(selectionID)) {
-	Display *dpy = myDpy;
-	XEvent ev;
-	Window requestor, originator;
-	Status result;
-
-	if (__isExternalAddress(requestorID)) {
-	    requestor = __WindowVal(requestorID);
-	} else if (__isSmallInteger(requestorID)) {
-	    requestor = (Window)__smallIntegerVal(requestorID);
-	} else if (requestorID == nil) {
-	    requestor = DefaultRootWindow(dpy);
-	} else {
-	    requestor = (Window)__unsignedLongIntVal(requestorID);
-	}
-	if (__isExternalAddress(windowID)) {
-	    originator = __WindowVal(windowID);
-	} else if (__isSmallInteger(windowID)) {
-	    originator = (Window)__smallIntegerVal(windowID);
-	} else if (windowID == nil) {
-	    originator = DefaultRootWindow(dpy);
-	} else {
-	    originator = (Window)__unsignedLongIntVal(windowID);
-	}
-
-	ev.xselection.type = SelectionNotify;
-	ev.xselection.display = dpy;
-	ev.xselection.selection = __AtomVal(selectionID);
-	ev.xselection.target = __AtomVal(targetID);
-	ev.xselection.requestor = originator;
-
-	if (__isExternalAddress(t)) {
-	    ev.xselection.time = (INT)(__externalAddressVal(t));
-	} else if (__isSmallInteger(t)) {
-	    ev.xselection.time = __smallIntegerVal(t);
-	} else if (t == nil) {
-	    ev.xselection.time = CurrentTime;
-	} else {
-	    ev.xselection.time = (INT)__unsignedLongIntVal(t);
-	}
+        && (__isAtomID(propertyID) || propertyID == nil)
+        && __isAtomID(targetID) && __isAtomID(selectionID)) {
+        Display *dpy = myDpy;
+        XEvent ev;
+        Window requestor;
+        Status result;
+
+        if (__isExternalAddress(requestorID)) {
+            requestor = __WindowVal(requestorID);
+        } else if (__isSmallInteger(requestorID)) {
+            requestor = (Window)__smallIntegerVal(requestorID);
+        } else if (requestorID == nil) {
+            requestor = DefaultRootWindow(dpy);
+        } else {
+            requestor = (Window)__unsignedLongIntVal(requestorID);
+        }
+
+        ev.xselection.type = SelectionNotify;
+        ev.xselection.display = dpy;
+        ev.xselection.selection = __AtomVal(selectionID);
+        ev.xselection.target = __AtomVal(targetID);
+        ev.xselection.requestor = requestor;
+
+        if (__isExternalAddress(t)) {
+            ev.xselection.time = (INT)(__externalAddressVal(t));
+        } else if (__isSmallInteger(t)) {
+            ev.xselection.time = __smallIntegerVal(t);
+        } else if (t == nil) {
+            ev.xselection.time = CurrentTime;
+        } else {
+            ev.xselection.time = (INT)__unsignedLongIntVal(t);
+        }
 #if 0
-	printf("ev.xselection.selection: %x\n", ev.xselection.selection);
-	printf("ev.xselection.target: %x\n", ev.xselection.target);
-	printf("ev.xselection.requestor: %x\n", ev.xselection.requestor);
-	printf("ev.xselection.time: %x\n", ev.xselection.time);
-	printf("requestor: %x\n", requestor);
-#endif
-
-	/* send nil property if selection cannot be converted */
-	if (propertyID == nil)
-	    ev.xselection.property = None;
-	else
-	    ev.xselection.property = __AtomVal(propertyID);
-
-
-	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));
-
-	ENTER_XLIB();
-	result = XSendEvent(dpy, requestor, False, 0 , &ev);
-	LEAVE_XLIB();
-
-	if ((result == BadValue) || (result == BadWindow)) {
-	    DPRINTF(("bad status\n"));
-	    RETURN (false);
-	}
-	ENTER_XLIB();
-	XFlush(dpy);
-	LEAVE_XLIB();
-	RETURN (true)
+        printf("ev.xselection.selection: %x\n", ev.xselection.selection);
+        printf("ev.xselection.target: %x\n", ev.xselection.target);
+        printf("ev.xselection.requestor: %x\n", ev.xselection.requestor);
+        printf("ev.xselection.time: %x\n", ev.xselection.time);
+        printf("requestor: %x\n", requestor);
+#endif
+
+        /* send nil property if selection cannot be converted */
+        if (propertyID == nil)
+            ev.xselection.property = None;
+        else
+            ev.xselection.property = __AtomVal(propertyID);
+
+
+        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));
+
+        ENTER_XLIB();
+        result = XSendEvent(dpy, requestor, False, 0 , &ev);
+        LEAVE_XLIB();
+
+        if ((result == BadValue) || (result == BadWindow)) {
+            DPRINTF(("bad status\n"));
+            RETURN (false);
+        }
+        ENTER_XLIB();
+        XFlush(dpy);
+        LEAVE_XLIB();
+        RETURN (true)
     }
 %}.
     self primitiveFailedOrClosedConnection.
@@ -10383,7 +10298,7 @@
     "Modified: / 17.6.1998 / 20:23:20 / cg"
 !
 
-setSelectionOwner:aWindowId of:selectionAtomSymbolOrID
+setSelectionOwner:aWindowId of:selectionAtomSymbolOrID time:anIntegerTimestamp
     "set the owner of a selection; return false if failed"
 
     <context: #return>
@@ -10397,9 +10312,9 @@
     selectionOwner := aWindowId.
 
     selectionAtomSymbolOrID isString ifTrue:[
-	selectionAtomID := self atomIDOf:selectionAtomSymbolOrID create:false.
+        selectionAtomID := self atomIDOf:selectionAtomSymbolOrID create:false.
     ] ifFalse:[
-	selectionAtomID := selectionAtomSymbolOrID.
+        selectionAtomID := selectionAtomSymbolOrID.
     ].
 
 %{
@@ -10408,20 +10323,34 @@
     if (__isExternalAddress(aWindowId)
      && __isAtomID(selectionAtomID)
      && ISCONNECTED) {
-	Display *dpy = myDpy;
-	Window owner;
-
-	win = __WindowVal(aWindowId);
-	DPRINTF(("setOwner prop=%x win=%x\n", __AtomVal(selectionAtomID), win));
-	ENTER_XLIB();
-	XSetSelectionOwner(dpy, __AtomVal(selectionAtomID), win, CurrentTime);
-	owner = XGetSelectionOwner(dpy, __AtomVal(selectionAtomID));
-	LEAVE_XLIB();
-	if (owner != win) {
-	    RETURN (false);
-	}
-	RETURN (true);
-    }
+        Display *dpy = myDpy;
+        Window owner;
+        Time time;
+
+        win = __WindowVal(aWindowId);
+
+        if (anIntegerTimestamp == nil) {
+            /* 
+             * the ICCCM convention says: you should set the time to the time when
+             * the selection was acquired and not to CurrentTime
+             */
+            time = CurrentTime;
+        } else if (__isInteger(anIntegerTimestamp)) {
+            time = __unsignedLongIntVal(anIntegerTimestamp);
+        } else 
+            goto err;
+
+        DPRINTF(("setOwner prop=%x win=%x\n", __AtomVal(selectionAtomID), win));
+        ENTER_XLIB();
+        XSetSelectionOwner(dpy, __AtomVal(selectionAtomID), win, time);
+        owner = XGetSelectionOwner(dpy, __AtomVal(selectionAtomID));
+        LEAVE_XLIB();
+        if (owner != win) {
+            RETURN (false);
+        }
+        RETURN (true);
+    }
+err:;
 %}.
     self primitiveFailedOrClosedConnection.
     ^ false
@@ -11566,10 +11495,201 @@
     ^ false "/ or true or what ?
 ! !
 
+!XWorkstation::SelectionFetcher class methodsFor:'documentation'!
+
+documentation
+"
+    This class is responsible for fetching the clipboard.
+    The X11 clipboard is implemented via asynchonous messages.
+
+    For each fetch operation an instance of this class is created.
+    The asynchronous messages are queued and executed in the
+    process that requests the clipboard.
+
+    [author:]
+        Stefan Vogel (stefan@zwerg)
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+
+"
+! !
+
+!XWorkstation::SelectionFetcher class methodsFor:'selections'!
+
+requestSelection:selectionId type:aTargetId onDevice:aDisplay for:aDrawableId
+    ^ self new requestSelection:selectionId type:aTargetId onDevice:aDisplay for:aDrawableId
+! !
+
+!XWorkstation::SelectionFetcher methodsFor:'accessing'!
+
+getSelection
+    "convert the data in buffer to a selection"
+
+    |selection|
+
+    buffer isNil ifTrue:[
+        ^ nil.
+    ].
+
+    targetID == (display atomIDOf:#STRING) ifTrue:[
+        display clipBoardEncoding notNil ifTrue:[
+            selection := buffer decodeFrom:display clipBoardEncoding
+        ].
+        selection := buffer.
+    ] ifFalse:[targetID == (display atomIDOf:#'UTF8_STRING') ifTrue:[
+"/ Transcript show:'UTF8: '; showCR:buffer storeString.
+        selection := CharacterArray fromUTF8Bytes:buffer
+    ] ifFalse:[targetID == (display atomIDOf:#TEXT) ifTrue:[
+"/ Transcript show:'TEXT: '; showCR:buffer storeString.
+        selection := buffer asString
+    ] ifFalse:[targetID == (display atomIDOf:#'COMPOUND_TEXT') ifTrue:[
+"/ Transcript show:'COMPOUND_TEXT: '; showCR:buffer storeString.
+        selection := buffer asString
+    ]]]].
+
+    selection notNil ifTrue:[
+        (selection endsWith:Character cr) ifTrue:[
+            selection := selection asStringCollection copyWith:''
+        ].
+        ^ selection.
+    ].
+
+    targetID == (display atomIDOf:#'ST_OBJECT') ifTrue:[
+        ^ (Object readBinaryFrom:(ReadStream on:buffer) onError:[nil])
+    ].
+
+    'XWorkstation: unimplemented property targetID: ' infoPrint. targetID infoPrint.
+    ' ' infoPrint. (display atomName:targetID) infoPrint.
+    ' buffer:' infoPrint. buffer infoPrintCR.
+    ^ ''
+! !
+
+!XWorkstation::SelectionFetcher methodsFor:'event handling'!
+
+message:aMessage
+    "got an asynchronous event from the display.
+     Save and wake up waiters"
+
+    message notNil ifTrue:[
+        'XWorkstation: message overflow' errorPrintCR.
+        ^ self.
+    ].
+
+    (incremental not and:[aMessage selector == #propertyChange:property:state:time:]) ifTrue:[
+        "ignore propertyChange messages if not in incremental transmission mode"
+        ^ self.
+    ].
+
+    message := aMessage.
+    sema signal.
+!
+
+propertyChange:aView property:aPropertyId state:stateSymbol time:time
+    "this is a forwarded propretyChange event from XWorkstation"
+
+    |property clipBoardContents|
+
+    stateSymbol ~~ #newValue ifTrue:[
+        "I am not interested in delete notifications"
+        ^ self.
+    ].
+
+    property := display getProperty:propertyID from:drawableID delete:true.
+    clipBoardContents := property value.
+    targetID ~= property key ifTrue:[
+        'XWorkstation: targetID change in incremental select' errorPrintCR.
+    ].
+
+    "property with size 0 signals end of transfer"
+    clipBoardContents size == 0 ifTrue:[
+        done := true.
+    ] ifFalse:[
+        buffer isNil ifTrue:[
+            buffer := clipBoardContents.
+        ] ifFalse:[
+            buffer := buffer, clipBoardContents.
+        ].
+    ].
+!
+
+selectionNotify:aView selection:selectionID target:targetID property:aPropertyID requestor:requestorID time:time
+    "this is a forwarded selectionNotify event from XWorkstation"
+
+    |property propertyKey|
+
+    propertyID == 0 ifTrue:[
+        "could not convert"
+        done := true.
+        ^ self.
+    ].
+
+    property := display getProperty:propertyID from:drawableID delete:true.
+    propertyKey := property key.
+    propertyKey == (display atomIDOf:#INCR) ifTrue:[
+        "this is an incremental transfer.
+         Wait for property change"
+        incremental := true.
+    ] ifFalse:[
+        propertyID := propertyKey.
+        buffer := property value.
+        done := true.
+    ].
+! !
+
+!XWorkstation::SelectionFetcher methodsFor:'selection actions'!
+
+requestSelection:selectionId type:aTargetId onDevice:aDisplay for:aDrawableId
+    "request the selection of type targetId.
+     Wait for next asynchronous message and process it,
+     until done"
+
+    display := aDisplay.
+    drawableID := aDrawableId.
+    propertyID := display atomIDOf:#'VT_SELECTION'.
+    targetID := aTargetId.
+    sema := Semaphore new name:'X11SelectionFetcher'.
+    done := false.
+    incremental := false.
+
+    [
+    
+        display registerSelectionFetcher:self.
+
+        display
+            requestSelection:selectionId
+            property:propertyID
+            type:aTargetId
+            for:drawableID.
+
+        [
+            |currentMessage|
+
+            sema wait.
+            currentMessage := message.
+            message := nil.
+            currentMessage sendTo:self.
+        ] doUntil:[done].
+    ] ensure:[
+        display unregisterSelectionFetcher:self.
+    ].
+
+    ^ self getSelection
+! !
+
+!XWorkstation::SelectionFetcher methodsFor:'testing'!
+
+matchesDrawableId:aDrawableId
+    ^ drawableID = aDrawableId
+! !
+
 !XWorkstation class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libview/XWorkstation.st,v 1.460 2004-09-14 12:30:34 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libview/XWorkstation.st,v 1.461 2004-09-14 23:06:05 stefan Exp $'
 ! !
 
 XWorkstation initialize!