- Implement interprocess clipboard communication.
- Support for the PRIMARY and CLIPBOARD selection atoms.
- Support for the TARGETS selection format.
- Expose native Windows clipboard formats through X selection targets.

diff --git a/include/clipboard.h b/include/clipboard.h
index 7aebde9..f6439fb 100644
--- a/include/clipboard.h
+++ b/include/clipboard.h
@@ -10,26 +10,35 @@
     WORD	wRefCount;
     WORD	wDataPresent;
     LPSTR	Name;
+    HANDLE16    hData16;
     HANDLE	hDataSrc32;
     HANDLE	hData32;
-    DWORD	BufSize;
+    ULONG       drvData;
     struct tagWINE_CLIPFORMAT *PrevFormat;
     struct tagWINE_CLIPFORMAT *NextFormat;
-    HANDLE16    hData16;
 } WINE_CLIPFORMAT, *LPWINE_CLIPFORMAT;
 
 typedef struct tagCLIPBOARD_DRIVER
 {
-    void (*pEmpty)(void);
-    void (*pSetData)(UINT);
-    BOOL (*pGetData)(UINT);
+    void (*pAcquire)(void);                     /* Acquire selection */
+    void (*pRelease)(void);                     /* Release selection */
+    void (*pSetData)(UINT);                     /* Set specified selection data */
+    BOOL (*pGetData)(UINT);                     /* Get specified selection data */
+    BOOL (*pIsFormatAvailable)(UINT);           /* Check if specified format is available */
+    BOOL (*pRegisterFormat)(LPCSTR);            /* Register a clipboard format */
+    BOOL (*pIsSelectionOwner)(void);            /* Check if we own the selection */
     void (*pResetOwner)(struct tagWND *, BOOL);
 } CLIPBOARD_DRIVER;
 
 extern CLIPBOARD_DRIVER *CLIPBOARD_Driver;
 
-extern void CLIPBOARD_ResetLock(HQUEUE16 hqRef, HQUEUE16 hqNew);
+extern LPWINE_CLIPFORMAT CLIPBOARD_LookupFormat( WORD wID );
+extern BOOL CLIPBOARD_IsCacheRendered();
 extern void CLIPBOARD_DeleteRecord(LPWINE_CLIPFORMAT lpFormat, BOOL bChange);
+extern void CLIPBOARD_EmptyCache( BOOL bChange );
 extern BOOL CLIPBOARD_IsPresent(WORD wFormat);
+extern char * CLIPBOARD_GetFormatName(UINT wFormat);
+extern void CLIPBOARD_ReleaseOwner();
+
 
 #endif /* __WINE_CLIPBOARD_H */
diff --git a/include/ttydrv.h b/include/ttydrv.h
index 687a6ce..273d432a 100644
--- a/include/ttydrv.h
+++ b/include/ttydrv.h
@@ -73,9 +73,13 @@
 
 extern struct tagCLIPBOARD_DRIVER TTYDRV_CLIPBOARD_Driver;
 
-extern void TTYDRV_CLIPBOARD_Empty(void);
+extern void TTYDRV_CLIPBOARD_Acquire(void);
+extern void TTYDRV_CLIPBOARD_Release(void);
 extern void TTYDRV_CLIPBOARD_SetData(UINT wFormat);
 extern BOOL TTYDRV_CLIPBOARD_GetData(UINT wFormat);
+extern BOOL TTYDRV_CLIPBOARD_IsFormatAvailable(UINT wFormat);
+extern BOOL TTYDRV_CLIPBOARD_RegisterFormat( LPCSTR FormatName );
+extern BOOL TTYDRV_CLIPBOARD_IsSelectionowner();
 extern void TTYDRV_CLIPBOARD_ResetOwner(struct tagWND *pWnd, BOOL bFooBar);
 
 /* TTY desktop driver */
diff --git a/include/x11drv.h b/include/x11drv.h
index e6921ce..e02f73c 100644
--- a/include/x11drv.h
+++ b/include/x11drv.h
@@ -313,11 +313,17 @@
 
 extern struct tagCLIPBOARD_DRIVER X11DRV_CLIPBOARD_Driver;
 
-extern void X11DRV_CLIPBOARD_Empty(void);
+extern void X11DRV_CLIPBOARD_Acquire(void);
+extern void X11DRV_CLIPBOARD_Release(void);
 extern void X11DRV_CLIPBOARD_SetData(UINT wFormat);
 extern BOOL X11DRV_CLIPBOARD_GetData(UINT wFormat);
+extern BOOL X11DRV_CLIPBOARD_IsFormatAvailable(UINT wFormat);
+extern BOOL X11DRV_CLIPBOARD_RegisterFormat( LPCSTR FormatName );
+extern BOOL X11DRV_CLIPBOARD_IsSelectionowner();
+extern UINT X11DRV_CLIPBOARD_MapPropertyToFormat(char *itemFmtName);
+extern Atom X11DRV_CLIPBOARD_MapFormatToProperty(UINT id);
 extern void X11DRV_CLIPBOARD_ResetOwner(struct tagWND *pWnd, BOOL bFooBar);
-extern void X11DRV_CLIPBOARD_ReleaseSelection(Window w, HWND hwnd);
+extern void X11DRV_CLIPBOARD_ReleaseSelection(Atom selType, Window w, HWND hwnd);
 
 /* X11 desktop driver */
 
diff --git a/ole/clipboard.c b/ole/clipboard.c
index 05b0a1b..3d4ed26 100644
--- a/ole/clipboard.c
+++ b/ole/clipboard.c
@@ -827,7 +827,7 @@
         WARN("(): WM_RENDERALLFORMATS failed to retrieve EnumFormatEtc!\n");
         return 0;
       }
-      
+
       while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
       {
         if ( rgelt.tymed == TYMED_HGLOBAL )
@@ -1093,6 +1093,9 @@
 	    STGMEDIUM*       pmedium)
 {
   HANDLE      hData = 0;
+  BOOL bClipboardOpen = FALSE;
+  HRESULT hr = S_OK;
+
   /*
    * Declare "This" pointer 
    */
@@ -1124,8 +1127,11 @@
 */
 
   /* 
-   * Otherwise, delegate to the Windows clipboard function GetClipboardData
+   * Otherwise, get the data from the windows clipboard using GetClipboardData
    */
+  if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
+    HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
+
   hData = GetClipboardData(pformatetcIn->cfFormat);
 
   /* 
@@ -1135,6 +1141,17 @@
   pmedium->u.hGlobal = (HGLOBAL)hData;
   pmedium->pUnkForRelease = NULL;
   
+  hr = S_OK;
+  
+CLEANUP:
+  /*
+   * Close Windows clipboard
+   */
+  if ( bClipboardOpen && !CloseClipboard() )
+     hr = CLIPBRD_E_CANT_CLOSE;
+
+  if ( FAILED(hr) )
+      return hr;
   return (hData == 0) ? DV_E_FORMATETC : S_OK;
 }
 
diff --git a/windows/clipboard.c b/windows/clipboard.c
index 542b02c..1662bd3 100644
--- a/windows/clipboard.c
+++ b/windows/clipboard.c
@@ -1,8 +1,19 @@
 /*
- * WINE clipboard function handling
+ * WIN32 clipboard implementation
  *
  * Copyright 1994 Martin Ayotte
  *	     1996 Alex Korobka
+ *	     1999 Noel Borthwick
+ *
+ * NOTES:
+ *    This file contains the implementation for the WIN32 Clipboard API
+ * and Wine's internal clipboard cache.
+ * The actual contents of the clipboard are held in the clipboard cache.
+ * The internal implementation talks to a "clipboard driver" to fill or
+ * expose the cache to the native device. (Currently only the X11 and
+ * TTY clipboard  driver are available)
+ *
+ * TODO: 
  *
  */
 
@@ -14,9 +25,11 @@
 #include <string.h>
 #include "winuser.h"
 #include "wine/winuser16.h"
+#include "wine/winbase16.h"
 #include "heap.h"
-#include "task.h"
 #include "message.h"
+#include "task.h"
+#include "queue.h"
 #include "clipboard.h"
 #include "xmalloc.h"
 #include "debugtools.h"
@@ -26,39 +39,53 @@
 #define  CF_REGFORMATBASE 	0xC000
 
 /**************************************************************************
- *			internal variables
+ *	  Clipboard context global variables
  */
 
 CLIPBOARD_DRIVER *CLIPBOARD_Driver = NULL;
 
-static HQUEUE16 hqClipLock   = 0;
+static HANDLE hClipLock   = 0;
 static BOOL bCBHasChanged  = FALSE;
 
-HWND hWndClipOwner  = 0;   /* current clipboard owner */
-HWND hWndClipWindow = 0;   /* window that opened clipboard */
+HWND hWndClipWindow = 0;          /* window that last opened clipboard */
+HWND hWndClipOwner  = 0;          /* current clipboard owner */
+HANDLE16 hTaskClipOwner = 0;      /* clipboard owner's task  */
 static HWND hWndViewer     = 0;   /* start of viewers chain */
 
 static WORD LastRegFormat = CF_REGFORMATBASE;
 
