- Add clipboard support for copying/pasting bitmaps or Pixmaps between Wine
  and native Linux applications.
- Respond to the MULTIPLE selection request target when Wine is the
  selection owner.
- Relax type checking for TARGETS selection.

diff --git a/windows/clipboard.c b/windows/clipboard.c
index 1662bd3..18c7ddf 100644
--- a/windows/clipboard.c
+++ b/windows/clipboard.c
@@ -796,27 +796,28 @@
       if( lpRender->wFormatID == CF_METAFILEPICT )
 	size = sizeof( METAFILEPICT16 );
       else
-	size = GlobalSize(lpRender->hData32);
+          size = GlobalSize(lpRender->hData32);
+      
       lpRender->hData16 = GlobalAlloc16(GMEM_ZEROINIT, size);
       if( !lpRender->hData16 )
 	ERR("(%04X) -- not enough memory in 16b heap\n", wFormat);
       else
       {
-      if( lpRender->wFormatID == CF_METAFILEPICT )
-      {
-	FIXME("\timplement function CopyMetaFilePict32to16\n");
-	FIXME("\tin the appropriate file.\n");
-#ifdef SOMEONE_IMPLEMENTED_ME
-	CopyMetaFilePict32to16( GlobalLock16(lpRender->hData16), 
-			        GlobalLock(lpRender->hData32) );
-#endif
-      }
-      else
-      {
-	memcpy( GlobalLock16(lpRender->hData16), 
-		GlobalLock(lpRender->hData32), 
-		size );
-      }
+        if( lpRender->wFormatID == CF_METAFILEPICT )
+        {
+          FIXME("\timplement function CopyMetaFilePict32to16\n");
+          FIXME("\tin the appropriate file.\n");
+  #ifdef SOMEONE_IMPLEMENTED_ME
+          CopyMetaFilePict32to16( GlobalLock16(lpRender->hData16), 
+                                  GlobalLock(lpRender->hData32) );
+  #endif
+        }
+        else
+        {
+          memcpy( GlobalLock16(lpRender->hData16), 
+                  GlobalLock(lpRender->hData32), 
+                  size );
+        }
 	GlobalUnlock16(lpRender->hData16);
 	GlobalUnlock(lpRender->hData32);
       }
diff --git a/windows/x11drv/clipboard.c b/windows/x11drv/clipboard.c
index 6636a4e..3db480b 100644
--- a/windows/x11drv/clipboard.c
+++ b/windows/x11drv/clipboard.c
@@ -43,8 +43,6 @@
  *    and vice versa. If a native format is available in the selection, it takes
  *    precedence, in order to avoid unnecessary conversions.
  *
- * TODO:
- *    - Support for converting between DIB and PIXMAP formats
  */
 
 #include "config.h"
@@ -62,6 +60,9 @@
 #include "win.h"
 #include "windef.h"
 #include "x11drv.h"
+#include "bitmap.h"
+#include "commctrl.h"
+#include "heap.h"
 
 DEFAULT_DEBUG_CHANNEL(clipboard)
 
@@ -83,9 +84,16 @@
 static unsigned long cSelectionTargets = 0;    /* Number of target formats reported by TARGETS selection */
 static Atom selectionCacheSrc = XA_PRIMARY;    /* The selection source from which the clipboard cache was filled */
 
+/*
+ * Dynamic pointer arrays to manage destruction of Pixmap resources
+ */
+static HDPA PropDPA = NULL;
+static HDPA PixmapDPA = NULL;
+
+
 
 /**************************************************************************
- *		X11DRV_CLIPBOARD_MapPropertyToID
+ *		X11DRV_CLIPBOARD_MapPropertyToFormat
  *
  *  Map an X selection property type atom name to a windows clipboard format ID
  */
@@ -102,10 +110,21 @@
         return RegisterClipboardFormatA(itemFmtName + strlen(FMT_PREFIX));
     else if ( 0 == strcmp(itemFmtName, "STRING") )
         return CF_OEMTEXT;
-    else if ( 0 == strcmp(itemFmtName, "PIXMAP") )
-        return CF_DIB;
-    else if ( 0 == strcmp(itemFmtName, "BITMAP") )
-        return CF_DIB;
+    else if ( 0 == strcmp(itemFmtName, "PIXMAP")
+                ||  0 == strcmp(itemFmtName, "BITMAP") )
+    {
+        /*
+         * Return CF_DIB as first preference, if WINE is the selection owner
+         * and if CF_DIB exists in the cache.
+         * If wine dowsn't own the selection we always return CF_DIB
+         */
+        if ( !X11DRV_CLIPBOARD_IsSelectionowner() )
+            return CF_DIB;
+        else if ( CLIPBOARD_IsPresent(CF_DIB) )
+            return CF_DIB;
+        else
+            return CF_BITMAP;
+    }
 
     WARN("\tNo mapping to Windows clipboard format for property %s\n", itemFmtName);
     return 0;
@@ -185,6 +204,7 @@
     return bRet;
 }
 
