diff --git a/dlls/user/user_main.c b/dlls/user/user_main.c index b0a47f43e5f..d406e34aeee 100644 --- a/dlls/user/user_main.c +++ b/dlls/user/user_main.c @@ -95,6 +95,7 @@ static BOOL load_driver(void) GET_USER_FUNC(GetClipboardData); GET_USER_FUNC(IsClipboardFormatAvailable); GET_USER_FUNC(RegisterClipboardFormat); + GET_USER_FUNC(GetClipboardFormatName); GET_USER_FUNC(IsSelectionOwner); GET_USER_FUNC(ResetSelectionOwner); GET_USER_FUNC(CreateWindow); diff --git a/dlls/x11drv/clipboard.c b/dlls/x11drv/clipboard.c index e7793ff2cd3..4c956bbddb3 100644 --- a/dlls/x11drv/clipboard.c +++ b/dlls/x11drv/clipboard.c @@ -68,6 +68,7 @@ # include #endif #include +#include #include "ts_xlib.h" #include "winreg.h" @@ -78,6 +79,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(clipboard); +/* Maximum wait time for slection notify */ +#define MAXSELECTIONNOTIFYWAIT 5 + /* Selection masks */ #define S_NOSELECTION 0 @@ -187,21 +191,20 @@ Atom X11DRV_CLIPBOARD_MapFormatToProperty(UINT wFormat) * Otherwise register a new atom. */ char str[256]; - char *fmtName = CLIPBOARD_GetFormatName(wFormat); + int plen = strlen(FMT_PREFIX); + strcpy(str, FMT_PREFIX); - if (fmtName) - { - strncat(str, fmtName, sizeof(str) - strlen(FMT_PREFIX)); + if (CLIPBOARD_GetFormatName(wFormat, str + plen, sizeof(str) - plen)) prop = TSXInternAtom(thread_display(), str, False); - } + break; } } if (prop == None) TRACE("\tNo mapping to X property for Windows clipboard format %d(%s)\n", - wFormat, CLIPBOARD_GetFormatName(wFormat)); + wFormat, CLIPBOARD_GetFormatName(wFormat, NULL, 0)); return prop; } @@ -377,6 +380,7 @@ int X11DRV_CLIPBOARD_CacheDataFormats( Atom SelectionName ) Atom* targetList=NULL; Window w; Window ownerSelection = 0; + time_t maxtm; TRACE("enter\n"); /* @@ -410,7 +414,8 @@ int X11DRV_CLIPBOARD_CacheDataFormats( Atom SelectionName ) /* * Wait until SelectionNotify is received */ - while( TRUE ) + maxtm = time(NULL) + MAXSELECTIONNOTIFYWAIT; /* Timeout after a maximum wait */ + while( maxtm - time(NULL) > 0 ) { if( XCheckTypedWindowEvent(display, w, SelectionNotify, &xe) ) if( xe.xselection.selection == selectionCacheSrc ) @@ -624,9 +629,9 @@ static BOOL X11DRV_CLIPBOARD_ReadSelection(UINT wFormat, Window w, Atom prop, At GlobalUnlock(hUnicodeText); if (!SetClipboardData(CF_UNICODETEXT, hUnicodeText)) { - ERR("Not SET! Need to free our own block\n"); - GlobalFree(hUnicodeText); - } + ERR("Not SET! Need to free our own block\n"); + GlobalFree(hUnicodeText); + } bRet = TRUE; } HeapFree(GetProcessHeap(), 0, lpstr); @@ -689,15 +694,22 @@ static BOOL X11DRV_CLIPBOARD_ReadSelection(UINT wFormat, Window w, Atom prop, At 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 (wFormat == CF_METAFILEPICT || wFormat == CF_ENHMETAFILE) + { + hClipData = X11DRV_CLIPBOARD_SerializeMetafile(wFormat, (HANDLE)val, cBytes, FALSE); + } + else + { + /* 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 ) @@ -1022,9 +1034,9 @@ BOOL X11DRV_IsClipboardFormatAvailable(UINT wFormat) * RegisterClipboardFormat (X11DRV.@) * * Registers a custom X clipboard format - * Returns: TRUE - success, FALSE - failure + * Returns: Format id or 0 on failure */ -BOOL X11DRV_RegisterClipboardFormat( LPCSTR FormatName ) +INT X11DRV_RegisterClipboardFormat( LPCSTR FormatName ) { Display *display = thread_display(); Atom prop = None; @@ -1042,7 +1054,7 @@ BOOL X11DRV_RegisterClipboardFormat( LPCSTR FormatName ) prop = TSXInternAtom(display, str, False); } - return (prop) ? TRUE : FALSE; + return prop; } /************************************************************************** @@ -1141,7 +1153,7 @@ BOOL X11DRV_GetClipboardData(UINT wFormat) else bRet = FALSE; - TRACE("\tpresent %s = %i\n", CLIPBOARD_GetFormatName(wFormat), bRet ); + TRACE("\tpresent %s = %i\n", CLIPBOARD_GetFormatName(wFormat, NULL, 0), bRet ); } TRACE("Returning %d\n", bRet); @@ -1313,3 +1325,89 @@ void X11DRV_CLIPBOARD_FreeResources( Atom property ) else prop = &(*prop)->next; } } + +/************************************************************************** + * X11DRV_GetClipboardFormatName + */ +BOOL X11DRV_GetClipboardFormatName( UINT wFormat, LPSTR retStr, UINT maxlen ) +{ + BOOL bRet = FALSE; + char *itemFmtName = TSXGetAtomName(thread_display(), wFormat); + INT prefixlen = strlen(FMT_PREFIX); + + if ( 0 == strncmp(itemFmtName, FMT_PREFIX, prefixlen ) ) + { + strncpy(retStr, itemFmtName + prefixlen, maxlen); + bRet = TRUE; + } + + TSXFree(itemFmtName); + + return bRet; +} + + +/************************************************************************** + * CLIPBOARD_SerializeMetafile + */ +HANDLE X11DRV_CLIPBOARD_SerializeMetafile(INT wformat, HANDLE hdata, INT cbytes, BOOL out) +{ + HANDLE h = 0; + + if (out) /* Serialize out, caller should free memory */ + { + if (wformat == CF_METAFILEPICT) + { + LPMETAFILEPICT lpmfp = (LPMETAFILEPICT) GlobalLock(hdata); + int size = GetMetaFileBitsEx(lpmfp->hMF, 0, NULL); + + h = GlobalAlloc(0, size + sizeof(METAFILEPICT)); + if (h) + { + LPVOID pdata = GlobalLock(h); + + memcpy(pdata, lpmfp, sizeof(METAFILEPICT)); + GetMetaFileBitsEx(lpmfp->hMF, size, pdata + sizeof(METAFILEPICT)); + + GlobalUnlock(h); + } + + GlobalUnlock(hdata); + } + else if (wformat == CF_ENHMETAFILE) + { + int size = GetEnhMetaFileBits(hdata, 0, NULL); + + h = GlobalAlloc(0, size); + if (h) + { + LPVOID pdata = GlobalLock(h); + GetEnhMetaFileBits(hdata, size, pdata); + GlobalUnlock(h); + } + } + } + else + { + if (wformat == CF_METAFILEPICT) + { + h = GlobalAlloc(0, sizeof(METAFILEPICT)); + if (h) + { + LPMETAFILEPICT pmfp = (LPMETAFILEPICT) GlobalLock(h); + + memcpy(pmfp, (LPVOID)hdata, sizeof(METAFILEPICT)); + pmfp->hMF = SetMetaFileBitsEx(cbytes - sizeof(METAFILEPICT), + (LPVOID)hdata + sizeof(METAFILEPICT)); + + GlobalUnlock(h); + } + } + else if (wformat == CF_ENHMETAFILE) + { + h = SetEnhMetaFileBits(cbytes, (LPVOID)hdata); + } + } + + return h; +} diff --git a/dlls/x11drv/event.c b/dlls/x11drv/event.c index c77418066dd..ff173bd38b0 100644 --- a/dlls/x11drv/event.c +++ b/dlls/x11drv/event.c @@ -584,7 +584,7 @@ static Atom EVENT_SelectionRequest_STRING( Display *display, Window requestor, */ itemFmtName = TSXGetAtomName(display, target); TRACE("Request for %s (wFormat=%x %s)\n", - itemFmtName, CF_UNICODETEXT, CLIPBOARD_GetFormatName(CF_UNICODETEXT)); + itemFmtName, CF_UNICODETEXT, CLIPBOARD_GetFormatName(CF_UNICODETEXT, NULL, 0)); TSXFree(itemFmtName); hUnicodeText = GetClipboardData(CF_UNICODETEXT); @@ -650,7 +650,7 @@ static Atom EVENT_SelectionRequest_PIXMAP( Display *display, Window requestor, itemFmtName = TSXGetAtomName(display, target); wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName); TRACE("Request for %s (wFormat=%x %s)\n", - itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat)); + itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat, NULL, 0 )); TSXFree(itemFmtName); hClipData = GetClipboardData(wFormat); @@ -683,7 +683,7 @@ static Atom EVENT_SelectionRequest_PIXMAP( Display *display, Window requestor, else { FIXME("%s to PIXMAP conversion not yet implemented!\n", - CLIPBOARD_GetFormatName(wFormat)); + CLIPBOARD_GetFormatName(wFormat, NULL, 0)); rprop = None; goto END; } @@ -739,6 +739,7 @@ static Atom EVENT_SelectionRequest_WCF( Display *display, Window requestor, char * itemFmtName; int cBytes; int xRc; + int bemf; /* * Map the requested X selection property type atom name to a @@ -747,11 +748,15 @@ static Atom EVENT_SelectionRequest_WCF( Display *display, Window requestor, itemFmtName = TSXGetAtomName(display, target); wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName); TRACE("Request for %s (wFormat=%x %s)\n", - itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat)); + itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat, NULL, 0)); TSXFree(itemFmtName); hClipData = GetClipboardData(wFormat); + bemf = wFormat == CF_METAFILEPICT || wFormat == CF_ENHMETAFILE; + if (bemf) + hClipData = X11DRV_CLIPBOARD_SerializeMetafile(wFormat, hClipData, sizeof(hClipData), TRUE); + if( hClipData && (lpClipData = GlobalLock(hClipData)) ) { cBytes = GlobalSize(hClipData); @@ -772,6 +777,9 @@ static Atom EVENT_SelectionRequest_WCF( Display *display, Window requestor, rprop = None; /* Fail the request */ } + if (bemf) /* We must free serialized metafile data */ + GlobalFree(hClipData); + return rprop; } diff --git a/dlls/x11drv/x11drv.spec b/dlls/x11drv/x11drv.spec index 81fdd0412d1..c9bd61f0e30 100644 --- a/dlls/x11drv/x11drv.spec +++ b/dlls/x11drv/x11drv.spec @@ -96,5 +96,6 @@ init X11DRV_Init @ cdecl GetClipboardData(long) X11DRV_GetClipboardData @ cdecl IsClipboardFormatAvailable(long) X11DRV_IsClipboardFormatAvailable @ cdecl RegisterClipboardFormat(str) X11DRV_RegisterClipboardFormat +@ cdecl GetClipboardFormatName(long str long) X11DRV_GetClipboardFormatName @ cdecl IsSelectionOwner() X11DRV_IsSelectionOwner @ cdecl ResetSelectionOwner(ptr long) X11DRV_ResetSelectionOwner diff --git a/include/clipboard.h b/include/clipboard.h index 7699d2ba6dd..500b7e566b3 100644 --- a/include/clipboard.h +++ b/include/clipboard.h @@ -44,7 +44,7 @@ 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 char * CLIPBOARD_GetFormatName(UINT wFormat, LPSTR buf, INT size); extern void CLIPBOARD_ReleaseOwner(); #endif /* __WINE_CLIPBOARD_H */ diff --git a/include/user.h b/include/user.h index 54a9b2da0d9..94eb5af1548 100644 --- a/include/user.h +++ b/include/user.h @@ -86,7 +86,8 @@ typedef struct tagUSER_DRIVER { void (*pSetClipboardData)(UINT); /* Set specified selection data */ BOOL (*pGetClipboardData)(UINT); /* Get specified selection data */ BOOL (*pIsClipboardFormatAvailable)(UINT); /* Check if specified format is available */ - BOOL (*pRegisterClipboardFormat)(LPCSTR); /* Register a clipboard format */ + INT (*pRegisterClipboardFormat)(LPCSTR); /* Register a clipboard format */ + BOOL (*pGetClipboardFormatName)(UINT, LPSTR, UINT); /* Get a clipboard format name */ BOOL (*pIsSelectionOwner)(void); /* Check if we own the selection */ void (*pResetSelectionOwner)(HWND, BOOL); diff --git a/include/x11drv.h b/include/x11drv.h index df8eabd0251..a43d0bbe4b6 100644 --- a/include/x11drv.h +++ b/include/x11drv.h @@ -366,6 +366,7 @@ extern Atom X11DRV_CLIPBOARD_MapFormatToProperty(UINT id); extern void X11DRV_CLIPBOARD_ReleaseSelection(Atom selType, Window w, HWND hwnd); extern BOOL X11DRV_IsSelectionOwner(void); extern BOOL X11DRV_GetClipboardData(UINT wFormat); +extern HANDLE X11DRV_CLIPBOARD_SerializeMetafile(INT wformat, HANDLE hdata, INT cbytes, BOOL out); /* X11 event driver */ diff --git a/windows/clipboard.c b/windows/clipboard.c index 5c2c20de876..29c674cb9f6 100644 --- a/windows/clipboard.c +++ b/windows/clipboard.c @@ -66,8 +66,6 @@ static HWND hWndClipOwner; /* current clipboard owner */ static HANDLE16 hTaskClipOwner; /* clipboard owner's task */ static HWND hWndViewer; /* start of viewers chain */ -static WORD LastRegFormat = CF_REGFORMATBASE; - /* Clipboard cache initial data. * WARNING: This data ordering is dependent on the WINE_CLIPFORMAT structure * declared in clipboard.h @@ -90,7 +88,8 @@ WINE_CLIPFORMAT ClipFormats[] = { { CF_DSPTEXT, 1, 0, "DSPText", 0, 0, 0, 0, &ClipFormats[13], &ClipFormats[15]}, { CF_DSPMETAFILEPICT, 1, 0, "DSPMetaFile Picture", 0, 0, 0, 0, &ClipFormats[14], &ClipFormats[16]}, { CF_DSPBITMAP, 1, 0, "DSPBitmap", 0, 0, 0, 0, &ClipFormats[15], &ClipFormats[17]}, - { CF_HDROP, 1, 0, "HDROP", 0, 0, 0, 0, &ClipFormats[16], NULL} + { CF_HDROP, 1, 0, "HDROP", 0, 0, 0, 0, &ClipFormats[16], &ClipFormats[18]}, + { CF_ENHMETAFILE, 1, 0, "Enhmetafile", 0, 0, 0, 0, &ClipFormats[17], NULL} }; @@ -391,10 +390,22 @@ HGLOBAL CLIPBOARD_GlobalDupMem( HGLOBAL hGlobalSrc ) * CLIPBOARD_GetFormatName * Gets the format name associated with an ID */ -char * CLIPBOARD_GetFormatName(UINT wFormat) +char * CLIPBOARD_GetFormatName(UINT wFormat, LPSTR buf, INT size) { LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat ); - return (lpFormat) ? lpFormat->Name : NULL; + + if (lpFormat) + { + if (buf) + { + strncpy(buf, lpFormat->Name, size); + CharLowerA(buf); + } + + return lpFormat->Name; + } + else + return NULL; } @@ -1126,7 +1137,7 @@ INT WINAPI CountClipboardFormats(void) && USER_Driver.pIsClipboardFormatAvailable( lpFormat->wFormatID ) ) ) { TRACE("\tdata found for format 0x%04x(%s)\n", - lpFormat->wFormatID, CLIPBOARD_GetFormatName(lpFormat->wFormatID)); + lpFormat->wFormatID, CLIPBOARD_GetFormatName(lpFormat->wFormatID, NULL, 0)); FormatCount++; } } @@ -1185,7 +1196,7 @@ UINT WINAPI RegisterClipboardFormatA( LPCSTR FormatName ) while(TRUE) { - if ( !strcmp(lpFormat->Name,FormatName) ) + if ( !strcasecmp(lpFormat->Name,FormatName) ) { lpFormat->wRefCount++; return lpFormat->wFormatID; @@ -1204,7 +1215,6 @@ UINT WINAPI RegisterClipboardFormatA( LPCSTR FormatName ) return 0; } lpFormat->NextFormat = lpNewFormat; - lpNewFormat->wFormatID = LastRegFormat; lpNewFormat->wRefCount = 1; if (!(lpNewFormat->Name = HeapAlloc(GetProcessHeap(), 0, strlen(FormatName)+1 ))) @@ -1214,6 +1224,7 @@ UINT WINAPI RegisterClipboardFormatA( LPCSTR FormatName ) return 0; } strcpy( lpNewFormat->Name, FormatName ); + CharLowerA(lpNewFormat->Name); lpNewFormat->wDataPresent = 0; lpNewFormat->hData16 = 0; @@ -1224,9 +1235,10 @@ UINT WINAPI RegisterClipboardFormatA( LPCSTR FormatName ) lpNewFormat->NextFormat = NULL; /* Pass on the registration request to the driver */ - USER_Driver.pRegisterClipboardFormat( FormatName ); + lpNewFormat->wFormatID = USER_Driver.pRegisterClipboardFormat(lpNewFormat->Name); - return LastRegFormat++; + TRACE("Registering format(%d): %s\n", lpNewFormat->wFormatID, FormatName); + return lpNewFormat->wFormatID; } @@ -1269,8 +1281,20 @@ INT WINAPI GetClipboardFormatNameA( UINT wFormat, LPSTR retStr, INT maxlen ) TRACE("(%04X, %p, %d) !\n", wFormat, retStr, maxlen); - if (lpFormat == NULL || lpFormat->Name == NULL || - lpFormat->wFormatID < CF_REGFORMATBASE) return 0; + if (lpFormat == NULL || lpFormat->Name == NULL) + { + /* Check if another wine process already registered the format */ + if (wFormat && !USER_Driver.pGetClipboardFormatName(wFormat, retStr, maxlen)) + { + RegisterClipboardFormatA(retStr); /* Make a cache entry */ + return strlen(retStr); + } + else + { + TRACE("wFormat=%d not found\n", wFormat); + return 0; + } + } TRACE("Name='%s' !\n", lpFormat->Name);