+/* Clipboard cache initial data.
+ * WARNING: This data ordering is dependendent on the WINE_CLIPFORMAT structure
+ * declared in clipboard.h
+ */
 WINE_CLIPFORMAT ClipFormats[16]  = {
-    { CF_TEXT, 1, 0, "Text", (HANDLE)NULL, (HANDLE)NULL, 0, NULL, &ClipFormats[1] , (HANDLE16)NULL},
-    { CF_BITMAP, 1, 0, "Bitmap", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[0], &ClipFormats[2] , (HANDLE16)NULL},
-    { CF_METAFILEPICT, 1, 0, "MetaFile Picture", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[1], &ClipFormats[3] , (HANDLE16)NULL},
-    { CF_SYLK, 1, 0, "Sylk", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[2], &ClipFormats[4] , (HANDLE16)NULL},
-    { CF_DIF, 1, 0, "DIF", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[3], &ClipFormats[5] , (HANDLE16)NULL},
-    { CF_TIFF, 1, 0, "TIFF", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[4], &ClipFormats[6] , (HANDLE16)NULL},
-    { CF_OEMTEXT, 1, 0, "OEM Text", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[5], &ClipFormats[7] , (HANDLE16)NULL},
-    { CF_DIB, 1, 0, "DIB", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[6], &ClipFormats[8] , (HANDLE16)NULL},
-    { CF_PALETTE, 1, 0, "Palette", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[7], &ClipFormats[9] , (HANDLE16)NULL},
-    { CF_PENDATA, 1, 0, "PenData", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[8], &ClipFormats[10] , (HANDLE16)NULL},
-    { CF_RIFF, 1, 0, "RIFF", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[9], &ClipFormats[11] , (HANDLE16)NULL},
-    { CF_WAVE, 1, 0, "Wave", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[10], &ClipFormats[12] , (HANDLE16)NULL},
-    { CF_OWNERDISPLAY, 1, 0, "Owner Display", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[11], &ClipFormats[13] , (HANDLE16)NULL},
-    { CF_DSPTEXT, 1, 0, "DSPText", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[12], &ClipFormats[14] , (HANDLE16)NULL},
-    { CF_DSPMETAFILEPICT, 1, 0, "DSPMetaFile Picture", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[13], &ClipFormats[15] , (HANDLE16)NULL},
-    { CF_DSPBITMAP, 1, 0, "DSPBitmap", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[14], NULL , (HANDLE16)NULL}
+    { CF_TEXT, 1, 0, "Text",  (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, NULL, &ClipFormats[1]},
+    { CF_BITMAP, 1, 0, "Bitmap", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[0], &ClipFormats[2]},
+    { CF_METAFILEPICT, 1, 0, "MetaFile Picture", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[1], &ClipFormats[3]},
+    { CF_SYLK, 1, 0, "Sylk", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[2], &ClipFormats[4]},
+    { CF_DIF, 1, 0, "DIF", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[3], &ClipFormats[5]},
+    { CF_TIFF, 1, 0, "TIFF", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[4], &ClipFormats[6]},
+    { CF_OEMTEXT, 1, 0, "OEM Text", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[5], &ClipFormats[7]},
+    { CF_DIB, 1, 0, "DIB", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[6], &ClipFormats[8]},
+    { CF_PALETTE, 1, 0, "Palette", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[7], &ClipFormats[9]},
+    { CF_PENDATA, 1, 0, "PenData", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[8], &ClipFormats[10]},
+    { CF_RIFF, 1, 0, "RIFF", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[9], &ClipFormats[11]},
+    { CF_WAVE, 1, 0, "Wave", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[10], &ClipFormats[12]},
+    { CF_OWNERDISPLAY, 1, 0, "Owner Display", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[11], &ClipFormats[13]},
+    { CF_DSPTEXT, 1, 0, "DSPText", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[12], &ClipFormats[14]},
+    { CF_DSPMETAFILEPICT, 1, 0, "DSPMetaFile Picture", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[13], &ClipFormats[15]},
+    { CF_DSPBITMAP, 1, 0, "DSPBitmap", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[14], NULL}
     };
 
+
+/**************************************************************************
+ *                Internal Clipboard implementation methods
+ **************************************************************************/
+
+
+/**************************************************************************
+ *                      CLIPBOARD_LookupFormat
+ */
 static LPWINE_CLIPFORMAT __lookup_format( LPWINE_CLIPFORMAT lpFormat, WORD wID )
 {
     while(TRUE)
@@ -70,25 +97,83 @@
     return lpFormat;
 }
 
-/**************************************************************************
- *                      CLIPBOARD_ResetLock
- */
-void CLIPBOARD_ResetLock( HQUEUE16 hqCurrent, HQUEUE16 hqNew )
+LPWINE_CLIPFORMAT CLIPBOARD_LookupFormat( WORD wID )
 {
-    if( hqClipLock == hqCurrent )
-    {
-	if( hqNew )
-	    hqClipLock = hqNew;
-	else
-	{
- 	    hWndClipOwner = 0;
-	    hWndClipWindow = 0;
-	    EmptyClipboard();
-	    hqClipLock = 0;
-	}
-    }
+  return __lookup_format( ClipFormats, wID );
 }
 
+/**************************************************************************
+ *                      CLIPBOARD_IsLocked
+ *  Check if the clipboard cache is available to the caller
+ */
+BOOL CLIPBOARD_IsLocked()
+{
+  BOOL bIsLocked = TRUE;
+  HANDLE16 hTaskCur = GetCurrentTask();
+
+  /*
+   * The clipboard is available:
+   * 1. if the caller's task has opened the clipboard,
+   * or
+   * 2. if the caller is the clipboard owners task, AND is responding to a
+   *    WM_RENDERFORMAT message.
+   */
+  if ( hClipLock == hTaskCur )
+      bIsLocked = FALSE;
+      
+  else if ( hTaskCur == hTaskClipOwner )
+  {
+      /* Check if we're currently executing inside a window procedure
+       * called in response to a WM_RENDERFORMAT message. A WM_RENDERFORMAT
+       * handler is not permitted to open the clipboard since it has been opened
+       * by another client. However the handler must have access to the
+       * clipboard in order to update data in response to this message.
+       */
+      MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() );
+      
+      if ( queue
+           && queue->smWaiting
+           && queue->smWaiting->msg == WM_RENDERFORMAT
+           && queue->smWaiting->hSrcQueue
+         )
+  	bIsLocked = FALSE;
+        
+      QUEUE_Unlock( queue );
+  }
+
+  return bIsLocked;
+}
+
+/**************************************************************************
+ *                      CLIPBOARD_ReleaseOwner
+ *   Gives up ownership of the clipboard
+ */
+void CLIPBOARD_ReleaseOwner()
+{
+   hWndClipOwner = 0;
+   hTaskClipOwner = 0;
+}
+
+/**************************************************************************
+ *                      CLIPBOARD_GlobalFreeProc
+ *
+ * This is a callback mechanism to allow HGLOBAL data to be released in
+ * the context of the process which allocated it. We post a WM_TIMER message
+ * to the owner window(in CLIPBOARD_DeleteRecord) and destroy the data(in idEvent)
+ * in this WndProc, which is invoked when the apps message loop calls DispatchMessage.
+ * This technique is discussed in Matt Pietrek's "Under the Hood".
+ * An article describing the same may be found in MSDN by searching for WM_TIMER.
+ * Note that this mechanism will probably stop working when WINE supports
+ * address space separation. When "queue events" are implemented in Wine we
+ * should switch to using that mechanism, since it is more robust and does not
+ * require a procedure address to be passed. See the SetWinEventHook API for
+ * more info on this.
+ */
+VOID CALLBACK CLIPBOARD_GlobalFreeProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime )
+{
+    /* idEvent is the HGLOBAL to be deleted */
+    GlobalFree( (HGLOBAL)idEvent );
+}
 
 /**************************************************************************
  *			CLIPBOARD_DeleteRecord
@@ -108,9 +193,18 @@
       if (lpFormat->hData32)
       {
         DeleteMetaFile( ((METAFILEPICT *)GlobalLock( lpFormat->hData32 ))->hMF );
-	GlobalFree(lpFormat->hData32);
+        PostMessageA(hWndClipOwner, WM_TIMER,
+                     (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
         if (lpFormat->hDataSrc32)
-          GlobalFree(lpFormat->hDataSrc32);
+        {
+          /* Release lpFormat->hData32 in the context of the process which created it.
+           * See CLIPBOARD_GlobalFreeProc for more details about this technique.
+           * GlobalFree(lpFormat->hDataSrc32);
+           */
+          PostMessageA(hWndClipOwner, WM_TIMER,
+                       (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
+        }
+          
 	if (lpFormat->hData16)
 	  /* HMETAFILE16 and HMETAFILE32 are apparently the same thing, 
 	     and a shallow copy is enough to share a METAFILEPICT
@@ -127,9 +221,23 @@
     else 
     {
       if (lpFormat->hData32)
-	GlobalFree(lpFormat->hData32);
+      {
+        /* Release lpFormat->hData32 in the context of the process which created it.
+         * See CLIPBOARD_GlobalFreeProc for more details about this technique.
+         * GlobalFree( lpFormat->hData32 );
+         */
+        PostMessageA(hWndClipOwner, WM_TIMER,
+                     (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
+      }
       if (lpFormat->hDataSrc32)
-        GlobalFree(lpFormat->hDataSrc32);
+      {
+        /* Release lpFormat->hData32 in the context of the process which created it.
+         * See CLIPBOARD_GlobalFreeProc for more details about this technique.
+         * GlobalFree(lpFormat->hDataSrc32);
+         */
+        PostMessageA(hWndClipOwner, WM_TIMER,
+                     (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
+      }
       if (lpFormat->hData16)
 	GlobalFree16(lpFormat->hData16);
     }
@@ -137,11 +245,29 @@
     lpFormat->wDataPresent = 0; 
     lpFormat->hData16 = 0;
     lpFormat->hData32 = 0;
+    lpFormat->hDataSrc32 = 0;
+    lpFormat->drvData = 0;
 
     if( bChange ) bCBHasChanged = TRUE;
 }
 
 /**************************************************************************
+ *			CLIPBOARD_EmptyCache
+ */
+void CLIPBOARD_EmptyCache( BOOL bChange )
+{
+    LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
+
+    while(lpFormat)
+    {
+	if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 )
+	     CLIPBOARD_DeleteRecord( lpFormat, bChange );
+
+	lpFormat = lpFormat->NextFormat;
+    }
+}
+
+/**************************************************************************
  *			CLIPBOARD_IsPresent
  */
 BOOL CLIPBOARD_IsPresent(WORD wFormat)
@@ -160,6 +286,30 @@
 }
 
 /**************************************************************************
+ *			CLIPBOARD_IsCacheRendered
+ *  Checks if any data needs to be rendered to the clipboard cache
+ *  RETURNS:
+ *    TRUE  - All clipboard data is available in the cache
+ *    FALSE - Some data is marked for delayed render and needs rendering
+ */
+BOOL CLIPBOARD_IsCacheRendered()
+{
+    LPWINE_CLIPFORMAT lpFormat = ClipFormats;
+    
+    /* check if all formats were rendered */
+    while(lpFormat)
+    {
+        if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
+            return FALSE;
+        
+        lpFormat = lpFormat->NextFormat;
+    }
+    
+    return TRUE;
+}
+
+
+/**************************************************************************
  *			CLIPBOARD_IsMemoryObject
  *  Tests if the clipboard format specifies a memory object
  */
@@ -217,6 +367,156 @@
 }
 
 /**************************************************************************
+ *			CLIPBOARD_GetFormatName
+ *  Gets the format name associated with an ID
+ */
+char * CLIPBOARD_GetFormatName(UINT wFormat)
+{
+    LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
+    return (lpFormat) ? lpFormat->Name : NULL;
+}
+
+
+/**************************************************************************
+ *                      CLIPBOARD_RenderFormat
+ */
+static BOOL CLIPBOARD_RenderFormat(LPWINE_CLIPFORMAT lpFormat)
+{
+  /*
+   * If WINE is not the selection owner, and the format is available
+   * we must ask the the driver to render the data to the clipboard cache.
+   */
+  if ( !CLIPBOARD_Driver->pIsSelectionOwner() 
+       && CLIPBOARD_Driver->pIsFormatAvailable( lpFormat->wFormatID ) )
+  {
+    if ( !CLIPBOARD_Driver->pGetData( lpFormat->wFormatID ) )
+      return FALSE;
+  }
+  /*
+   * If Wine owns the clipboard, and the data is marked for delayed render,
+   * render it now.
+   */
+  else if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
+  {
+    if( IsWindow(hWndClipOwner) )
+    {
+      /* Send a WM_RENDERFORMAT message to notify the owner to render the
+       * data requested into the clipboard.
+       */
+      TRACE("Sending WM_RENDERFORMAT message\n");
+      SendMessage16(hWndClipOwner,WM_RENDERFORMAT,
+                    (WPARAM16)lpFormat->wFormatID,0L);
+    }
+    else
+    {
+      WARN("\thWndClipOwner (%04x) is lost!\n", 
+	   hWndClipOwner);
+      CLIPBOARD_ReleaseOwner();
+      lpFormat->wDataPresent = 0;
+      return FALSE;
+    }
+  }
+
+  return (lpFormat->hData16 || lpFormat->hData32) ? TRUE : FALSE;
+}
+
+
+/**************************************************************************
+ *                      CLIPBOARD_RenderText
+ *
+ * Renders text to the clipboard buffer converting between UNIX and DOS formats.
+ *
+ * RETURNS: pointer to the WINE_CLIPFORMAT if successful, NULL otherwise
+ *
+ * FIXME: Should be a pair of driver functions that convert between OEM text and Windows.
+ *
+ */
+static LPWINE_CLIPFORMAT CLIPBOARD_RenderText( UINT wFormat )
+{
+    LPWINE_CLIPFORMAT lpSource = ClipFormats; 
+    LPWINE_CLIPFORMAT lpTarget;
+    
+    /* Asked for CF_TEXT and not available - always attempt to convert from CF_OEM_TEXT */
+    if( wFormat == CF_TEXT && !ClipFormats[CF_TEXT-1].wDataPresent )
+    {
+        /* Convert OEMTEXT -> TEXT */
+        lpSource = &ClipFormats[CF_OEMTEXT-1];
+        lpTarget = &ClipFormats[CF_TEXT-1];
+
+        TRACE("\tOEMTEXT -> TEXT\n");
+    }
+    /* Asked for CF_OEM_TEXT, and CF_TEXT available */
+    else if( wFormat == CF_OEMTEXT && !ClipFormats[CF_OEMTEXT-1].wDataPresent
+				   &&  ClipFormats[CF_TEXT-1].wDataPresent )
+    {
+	/* Convert TEXT -> OEMTEXT */
+        lpSource = &ClipFormats[CF_TEXT-1];
+	lpTarget = &ClipFormats[CF_OEMTEXT-1];
+	
+	TRACE("\tTEXT -> OEMTEXT\n");
+    }
+    /* Text format requested is available - no conversion necessary */
+    else
+    {
+	lpSource = __lookup_format( ClipFormats, wFormat );
+	lpTarget = lpSource;
+    }
+
+    /* First render the source text format */
+    if ( !lpSource || !CLIPBOARD_RenderFormat(lpSource) ) return NULL;
+
+    /* Convert to the desired target text format, if necessary */
+    if( lpTarget != lpSource && !lpTarget->hData16 && !lpTarget->hData32 )
+    {
+        UINT16 size;
+        LPCSTR lpstrS; 
+        LPSTR  lpstrT;
+    
+        if (lpSource->hData32)
+        {
+          size = GlobalSize( lpSource->hData32 );
+          lpstrS = (LPSTR)GlobalLock(lpSource->hData32);
+        }
+        else
+        {
+          size = GlobalSize16( lpSource->hData16 );
+          lpstrS = (LPSTR)GlobalLock16(lpSource->hData16);
+        }
+    
+        if( !lpstrS ) return NULL;
+        TRACE("\tconverting from '%s' to '%s', %i chars\n",
+                                          lpSource->Name, lpTarget->Name, size);
+    
+        lpTarget->hData32 = GlobalAlloc(GMEM_ZEROINIT, size);
+        lpstrT = (LPSTR)GlobalLock(lpTarget->hData32);
+    
+        if( lpstrT )
+        {
+            if( lpSource->wFormatID == CF_TEXT )
+                CharToOemBuffA(lpstrS, lpstrT, size);
+            else
+                OemToCharBuffA(lpstrS, lpstrT, size);
+            TRACE("\tgot %s\n", lpstrT);
+            GlobalUnlock(lpTarget->hData32);
+        }
+        else
+            lpTarget->hData32 = 0;
+
+        /* Unlock source */
+        if (lpSource->hData32)
+          GlobalUnlock(lpSource->hData32);
+        else
+          GlobalUnlock16(lpSource->hData16);
+    }
+
+    return (lpTarget->hData16 || lpTarget->hData32) ? lpTarget : NULL;
+}
+
+/**************************************************************************
+ *                WIN32 Clipboard implementation 
+ **************************************************************************/
+
+/**************************************************************************
  *            OpenClipboard16   (USER.137)
  */
 BOOL16 WINAPI OpenClipboard16( HWND16 hWnd )