+
 /**************************************************************************
  *		X11DRV_CLIPBOARD_CacheDataFormats
  *
@@ -259,7 +279,7 @@
 
     /* Read the TARGETS property contents */
     if(TSXGetWindowProperty(display, xe.xselection.requestor, xe.xselection.property,
-                            0, 0x3FFF, True, XA_ATOM, &atype, &aformat,
+                            0, 0x3FFF, True, AnyPropertyType/*XA_ATOM*/, &atype, &aformat,
                             &cSelectionTargets, &remain, (unsigned char**)&targetList) != Success)
         TRACE("\tCouldn't read TARGETS property\n");
     else
@@ -270,7 +290,7 @@
         * The TARGETS property should have returned us a list of atoms
         * corresponding to each selection target format supported.
         */
-       if(atype == XA_ATOM && aformat == 32)
+       if( (atype == XA_ATOM || atype == aTargets) && aformat == 32 )
        {
           int i;
           LPWINE_CLIPFORMAT lpFormat;
@@ -291,9 +311,13 @@
               {
                   lpFormat = CLIPBOARD_LookupFormat( wFormat );
                   
-                  /* Don't replace if the property already cached is a native format */
-                  if (lpFormat->wDataPresent
-                      && X11DRV_CLIPBOARD_IsNativeProperty(lpFormat->drvData))
+                  /* Don't replace if the property already cached is a native format,
+                   * or if a PIXMAP is being replaced by a BITMAP.
+                   */
+                  if (lpFormat->wDataPresent &&
+                        ( X11DRV_CLIPBOARD_IsNativeProperty(lpFormat->drvData)
+                          || (lpFormat->drvData == XA_PIXMAP && targetList[i] == XA_BITMAP) )
+                     )
                   {
                       TRACE("\tAtom# %d: '%s' --> FormatID(%d) %s (Skipped)\n",
                             i, itemFmtName, wFormat, lpFormat->Name);
@@ -326,7 +350,7 @@
  *  This method is invoked only to read the contents of a the selection owned
  *  by an external application. i.e. when we do not own the X selection.
  */
-static BOOL X11DRV_CLIPBOARD_ReadSelection(UINT wFormat, Window w, Atom prop, Atom reqFormat)
+static BOOL X11DRV_CLIPBOARD_ReadSelection(UINT wFormat, Window w, Atom prop, Atom reqType)
 {
     Atom	      atype=AnyPropertyType;
     int		      aformat;
@@ -336,26 +360,27 @@
     LPWINE_CLIPFORMAT lpFormat;
     BOOL              bRet = FALSE;
     HWND              hWndClipWindow = GetOpenClipboardWindow();
+
     
     if(prop == None)
         return bRet;
 
     TRACE("Reading X selection...\n");
 
-    TRACE("\tretrieving property %s into %s\n",
-          TSXGetAtomName(display,reqFormat), TSXGetAtomName(display,prop) );
+    TRACE("\tretrieving property %s from window %ld into %s\n",
+          TSXGetAtomName(display,reqType), (long)w, TSXGetAtomName(display,prop) );
 
     /*
-     * Retrieve the property in the required X format.
      * First request a zero length in order to figure out the request size.
      */
-    if(TSXGetWindowProperty(display,w,prop,0,0,True,reqFormat,
+    if(TSXGetWindowProperty(display,w,prop,0,0,False, AnyPropertyType/*reqType*/,
                             &atype, &aformat, &nitems, &itemSize, &val) != Success)
     {
         WARN("\tcouldn't get property size\n");
         return bRet;
     }
-    /* Free property if one was returned */
+
+    /* Free zero length return data if any */
     if ( val )
     {
        TSXFree(val);
@@ -365,7 +390,10 @@
     TRACE("\tretrieving %ld bytes...\n", itemSize * aformat/8);
     lRequestLength = (itemSize * aformat/8)/4  + 1;
     
-    if(TSXGetWindowProperty(display,w,prop,0,lRequestLength,True,reqFormat,
+    /*
+     * Retrieve the actual property in the required X format.
+     */
+    if(TSXGetWindowProperty(display,w,prop,0,lRequestLength,False,AnyPropertyType/*reqType*/,
                             &atype, &aformat, &nitems, &remain, &val) != Success)
     {
         WARN("\tcouldn't read property\n");
@@ -378,14 +406,14 @@
     if (remain)
     {
         WARN("\tCouldn't read entire property- selection may be too large! Remain=%ld\n", remain);
-        return bRet;
+        goto END;
     }
     
     /*
      * Translate the X property into the appropriate Windows clipboard
      * format, if possible.
      */
-    if ( (reqFormat == XA_STRING)
+    if ( (reqType == XA_STRING)
          && (atype == XA_STRING) && (aformat == 8) ) /* treat Unix text as CF_OEMTEXT */
     {
       HANDLE16   hText = 0;
@@ -432,16 +460,56 @@
           bRet = TRUE;
       }
     }
-    else if ( reqFormat == XA_PIXMAP ) /* treat PIXMAP as CF_DIB or CF_BITMAP */
+    else if ( reqType == XA_PIXMAP || reqType == XA_BITMAP ) /* treat PIXMAP as CF_DIB or CF_BITMAP */
     {
-      if (wFormat == CF_BITMAP )
-          FIXME("PIXMAP to CF_BITMAP conversion not yet implemented!\n");
-      else if (wFormat == CF_DIB )
-          FIXME("PIXMAP to CF_DIB conversion not yet implemented!\n");
+      /* Get the first pixmap handle passed to us */
+      Pixmap *pPixmap = (Pixmap *)val;
+      HANDLE hTargetImage = NULL;  /* Handle to store the converted bitmap or DIB */
+      
+      if (aformat != 32 || nitems < 1 || atype != XA_PIXMAP
+          || (wFormat != CF_BITMAP && wFormat != CF_DIB))
+      {
+          WARN("\tUnimplemented format conversion request\n");
+          goto END;
+      }
+          
+      if ( wFormat == CF_BITMAP )
+      {
+        /* For CF_BITMAP requests we must return an HBITMAP */
+        hTargetImage = X11DRV_BITMAP_CreateBitmapFromPixmap(*pPixmap, TRUE);
+      }
+      else if (wFormat == CF_DIB)
+      {
+        HWND hwnd = GetOpenClipboardWindow();
+        HDC hdc = GetDC(hwnd);
+        
+        /* For CF_DIB requests we must return an HGLOBAL storing a packed DIB */
+        hTargetImage = X11DRV_DIB_CreateDIBFromPixmap(*pPixmap, hdc, TRUE);
+        
+        ReleaseDC(hdc, hwnd);
+      }
+
+      if (!hTargetImage)
+      {
+          WARN("PIXMAP conversion failed!\n" );
+          goto END;
+      }
+      
+      /* Delete previous clipboard data */
+      lpFormat = CLIPBOARD_LookupFormat(wFormat);
+      if (lpFormat->wDataPresent && (lpFormat->hData16 || lpFormat->hData32))
+          CLIPBOARD_DeleteRecord(lpFormat, !(hWndClipWindow));
+      
+      /* Update the clipboard record */
+      lpFormat->wDataPresent = 1;
+      lpFormat->hData32 = hTargetImage;
+      lpFormat->hData16 = 0;
+
+      bRet = TRUE;
     }
  
-    /* For other data types simply copy the X data without conversion */
-    else
+    /* For native properties simply copy the X data without conversion */
+    else if (X11DRV_CLIPBOARD_IsNativeProperty(reqType)) /* <WCF>* */
     {
       HANDLE hClipData = 0;
       void*  lpClipData;
@@ -475,9 +543,20 @@
           bRet = TRUE;
       }
     }
- 
-    /* Free the retrieved property */
-    TSXFree(val);
+    else
+    {
+        WARN("\tUnimplemented format conversion request\n");
+        goto END;
+    }
+
+END:
+    /* Delete the property on the window now that we are done
+     * This will send a PropertyNotify event to the selection owner. */
+    TSXDeleteProperty(display,w,prop);
+    
+    /* Free the retrieved property data */
+    if (val)
+       TSXFree(val);
     
     return bRet;
 }
@@ -629,6 +708,24 @@
         
 	LeaveCriticalSection(&X11DRV_CritSection);
     }
+
+    /* Get rid of any Pixmap resources we may still have */
+    if (PropDPA)
+        DPA_Destroy( PropDPA );
+    if (PixmapDPA)
+    {
+      int i;
+      Pixmap pixmap;
+      for( i = 0; ; i++ )
+      {
+        if ( (pixmap = ((Pixmap)DPA_GetPtr(PixmapDPA, i))) )
+          XFreePixmap(display, pixmap);
+        else
+          break;
+      }
+      DPA_Destroy( PixmapDPA );
+    }
+    PixmapDPA = PropDPA = NULL;
 }
 
 /**************************************************************************
@@ -675,6 +772,12 @@
 
         if (selectionAcquired)
         {
+            /* Create dynamic pointer arrays to manage Pixmap resources we may expose */
+            if (!PropDPA)
+                PropDPA = DPA_CreateEx( 2, SystemHeap );
+            if (!PixmapDPA)
+                PixmapDPA = DPA_CreateEx( 2, SystemHeap );
+            
 	    selectionWindow = owner;
 	    TRACE("Grabbed X selection, owner=(%08x)\n", (unsigned) owner);
         }
@@ -989,4 +1092,57 @@
     }
 }
 
+/**************************************************************************
+ *		X11DRV_CLIPBOARD_RegisterPixmapResource
+ * Registers a Pixmap resource which is to be associated with a property Atom.
+ * When the property is destroyed we also destroy the Pixmap through the
+ * PropertyNotify event.
+ */
+BOOL X11DRV_CLIPBOARD_RegisterPixmapResource( Atom property, Pixmap pixmap )
+{
+  if ( -1 == DPA_InsertPtr( PropDPA, 0, (void*)property ) )
+    return FALSE;
+    
+  if ( -1 == DPA_InsertPtr( PixmapDPA, 0, (void*)pixmap ) )
+    return FALSE;
+
+  return TRUE;
+}
+
+/**************************************************************************
+ *		X11DRV_CLIPBOARD_FreeResources
+ *
+ * Called from EVENT_PropertyNotify() to give us a chance to destroy
+ * any resources associated with this property.
+ */
+void X11DRV_CLIPBOARD_FreeResources( Atom property )
+{
+    /* Do a simple linear search to see if we have a Pixmap resource
+     * associated with this property and release it.
+     */
+    int i;
+    Pixmap pixmap;
+    Atom cacheProp = NULL;
+    for( i = 0; ; i++ )
+    {
+        if ( !(cacheProp = ((Atom)DPA_GetPtr(PropDPA, i))) )
+            break;
+        
+        if ( cacheProp == property )
+        {
+            /* Lookup the associated Pixmap and free it */
+            pixmap = (Pixmap)DPA_GetPtr(PixmapDPA, i);
+  
+            TRACE("Releasing pixmap %ld for Property %s\n",
+                  (long)pixmap, TSXGetAtomName(display, cacheProp));
+            
+            XFreePixmap(display, pixmap);
+
+            /* Free the entries from the table */
+            DPA_DeletePtr(PropDPA, i);
+            DPA_DeletePtr(PixmapDPA, i);
+        }
+    }
+}
+
 #endif /* !defined(X_DISPLAY_MISSING) */
diff --git a/windows/x11drv/event.c b/windows/x11drv/event.c
index e55924b..d2281a3 100644
--- a/windows/x11drv/event.c
+++ b/windows/x11drv/event.c
@@ -2,6 +2,7 @@
  * X11 event driver
  *
  * Copyright 1993 Alexandre Julliard
+ *	     1999 Noel Borthwick
  */
 
 #include "config.h"
@@ -79,6 +80,7 @@
   "ClientMessage", "MappingNotify"
 };
 
+
 static void CALLBACK EVENT_Flush( ULONG_PTR arg );
 static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg );
 static void EVENT_ProcessEvent( XEvent *event );
@@ -93,8 +95,9 @@
 static void EVENT_Expose( HWND hWnd, XExposeEvent *event );
 static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event );
 static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event );
