- 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
};