@@ -236,12 +536,14 @@
 
     TRACE("(%04x)...\n", hWnd);
 
-    if (!hqClipLock)
+    if (!hClipLock)
     {
-	 hqClipLock = GetFastQueue16();
-    	 hWndClipWindow = hWnd;
-	 bCBHasChanged = FALSE;
-	 bRet = TRUE;
+        hClipLock = GetCurrentTask();
+
+        /* Save current user of the clipboard */
+        hWndClipWindow = hWnd;
+        bCBHasChanged = FALSE;
+        bRet = TRUE;
     }
     else bRet = FALSE;
 
@@ -264,15 +566,15 @@
  */
 BOOL WINAPI CloseClipboard(void)
 {
-    TRACE("!\n");
+    TRACE("()\n");
 
-    if (hqClipLock == GetFastQueue16())
+    if (hClipLock == GetCurrentTask())
     {
 	hWndClipWindow = 0;
 
         if (bCBHasChanged && hWndViewer) 
 	    SendMessage16(hWndViewer, WM_DRAWCLIPBOARD, 0, 0L);
-	hqClipLock = 0;
+	hClipLock = 0;
     }
     return TRUE;
 }
@@ -289,31 +591,34 @@
 
 /**************************************************************************
  *            EmptyClipboard32   (USER32.169)
+ *  Empties and acquires ownership of the clipboard
  */
 BOOL WINAPI EmptyClipboard(void)
 {
-    LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
+    TRACE("()\n");
 
-    TRACE("(void)\n");
-
-    if (hqClipLock != GetFastQueue16()) return FALSE;
-
+    if (hClipLock != GetCurrentTask())
+    {
+        WARN("Clipboard not opened by calling task!");
+        return FALSE;
+    }
+    
     /* destroy private objects */
 
     if (hWndClipOwner)
 	SendMessage16(hWndClipOwner, WM_DESTROYCLIPBOARD, 0, 0L);
-  
-    while(lpFormat) 
-    {
-	if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 )
-	     CLIPBOARD_DeleteRecord( lpFormat, TRUE );
 
-	lpFormat = lpFormat->NextFormat;
-    }
+    /* empty the cache */
+    CLIPBOARD_EmptyCache(TRUE);
 
+    /* Assign ownership of the clipboard to the current client */
     hWndClipOwner = hWndClipWindow;
 
-    CLIPBOARD_Driver->pEmpty();
+    /* Save the current task */
+    hTaskClipOwner = GetCurrentTask();
+    
+    /* Tell the driver to acquire the selection */
+    CLIPBOARD_Driver->pAcquire();
 
     return TRUE;
 }
@@ -321,18 +626,22 @@
 
 /**************************************************************************
  *            GetClipboardOwner16   (USER.140)
+ *  FIXME: Can't return the owner if the clipbard is owned by an external app
  */
 HWND16 WINAPI GetClipboardOwner16(void)
 {
+    TRACE("()\n");
     return hWndClipOwner;
 }
 
 
 /**************************************************************************
  *            GetClipboardOwner32   (USER32.225)
+ *  FIXME: Can't return the owner if the clipbard is owned by an external app
  */
 HWND WINAPI GetClipboardOwner(void)
 {
+    TRACE("()\n");
     return hWndClipOwner;
 }
 
@@ -348,14 +657,19 @@
 
     /* NOTE: If the hData is zero and current owner doesn't match
      * the window that opened the clipboard then this application
-     * is screwed because WM_RENDERFORMAT will go to the owner
+     * is screwed because WM_RENDERFORMAT will go to the owner.
      * (to become the owner it must call EmptyClipboard() before
      *  adding new data).
      */
 