-static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event);
+static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
+static void EVENT_PropertyNotify( XPropertyEvent *event );
 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
 static void EVENT_MapNotify( HWND pWnd, XMapEvent *event );
 static void EVENT_UnmapNotify( HWND pWnd, XUnmapEvent *event );
@@ -222,14 +225,14 @@
     }
   }
 
-  if ( !hWnd && event->xany.window != X11DRV_GetXRootWindow() )
+  if ( !hWnd && event->xany.window != X11DRV_GetXRootWindow()
+             && event->type != PropertyNotify )
       ERR_(event)("Got event %s for unknown Window %08lx\n",
            event_names[event->type], event->xany.window );
   else
       TRACE_(event)("Got event %s for hwnd %04x\n",
 	     event_names[event->type], hWnd );
 
-  
   switch(event->type)
     {
     case KeyPress:
@@ -322,7 +325,7 @@
 
     case SelectionRequest:
       if (!hWnd || bUserRepaintDisabled) return;
-      EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event );
+      EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
       break;
 
     case SelectionClear:
@@ -330,6 +333,10 @@
       EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
       break;
       
+    case PropertyNotify:
+      EVENT_PropertyNotify( (XPropertyEvent *)event );
+      break;
+
     case ClientMessage:
       if (!hWnd || bUserRepaintDisabled) return;
       EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