-    if( (hqClipLock != GetFastQueue16()) || !lpFormat ||
-	(!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) ) return 0; 
+    if( CLIPBOARD_IsLocked() || !lpFormat ||
+        (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
+    {
+        WARN("Invalid hData or clipboard not opened by calling task!");
+        return 0;
+    }
 
+    /* Pass on the request to the driver */
     CLIPBOARD_Driver->pSetData(wFormat);
 
     if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 ) 
@@ -396,17 +710,23 @@
 
     /* NOTE: If the hData is zero and current owner doesn't match
      * the window that opened the clipboard then this application
-     * is screwed because WM_RENDERFORMAT will go to the owner
+     * is screwed because WM_RENDERFORMAT will go to the owner.
      * (to become the owner it must call EmptyClipboard() before
      *  adding new data).
      */
 
-    if( (hqClipLock != GetFastQueue16()) || !lpFormat ||
-	(!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) ) return 0; 
+    if( CLIPBOARD_IsLocked() || !lpFormat ||
+        (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
+    {
+        WARN("Invalid hData or clipboard not opened by calling task!");
+        return 0;
+    }
 
-    CLIPBOARD_Driver->pSetData(wFormat);
+    /* Tell the driver to acquire the selection */
+    CLIPBOARD_Driver->pAcquire();
 
-    if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 ) 
+    if ( lpFormat->wDataPresent &&
+         (lpFormat->hData16 || lpFormat->hData32) )
     {
 	CLIPBOARD_DeleteRecord(lpFormat, TRUE);
 
@@ -435,163 +755,76 @@
     if ( CLIPBOARD_IsMemoryObject(wFormat) && hData && !(GlobalFlags(hData) & GMEM_DDESHARE) )
         lpFormat->hData32 = CLIPBOARD_GlobalDupMem( hData );
     else
-    lpFormat->hData32 = hData;          /* 0 is legal, see WM_RENDERFORMAT */
+        lpFormat->hData32 = hData;          /* 0 is legal, see WM_RENDERFORMAT */
     
     lpFormat->hData16 = 0;
 
-    return lpFormat->hData32;
+    return lpFormat->hData32;   /* Should we return lpFormat->hDataSrc32 */
 }
 
 
 /**************************************************************************
- *                      CLIPBOARD_RenderFormat
- */
-static BOOL CLIPBOARD_RenderFormat(LPWINE_CLIPFORMAT lpFormat)
-{
-  if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
-  {
-    if( IsWindow(hWndClipOwner) )
-      SendMessage16(hWndClipOwner,WM_RENDERFORMAT,
-		    (WPARAM16)lpFormat->wFormatID,0L);
-    else
-    {
-      WARN("\thWndClipOwner (%04x) is lost!\n", 
-	   hWndClipOwner);
-      hWndClipOwner = 0; lpFormat->wDataPresent = 0;
-      return FALSE;
-    }
-  }
-  return (lpFormat->hData16 || lpFormat->hData32) ? TRUE : FALSE;
-}
-
-/**************************************************************************
- *                      CLIPBOARD_RenderText
- *
- * Convert text between UNIX and DOS formats.
- *
- * FIXME: Should be a pair of driver functions that convert between OEM text and Windows.
- *
- */
-static BOOL CLIPBOARD_RenderText(LPWINE_CLIPFORMAT lpTarget, LPWINE_CLIPFORMAT lpSource)
-{
-    UINT16 size;
-    LPCSTR lpstrS; 
-    LPSTR  lpstrT;
-
-    if (lpSource->hData32)
-    {
-      size = GlobalSize( lpSource->hData32 );
-      lpstrS = (LPSTR)GlobalLock(lpSource->hData32);
-    }
-    else
-    {
-      size = GlobalSize16( lpSource->hData16 );
-      lpstrS = (LPSTR)GlobalLock16(lpSource->hData16);
-    }
-
-    if( !lpstrS ) return FALSE;
-    TRACE("\tconverting from '%s' to '%s', %i chars\n",
-			   	      lpSource->Name, lpTarget->Name, size);
-
-    lpTarget->hData32 = GlobalAlloc(GMEM_ZEROINIT, size); 
-    lpstrT = (LPSTR)GlobalLock(lpTarget->hData32);
-
-    if( lpstrT )
-    {
-	if( lpSource->wFormatID == CF_TEXT )
-	    CharToOemBuffA(lpstrS, lpstrT, size);
-	else
-	    OemToCharBuffA(lpstrS, lpstrT, size);
-	TRACE("\tgot %s\n", lpstrT);
-	GlobalUnlock(lpTarget->hData32);
-	if (lpSource->hData32)
-	  GlobalUnlock(lpSource->hData32);
-	else
-	  GlobalUnlock16(lpSource->hData16);
-	return TRUE;
-    }
-
-    lpTarget->hData32 = 0;
-    if (lpSource->hData32)
-      GlobalUnlock(lpSource->hData32);
-    else
-      GlobalUnlock16(lpSource->hData16);
-    return FALSE;
-}
-
-/**************************************************************************
  *             GetClipboardData16   (USER.142)
  */
 HANDLE16 WINAPI GetClipboardData16( UINT16 wFormat )
 {
     LPWINE_CLIPFORMAT lpRender = ClipFormats; 
-    LPWINE_CLIPFORMAT lpUpdate = NULL;
-
-    if (hqClipLock != GetFastQueue16()) return 0;
 
     TRACE("(%04X)\n", wFormat);
 
-    if( wFormat == CF_TEXT && !lpRender[CF_TEXT-1].wDataPresent 
-			   &&  lpRender[CF_OEMTEXT-1].wDataPresent )
+    if (CLIPBOARD_IsLocked())
     {
-	lpRender = &ClipFormats[CF_OEMTEXT-1];
-	lpUpdate = &ClipFormats[CF_TEXT-1];
-
-	TRACE("\tOEMTEXT -> TEXT\n");
+        WARN("Clipboard not opened by calling task!");
+        return 0;
     }
-    else if( wFormat == CF_OEMTEXT && !lpRender[CF_OEMTEXT-1].wDataPresent
-				   &&  lpRender[CF_TEXT-1].wDataPresent )
+
+    if( wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
     {
-        lpRender = &ClipFormats[CF_TEXT-1];
-	lpUpdate = &ClipFormats[CF_OEMTEXT-1];
-	
-	TRACE("\tTEXT -> OEMTEXT\n");
+	lpRender = CLIPBOARD_RenderText(wFormat);
+        if ( !lpRender ) return 0;
     }
     else
     {
 	lpRender = __lookup_format( ClipFormats, wFormat );
-	lpUpdate = lpRender;
+        if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
     }
    
-    if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0; 
-    if( lpUpdate != lpRender && !lpUpdate->hData16 && !lpUpdate->hData32 ) 
-	CLIPBOARD_RenderText(lpUpdate, lpRender);
-
-    if( lpUpdate->hData32 && !lpUpdate->hData16 )
+    /* Convert between 32 -> 16 bit data, if necessary */
+    if( lpRender->hData32 && !lpRender->hData16 )
     {
       int size;
-      if( lpUpdate->wFormatID == CF_METAFILEPICT )
+      if( lpRender->wFormatID == CF_METAFILEPICT )
 	size = sizeof( METAFILEPICT16 );
       else
-	size = GlobalSize(lpUpdate->hData32);
-      lpUpdate->hData16 = GlobalAlloc16(GMEM_ZEROINIT, size);
-      if( !lpUpdate->hData16 )
+	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( lpUpdate->wFormatID == CF_METAFILEPICT )
+      if( lpRender->wFormatID == CF_METAFILEPICT )
       {
 	FIXME("\timplement function CopyMetaFilePict32to16\n");
 	FIXME("\tin the appropriate file.\n");
 #ifdef SOMEONE_IMPLEMENTED_ME
-	CopyMetaFilePict32to16( GlobalLock16(lpUpdate->hData16), 
-			        GlobalLock(lpUpdate->hData32) );
+	CopyMetaFilePict32to16( GlobalLock16(lpRender->hData16), 
+			        GlobalLock(lpRender->hData32) );
 #endif
       }
       else
       {
-	memcpy( GlobalLock16(lpUpdate->hData16), 
-		GlobalLock(lpUpdate->hData32), 
+	memcpy( GlobalLock16(lpRender->hData16), 
+		GlobalLock(lpRender->hData32), 
 		size );
       }
-	GlobalUnlock16(lpUpdate->hData16);
-	GlobalUnlock(lpUpdate->hData32);
+	GlobalUnlock16(lpRender->hData16);
+	GlobalUnlock(lpRender->hData32);
       }
     }
 
     TRACE("\treturning %04x (type %i)\n", 
-			      lpUpdate->hData16, lpUpdate->wFormatID);
-    return lpUpdate->hData16;
+			      lpRender->hData16, lpRender->wFormatID);
+    return lpRender->hData16;
 }
 
 
@@ -601,71 +834,61 @@
 HANDLE WINAPI GetClipboardData( UINT wFormat )
 {
     LPWINE_CLIPFORMAT lpRender = ClipFormats; 
-    LPWINE_CLIPFORMAT lpUpdate = NULL;
-
-    if (hqClipLock != GetFastQueue16()) return 0;
 
     TRACE("(%08X)\n", wFormat);
 
-    if( wFormat == CF_TEXT && !lpRender[CF_TEXT-1].wDataPresent 
-			   &&  lpRender[CF_OEMTEXT-1].wDataPresent )
+    if (CLIPBOARD_IsLocked())
     {
-	lpRender = &ClipFormats[CF_OEMTEXT-1];
-	lpUpdate = &ClipFormats[CF_TEXT-1];
-
-	TRACE("\tOEMTEXT -> TEXT\n");
+        WARN("Clipboard not opened by calling task!");
+        return 0;
     }
-    else if( wFormat == CF_OEMTEXT && !lpRender[CF_OEMTEXT-1].wDataPresent
-				   &&  lpRender[CF_TEXT-1].wDataPresent )
+
+    if( wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
     {
-        lpRender = &ClipFormats[CF_TEXT-1];
-	lpUpdate = &ClipFormats[CF_OEMTEXT-1];
-	
-	TRACE("\tTEXT -> OEMTEXT\n");
+	lpRender = CLIPBOARD_RenderText(wFormat);
+        if ( !lpRender ) return 0;
     }
     else
     {
 	lpRender = __lookup_format( ClipFormats, wFormat );
-	lpUpdate = lpRender;
+        if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
     }
    
-    if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0; 
-    if( lpUpdate != lpRender && !lpUpdate->hData16 && !lpUpdate->hData32 ) 
-	CLIPBOARD_RenderText(lpUpdate, lpRender);
-
-    if( lpUpdate->hData16 && !lpUpdate->hData32 )
+    /* Convert between 16 -> 32 bit data, if necessary */
+    if( lpRender->hData16 && !lpRender->hData32 )
     {
       int size;
-      if( lpUpdate->wFormatID == CF_METAFILEPICT )
+      if( lpRender->wFormatID == CF_METAFILEPICT )
 	size = sizeof( METAFILEPICT );
       else
-	size = GlobalSize16(lpUpdate->hData16);
-      lpUpdate->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE,
+	size = GlobalSize16(lpRender->hData16);
+      lpRender->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE,
                                       size);
-      if( lpUpdate->wFormatID == CF_METAFILEPICT )
+      if( lpRender->wFormatID == CF_METAFILEPICT )
       {
 	FIXME("\timplement function CopyMetaFilePict16to32\n");
 	FIXME("\tin the appropriate file.\n");
 #ifdef SOMEONE_IMPLEMENTED_ME
-	CopyMetaFilePict16to32( GlobalLock16(lpUpdate->hData32), 
-			        GlobalLock(lpUpdate->hData16) );
+	CopyMetaFilePict16to32( GlobalLock16(lpRender->hData32), 
+			        GlobalLock(lpRender->hData16) );
 #endif
       }
       else
       {
-	memcpy( GlobalLock(lpUpdate->hData32), 
-		GlobalLock16(lpUpdate->hData16), 
+	memcpy( GlobalLock(lpRender->hData32), 
+		GlobalLock16(lpRender->hData16), 
 		size );
       }
-      GlobalUnlock(lpUpdate->hData32);
-      GlobalUnlock16(lpUpdate->hData16);
+      GlobalUnlock(lpRender->hData32);
+      GlobalUnlock16(lpRender->hData16);
     }
 
     TRACE("\treturning %04x (type %i)\n", 
-			      lpUpdate->hData32, lpUpdate->wFormatID);
-    return lpUpdate->hData32;
+			      lpRender->hData32, lpRender->wFormatID);
+    return lpRender->hData32;
 }
 
+
 /**************************************************************************
  *           CountClipboardFormats16   (USER.143)
  */
@@ -683,20 +906,30 @@
     INT FormatCount = 0;
     LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
 
-    TRACE("(void)\n");
+    TRACE("()\n");
 
     while(TRUE) 
     {
 	if (lpFormat == NULL) break;
 
- 	if( lpFormat->wFormatID != CF_TEXT )
- 	    CLIPBOARD_Driver->pGetData( lpFormat->wFormatID );
- 
-	if (lpFormat->wDataPresent) 
-	{
-            TRACE("\tdata found for format %i\n", lpFormat->wFormatID);
-	    FormatCount++;
-	}
+        if( lpFormat->wFormatID != CF_TEXT ) /* Don't count CF_TEXT */
+        {
+          /*
+           * The format is available if either:
+           * 1. The data is already in the cache.
+           * 2. The selection is not owned by us(WINE) and the data is
+           *    available to the clipboard driver.
+           */
+          if ( lpFormat->wDataPresent ||
+               ( !CLIPBOARD_Driver->pIsSelectionOwner()
+                 && CLIPBOARD_Driver->pIsFormatAvailable( lpFormat->wFormatID ) ) )
+          {
+              TRACE("\tdata found for format %i(%s)\n",
+                    lpFormat->wFormatID, CLIPBOARD_GetFormatName(lpFormat->wFormatID));
+              FormatCount++;
+          }
+        }
+
 	lpFormat = lpFormat->NextFormat;
     }
 
@@ -724,14 +957,16 @@
  */
 UINT WINAPI EnumClipboardFormats( UINT wFormat )
 {
-    LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
+    LPWINE_CLIPFORMAT lpFormat = ClipFormats;
+    BOOL bFormatPresent;
 
     TRACE("(%04X)\n", wFormat);
 
-    if( hqClipLock != GetFastQueue16() ) return 0;
-
-    if( wFormat < CF_OEMTEXT )
-        CLIPBOARD_Driver->pGetData( CF_OEMTEXT );
+    if (CLIPBOARD_IsLocked())
+    {
+        WARN("Clipboard not opened by calling task!");
+        return 0;
+    }
 
     if (wFormat == 0) /* start from the beginning */
 	lpFormat = ClipFormats;
@@ -748,13 +983,22 @@
     {
 	if (lpFormat == NULL) return 0;
 
-	if( lpFormat->wFormatID != CF_OEMTEXT && lpFormat->wFormatID != CF_TEXT )
-	    CLIPBOARD_Driver->pGetData( lpFormat->wFormatID );
+        /* Synthesize CF_TEXT from CF_OEMTEXT and vice versa */
+	bFormatPresent = (lpFormat->wDataPresent ||
+           (lpFormat->wFormatID == CF_OEMTEXT && ClipFormats[CF_TEXT-1].wDataPresent) ||
+	   (lpFormat->wFormatID == CF_TEXT && ClipFormats[CF_OEMTEXT-1].wDataPresent) );
 
-	if (lpFormat->wDataPresent || 
-	   (lpFormat->wFormatID == CF_OEMTEXT && ClipFormats[CF_TEXT-1].wDataPresent) ||
-	   (lpFormat->wFormatID == CF_TEXT && ClipFormats[CF_OEMTEXT-1].wDataPresent) )
+        /* Query the driver if not yet in the cache */
+        if (!bFormatPresent && !CLIPBOARD_Driver->pIsSelectionOwner())
+        {
+            bFormatPresent =
+               CLIPBOARD_Driver->pIsFormatAvailable( (lpFormat->wFormatID == CF_TEXT) ?
+                                                      CF_OEMTEXT : lpFormat->wFormatID );
+        }
+
+	if (bFormatPresent)
 	    break;
+
 	lpFormat = lpFormat->NextFormat;
     }
 
@@ -803,10 +1047,13 @@
     lpNewFormat->hData16 = 0;
     lpNewFormat->hDataSrc32 = 0;
     lpNewFormat->hData32 = 0;
-    lpNewFormat->BufSize = 0;
+    lpNewFormat->drvData = 0;
     lpNewFormat->PrevFormat = lpFormat;
     lpNewFormat->NextFormat = NULL;
 
+    /* Pass on the registration request to the driver */
+    CLIPBOARD_Driver->pRegisterFormat( FormatName );
+    
     return LastRegFormat++;
 }
 
@@ -831,6 +1078,7 @@
     return ret;
 }
 
+
 /**************************************************************************
  *            GetClipboardFormatName16   (USER.146)
  */
@@ -877,6 +1125,7 @@
  */
 HWND16 WINAPI SetClipboardViewer16( HWND16 hWnd )
 {
+    TRACE("(%04x)\n", hWnd);
     return SetClipboardViewer( hWnd );
 }
 
@@ -900,6 +1149,7 @@
  */
 HWND16 WINAPI GetClipboardViewer16(void)
 {
+    TRACE("()\n");
     return hWndViewer;
 }
 
@@ -909,6 +1159,7 @@
  */
 HWND WINAPI GetClipboardViewer(void)
 {
+    TRACE("()\n");
     return hWndViewer;
 }
 
@@ -921,6 +1172,7 @@
     return ChangeClipboardChain(hWnd, hWndNext);
 }
 
+
 /**************************************************************************
  *           ChangeClipboardChain32   (USER32.22)
  */
@@ -942,7 +1194,6 @@
 }
 
 
-
 /**************************************************************************
  *           IsClipboardFormatAvailable16   (USER.193)
  */
@@ -957,28 +1208,42 @@
  */
 BOOL WINAPI IsClipboardFormatAvailable( UINT wFormat )
 {
-    TRACE("(%04X) !\n", wFormat);
+    BOOL bRet;
 
-    CLIPBOARD_Driver->pGetData( (wFormat == CF_TEXT) ? CF_OEMTEXT : wFormat );
+    if (wFormat == 0)  /* Reject this case quickly */
+        bRet = FALSE;
 
-    return CLIPBOARD_IsPresent(wFormat);
+    /* If WINE is not the clipboard selection owner ask the clipboard driver */
+    else if ( !CLIPBOARD_Driver->pIsSelectionOwner() )
+        bRet = CLIPBOARD_Driver->pIsFormatAvailable( (wFormat == CF_TEXT) ?
+                                                     CF_OEMTEXT : wFormat );
+    /* Check if the format is in the local cache */
+    else 
+        bRet = CLIPBOARD_IsPresent(wFormat);
+
+    TRACE("(%04X)- ret(%d)\n", wFormat, bRet);
+    return bRet;
 }
 
 
 /**************************************************************************
  *             GetOpenClipboardWindow16   (USER.248)
+ *  FIXME: This wont work if an external app owns the selection
  */
 HWND16 WINAPI GetOpenClipboardWindow16(void)
 {
+    TRACE("()\n");
     return hWndClipWindow;
 }
 
 
 /**************************************************************************
  *             GetOpenClipboardWindow32   (USER32.277)
+ *  FIXME: This wont work if an external app owns the selection
  */
 HWND WINAPI GetOpenClipboardWindow(void)
 {
+    TRACE("()\n");
     return hWndClipWindow;
 }
 
@@ -999,6 +1264,7 @@
 INT WINAPI GetPriorityClipboardFormat( UINT *lpPriorityList, INT nCount )
 {
     int Counter;
+    TRACE("()\n");
 
     if(CountClipboardFormats() == 0) 
     { 
@@ -1014,5 +1280,3 @@
     return -1;
 }
 
-
-
diff --git a/windows/ttydrv/clipboard.c b/windows/ttydrv/clipboard.c
index f608b7c..d836d80 100644
--- a/windows/ttydrv/clipboard.c
+++ b/windows/ttydrv/clipboard.c
@@ -13,9 +13,16 @@
 char *TTYDRV_CLIPBOARD_szSelection = NULL;
 
 /***********************************************************************
- *		TTYDRV_CLIPBOARD_EmptyClipboard
+ *		TTYDRV_CLIPBOARD_Acquire
  */
-void TTYDRV_CLIPBOARD_Empty()
+void TTYDRV_CLIPBOARD_Acquire()
+{
+}
+
+/***********************************************************************
+ *		TTYDRV_CLIPBOARD_Release
+ */
+void TTYDRV_CLIPBOARD_Release()
 {
   if(TTYDRV_CLIPBOARD_szSelection)
     {
@@ -40,6 +47,35 @@
 }
 
 /***********************************************************************
+ *		TTYDRV_CLIPBOARD_IsFormatAvailable
+ */
+BOOL TTYDRV_CLIPBOARD_IsFormatAvailable(UINT wFormat)
+{
+  return FALSE;
+}
+
+/**************************************************************************
+ *		TTYDRV_CLIPBOARD_RegisterFormat
+ *
+ * Registers a custom clipboard format
+ * Returns: TRUE - new format registered, FALSE - Format already registered
+ */
+BOOL TTYDRV_CLIPBOARD_RegisterFormat( LPCSTR FormatName )
+{
+  return TRUE;
+}
+
+/**************************************************************************
+ *		X11DRV_CLIPBOARD_IsSelectionowner
+ *
+ * Returns: TRUE - We(WINE) own the selection, FALSE - Selection not owned by us
+ */
+BOOL TTYDRV_CLIPBOARD_IsSelectionowner()
+{
+    return FALSE;
+}
+
+/***********************************************************************
  *		TTYDRV_CLIPBOARD_ResetOwner
  */
 void TTYDRV_CLIPBOARD_ResetOwner(WND *pWnd, BOOL bFooBar)
diff --git a/windows/ttydrv/init.c b/windows/ttydrv/init.c
index 4e1b8c5..1cacee2 100644
--- a/windows/ttydrv/init.c
+++ b/windows/ttydrv/init.c
@@ -24,9 +24,13 @@
 
 CLIPBOARD_DRIVER TTYDRV_CLIPBOARD_Driver =
 {
-  TTYDRV_CLIPBOARD_Empty,
+  TTYDRV_CLIPBOARD_Acquire,
+  TTYDRV_CLIPBOARD_Release,
   TTYDRV_CLIPBOARD_SetData,
   TTYDRV_CLIPBOARD_GetData,
+  TTYDRV_CLIPBOARD_IsFormatAvailable,
+  TTYDRV_CLIPBOARD_RegisterFormat,
+  TTYDRV_CLIPBOARD_IsSelectionowner,
   TTYDRV_CLIPBOARD_ResetOwner
 };
 
diff --git a/windows/user.c b/windows/user.c
index ea30472..9297ee7 100644
--- a/windows/user.c
+++ b/windows/user.c
@@ -153,7 +153,6 @@
 
         QUEUE_SetExitingQueue( hQueue );
         WIN_ResetQueueWindows( desktop, hQueue, (HQUEUE16)0);
-        CLIPBOARD_ResetLock( hQueue, 0 );
         QUEUE_SetExitingQueue( 0 );
 
         /* Free the message queue */
@@ -168,8 +167,13 @@
  */
 static void USER_AppExit( HINSTANCE16 hInstance )
 {
-    /* FIXME: empty clipboard if needed, maybe destroy menus (Windows
-     *	      only complains about them but does nothing);
+    /* FIXME: maybe destroy menus (Windows only complains about them
+     * but does nothing);
+     */
+
+    /*  TODO: Start up persistant WINE X clipboard server process which will
+     *  take ownership of the X selection and continue to service selection
+     *  requests from other apps.
      */
 
     /* ModuleUnload() in "Internals" */
diff --git a/windows/x11drv/clipboard.c b/windows/x11drv/clipboard.c
index 5ed4d24..6636a4e 100644
--- a/windows/x11drv/clipboard.c
+++ b/windows/x11drv/clipboard.c
@@ -1,8 +1,50 @@
 /*
- * X11 windows driver
+ * X11 clipboard windows driver
  *
  * Copyright 1994 Martin Ayotte
  *	     1996 Alex Korobka
+ *	     1999 Noel Borthwick
+ *
+ * NOTES:
+ *    This file contains the X specific implementation for the windows
+ *    Clipboard API.
+ *
+ *    Wine's internal clipboard is exposed to external apps via the X
+ *    selection mechanism.
+ *    Currently the driver asserts ownership via two selection atoms:
+ *    1. PRIMARY(XA_PRIMARY)
+ *    2. CLIPBOARD
+ *
+ *    In our implementation, the CLIPBOARD selection takes precedence over PRIMARY.
+ *    i.e. if a CLIPBOARD selection is available, it is used instead of PRIMARY.
+ *    When Wine taks ownership of the clipboard, it takes ownership of BOTH selections.
+ *    While giving up selection ownership, if the CLIPBOARD selection is lost,
+ *    it will lose both PRIMARY and CLIPBOARD and empty the clipboard.
+ *    However if only PRIMARY is lost, it will continue to hold the CLIPBOARD selection
+ *    (leaving the clipboard cache content unaffected).
+ *
+ *      Every format exposed via a windows clipboard format is also exposed through
+ *    a corresponding X selection target. A selection target atom is synthesized
+ *    whenever a new Windows clipboard format is registered via RegisterClipboardFormat,
+ *    or when a built in format is used for the first time.
+ *    Windows native format are exposed by prefixing the format name with "<WCF>"
+ *    This allows us to uniquely identify windows native formats exposed by other
+ *    running WINE apps.
+ *
+ *      In order to allow external applications to query WINE for supported formats,
+ *    we respond to the "TARGETS" selection target. (See EVENT_SelectionRequest
+ *    for implementation) We use the same mechanism to query external clients for
+ *    availability of a particular format, by cacheing the list of available targets
+ *    by using the clipboard cache's "delayed render" mechanism. If a selection client
+ *    does not support the "TARGETS" selection target, we actually attempt to retrieve
+ *    the format requested as a fallback mechanism.
+ *
+ *      Certain Windows native formats are automatically converted to X native formats
+ *    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"
@@ -10,6 +52,7 @@
 #ifndef X_DISPLAY_MISSING
 
 #include <X11/Xatom.h>
+#include <string.h>
 #include "ts_xlib.h"
 
 #include "wine/winuser16.h"
@@ -22,129 +65,435 @@
 
 DEFAULT_DEBUG_CHANNEL(clipboard)
 
-extern HWND hWndClipOwner;
-extern HWND hWndClipWindow;
-extern WINE_CLIPFORMAT ClipFormats[];
+/* Selection masks */
 
-static Bool   selectionAcquired = False;
-static Window selectionWindow = None;
-static Window selectionPrevWindow = None;
+#define S_NOSELECTION    0
+#define S_PRIMARY        1
+#define S_CLIPBOARD      2
+
+/* X selection context info */
+
+static char _CLIPBOARD[] = "CLIPBOARD";        /* CLIPBOARD atom name */
+static char FMT_PREFIX[] = "<WCF>";            /* Prefix for windows specific formats */
+static int    selectionAcquired = 0;           /* Contains the current selection masks */
+static Window selectionWindow = None;          /* The top level X window which owns the selection */
+static Window selectionPrevWindow = None;      /* The last X window that owned the selection */
+static Window PrimarySelectionOwner = None;    /* The window which owns the primary selection */
+static Window ClipboardSelectionOwner = None;  /* The window which owns the clipboard selection */
+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 */
+
 
 /**************************************************************************
- * 		X11DRV_CLIPBOARD_CheckSelection	[Internal]
+ *		X11DRV_CLIPBOARD_MapPropertyToID
  *
- * Prevent X selection from being lost when a top level window is
- * destroyed.
+ *  Map an X selection property type atom name to a windows clipboard format ID
  */
-static void X11DRV_CLIPBOARD_CheckSelection(WND* pWnd)
+UINT X11DRV_CLIPBOARD_MapPropertyToFormat(char *itemFmtName)
 {
-    TRACE("\tchecking %08x\n",
-        (unsigned) X11DRV_WND_GetXWindow(pWnd)
-    );
+    /*
+     * If the property name starts with FMT_PREFIX strip this off and
+     * get the ID for a custom Windows registered format with this name.
+     * We can also understand STRING, PIXMAP and BITMAP.
+     */
+    if ( NULL == itemFmtName )
+        return 0;
+    else if ( 0 == strncmp(itemFmtName, FMT_PREFIX, strlen(FMT_PREFIX)) )
+        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;
 
-    if( selectionAcquired && selectionWindow != None &&
-        X11DRV_WND_GetXWindow(pWnd) == selectionWindow )
+    WARN("\tNo mapping to Windows clipboard format for property %s\n", itemFmtName);
+    return 0;
+}
+
+/**************************************************************************
+ *		X11DRV_CLIPBOARD_MapFormatToProperty
+ *
+ *  Map a windows clipboard format ID to an X selection property atom
+ */
+Atom X11DRV_CLIPBOARD_MapFormatToProperty(UINT wFormat)
+{
+    Atom prop = None;
+    
+    switch (wFormat)
     {
-	selectionPrevWindow = selectionWindow;
-	selectionWindow = None;
+        case CF_OEMTEXT:
+        case CF_TEXT:
+            prop = XA_STRING;
+            break;
 
-	if( pWnd->next ) 
-	    selectionWindow = X11DRV_WND_GetXWindow(pWnd->next);
-	else if( pWnd->parent )
-             if( pWnd->parent->child != pWnd ) 
-                 selectionWindow = X11DRV_WND_GetXWindow(pWnd->parent->child);
+        case CF_DIB:
+        case CF_BITMAP:
+        {
+            /*
+             * Request a PIXMAP, only if WINE is NOT the selection owner,
+             * AND the requested format is not in the cache.
+             */
+            if ( !X11DRV_CLIPBOARD_IsSelectionowner() && !CLIPBOARD_IsPresent(wFormat) )
+            {
+              prop = XA_PIXMAP;
+              break;
+            }
+            /* Fall thru to the default case in order to use the native format */
+        }
+        
+        default:
+        {
+            /*
+             * If an X atom is registered for this format, return that
+             * Otherwise register a new atom.
+             */
+            char str[256];
+            char *fmtName = CLIPBOARD_GetFormatName(wFormat);
+            strcpy(str, FMT_PREFIX);
 
-	TRACE("\tswitching selection from %08x to %08x\n", 
-                    (unsigned)selectionPrevWindow, (unsigned)selectionWindow);
-
-	if( selectionWindow != None )
-	{
-	    TSXSetSelectionOwner(display, XA_PRIMARY, selectionWindow, CurrentTime);
-	    if( TSXGetSelectionOwner(display, XA_PRIMARY) != selectionWindow )
-		selectionWindow = None;
-	}
+            if (fmtName)
+            {
+                strncat(str, fmtName, sizeof(str) - strlen(FMT_PREFIX));
+                prop = TSXInternAtom(display, str, False);
+            }
+            break;
+        }
     }
+
+    if (prop == None)
+        TRACE("\tNo mapping to X property for Windows clipboard format %d(%s)\n",
+              wFormat, CLIPBOARD_GetFormatName(wFormat));
+    
+    return prop;
+}
+
+/**************************************************************************
+ *	        X11DRV_CLIPBOARD_IsNativeProperty
+ *
+ *  Checks if a property is a native property type
+ */
+BOOL X11DRV_CLIPBOARD_IsNativeProperty(Atom prop)
+{
+    char *itemFmtName = TSXGetAtomName(display, prop);
+    BOOL bRet = FALSE;
+    
+    if ( 0 == strncmp(itemFmtName, FMT_PREFIX, strlen(FMT_PREFIX)) )
+        bRet = TRUE;
+    
+    TSXFree(itemFmtName);
+    return bRet;
+}
+
+/**************************************************************************
+ *		X11DRV_CLIPBOARD_CacheDataFormats
+ *
+ * Caches the list of data formats available from the current selection.
+ * This queries the selection owner for the TARGETS property and saves all
+ * reported property types.
+ */
+int X11DRV_CLIPBOARD_CacheDataFormats( Atom SelectionName )
+{
+    HWND           hWnd = NULL;
+    HWND           hWndClipWindow = GetOpenClipboardWindow();
+    WND*           wnd = NULL;
+    XEvent         xe;
+    Atom           aTargets;
+    Atom           atype=AnyPropertyType;
+    int		   aformat;
+    unsigned long  remain;
+    Atom*	   targetList=NULL;
+    Window         w;
+    Window         ownerSelection = NULL;
+        
+    /*
+     * Empty the clipboard cache 
+     */
+    CLIPBOARD_EmptyCache(TRUE);
+
+    cSelectionTargets = 0;
+    selectionCacheSrc = SelectionName;
+    
+    hWnd = (hWndClipWindow) ? hWndClipWindow : GetActiveWindow();
+
+    ownerSelection = TSXGetSelectionOwner(display, SelectionName);
+    if ( !hWnd || (ownerSelection == None) )
+        return cSelectionTargets;
+
+    /*
+     * Query the selection owner for the TARGETS property
+     */
+    wnd = WIN_FindWndPtr(hWnd);
+    w = X11DRV_WND_FindXWindow(wnd);
+    WIN_ReleaseWndPtr(wnd);
+    wnd = NULL;
+
+    aTargets = TSXInternAtom(display, "TARGETS", False);
+
+    TRACE("Requesting TARGETS selection for '%s' (owner=%08x)...\n",
+          TSXGetAtomName(display, selectionCacheSrc), (unsigned)ownerSelection );
+          
+    EnterCriticalSection( &X11DRV_CritSection );
+    XConvertSelection(display, selectionCacheSrc, aTargets,
+                    TSXInternAtom(display, "SELECTION_DATA", False),
+                    w, CurrentTime);
+
+    /*
+     * Wait until SelectionNotify is received
+     */
+    while( TRUE )
+    {
+       if( XCheckTypedWindowEvent(display, w, SelectionNotify, &xe) )
+           if( xe.xselection.selection == selectionCacheSrc )
+               break;
+    }
+    LeaveCriticalSection( &X11DRV_CritSection );
+
+    /* Verify that the selection returned a valid TARGETS property */
+    if ( (xe.xselection.target != aTargets)
+          || (xe.xselection.property == None) )
+    {
+        TRACE("\tCould not retrieve TARGETS\n");
+        return cSelectionTargets;
+    }
+
+    /* Read the TARGETS property contents */
+    if(TSXGetWindowProperty(display, xe.xselection.requestor, xe.xselection.property,
+                            0, 0x3FFF, True, XA_ATOM, &atype, &aformat,
+                            &cSelectionTargets, &remain, (unsigned char**)&targetList) != Success)
+        TRACE("\tCouldn't read TARGETS property\n");
+    else
+    {
+       TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
+             TSXGetAtomName(display,atype),aformat,cSelectionTargets, remain);
+       /*
+        * The TARGETS property should have returned us a list of atoms
+        * corresponding to each selection target format supported.
+        */
+       if(atype == XA_ATOM && aformat == 32)
+       {
+          int i;
+          LPWINE_CLIPFORMAT lpFormat;
+          
+          /* Cache these formats in the clipboard cache */
+
+          for (i = 0; i < cSelectionTargets; i++)
+          {
+              char *itemFmtName = TSXGetAtomName(display, targetList[i]);
+              UINT wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
+
+              /*
+               * If the clipboard format maps to a Windows format, simply store
+               * the atom identifier and record its availablity status
+               * in the clipboard cache.
+               */
+              if (wFormat)
+              {
+                  lpFormat = CLIPBOARD_LookupFormat( wFormat );
+                  
+                  /* Don't replace if the property already cached is a native format */
+                  if (lpFormat->wDataPresent
+                      && X11DRV_CLIPBOARD_IsNativeProperty(lpFormat->drvData))
+                  {
+                      TRACE("\tAtom# %d: '%s' --> FormatID(%d) %s (Skipped)\n",
+                            i, itemFmtName, wFormat, lpFormat->Name);
+                  }
+                  else
+                  {
+                      lpFormat->wDataPresent = 1;
+                      lpFormat->drvData = targetList[i];
+                      TRACE("\tAtom# %d: '%s' --> FormatID(%d) %s\n",
+                            i, itemFmtName, wFormat, lpFormat->Name);
+                  }
+              }
+              
+              TSXFree(itemFmtName);
+          }
+       }
+
+       /* Free the list of targets */
+       TSXFree(targetList);
+    }
+    
+    return cSelectionTargets;
 }
 
 /**************************************************************************
  *		X11DRV_CLIPBOARD_ReadSelection
+ *  Reads the contents of the X selection property into the WINE clipboard cache
+ *  converting the selection into a format compatible with the windows clipboard
+ *  if possible.
+ *  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 void X11DRV_CLIPBOARD_ReadSelection(Window w, Atom prop)
+static BOOL X11DRV_CLIPBOARD_ReadSelection(UINT wFormat, Window w, Atom prop, Atom reqFormat)
 {
-    HANDLE 	 hText = 0;
-    LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
+    Atom	      atype=AnyPropertyType;
+    int		      aformat;
+    unsigned long     nitems,remain,itemSize;
+    long              lRequestLength;
+    unsigned char*    val=NULL;
+    LPWINE_CLIPFORMAT lpFormat;
+    BOOL              bRet = FALSE;
+    HWND              hWndClipWindow = GetOpenClipboardWindow();
+    
+    if(prop == None)
+        return bRet;
 
     TRACE("Reading X selection...\n");
 
-    if(prop != None)
+    TRACE("\tretrieving property %s into %s\n",
+          TSXGetAtomName(display,reqFormat), 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,
+                            &atype, &aformat, &nitems, &itemSize, &val) != Success)
     {
-	Atom		atype=AnyPropertyType;
-	int		aformat;
-	unsigned long 	nitems,remain;
-	unsigned char*	val=NULL;
+        WARN("\tcouldn't get property size\n");
+        return bRet;
+    }
+    /* Free property if one was returned */
+    if ( val )
+    {
+       TSXFree(val);
+       val = NULL;
+    }
+    
+    TRACE("\tretrieving %ld bytes...\n", itemSize * aformat/8);
+    lRequestLength = (itemSize * aformat/8)/4  + 1;
+    
+    if(TSXGetWindowProperty(display,w,prop,0,lRequestLength,True,reqFormat,
+                            &atype, &aformat, &nitems, &remain, &val) != Success)
+    {
+        WARN("\tcouldn't read property\n");
+        return bRet;
+    }
 
-        TRACE("\tgot property %s\n",TSXGetAtomName(display,prop));
+    TRACE("\tType %s,Format %d,nitems %ld,remain %ld,value %s\n",
+          atype ? TSXGetAtomName(display,atype) : NULL, aformat,nitems,remain,val);
+    
+    if (remain)
+    {
+        WARN("\tCouldn't read entire property- selection may be too large! Remain=%ld\n", remain);
+        return bRet;
+    }
+    
+    /*
+     * Translate the X property into the appropriate Windows clipboard
+     * format, if possible.
+     */
+    if ( (reqFormat == XA_STRING)
+         && (atype == XA_STRING) && (aformat == 8) ) /* treat Unix text as CF_OEMTEXT */
+    {
+      HANDLE16   hText = 0;
+      int 	   i,inlcount = 0;
+      char*      lpstr;
+ 
+      TRACE("\tselection is '%s'\n",val);
+ 
+      for(i=0; i <= nitems; i++)
+          if( val[i] == '\n' ) inlcount++;
+ 
+      if( nitems )
+      {
+        hText=GlobalAlloc16(GMEM_MOVEABLE, nitems + inlcount + 1);
+        if( (lpstr = (char*)GlobalLock16(hText)) )
+        {
+          for(i=0,inlcount=0; i <= nitems; i++)
+          {
+             if( val[i] == '\n' ) lpstr[inlcount++]='\r';
+             lpstr[inlcount++]=val[i];
+          }
+          GlobalUnlock16(hText);
+        }
+        else
+            hText = 0;
+      }
+      
+      if( hText )
+      {
+          /* delete previous CF_TEXT and CF_OEMTEXT data */
+          lpFormat = CLIPBOARD_LookupFormat(CF_TEXT);
+          if (lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32) 
+              CLIPBOARD_DeleteRecord(lpFormat, !(hWndClipWindow));
+          
+          lpFormat = CLIPBOARD_LookupFormat(CF_OEMTEXT);
+          if (lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32)  
+              CLIPBOARD_DeleteRecord(lpFormat, !(hWndClipWindow));
+ 
+          /* Update the CF_OEMTEXT record */
+          lpFormat->wDataPresent = 1;
+          lpFormat->hData32 = 0;
+          lpFormat->hData16 = hText;
+ 
+          bRet = TRUE;
+      }
+    }
+    else if ( reqFormat == XA_PIXMAP ) /* 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");
+    }
+ 
+    /* For other data types simply copy the X data without conversion */
+    else
+    {
+      HANDLE hClipData = 0;
+      void*  lpClipData;
+      int cBytes = nitems * aformat/8;
 
-        /* TODO: Properties longer than 64K */
+      if( cBytes )
+      {
+        /* Turn on the DDESHARE flag to enable shared 32 bit memory */
+        hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cBytes );
+        if( (lpClipData = GlobalLock(hClipData)) )
+        {
+            memcpy(lpClipData, val, cBytes);
+            GlobalUnlock(hClipData);
+        }
+        else
+            hClipData = 0;
+      }
+      
+      if( hClipData )
+      {
+          /* delete previous clipboard record if any */
+          lpFormat = CLIPBOARD_LookupFormat(wFormat);
+          if (lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32) 
+              CLIPBOARD_DeleteRecord(lpFormat, !(hWndClipWindow));
+          
+          /* Update the clipboard record */
+          lpFormat->wDataPresent = 1;
+          lpFormat->hData32 = hClipData;
+          lpFormat->hData16 = 0;
 
-	if(TSXGetWindowProperty(display,w,prop,0,0x3FFF,True,XA_STRING,
-	    &atype, &aformat, &nitems, &remain, &val) != Success)
-	    WARN("\tcouldn't read property\n");
-	else
-	{
-           TRACE("\tType %s,Format %d,nitems %ld,value %s\n",
-		             TSXGetAtomName(display,atype),aformat,nitems,val);
-
-	   if(atype == XA_STRING && aformat == 8)
-	   {
-	      int 	i,inlcount = 0;
-	      char*	lpstr;
-
-	      TRACE("\tselection is '%s'\n",val);
-
-	      for(i=0; i <= nitems; i++)
-		  if( val[i] == '\n' ) inlcount++;
-
-	      if( nitems )
-	      {
-	        hText=GlobalAlloc(GMEM_MOVEABLE, nitems + inlcount + 1);
-	        if( (lpstr = (char*)GlobalLock(hText)) )
-	          for(i=0,inlcount=0; i <= nitems; i++)
-	          {
-	  	     if( val[i] == '\n' ) lpstr[inlcount++]='\r';
-		     lpstr[inlcount++]=val[i];
-		  }
-	        else hText = 0;
-	      }
-	   }
-	   TSXFree(val);
-	}
-   }
-
-   /* delete previous CF_TEXT and CF_OEMTEXT data */
-
-   if( hText )
-   {
-       lpFormat = &ClipFormats[CF_TEXT-1];
-       if (lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32) 
-           CLIPBOARD_DeleteRecord(lpFormat, !(hWndClipWindow));
-       lpFormat = &ClipFormats[CF_OEMTEXT-1];
-       if (lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32)  
-           CLIPBOARD_DeleteRecord(lpFormat, !(hWndClipWindow));
-       lpFormat->wDataPresent = 1;
-       lpFormat->hData32 = hText;
-       lpFormat->hData16 = 0;
-   }
+          bRet = TRUE;
+      }
+    }
+ 
+    /* Free the retrieved property */
+    TSXFree(val);
+    
+    return bRet;
 }
 
 /**************************************************************************
  *		X11DRV_CLIPBOARD_ReleaseSelection
  *
- * Wine might have lost XA_PRIMARY selection because of
- * EmptyClipboard() or other client. 
+ * Release an XA_PRIMARY or XA_CLIPBOARD selection that we own, in response
+ * to a SelectionClear event.
+ * This can occur in response to another client grabbing the X selection.
+ * If the XA_CLIPBOARD selection is lost we relinquish XA_PRIMARY as well.
  */