@@ -834,190 +841,468 @@
 
 
 /***********************************************************************
+ *           EVENT_SelectionRequest_TARGETS
+ *  Service a TARGETS selection request event
+ */
+static Atom EVENT_SelectionRequest_TARGETS( Window requestor, Atom target, Atom rprop )
+{
+    Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
+    Atom* targets;
+    Atom prop;
+    UINT wFormat;
+    unsigned long cTargets;
+    BOOL bHavePixmap;
+    int xRc;
+
+    TRACE_(event)("Request for %s\n", TSXGetAtomName(display, target));
+    
+    /*
+     * Count the number of items we wish to expose as selection targets.
+     * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
+     */
+    cTargets = CountClipboardFormats() + 1;
+    if ( CLIPBOARD_IsPresent(CF_DIB) ||  CLIPBOARD_IsPresent(CF_BITMAP) )
+       cTargets++;
+    
+    /* Allocate temp buffer */
+    targets = (Atom*)HEAP_xalloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
+
+    /* Create TARGETS property list (First item in list is TARGETS itself) */
+
+    for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
+          (wFormat = EnumClipboardFormats( wFormat )); )
+    {
+        if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
+        {
+            /* Scan through what we have so far to avoid duplicates */
+            int i;
+            BOOL bExists;
+            for (i = 0, bExists = FALSE; i < cTargets; i++)
+            {
+                if (targets[i] == prop)
+                {
+                    bExists = TRUE;
+                    break;
+                }
+            }
+            if (!bExists)
+            {
+                targets[cTargets++] = prop;
+            
+                /* Add PIXMAP prop for bitmaps additionally */
+                if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
+                     && !bHavePixmap )
+                {
+                    targets[cTargets++] = XA_PIXMAP;
+                    bHavePixmap = TRUE;
+                }
+            }
+        }
+    }
+
+#ifdef DEBUG_RUNTIME
+{
+    int i;
+    for ( i = 0; i < cTargets; i++)
+    {
+        if (targets[i])
+        {
+          char *itemFmtName = TSXGetAtomName(display, targets[i]);
+          TRACE_(event)("\tAtom# %d:  Type %s\n", i, itemFmtName);
+          TSXFree(itemFmtName);
+        }
+    }
+}
+#endif
+    
+    /* Update the X property */
+    TRACE_(event)("\tUpdating property %s...", TSXGetAtomName(display, rprop));
+
+    /* We may want to consider setting the type to xaTargets instead,
+     * in case some apps expect this instead of XA_ATOM */
+    xRc = TSXChangeProperty(display, requestor, rprop,
+                            XA_ATOM, 32, PropModeReplace,
+                            (unsigned char *)targets, cTargets);
+    TRACE_(event)("(Rc=%d)\n", xRc);
+    
+    HeapFree( GetProcessHeap(), 0, targets );
+
+    return rprop;
+}
+
+
+/***********************************************************************
+ *           EVENT_SelectionRequest_STRING
+ *  Service a STRING selection request event
+ */
+static Atom EVENT_SelectionRequest_STRING( Window requestor, Atom target, Atom rprop )
+{
+    HANDLE16 hText;
+    LPSTR  text;
+    int    size,i,j;
+    char* lpstr = 0;
+    char *itemFmtName;
+    int xRc;
+
+    /*
+     * Map the requested X selection property type atom name to a
+     * windows clipboard format ID.
+     */
+    itemFmtName = TSXGetAtomName(display, target);
+    TRACE_(event)("Request for %s (wFormat=%x %s)\n",
+                  itemFmtName, CF_TEXT, CLIPBOARD_GetFormatName(CF_TEXT));
+    TSXFree(itemFmtName);
+
+    if ( !CLIPBOARD_IsPresent(CF_TEXT) )
+    {
+       rprop = None;
+       goto END;
+    }
+
+    hText = GetClipboardData16(CF_TEXT);
+    text = GlobalLock16(hText);
+    size = GlobalSize16(hText);
+    
+    /* remove carriage returns */
+    
+    lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
+    for(i=0,j=0; i < size && text[i]; i++ )
+    {
+        if( text[i] == '\r' && 
+            (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
+        lpstr[j++] = text[i];
+    }
+    lpstr[j]='\0';
+    
+    /* Update the X property */
+    TRACE_(event)("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
+    xRc = TSXChangeProperty(display, requestor, rprop,
+                            XA_STRING, 8, PropModeReplace,
+                            lpstr, j);
+    TRACE_(event)("(Rc=%d)\n", xRc);
+
+    GlobalUnlock16(hText);
+    HeapFree( GetProcessHeap(), 0, lpstr );
+
+END:
+    return rprop;
+}
+
+/***********************************************************************
+ *           EVENT_SelectionRequest_PIXMAP
+ *  Service a PIXMAP selection request event
+ */
+static Atom EVENT_SelectionRequest_PIXMAP( Window requestor, Atom target, Atom rprop )
+{
+    HANDLE hClipData = 0;
+    Pixmap pixmap = NULL;
+    UINT   wFormat;
+    char * itemFmtName;
+    int xRc;
+#if(0)
+    XSetWindowAttributes win_attr;
+    XWindowAttributes win_attr_src;
+#endif
+    
+    /*
+     * Map the requested X selection property type atom name to a
+     * windows clipboard format ID.
+     */
+    itemFmtName = TSXGetAtomName(display, target);
+    wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
+    TRACE_(event)("Request for %s (wFormat=%x %s)\n",
+                  itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
+    TSXFree(itemFmtName);
+    
+    hClipData = GetClipboardData(wFormat);
+    if ( !hClipData )
+    {
+        TRACE_(event)("Could not retrieve a Pixmap compatible format from clipboard!\n");
+        rprop = None; /* Fail the request */
+        goto END;
+    }
+
+    if (wFormat == CF_DIB)
+    {
+        HWND hwnd = GetOpenClipboardWindow();
+        HDC hdc = GetDC(hwnd);
+        
+        /* For convert from packed DIB to Pixmap */
+        pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
+        
+        ReleaseDC(hdc, hwnd);
+    }
+    else if (wFormat == CF_BITMAP)
+    {
+        HWND hwnd = GetOpenClipboardWindow();
+        HDC hdc = GetDC(hwnd);
+        
+        pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
+
+        ReleaseDC(hdc, hwnd);
+    }
+    else
+    {
+        FIXME_(event)("%s to PIXMAP conversion not yet implemented!\n",
+                      CLIPBOARD_GetFormatName(wFormat));
+        rprop = None;
+        goto END;
+    }
+
+    TRACE_(event)("\tUpdating property %s on Window %ld with %s %ld...\n",
+                  TSXGetAtomName(display, rprop), (long)requestor,
+                  TSXGetAtomName(display, target),
+                  pixmap);
+
+    /* Store the Pixmap handle in the property */
+    xRc = TSXChangeProperty(display, requestor, rprop, target, 
+                            32, PropModeReplace,
+                            (unsigned char *)&pixmap, 1);
+    TRACE_(event)("(Rc=%d)\n", xRc);
+
+    /* Enable the code below if you want to handle destroying Pixmap resources
+     * in response to property notify events. Clients like XPaint don't
+     * appear to be duplicating Pixmaps so they don't like us deleting,
+     * the resource in response to the property being deleted.
+     */
+#if(0)
+    /* Express interest in property notify events so that we can delete the
+     * pixmap when the client deletes the property atom.
+     */
+    xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
+    TRACE_(event)("Turning on PropertyChangeEvent notifications from window %ld\n",
+                 (long)requestor);
+    win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
+    TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
+
+    /* Register the Pixmap we created with the request property Atom.
+     * When this property is destroyed we also destroy the Pixmap in
+     * response to the PropertyNotify event.
+     */
+    X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
+#endif
+    
+END:
+    return rprop;
+}
+
+
+/***********************************************************************
+ *           EVENT_SelectionRequest_WCF
+ *  Service a Wine Clipboard Format selection request event.
+ *  For <WCF>* data types we simply copy the data to X without conversion.
+ */
+static Atom EVENT_SelectionRequest_WCF( Window requestor, Atom target, Atom rprop )
+{
+    HANDLE hClipData = 0;
+    void*  lpClipData;
+    UINT   wFormat;
+    char * itemFmtName;
+    int cBytes;
+    int xRc;
+    
+    /*
+     * Map the requested X selection property type atom name to a
+     * windows clipboard format ID.
+     */
+    itemFmtName = TSXGetAtomName(display, target);
+    wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
+    TRACE_(event)("Request for %s (wFormat=%x %s)\n",
+                  itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
+    TSXFree(itemFmtName);
+    
+    hClipData = GetClipboardData16(wFormat);
+    
+    if( hClipData && (lpClipData = GlobalLock16(hClipData)) )
+    {
+        cBytes = GlobalSize16(hClipData);
+        
+        TRACE_(event)("\tUpdating property %s, %d bytes...\n",
+                      TSXGetAtomName(display, rprop), cBytes);
+        
+        xRc = TSXChangeProperty(display, requestor, rprop,
+                                target, 8, PropModeReplace,
+                                (unsigned char *)lpClipData, cBytes);
+        TRACE_(event)("(Rc=%d)\n", xRc);
+        
+        GlobalUnlock16(hClipData);
+    }
+    else
+    {
+        TRACE_(event)("\tCould not retrieve native format!\n");
+        rprop = None; /* Fail the request */
+    }
+    
+    return rprop;
+}
+
+
+/***********************************************************************
+ *           EVENT_SelectionRequest_MULTIPLE
+ *  Service a MULTIPLE selection request event
+ *  rprop contains a list of (target,property) atom pairs.
+ *  The first atom names a target and the second names a property.
+ *  The effect is as if we have received a sequence of SelectionRequest events
+ *  (one for each atom pair) except that:
+ *  1. We reply with a SelectionNotify only when all the requested conversions
+ *  have been performed.
+ *  2. If we fail to convert the target named by an atom in the MULTIPLE property,
+ *  we replace the atom in the property by None.
+ */
+static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
+{
+    Atom           rprop;
+    Atom           atype=AnyPropertyType;
+    int		   aformat;
+    unsigned long  remain;
+    Atom*	   targetPropList=NULL;
+    unsigned long  cTargetPropList = 0;
+/*  Atom           xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
+    
+   /* If the specified property is None the requestor is an obsolete client.
+    * We support these by using the specified target atom as the reply property.
+    */
+    rprop = pevent->property;
+    if( rprop == None ) 
+        rprop = pevent->target;
+    if (!rprop)
+        goto END;
+
+    /* Read the MULTIPLE property contents. This should contain a list of
+     * (target,property) atom pairs.
+     */
+    if(TSXGetWindowProperty(display, pevent->requestor, rprop,
+                            0, 0x3FFF, False, AnyPropertyType, &atype, &aformat,
+                            &cTargetPropList, &remain, (unsigned char**)&targetPropList) != Success)
+        TRACE_(event)("\tCouldn't read MULTIPLE property\n");
+    else
+    {
+       TRACE_(event)("\tType %s,Format %d,nItems %ld, Remain %ld\n",
+                     TSXGetAtomName(display,atype),aformat,cTargetPropList,remain);
+
+       /*
+        * Make sure we got what we expect.
+        * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
+        * in a MULTIPLE selection request should be of type ATOM_PAIR.
+        * However some X apps(such as XPaint) are not compliant with this and return
+        * a user defined atom in atype when XGetWindowProperty is called.
+        * The data *is* an atom pair but is not denoted as such.
+        */
+       if(aformat == 32 /* atype == xAtomPair */ )
+       {
+          int i;
+          
+          /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
+           * for each (target,property) pair */
+
+          for (i = 0; i < cTargetPropList; i+=2)
+          {
+              char *targetName = TSXGetAtomName(display, targetPropList[i]);
+              char *propName = TSXGetAtomName(display, targetPropList[i+1]);
+              XSelectionRequestEvent event;
+
+              TRACE_(event)("MULTIPLE(%d): Target='%s' Prop='%s'\n", i/2, targetName, propName);
+              TSXFree(targetName);
+              TSXFree(propName);
+              
+              /* We must have a non "None" property to service a MULTIPLE target atom */
+              if ( !targetPropList[i+1] )
+              {
+                  TRACE_(event)("\tMULTIPLE(%d): Skipping target with empty property!", i);
+                  continue;
+              }
+              
+              /* Set up an XSelectionRequestEvent for this (target,property) pair */
+              memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
+              event.target = targetPropList[i];
+              event.property = targetPropList[i+1];
+                  
+              /* Fire a SelectionRequest, informing the handler that we are processing
+               * a MULTIPLE selection request event.
+               */
+              EVENT_SelectionRequest( hWnd, &event, TRUE );
+          }
+       }
+
+       /* Free the list of targets/properties */
+       TSXFree(targetPropList);
+    }
+
+END:
+    return rprop;
+}
+
+
+/***********************************************************************
  *           EVENT_SelectionRequest
+ *  Process an event selection request event.
+ *  The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
+ *  recursively while servicing a "MULTIPLE" selection target.
+ *
  *  Note: We only receive this event when WINE owns the X selection
  */
-static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event )
+static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
 {
   XSelectionEvent result;
   Atom 	          rprop = None;
   Window          request = event->requestor;
-  UINT            wFormat;
-  char *          itemFmtName;
   BOOL            couldOpen = FALSE;
-  Atom            xaClipboard = XInternAtom(display, "CLIPBOARD", False);
-  Atom            xaTargets = XInternAtom(display, "TARGETS", False);
-  int             xRc;
-
-  /*
-   * Map the requested X selection property type atom name to a
-   * windows clipboard format ID.
-   */
-  itemFmtName = TSXGetAtomName(display, event->target);
-  wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
-  TRACE_(event)("Request for %s\n", itemFmtName);
-  TSXFree(itemFmtName);
+  Atom            xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
+  Atom            xaTargets = TSXInternAtom(display, "TARGETS", False);
+  Atom            xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
 
   /*
    * We can only handle the selection request if :
-   * The selection is PRIMARY or CLIPBOARD,
-   * AND we can successfully open the clipboard.
-   * AND we have a request for a TARGETS selection target,
-   *     OR the requested format is available in the clipboard
+   * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
+   * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
+   * since this has been already done.
    */
-  if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
-      || !(couldOpen = OpenClipboard(hWnd)) )
-     goto END;
-  if ( (event->target != xaTargets)
-       && ( (0 == wFormat) || !CLIPBOARD_IsPresent(wFormat) ) )
-     goto END;
+  if ( !bIsMultiple )
+  {
+    if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
+        || !(couldOpen = OpenClipboard(hWnd)) )
+       goto END;
+  }
 
-  /* We can handle the request */
-       
+  /* If the specified property is None the requestor is an obsolete client.
+   * We support these by using the specified target atom as the reply property.
+   */
   rprop = event->property;
-  
   if( rprop == None ) 
       rprop = event->target;
   
   if(event->target == xaTargets)  /*  Return a list of all supported targets */
   {
-      Atom* targets;
-      Atom prop;
-      UINT wFormat;
-      unsigned long cTargets;
-      BOOL bHavePixmap;
-
-      /*
-       * Count the number of items we wish to expose as selection targets.
-       * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
-       */
-      cTargets = CountClipboardFormats() + 1;
-      if ( CLIPBOARD_IsPresent(CF_DIB) ||  CLIPBOARD_IsPresent(CF_BITMAP) )
-         cTargets++;
-      
-      /* Allocate temp buffer */
-      targets = (Atom*)HEAP_xalloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
-
-      /* Create TARGETS property list (First item in list is TARGETS itself) */
-
-      for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
-            (wFormat = EnumClipboardFormats( wFormat )); )
-      {
-          if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
-          {
-              /* Scan through what we have so far to avoid duplicates */
-              int i;
-              BOOL bExists;
-              for (i = 0, bExists = FALSE; i < cTargets; i++)
-              {
-                  if (targets[i] == prop)
-                  {
-                      bExists = TRUE;
-                      break;
-                  }
-              }
-              if (!bExists)
-              {
-                  targets[cTargets++] = prop;
-              
-                  /* Add PIXMAP prop for bitmaps additionally */
-                  if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
-                       && !bHavePixmap )
-                  {
-                      targets[cTargets++] = XA_PIXMAP;
-                      bHavePixmap = TRUE;
-                  }
-              }
-          }
-      }
-
-#ifdef DEBUG_RUNTIME
-{
-      int i;
-      for ( i = 0; i < cTargets; i++)
-      {
-          if (targets[i])
-          {
-            char *itemFmtName = TSXGetAtomName(display, targets[i]);
-            TRACE_(event)("\tAtom# %d:  Type %s\n", i, itemFmtName);
-            TSXFree(itemFmtName);
-          }
-      }
-}
-#endif
-      
-      /* Update the X property */
-      TRACE_(event)("\tUpdating property %s...", TSXGetAtomName(display, rprop));
-      xRc = TSXChangeProperty(display, request, rprop,
-                              XA_ATOM, 32, PropModeReplace,
-                              (unsigned char *)targets, cTargets);
-      TRACE_(event)("(Rc=%d)\n", xRc);
-      
-      HeapFree( GetProcessHeap(), 0, targets );
+      /* TARGETS selection request */
+      rprop = EVENT_SelectionRequest_TARGETS( request, event->target, rprop );
+  }
+  else if(event->target == xaMultiple)  /*  rprop contains a list of (target, property) atom pairs */
+  {
+      /* MULTIPLE selection request */
+      rprop = EVENT_SelectionRequest_MULTIPLE(  hWnd, event );
   }
   else if(event->target == XA_STRING)  /* treat CF_TEXT as Unix text */
   {
-      HANDLE16 hText;
-      LPSTR  text;
-      int    size,i,j;
-      
-      char* lpstr = 0;
-      
-      hText = GetClipboardData16(CF_TEXT);
-      text = GlobalLock16(hText);
-      size = GlobalSize16(hText);
-      
-      /* remove carriage returns */
-      
-      lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
-      for(i=0,j=0; i < size && text[i]; i++ )
-      {
-          if( text[i] == '\r' && 
-              (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
-          lpstr[j++] = text[i];
-      }
-      lpstr[j]='\0';
-      
-      /* Update the X property */
-      TRACE_(event)("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
-      xRc = TSXChangeProperty(display, request, rprop, 
-                              XA_STRING, 8, PropModeReplace,
-                              lpstr, j);
-      TRACE_(event)("(Rc=%d)\n", xRc);
-
-      GlobalUnlock16(hText);
-      HeapFree( GetProcessHeap(), 0, lpstr );
+      /* XA_STRING selection request */
+      rprop = EVENT_SelectionRequest_STRING( request, event->target, rprop );
   }
   else if(event->target == XA_PIXMAP)  /*  Convert DIB's to Pixmaps */
   {
-      FIXME_(event)("DIB to PIXMAP conversion not yet implemented!\n");
-      rprop = None;
+      /* XA_PIXMAP selection request */
+      rprop = EVENT_SelectionRequest_PIXMAP( request, event->target, rprop );
   }
-  else  /* For other data types (WCF_*) simply copy the data to X without conversion */
+  else if(event->target == XA_BITMAP)  /*  Convert DIB's to 1-bit Pixmaps */
   {
-      HANDLE hClipData = 0;
-      void*  lpClipData;
-      int cBytes;
-      
-      hClipData = GetClipboardData16(wFormat);
-      
-      if( hClipData && (lpClipData = GlobalLock16(hClipData)) )
-      {
-          cBytes = GlobalSize16(hClipData);
-          
-          TRACE_(event)("\tUpdating property %s, %d bytes...\n",
-                        TSXGetAtomName(display, rprop), cBytes);
-          
-          xRc = TSXChangeProperty(display, request, rprop, 
-                                  event->target, 8, PropModeReplace,
-                                  (unsigned char *)lpClipData, cBytes);
-          TRACE_(event)("(Rc=%d)\n", xRc);
-          
-          GlobalUnlock16(hClipData);
-      }
-      else
-          rprop = None; /* Fail the request */
+      /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
+      rprop = EVENT_SelectionRequest_PIXMAP( request, XA_PIXMAP, rprop );
   }
+  else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
+  {
+      /* All <WCF> selection requests */
+      rprop = EVENT_SelectionRequest_WCF( request, event->target, rprop );
+  }
+  else
+      rprop = None;  /* Don't support this format */
 
 END:
   /* close clipboard only if we opened before */
@@ -1026,16 +1311,21 @@
   if( rprop == None) 
       TRACE_(event)("\tRequest ignored\n");
 
-  /* reply to sender */
-  
-  result.type = SelectionNotify;
-  result.display = display;
-  result.requestor = request;
-  result.selection = event->selection;
-  result.property = rprop;
-  result.target = event->target;
-  result.time = event->time;
-  TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
+  /* reply to sender 
+   * SelectionNotify should be sent only at the end of a MULTIPLE request
+   */
+  if ( !bIsMultiple )
+  {
+    result.type = SelectionNotify;
+    result.display = display;
+    result.requestor = request;
+    result.selection = event->selection;
+    result.property = rprop;
+    result.target = event->target;
+    result.time = event->time;
+    TRACE_(event)("Sending SelectionNotify event...\n");
+    TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
+  }
 }
 
 /***********************************************************************
@@ -1043,12 +1333,45 @@
  */
 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
 {
-  Atom xaClipboard = XInternAtom(display, "CLIPBOARD", False);
+  Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
     
   if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
       X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
 }
 
+/***********************************************************************
+ *           EVENT_PropertyNotify
+ *   We use this to release resources like Pixmaps when a selection
+ *   client no longer needs them.
+ */
+static void EVENT_PropertyNotify( XPropertyEvent *event )
+{
+  /* Check if we have any resources to free */
+  TRACE_(event)("Received PropertyNotify event: ");
+
+  switch(event->state)
+  {
+    case PropertyDelete:
+    {
+      TRACE_(event)("\tPropertyDelete for atom %s on window %ld\n",
+                    TSXGetAtomName(event->display, event->atom), (long)event->window);
+      
+      if (X11DRV_CLIPBOARD_IsSelectionowner())
+          X11DRV_CLIPBOARD_FreeResources( event->atom );
+      break;
+    }
+
+    case PropertyNewValue:
+    {
+      TRACE_(event)("\tPropertyNewValue for atom %s on window %ld\n\n",
+                    TSXGetAtomName(event->display, event->atom), (long)event->window);
+      break;
+    }
+    
+    default:
+      break;
+  }
+}
 
 /**********************************************************************
  *           EVENT_DropFromOffix