-void X11DRV_CLIPBOARD_ReleaseSelection(Window w, HWND hwnd)
+void X11DRV_CLIPBOARD_ReleaseSelection(Atom selType, Window w, HWND hwnd)
 {
+    Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
+    
     /* w is the window that lost selection,
      * 
      * selectionPrevWindow is nonzero if CheckSelection() was called. 
@@ -159,17 +508,81 @@
 	{
 	    /* alright, we really lost it */
 
-	    selectionAcquired = False;
-	    selectionWindow = None; 
+            if ( selType == xaClipboard )  /* completely give up the selection */
+            {
+              TRACE("Lost CLIPBOARD selection\n");
+                
+              /* We are completely giving up the selection.
+               * Make sure we can open the windows clipboard first. */
+              
+              if ( !OpenClipboard(hwnd) )
+              {
+                  /*
+                   * We can't empty the clipboard if we cant open it so abandon.
+                   * Wine will think that it still owns the selection but this is
+                   * safer than losing the selection without properly emptying
+                   * the clipboard. Perhaps we should forcibly re-assert ownership
+                   * of the CLIPBOARD selection in this case...
+                   */
+                  ERR("\tClipboard is busy. Could not give up selection!\n");
+                  return;
+              }
 
-	    /* but we'll keep existing data for internal use */
+              selectionPrevWindow = selectionWindow;
+              selectionWindow = None;
+              PrimarySelectionOwner = ClipboardSelectionOwner = 0;
+              
+              /* Voluntarily give up the PRIMARY selection if we still own it */
+              if ( selectionAcquired & S_PRIMARY )
+              {
+                  XEvent xe;
+                  TRACE("Releasing XA_PRIMARY selection\n");
+                  
+                  TSXSetSelectionOwner(display, XA_PRIMARY, None, CurrentTime);
+
+                  /* Wait until SelectionClear is processed */
+                  if( selectionPrevWindow )
+                      while( !XCheckTypedWindowEvent( display, selectionPrevWindow,
+                                                      SelectionClear, &xe ) );
+              }
+
+              /* Empty the windows clipboard.
+               * We should pretend that we still own the selection BEFORE calling
+               * EmptyClipboard() since otherwise this has the side effect of
+               * triggering X11DRV_CLIPBOARD_Acquire() and causing the X selection
+               * to be re-acquired by us!
+               */
+              selectionAcquired = (S_PRIMARY | S_CLIPBOARD);
+              EmptyClipboard();
+              selectionAcquired = S_NOSELECTION;
+              
+              CloseClipboard();
+
+              /* Give up ownership of the windows clipboard */
+              CLIPBOARD_ReleaseOwner();
+            }
+            else if ( selType == XA_PRIMARY ) /* Give up only PRIMARY selection */
+            {
+                TRACE("Lost PRIMARY selection\n");
+                PrimarySelectionOwner = 0;
+                selectionAcquired &= ~S_PRIMARY;  /* clear S_PRIMARY mask */
+            }
+
+            cSelectionTargets = 0;
 	}
+        /* but we'll keep existing data for internal use */
 	else if( w == selectionPrevWindow )
 	{
+            Atom xaClipboard = TSXInternAtom(display, _CLIPBOARD, False);
+            
 	    w = TSXGetSelectionOwner(display, XA_PRIMARY);
 	    if( w == None )
 		TSXSetSelectionOwner(display, XA_PRIMARY, selectionWindow, CurrentTime);
-	}
+
+	    w = TSXGetSelectionOwner(display, xaClipboard);
+	    if( w == None )
+		TSXSetSelectionOwner(display, xaClipboard, selectionWindow, CurrentTime);
+        }
     }
 
     selectionPrevWindow = None;
@@ -177,14 +590,18 @@
 
 /**************************************************************************
  *		X11DRV_CLIPBOARD_Empty
+ *  Voluntarily release all currently owned X selections
  */
-void X11DRV_CLIPBOARD_Empty()
+void X11DRV_CLIPBOARD_Release()
 {
     if( selectionAcquired )
     {
 	XEvent xe;
+        Window savePrevWindow = selectionWindow;
+        Atom xaClipboard = TSXInternAtom(display, _CLIPBOARD, False);
+        BOOL bHasPrimarySelection = selectionAcquired & S_PRIMARY;
 
-	selectionAcquired   = False;
+	selectionAcquired   = S_NOSELECTION;
 	selectionPrevWindow = selectionWindow;
 	selectionWindow     = None;
       
@@ -192,135 +609,384 @@
 	     (unsigned)selectionPrevWindow);
       
 	EnterCriticalSection(&X11DRV_CritSection);
-	XSetSelectionOwner(display, XA_PRIMARY, None, CurrentTime);
 
+        TRACE("Releasing CLIPBOARD selection\n");
+        XSetSelectionOwner(display, xaClipboard, None, CurrentTime);
 	if( selectionPrevWindow )
 	    while( !XCheckTypedWindowEvent( display, selectionPrevWindow,
-					    SelectionClear, &xe ) );
+                                            SelectionClear, &xe ) );
+
+        if ( bHasPrimarySelection )
+        {
+            TRACE("Releasing XA_PRIMARY selection\n");
+            selectionPrevWindow = savePrevWindow; /* May be cleared in X11DRV_CLIPBOARD_ReleaseSelection */
+            XSetSelectionOwner(display, XA_PRIMARY, None, CurrentTime);
+    
+            if( selectionPrevWindow )
+                while( !XCheckTypedWindowEvent( display, selectionPrevWindow,
+                                                SelectionClear, &xe ) );
+        }
+        
 	LeaveCriticalSection(&X11DRV_CritSection);
     }
 }
 
 /**************************************************************************
+ *		X11DRV_CLIPBOARD_Acquire()
+ */
+void X11DRV_CLIPBOARD_Acquire()
+{
+    Window       owner;
+    HWND         hWndClipWindow = GetOpenClipboardWindow();
+
+    /*
+     * Acquire X selection if we don't already own it.
+     * Note that we only acquire the selection if it hasn't been already
+     * acquired by us, and ignore the fact that another X window may be
+     * asserting ownership. The reason for this is we need *any* top level
+     * X window to hold selection ownership. The actual clipboard data requests
+     * are made via GetClipboardData from EVENT_SelectionRequest and this
+     * ensures that the real HWND owner services the request.
+     * If the owning X window gets destroyed the selection ownership is
+     * re-cycled to another top level X window in X11DRV_CLIPBOARD_ResetOwner.
+     *
+     */
+
+    if ( !(selectionAcquired == (S_PRIMARY | S_CLIPBOARD)) )
+    {
+        Atom xaClipboard = TSXInternAtom(display, _CLIPBOARD, False);
+        WND *tmpWnd = WIN_FindWndPtr( hWndClipWindow ? hWndClipWindow : AnyPopup() );
+        owner = X11DRV_WND_FindXWindow(tmpWnd );
+        WIN_ReleaseWndPtr(tmpWnd);
+
+        /* Grab PRIMARY selection if not owned */
+        if ( !(selectionAcquired & S_PRIMARY) )
+            TSXSetSelectionOwner(display, XA_PRIMARY, owner, CurrentTime);
+        
+        /* Grab CLIPBOARD selection if not owned */
+        if ( !(selectionAcquired & S_CLIPBOARD) )
+            TSXSetSelectionOwner(display, xaClipboard, owner, CurrentTime);
+
+        if( TSXGetSelectionOwner(display,XA_PRIMARY) == owner )
+	    selectionAcquired |= S_PRIMARY;
+
+        if( TSXGetSelectionOwner(display,xaClipboard) == owner)
+	    selectionAcquired |= S_CLIPBOARD;
+
+        if (selectionAcquired)
+        {
+	    selectionWindow = owner;
+	    TRACE("Grabbed X selection, owner=(%08x)\n", (unsigned) owner);
+        }
+    }
+}
+
+/**************************************************************************
+ *		X11DRV_CLIPBOARD_IsFormatAvailable
+ *
+ * Checks if the specified format is available in the current selection
+ * Only invoked when WINE is not the selection owner
+ */
+BOOL X11DRV_CLIPBOARD_IsFormatAvailable(UINT wFormat)
+{
+    Atom xaClipboard = TSXInternAtom(display, _CLIPBOARD, False);
+    Window ownerPrimary = TSXGetSelectionOwner(display,XA_PRIMARY);
+    Window ownerClipboard = TSXGetSelectionOwner(display,xaClipboard);
+
+    /*
+     * If the selection has not been previously cached, or the selection has changed,
+     * try and cache the list of available selection targets from the current selection.
+     */
+    if ( !cSelectionTargets || (PrimarySelectionOwner != ownerPrimary)
+                         || (ClipboardSelectionOwner != ownerClipboard) )
+    {
+        /*
+         * First try cacheing the CLIPBOARD selection.
+         * If unavailable try PRIMARY.
+         */
+        if ( X11DRV_CLIPBOARD_CacheDataFormats(xaClipboard) == 0 )
+        {
+            X11DRV_CLIPBOARD_CacheDataFormats(XA_PRIMARY);
+        }
+
+        ClipboardSelectionOwner = ownerClipboard;
+        PrimarySelectionOwner = ownerPrimary;
+    }
+
+    /* Exit if there is no selection */
+    if ( !ownerClipboard && !ownerPrimary )
+        return FALSE;
+
+    if ( wFormat == CF_TEXT )
+        wFormat = CF_OEMTEXT;
+    
+    /* Check if the format is available in the clipboard cache */
+    if ( CLIPBOARD_IsPresent(wFormat) )
+        return TRUE;
+
+    /*
+     * Many X client apps (such as XTerminal) don't support being queried
+     * for the "TARGETS" target atom. To handle such clients we must actually
+     * try to convert the selection to the requested type.
+     */
+    if ( !cSelectionTargets )
+        return X11DRV_CLIPBOARD_GetData( wFormat );
+        
+    return FALSE;
+}
+
+/**************************************************************************
+ *		X11DRV_CLIPBOARD_RegisterFormat
+ *
+ * Registers a custom X clipboard format
+ * Returns: TRUE - success,  FALSE - failure
+ */
+BOOL X11DRV_CLIPBOARD_RegisterFormat( LPCSTR FormatName )
+{
+    Atom prop = None;
+    char str[256];
+    
+    /*
+     * If an X atom is registered for this format, return that
+     * Otherwise register a new atom.
+     */
+    if (FormatName)
+    {
+        /* Add a WINE specific prefix to the format */
+        strcpy(str, FMT_PREFIX);
+        strncat(str, FormatName, sizeof(str) - strlen(FMT_PREFIX));
+        prop = TSXInternAtom(display, str, False);
+    }
+    
+    return (prop) ? TRUE : FALSE;
+}
+
+/**************************************************************************
+ *		X11DRV_CLIPBOARD_IsSelectionowner
+ *
+ * Returns: TRUE - We(WINE) own the selection, FALSE - Selection not owned by us
+ */
+BOOL X11DRV_CLIPBOARD_IsSelectionowner()
+{
+    return selectionAcquired;
+}
+
+/**************************************************************************
  *		X11DRV_CLIPBOARD_SetData
+ *
+ * We don't need to do anything special here since the clipboard code
+ * maintains the cache. 
+ *
  */
 void X11DRV_CLIPBOARD_SetData(UINT wFormat)
 {
-    Window       owner;
-
-    /* Acquire X selection if text format */
-
-    if( !selectionAcquired && 
-	(wFormat == CF_TEXT || wFormat == CF_OEMTEXT) )
-    {
-        WND *tmpWnd = WIN_FindWndPtr( hWndClipWindow ? hWndClipWindow : AnyPopup() );
-	owner = X11DRV_WND_FindXWindow(tmpWnd );
-
-	TSXSetSelectionOwner(display,XA_PRIMARY, owner, CurrentTime);
-	if( TSXGetSelectionOwner(display,XA_PRIMARY) == owner )
-	{
-	    selectionAcquired = True;
-	    selectionWindow = owner;
-
-	    TRACE("Grabbed X selection, owner=(%08x)\n", 
-						(unsigned) owner);
-	}
-        WIN_ReleaseWndPtr(tmpWnd);
-    }
+    /* Make sure we have acquired the X selection */
+    X11DRV_CLIPBOARD_Acquire();
 }
 
 /**************************************************************************
  *		X11DRV_CLIPBOARD_GetData
  *
+ * This method is invoked only when we DO NOT own the X selection
+ *
  * NOTE: Clipboard driver doesn't get requests for CF_TEXT data, only
- *	 for CF_OEMTEXT.
+ * for CF_OEMTEXT.
+ * We always get the data from the selection client each time,
+ * since we have no way of determining if the data in our cache is stale.
  */
 BOOL X11DRV_CLIPBOARD_GetData(UINT wFormat)
 {
     BOOL bRet = selectionAcquired;
+    HWND hWndClipWindow = GetOpenClipboardWindow();
     HWND hWnd = (hWndClipWindow) ? hWndClipWindow : GetActiveWindow();
     WND* wnd = NULL;
+    LPWINE_CLIPFORMAT lpFormat;
 
-    if( wFormat != CF_OEMTEXT ) return FALSE;
-
-    if( !bRet && (wnd = WIN_FindWndPtr(hWnd)) )
+    if( !selectionAcquired && (wnd = WIN_FindWndPtr(hWnd)) )
     {
 	XEvent xe;
+        Atom propRequest;
 	Window w = X11DRV_WND_FindXWindow(wnd);
+        WIN_ReleaseWndPtr(wnd);
+        wnd = NULL;
 
-	TRACE("Requesting XA_STRING selection...\n");
+        /* Map the format ID requested to an X selection property.
+         * If the format is in the cache, use the atom associated
+         * with it.
+         */
+        
+        lpFormat = CLIPBOARD_LookupFormat( wFormat );
+        if (lpFormat && lpFormat->wDataPresent && lpFormat->drvData)
+            propRequest = (Atom)lpFormat->drvData;
+        else
+            propRequest = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat);
 
-	EnterCriticalSection( &X11DRV_CritSection );
-	XConvertSelection(display, XA_PRIMARY, XA_STRING,
-			XInternAtom(display, "PRIMARY_TEXT", False),
-			w, CurrentTime);
+        if (propRequest)
+        {
+            TRACE("Requesting %s selection from %s...\n",
+                  TSXGetAtomName(display, propRequest),
+                  TSXGetAtomName(display, selectionCacheSrc) );
     
-        /* wait until SelectionNotify is received */
+            EnterCriticalSection( &X11DRV_CritSection );
+            XConvertSelection(display, selectionCacheSrc, propRequest,
+                            TSXInternAtom(display, "SELECTION_DATA", False),
+                            w, CurrentTime);
+        
+            /* wait until SelectionNotify is received */
+    
+            while( TRUE )
+            {
+               if( XCheckTypedWindowEvent(display, w, SelectionNotify, &xe) )
+                   if( xe.xselection.selection == selectionCacheSrc )
+                       break;
+            }
+            LeaveCriticalSection( &X11DRV_CritSection );
+        
+            /*
+             *  Read the contents of the X selection property into WINE's
+             *  clipboard cache converting the selection to be compatible if possible.
+             */
+            bRet = X11DRV_CLIPBOARD_ReadSelection( wFormat,
+                                                   xe.xselection.requestor,
+                                                   xe.xselection.property,
+                                                   xe.xselection.target);
+        }
+        else
+            bRet = FALSE;
 
-	while( TRUE )
-	{
-	   if( XCheckTypedWindowEvent(display, w, SelectionNotify, &xe) )
-	       if( xe.xselection.selection == XA_PRIMARY )
-		   break;
-	}
-	LeaveCriticalSection( &X11DRV_CritSection );
-
-	if (xe.xselection.target != XA_STRING) 
-	    X11DRV_CLIPBOARD_ReadSelection( 0, None );
-	else 
-	    X11DRV_CLIPBOARD_ReadSelection( xe.xselection.requestor, 
-					    xe.xselection.property );
-
-	/* treat Unix text as CF_OEMTEXT */
-
-	bRet = (BOOL)ClipFormats[CF_OEMTEXT-1].wDataPresent;
-
-	TRACE("\tpresent CF_OEMTEXT = %i\n", bRet );
-	WIN_ReleaseWndPtr(wnd);
+        TRACE("\tpresent %s = %i\n", CLIPBOARD_GetFormatName(wFormat), bRet );
     }
+    
     return bRet;
 }
 
 /**************************************************************************
  *		X11DRV_CLIPBOARD_ResetOwner
  *
- * Called from DestroyWindow().
+ * Called from DestroyWindow() to prevent X selection from being lost when
+ * a top level window is destroyed, by switching ownership to another top
+ * level window.
+ * Any top level window can own the selection. See X11DRV_CLIPBOARD_Acquire
+ * for a more detailed description of this.
  */
 void X11DRV_CLIPBOARD_ResetOwner(WND *pWnd, BOOL bFooBar)
 {
-    LPWINE_CLIPFORMAT lpFormat = ClipFormats;
+    HWND hWndClipOwner = 0;
+    Window XWnd = X11DRV_WND_GetXWindow(pWnd);
+    Atom xaClipboard;
+    BOOL bLostSelection = FALSE;
 
-    if(bFooBar && X11DRV_WND_GetXWindow(pWnd))
-      return;
+    /* There is nothing to do if we don't own the selection,
+     * or if the X window which currently owns the selecion is different
+     * from the one passed in.
+     */
+    if ( !selectionAcquired || XWnd != selectionWindow
+         || selectionWindow == None )
+       return;
 
-    if(!bFooBar && !X11DRV_WND_GetXWindow(pWnd))
-      return;
+    if ( (bFooBar && XWnd) || (!bFooBar && !XWnd) )
+       return;
 
-    TRACE("clipboard owner = %04x, selection = %08x\n", 
-				hWndClipOwner, (unsigned)selectionWindow);
+    hWndClipOwner = GetClipboardOwner();
+    xaClipboard = TSXInternAtom(display, _CLIPBOARD, False);
+    
+    TRACE("clipboard owner = %04x, selection window = %08x\n",
+          hWndClipOwner, (unsigned)selectionWindow);
 
-    if( pWnd->hwndSelf == hWndClipOwner)
+#if(0)
+    /* Check if all formats are already in the clipboard cache */
+    if( !CLIPBOARD_IsCacheRendered() )
     {
 	SendMessage16(hWndClipOwner,WM_RENDERALLFORMATS,0,0L);
 
 	/* check if all formats were rendered */
-
-	while(lpFormat)
-	{
-	    if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
-	    {
-		TRACE("\tdata missing for clipboard format %i\n", 
-				   lpFormat->wFormatID); 
-		lpFormat->wDataPresent = 0;
-	    }
-	    lpFormat = lpFormat->NextFormat;
-	}
-	hWndClipOwner = 0;
+        if ( !CLIPBOARD_IsCacheRendered() )
+        {
+	    ERR("\tCould not render all formats\n");
+            CLIPBOARD_ReleaseOwner();
+        }
     }
-
+#endif
+    
     /* now try to salvage current selection from being destroyed by X */
 
-    if( X11DRV_WND_GetXWindow(pWnd) ) X11DRV_CLIPBOARD_CheckSelection(pWnd);
+    TRACE("\tchecking %08x\n", (unsigned) XWnd);
+
+    selectionPrevWindow = selectionWindow;
+    selectionWindow = None;
+
+    if( pWnd->next ) 
+        selectionWindow = X11DRV_WND_GetXWindow(pWnd->next);
+    else if( pWnd->parent )
+         if( pWnd->parent->child != pWnd ) 
+             selectionWindow = X11DRV_WND_GetXWindow(pWnd->parent->child);
+
+    if( selectionWindow != None )
+    {
+        /* We must pretend that we don't own the selection while making the switch
+         * since a SelectionClear event will be sent to the last owner.
+         * If there is no owner X11DRV_CLIPBOARD_ReleaseSelection will do nothing.
+         */
+        int saveSelectionState = selectionAcquired;
+        selectionAcquired = False;
+
+        TRACE("\tswitching selection from %08x to %08x\n", 
+                    (unsigned)selectionPrevWindow, (unsigned)selectionWindow);
+    
+        /* Assume ownership for the PRIMARY and CLIPBOARD selection */
+        if ( saveSelectionState & S_PRIMARY )
+            TSXSetSelectionOwner(display, XA_PRIMARY, selectionWindow, CurrentTime);
+        
+        TSXSetSelectionOwner(display, xaClipboard, selectionWindow, CurrentTime);
+        
+        /* Lose the selection if something went wrong */
+        if ( ( (saveSelectionState & S_PRIMARY) &&
+               (TSXGetSelectionOwner(display, XA_PRIMARY) != selectionWindow) )
+             || (TSXGetSelectionOwner(display, xaClipboard) != selectionWindow) )
+        {
+            bLostSelection = TRUE;
+            goto END;
+        }
+        else
+        {
+            /* Update selection state */
+            selectionAcquired = saveSelectionState;
+            if (saveSelectionState & S_PRIMARY)
+               PrimarySelectionOwner = selectionWindow;
+            
+            ClipboardSelectionOwner = selectionWindow;
+        }
+    }
+    else
+    {
+        bLostSelection = TRUE;
+        goto END;
+    }
+
+END:
+    if (bLostSelection)
+    {
+       /* Empty the windows clipboard.
+        * We should pretend that we still own the selection BEFORE calling
+        * EmptyClipboard() since otherwise this has the side effect of
+        * triggering X11DRV_CLIPBOARD_Acquire() and causing the X selection
+        * to be re-acquired by us!
+        */
+
+       TRACE("\tLost the selection! Emptying the clipboard...\n");
+    
+       OpenClipboard(NULL);
+       selectionAcquired = (S_PRIMARY | S_CLIPBOARD);
+       EmptyClipboard();
+       selectionAcquired = S_NOSELECTION;
+       
+       CloseClipboard();
+ 
+       /* Give up ownership of the windows clipboard */
+       CLIPBOARD_ReleaseOwner();
+       ClipboardSelectionOwner = PrimarySelectionOwner = 0;
+       selectionWindow = 0;
+    }
 }
 
 #endif /* !defined(X_DISPLAY_MISSING) */
diff --git a/windows/x11drv/event.c b/windows/x11drv/event.c
index 9696ed7..e55924b 100644
--- a/windows/x11drv/event.c
+++ b/windows/x11drv/event.c
@@ -835,64 +835,196 @@
 
 /***********************************************************************
  *           EVENT_SelectionRequest
+ *  Note: We only receive this event when WINE owns the X selection
  */
 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event )
 {
   XSelectionEvent result;
-  Atom 	    rprop = None;
-  Window    request = event->requestor;
+  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;
 
-  if(event->target == XA_STRING)
+  /*
+   * 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);
+
+  /*
+   * 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
+   */
+  if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
+      || !(couldOpen = OpenClipboard(hWnd)) )
+     goto END;
+  if ( (event->target != xaTargets)
+       && ( (0 == wFormat) || !CLIPBOARD_IsPresent(wFormat) ) )
+     goto END;
+
+  /* We can handle the request */
+       
+  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 );
+  }
+  else if(event->target == XA_STRING)  /* treat CF_TEXT as Unix text */
   {
       HANDLE16 hText;
       LPSTR  text;
       int    size,i,j;
       
-      rprop = event->property;
+      char* lpstr = 0;
       
-      if( rprop == None ) 
-	  rprop = event->target;
+      hText = GetClipboardData16(CF_TEXT);
+      text = GlobalLock16(hText);
+      size = GlobalSize16(hText);
       
-      if( event->selection != XA_PRIMARY ) 
-	  rprop = None;
-      else 
-      if( !CLIPBOARD_IsPresent(CF_OEMTEXT) ) 
-	  rprop = None;
-      else
+      /* remove carriage returns */
+      
+      lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
+      for(i=0,j=0; i < size && text[i]; i++ )
       {
-	  /* open to make sure that clipboard is available */
-
-	  BOOL couldOpen = OpenClipboard( hWnd );
-	  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';
-	  
-	  TSXChangeProperty(display, request, rprop, 
-			    XA_STRING, 8, PropModeReplace, 
-			    lpstr, j);
-	  HeapFree( GetProcessHeap(), 0, lpstr );
-	  
-	  /* close only if we opened before */
-	  
-	  if(couldOpen) CloseClipboard();
+          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 );
   }
+  else if(event->target == XA_PIXMAP)  /*  Convert DIB's to Pixmaps */
+  {
+      FIXME_(event)("DIB to PIXMAP conversion not yet implemented!\n");
+      rprop = None;
+  }
+  else  /* For other data types (WCF_*) simply copy the data to X without conversion */
+  {
+      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 */
+  }
+
+END:
+  /* close clipboard only if we opened before */
+  if(couldOpen) CloseClipboard();
   
   if( rprop == None) 
-      TRACE_(event)("Request for %s ignored\n", TSXGetAtomName(display,event->target));
+      TRACE_(event)("\tRequest ignored\n");
 
   /* reply to sender */
   
@@ -911,8 +1043,10 @@
  */
 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
 {
-  if (event->selection != XA_PRIMARY) return;
-  X11DRV_CLIPBOARD_ReleaseSelection( event->window, hWnd );
+  Atom xaClipboard = XInternAtom(display, "CLIPBOARD", False);
+    
+  if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
+      X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
 }
 
 
@@ -1210,7 +1344,7 @@
       bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
 
       if ( !Options.managed || !bIsDisabled )
-          PostMessage16( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
+      PostMessage16( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
     }
     else if ( event->message_type == dndProtocol &&
 	      (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
diff --git a/windows/x11drv/init.c b/windows/x11drv/init.c
index 1b6be7c..f423702 100644
--- a/windows/x11drv/init.c
+++ b/windows/x11drv/init.c
@@ -28,9 +28,13 @@
 
 CLIPBOARD_DRIVER X11DRV_CLIPBOARD_Driver =
 {
-  X11DRV_CLIPBOARD_Empty,
+  X11DRV_CLIPBOARD_Acquire,
+  X11DRV_CLIPBOARD_Release,
   X11DRV_CLIPBOARD_SetData,
   X11DRV_CLIPBOARD_GetData,
+  X11DRV_CLIPBOARD_IsFormatAvailable,
+  X11DRV_CLIPBOARD_RegisterFormat,
+  X11DRV_CLIPBOARD_IsSelectionowner,
   X11DRV_CLIPBOARD_ResetOwner
 };