- Add clipboard support for copying/pasting bitmaps or Pixmaps between Wine

and native Linux applications.
- Respond to the MULTIPLE selection request target when Wine is the
  selection owner.
- Relax type checking for TARGETS selection.
This commit is contained in:
Noel Borthwick 1999-09-20 15:42:47 +00:00 committed by Alexandre Julliard
parent f52e109dea
commit d05b7beb5a
11 changed files with 1041 additions and 220 deletions

View File

@ -2,6 +2,7 @@
* X11DRV bitmap objects
*
* Copyright 1993 Alexandre Julliard
* 1999 Noel Borthwick
*/
#include "config.h"
@ -532,6 +533,132 @@ BOOL X11DRV_BITMAP_DeleteObject( HBITMAP hbitmap, BITMAPOBJ * bmp )
return TRUE;
}
/**************************************************************************
* X11DRV_BITMAP_CreateBitmapHeaderFromPixmap
*
* Allocates an HBITMAP which references the Pixmap passed in.
* Note: This function makes the bitmap an owner of the Pixmap so subsequently
* calling DeleteObject on this will free the Pixmap as well.
*/
HBITMAP X11DRV_BITMAP_CreateBitmapHeaderFromPixmap(Pixmap pixmap)
{
HBITMAP hBmp = 0;
BITMAPOBJ *pBmp = NULL;
X11DRV_PHYSBITMAP *pPhysBmp = NULL;
Window root;
int x,y; /* Unused */
unsigned border_width; /* Unused */
unsigned int depth, width, height;
/* Get the Pixmap dimensions and bit depth */
if ( 0 == TSXGetGeometry(display, pixmap, &root, &x, &y, &width, &height,
&border_width, &depth) )
goto END;
TRACE("\tPixmap properties: width=%d, height=%d, depth=%d\n",
width, height, depth);
/*
* Create an HBITMAP with the same dimensions and BPP as the pixmap,
* and make it a container for the pixmap passed.
*/
hBmp = CreateBitmap( width, height, 1, depth, NULL );
/*Allocate DDBitmap and physBitmap structures in BITMAPOBJ.
* The hBmp is just a filled in BITMAPOBJ header at this point.
*/
pBmp = (BITMAPOBJ *)GDI_GetObjPtr( hBmp, BITMAP_MAGIC );
pPhysBmp = X11DRV_AllocBitmap( pBmp );
if( !pPhysBmp )
{
DeleteObject(hBmp);
hBmp = NULL;
goto END;
}
/* Point to our Pixmap in the physical bitmap structure */
pPhysBmp->pixmap = pixmap;
END:
TRACE("\tReturning HBITMAP %x\n", hBmp);
return hBmp;
}
/**************************************************************************
* X11DRV_BITMAP_CreateBitmapFromPixmap
*
* Allocates an HBITMAP and copies the Pixmap data into it.
* If bDeletePixmap is TRUE, the Pixmap passed in is deleted after the conversion.
*/
HBITMAP X11DRV_BITMAP_CreateBitmapFromPixmap(Pixmap pixmap, BOOL bDeletePixmap)
{
HBITMAP hBmp = 0, hBmpCopy = 0;
BITMAPOBJ *pBmp = NULL;
unsigned int width, height;
/* Allocate an HBITMAP which references the Pixmap passed to us */
hBmp = X11DRV_BITMAP_CreateBitmapHeaderFromPixmap(pixmap);
if (!hBmp)
{
TRACE("\tCould not create bitmap header for Pixmap\n");
goto END;
}
/* Get the bitmap dimensions */
width = pBmp->bitmap.bmWidth;
height = pBmp->bitmap.bmHeight;
hBmpCopy = CopyImage(hBmp, IMAGE_BITMAP, width, height, LR_CREATEDIBSECTION);
/* We can now get rid of the HBITMAP wrapper we created earlier.
* Note: Simply calling DeleteObject will free the embedded Pixmap as well.
*/
if (!bDeletePixmap)
{
/* Manually free the DDBitmap internals to prevent the Pixmap
* from being deleted by DeleteObject.
*/
pBmp = (BITMAPOBJ *)GDI_GetObjPtr( hBmp, BITMAP_MAGIC );
HeapFree( GetProcessHeap(), 0, pBmp->DDBitmap->physBitmap );
HeapFree( GetProcessHeap(), 0, pBmp->DDBitmap );
pBmp->DDBitmap = NULL;
}
DeleteObject(hBmp);
END:
TRACE("\tReturning HBITMAP %x\n", hBmpCopy);
return hBmpCopy;
}
/**************************************************************************
* X11DRV_BITMAP_CreatePixmapFromBitmap
*
* Creates a Pixmap from a bitmap
*/
Pixmap X11DRV_BITMAP_CreatePixmapFromBitmap( HBITMAP hBmp, HDC hdc )
{
HGLOBAL hPackedDIB = NULL;
Pixmap pixmap = NULL;
/*
* Create a packed DIB from the bitmap passed to us.
* A packed DIB contains a BITMAPINFO structure followed immediately by
* an optional color palette and the pixel data.
*/
hPackedDIB = DIB_CreateDIBFromBitmap(hdc, hBmp);
/* Create a Pixmap from the packed DIB */
pixmap = X11DRV_DIB_CreatePixmapFromDIB( hPackedDIB, hdc );
/* Free the temporary packed DIB */
GlobalFree(hPackedDIB);
return pixmap;
}
/***********************************************************************
* X11DRV_BITMAP_Pixmap
*

View File

@ -3418,6 +3418,114 @@ void X11DRV_DIB_DeleteDIBSection(BITMAPOBJ *bmp)
}
/**************************************************************************
* X11DRV_DIB_CreateDIBFromPixmap
*
* Allocates a packed DIB and copies the Pixmap data into it.
* If bDeletePixmap is TRUE, the Pixmap passed in is deleted after the conversion.
*/
HGLOBAL X11DRV_DIB_CreateDIBFromPixmap(Pixmap pixmap, HDC hdc, BOOL bDeletePixmap)
{
HBITMAP hBmp = 0;
BITMAPOBJ *pBmp = NULL;
HGLOBAL hPackedDIB = NULL;
/* Allocates an HBITMAP which references the Pixmap passed to us */
hBmp = X11DRV_BITMAP_CreateBitmapHeaderFromPixmap(pixmap);
if (!hBmp)
{
TRACE_(bitmap)("\tCould not create bitmap header for Pixmap\n");
goto END;
}
/*
* Create a packed DIB from the Pixmap wrapper bitmap created above.
* A packed DIB contains a BITMAPINFO structure followed immediately by
* an optional color palette and the pixel data.
*/
hPackedDIB = DIB_CreateDIBFromBitmap(hdc, hBmp);
/* Get a pointer to the BITMAPOBJ structure */
pBmp = (BITMAPOBJ *)GDI_GetObjPtr( hBmp, BITMAP_MAGIC );
/* We can now get rid of the HBITMAP wrapper we created earlier.
* Note: Simply calling DeleteObject will free the embedded Pixmap as well.
*/
if (!bDeletePixmap)
{
/* Manually free the DDBitmap internals to prevent the Pixmap
* from being deleted by DeleteObject.
*/
HeapFree( GetProcessHeap(), 0, pBmp->DDBitmap->physBitmap );
HeapFree( GetProcessHeap(), 0, pBmp->DDBitmap );
pBmp->DDBitmap = NULL;
}
DeleteObject(hBmp);
END:
TRACE_(bitmap)("\tReturning packed DIB %x\n", hPackedDIB);
return hPackedDIB;
}
/**************************************************************************
* X11DRV_DIB_CreatePixmapFromDIB
*
* Creates a Pixmap from a packed DIB
*/
Pixmap X11DRV_DIB_CreatePixmapFromDIB( HGLOBAL hPackedDIB, HDC hdc )
{
Pixmap pixmap = NULL;
HBITMAP hBmp = 0;
BITMAPOBJ *pBmp = NULL;
LPBYTE pPackedDIB = NULL;
LPBITMAPINFO pbmi = NULL;
LPBITMAPINFOHEADER pbmiHeader = NULL;
LPBYTE pbits = NULL;
/* Get a pointer to the packed DIB's data */
pPackedDIB = (LPBYTE)GlobalLock(hPackedDIB);
pbmiHeader = (LPBITMAPINFOHEADER)pPackedDIB;
pbmi = (LPBITMAPINFO)pPackedDIB;
pbits = (LPBYTE)(pPackedDIB
+ DIB_BitmapInfoSize( (LPBITMAPINFO)pbmiHeader, DIB_RGB_COLORS ));
/* Create a DDB from the DIB */
hBmp = CreateDIBitmap(hdc,
pbmiHeader,
CBM_INIT,
(LPVOID)pbits,
pbmi,
DIB_RGB_COLORS);
GlobalUnlock(hPackedDIB);
TRACE_(bitmap)("CreateDIBitmap returned %x\n", hBmp);
/* Retrieve the internal Pixmap from the DDB */
pBmp = (BITMAPOBJ *) GDI_GetObjPtr( hBmp, BITMAP_MAGIC );
if (pBmp->DDBitmap && pBmp->DDBitmap->physBitmap)
{
pixmap = ((X11DRV_PHYSBITMAP *)(pBmp->DDBitmap->physBitmap))->pixmap;
if (!pixmap)
TRACE_(bitmap)("NULL Pixmap in DDBitmap->physBitmap!\n");
/* Manually free the BITMAPOBJ internals so that we can steal its pixmap */
HeapFree( GetProcessHeap(), 0, pBmp->DDBitmap->physBitmap );
HeapFree( GetProcessHeap(), 0, pBmp->DDBitmap );
pBmp->DDBitmap = NULL; /* Its not a DDB anymore */
}
/* Delete the DDB we created earlier now that we have stolen its pixmap */
DeleteObject(hBmp);
TRACE_(bitmap)("\tReturning Pixmap %ld\n", pixmap);
return pixmap;
}
#endif /* !defined(X_DISPLAY_MISSING) */

View File

@ -62,7 +62,7 @@ extern int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, DWORD *width,
extern void DIB_UpdateDIBSection( DC *dc, BOOL toDIB );
extern void DIB_DeleteDIBSection( BITMAPOBJ *bmp );
extern void DIB_SelectDIBSection( DC *dc, BITMAPOBJ *bmp );
extern void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags,
BYTE pix);
extern void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix);
extern HGLOBAL DIB_CreateDIBFromBitmap(HDC hdc, HBITMAP hBmp);
#endif /* __WINE_BITMAP_H */

View File

@ -59,6 +59,7 @@ extern int TSXConvertSelection(Display*, Atom, Atom, Atom, Window, Time);
extern int TSXCopyArea(Display*, Drawable, Drawable, GC, int, int, unsigned int, unsigned int, int, int);
extern int TSXCopyPlane(Display*, Drawable, Drawable, GC, int, int, unsigned int, unsigned int, int, int, unsigned long);
extern int TSXDefineCursor(Display*, Window, Cursor);
extern int TSXDeleteProperty(Display*, Window, Atom);
extern int TSXDestroyWindow(Display*, Window);
extern int TSXDisplayKeycodes(Display*, int*, int*);
extern int TSXDrawArc(Display*, Drawable, GC, int, int, unsigned int, unsigned int, int, int);

View File

@ -169,6 +169,11 @@ extern XImage *X11DRV_BITMAP_GetXImage( const struct tagBITMAPOBJ *bmp );
extern int X11DRV_DIB_GetXImageWidthBytes( int width, int depth );
extern BOOL X11DRV_DIB_Init(void);
extern X11DRV_PHYSBITMAP *X11DRV_AllocBitmap( struct tagBITMAPOBJ *bmp );
extern HBITMAP X11DRV_BITMAP_CreateBitmapHeaderFromPixmap(Pixmap pixmap);
extern HGLOBAL X11DRV_DIB_CreateDIBFromPixmap(Pixmap pixmap, HDC hdc, BOOL bDeletePixmap);
extern HBITMAP X11DRV_BITMAP_CreateBitmapFromPixmap(Pixmap pixmap, BOOL bDeletePixmap);
extern Pixmap X11DRV_DIB_CreatePixmapFromDIB( HGLOBAL hPackedDIB, HDC hdc );
extern Pixmap X11DRV_BITMAP_CreatePixmapFromBitmap( HBITMAP hBmp, HDC hdc );
extern BOOL X11DRV_SetupGCForPatBlt( struct tagDC *dc, GC gc,
BOOL fMapColors );
@ -325,11 +330,15 @@ extern void X11DRV_USER_EndDebugging(void);
extern struct tagCLIPBOARD_DRIVER X11DRV_CLIPBOARD_Driver;
extern void X11DRV_CLIPBOARD_FreeResources( Atom property );
extern BOOL X11DRV_CLIPBOARD_RegisterPixmapResource( Atom property, Pixmap pixmap );
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_IsNativeProperty(Atom prop);
extern BOOL X11DRV_CLIPBOARD_RegisterFormat( LPCSTR FormatName );
extern BOOL X11DRV_CLIPBOARD_IsSelectionowner();
extern UINT X11DRV_CLIPBOARD_MapPropertyToFormat(char *itemFmtName);

View File

@ -978,3 +978,87 @@ void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
}
}
}
/***********************************************************************
* DIB_CreateDIBFromBitmap
* Allocates a packed DIB and copies the bitmap data into it.
*/
HGLOBAL DIB_CreateDIBFromBitmap(HDC hdc, HBITMAP hBmp)
{
BITMAPOBJ *pBmp = NULL;
HGLOBAL hPackedDIB = 0;
LPBYTE pPackedDIB = NULL;
LPBITMAPINFOHEADER pbmiHeader = NULL;
unsigned int width, height, depth, cDataSize = 0, cPackedSize = 0,
OffsetBits = 0, nLinesCopied = 0;
/* Get a pointer to the BITMAPOBJ structure */
pBmp = (BITMAPOBJ *)GDI_GetObjPtr( hBmp, BITMAP_MAGIC );
/* Get the bitmap dimensions */
width = pBmp->bitmap.bmWidth;
height = pBmp->bitmap.bmHeight;
depth = pBmp->bitmap.bmBitsPixel;
/*
* A packed DIB contains a BITMAPINFO structure followed immediately by
* an optional color palette and the pixel data.
*/
/* Calculate the size of the packed DIB */
cDataSize = DIB_GetDIBImageBytes( width, height, depth );
cPackedSize = sizeof(BITMAPINFOHEADER)
+ ( (depth <= 8) ? (sizeof(RGBQUAD) * (1 << depth)) : 0 )
+ cDataSize;
/* Get the offset to the bits */
OffsetBits = cPackedSize - cDataSize;
/* Allocate the packed DIB */
TRACE("\tAllocating packed DIB of size %d\n", cPackedSize);
hPackedDIB = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE /*| GMEM_ZEROINIT*/,
cPackedSize );
if ( !hPackedDIB )
{
WARN("Could not allocate packed DIB!\n");
goto END;
}
/* A packed DIB starts with a BITMAPINFOHEADER */
pPackedDIB = (LPBYTE)GlobalLock(hPackedDIB);
pbmiHeader = (LPBITMAPINFOHEADER)pPackedDIB;
/* Init the BITMAPINFOHEADER */
pbmiHeader->biSize = sizeof(BITMAPINFOHEADER);
pbmiHeader->biWidth = width;
pbmiHeader->biHeight = height;
pbmiHeader->biPlanes = 1;
pbmiHeader->biBitCount = depth;
pbmiHeader->biCompression = BI_RGB;
pbmiHeader->biSizeImage = 0;
pbmiHeader->biXPelsPerMeter = pbmiHeader->biYPelsPerMeter = 0;
pbmiHeader->biClrUsed = 0;
pbmiHeader->biClrImportant = 0;
/* Retrieve the DIB bits from the bitmap and fill in the
* DIB color table if present */
nLinesCopied = GetDIBits(hdc, /* Handle to device context */
hBmp, /* Handle to bitmap */
0, /* First scan line to set in dest bitmap */
height, /* Number of scan lines to copy */
pPackedDIB + OffsetBits, /* [out] Address of array for bitmap bits */
(LPBITMAPINFO) pbmiHeader, /* [out] Address of BITMAPINFO structure */
0); /* RGB or palette index */
GlobalUnlock(hPackedDIB);
/* Cleanup if GetDIBits failed */
if (nLinesCopied != height)
{
TRACE("\tGetDIBits returned %d. Actual lines=%d\n", nLinesCopied, height);
GlobalFree(hPackedDIB);
hPackedDIB = 0;
}
END:
return hPackedDIB;
}

View File

@ -34,6 +34,7 @@ XCreateRegion
XCreateWindow
XDefineCursor
XDeleteContext
XDeleteProperty
XDestroyImage
XDestroyRegion
XDestroyWindow

View File

@ -488,6 +488,17 @@ int TSXDefineCursor(Display* a0, Window a1, Cursor a2)
return r;
}
int TSXDeleteProperty(Display* a0, Window a1, Atom a2)
{
int r;
TRACE("Call XDeleteProperty\n");
EnterCriticalSection( &X11DRV_CritSection );
r = XDeleteProperty(a0, a1, a2);
LeaveCriticalSection( &X11DRV_CritSection );
TRACE("Ret XDeleteProperty\n");
return r;
}
int TSXDestroyWindow(Display* a0, Window a1)
{
int r;

View File

@ -796,27 +796,28 @@ HANDLE16 WINAPI GetClipboardData16( UINT16 wFormat )
if( lpRender->wFormatID == CF_METAFILEPICT )
size = sizeof( METAFILEPICT16 );
else
size = GlobalSize(lpRender->hData32);
size = GlobalSize(lpRender->hData32);
lpRender->hData16 = GlobalAlloc16(GMEM_ZEROINIT, size);
if( !lpRender->hData16 )
ERR("(%04X) -- not enough memory in 16b heap\n", wFormat);
else
{
if( lpRender->wFormatID == CF_METAFILEPICT )
{
FIXME("\timplement function CopyMetaFilePict32to16\n");
FIXME("\tin the appropriate file.\n");
#ifdef SOMEONE_IMPLEMENTED_ME
CopyMetaFilePict32to16( GlobalLock16(lpRender->hData16),
GlobalLock(lpRender->hData32) );
#endif
}
else
{
memcpy( GlobalLock16(lpRender->hData16),
GlobalLock(lpRender->hData32),
size );
}
if( lpRender->wFormatID == CF_METAFILEPICT )
{
FIXME("\timplement function CopyMetaFilePict32to16\n");
FIXME("\tin the appropriate file.\n");
#ifdef SOMEONE_IMPLEMENTED_ME
CopyMetaFilePict32to16( GlobalLock16(lpRender->hData16),
GlobalLock(lpRender->hData32) );
#endif
}
else
{
memcpy( GlobalLock16(lpRender->hData16),
GlobalLock(lpRender->hData32),
size );
}
GlobalUnlock16(lpRender->hData16);
GlobalUnlock(lpRender->hData32);
}

View File

@ -43,8 +43,6 @@
* and vice versa. If a native format is available in the selection, it takes
* precedence, in order to avoid unnecessary conversions.
*
* TODO:
* - Support for converting between DIB and PIXMAP formats
*/
#include "config.h"
@ -62,6 +60,9 @@
#include "win.h"
#include "windef.h"
#include "x11drv.h"
#include "bitmap.h"
#include "commctrl.h"
#include "heap.h"
DEFAULT_DEBUG_CHANNEL(clipboard)
@ -83,9 +84,16 @@ static Window ClipboardSelectionOwner = None; /* The window which owns the clip
static unsigned long cSelectionTargets = 0; /* Number of target formats reported by TARGETS selection */
static Atom selectionCacheSrc = XA_PRIMARY; /* The selection source from which the clipboard cache was filled */
/*
* Dynamic pointer arrays to manage destruction of Pixmap resources
*/
static HDPA PropDPA = NULL;
static HDPA PixmapDPA = NULL;
/**************************************************************************
* X11DRV_CLIPBOARD_MapPropertyToID
* X11DRV_CLIPBOARD_MapPropertyToFormat
*
* Map an X selection property type atom name to a windows clipboard format ID
*/
@ -102,10 +110,21 @@ UINT X11DRV_CLIPBOARD_MapPropertyToFormat(char *itemFmtName)
return RegisterClipboardFormatA(itemFmtName + strlen(FMT_PREFIX));
else if ( 0 == strcmp(itemFmtName, "STRING") )
return CF_OEMTEXT;
else if ( 0 == strcmp(itemFmtName, "PIXMAP") )
return CF_DIB;
else if ( 0 == strcmp(itemFmtName, "BITMAP") )
return CF_DIB;
else if ( 0 == strcmp(itemFmtName, "PIXMAP")
|| 0 == strcmp(itemFmtName, "BITMAP") )
{
/*
* Return CF_DIB as first preference, if WINE is the selection owner
* and if CF_DIB exists in the cache.
* If wine dowsn't own the selection we always return CF_DIB
*/
if ( !X11DRV_CLIPBOARD_IsSelectionowner() )
return CF_DIB;
else if ( CLIPBOARD_IsPresent(CF_DIB) )
return CF_DIB;
else
return CF_BITMAP;
}
WARN("\tNo mapping to Windows clipboard format for property %s\n", itemFmtName);
return 0;
@ -185,6 +204,7 @@ BOOL X11DRV_CLIPBOARD_IsNativeProperty(Atom prop)
return bRet;
}
/**************************************************************************
* X11DRV_CLIPBOARD_CacheDataFormats
*
@ -259,7 +279,7 @@ int X11DRV_CLIPBOARD_CacheDataFormats( Atom SelectionName )
/* Read the TARGETS property contents */
if(TSXGetWindowProperty(display, xe.xselection.requestor, xe.xselection.property,
0, 0x3FFF, True, XA_ATOM, &atype, &aformat,
0, 0x3FFF, True, AnyPropertyType/*XA_ATOM*/, &atype, &aformat,
&cSelectionTargets, &remain, (unsigned char**)&targetList) != Success)
TRACE("\tCouldn't read TARGETS property\n");
else
@ -270,7 +290,7 @@ int X11DRV_CLIPBOARD_CacheDataFormats( Atom SelectionName )
* The TARGETS property should have returned us a list of atoms
* corresponding to each selection target format supported.
*/
if(atype == XA_ATOM && aformat == 32)
if( (atype == XA_ATOM || atype == aTargets) && aformat == 32 )
{
int i;
LPWINE_CLIPFORMAT lpFormat;
@ -291,9 +311,13 @@ int X11DRV_CLIPBOARD_CacheDataFormats( Atom SelectionName )
{
lpFormat = CLIPBOARD_LookupFormat( wFormat );
/* Don't replace if the property already cached is a native format */
if (lpFormat->wDataPresent
&& X11DRV_CLIPBOARD_IsNativeProperty(lpFormat->drvData))
/* Don't replace if the property already cached is a native format,
* or if a PIXMAP is being replaced by a BITMAP.
*/
if (lpFormat->wDataPresent &&
( X11DRV_CLIPBOARD_IsNativeProperty(lpFormat->drvData)
|| (lpFormat->drvData == XA_PIXMAP && targetList[i] == XA_BITMAP) )
)
{
TRACE("\tAtom# %d: '%s' --> FormatID(%d) %s (Skipped)\n",
i, itemFmtName, wFormat, lpFormat->Name);
@ -326,7 +350,7 @@ int X11DRV_CLIPBOARD_CacheDataFormats( Atom SelectionName )
* This method is invoked only to read the contents of a the selection owned
* by an external application. i.e. when we do not own the X selection.
*/
static BOOL X11DRV_CLIPBOARD_ReadSelection(UINT wFormat, Window w, Atom prop, Atom reqFormat)
static BOOL X11DRV_CLIPBOARD_ReadSelection(UINT wFormat, Window w, Atom prop, Atom reqType)
{
Atom atype=AnyPropertyType;
int aformat;
@ -336,26 +360,27 @@ static BOOL X11DRV_CLIPBOARD_ReadSelection(UINT wFormat, Window w, Atom prop, At
LPWINE_CLIPFORMAT lpFormat;
BOOL bRet = FALSE;
HWND hWndClipWindow = GetOpenClipboardWindow();
if(prop == None)
return bRet;
TRACE("Reading X selection...\n");
TRACE("\tretrieving property %s into %s\n",
TSXGetAtomName(display,reqFormat), TSXGetAtomName(display,prop) );
TRACE("\tretrieving property %s from window %ld into %s\n",
TSXGetAtomName(display,reqType), (long)w, TSXGetAtomName(display,prop) );
/*
* Retrieve the property in the required X format.
* First request a zero length in order to figure out the request size.
*/
if(TSXGetWindowProperty(display,w,prop,0,0,True,reqFormat,
if(TSXGetWindowProperty(display,w,prop,0,0,False, AnyPropertyType/*reqType*/,
&atype, &aformat, &nitems, &itemSize, &val) != Success)
{
WARN("\tcouldn't get property size\n");
return bRet;
}
/* Free property if one was returned */
/* Free zero length return data if any */
if ( val )
{
TSXFree(val);
@ -365,7 +390,10 @@ static BOOL X11DRV_CLIPBOARD_ReadSelection(UINT wFormat, Window w, Atom prop, At
TRACE("\tretrieving %ld bytes...\n", itemSize * aformat/8);
lRequestLength = (itemSize * aformat/8)/4 + 1;
if(TSXGetWindowProperty(display,w,prop,0,lRequestLength,True,reqFormat,
/*
* Retrieve the actual property in the required X format.
*/
if(TSXGetWindowProperty(display,w,prop,0,lRequestLength,False,AnyPropertyType/*reqType*/,
&atype, &aformat, &nitems, &remain, &val) != Success)
{
WARN("\tcouldn't read property\n");
@ -378,14 +406,14 @@ static BOOL X11DRV_CLIPBOARD_ReadSelection(UINT wFormat, Window w, Atom prop, At
if (remain)
{
WARN("\tCouldn't read entire property- selection may be too large! Remain=%ld\n", remain);
return bRet;
goto END;
}
/*
* Translate the X property into the appropriate Windows clipboard
* format, if possible.
*/
if ( (reqFormat == XA_STRING)
if ( (reqType == XA_STRING)
&& (atype == XA_STRING) && (aformat == 8) ) /* treat Unix text as CF_OEMTEXT */
{
HANDLE16 hText = 0;
@ -432,16 +460,56 @@ static BOOL X11DRV_CLIPBOARD_ReadSelection(UINT wFormat, Window w, Atom prop, At
bRet = TRUE;
}
}
else if ( reqFormat == XA_PIXMAP ) /* treat PIXMAP as CF_DIB or CF_BITMAP */
else if ( reqType == XA_PIXMAP || reqType == XA_BITMAP ) /* treat PIXMAP as CF_DIB or CF_BITMAP */
{
if (wFormat == CF_BITMAP )
FIXME("PIXMAP to CF_BITMAP conversion not yet implemented!\n");
else if (wFormat == CF_DIB )
FIXME("PIXMAP to CF_DIB conversion not yet implemented!\n");
/* Get the first pixmap handle passed to us */
Pixmap *pPixmap = (Pixmap *)val;
HANDLE hTargetImage = NULL; /* Handle to store the converted bitmap or DIB */
if (aformat != 32 || nitems < 1 || atype != XA_PIXMAP
|| (wFormat != CF_BITMAP && wFormat != CF_DIB))
{
WARN("\tUnimplemented format conversion request\n");
goto END;
}
if ( wFormat == CF_BITMAP )
{
/* For CF_BITMAP requests we must return an HBITMAP */
hTargetImage = X11DRV_BITMAP_CreateBitmapFromPixmap(*pPixmap, TRUE);
}
else if (wFormat == CF_DIB)
{
HWND hwnd = GetOpenClipboardWindow();
HDC hdc = GetDC(hwnd);
/* For CF_DIB requests we must return an HGLOBAL storing a packed DIB */
hTargetImage = X11DRV_DIB_CreateDIBFromPixmap(*pPixmap, hdc, TRUE);
ReleaseDC(hdc, hwnd);
}
if (!hTargetImage)
{
WARN("PIXMAP conversion failed!\n" );
goto END;
}
/* Delete previous clipboard data */
lpFormat = CLIPBOARD_LookupFormat(wFormat);
if (lpFormat->wDataPresent && (lpFormat->hData16 || lpFormat->hData32))
CLIPBOARD_DeleteRecord(lpFormat, !(hWndClipWindow));
/* Update the clipboard record */
lpFormat->wDataPresent = 1;
lpFormat->hData32 = hTargetImage;
lpFormat->hData16 = 0;
bRet = TRUE;
}
/* For other data types simply copy the X data without conversion */
else
/* For native properties simply copy the X data without conversion */
else if (X11DRV_CLIPBOARD_IsNativeProperty(reqType)) /* <WCF>* */
{
HANDLE hClipData = 0;
void* lpClipData;
@ -475,9 +543,20 @@ static BOOL X11DRV_CLIPBOARD_ReadSelection(UINT wFormat, Window w, Atom prop, At
bRet = TRUE;
}
}
/* Free the retrieved property */
TSXFree(val);
else
{
WARN("\tUnimplemented format conversion request\n");
goto END;
}
END:
/* Delete the property on the window now that we are done
* This will send a PropertyNotify event to the selection owner. */
TSXDeleteProperty(display,w,prop);
/* Free the retrieved property data */
if (val)
TSXFree(val);
return bRet;
}
@ -629,6 +708,24 @@ void X11DRV_CLIPBOARD_Release()
LeaveCriticalSection(&X11DRV_CritSection);
}
/* Get rid of any Pixmap resources we may still have */
if (PropDPA)
DPA_Destroy( PropDPA );
if (PixmapDPA)
{
int i;
Pixmap pixmap;
for( i = 0; ; i++ )
{
if ( (pixmap = ((Pixmap)DPA_GetPtr(PixmapDPA, i))) )
XFreePixmap(display, pixmap);
else
break;
}
DPA_Destroy( PixmapDPA );
}
PixmapDPA = PropDPA = NULL;
}
/**************************************************************************
@ -675,6 +772,12 @@ void X11DRV_CLIPBOARD_Acquire()
if (selectionAcquired)
{
/* Create dynamic pointer arrays to manage Pixmap resources we may expose */
if (!PropDPA)
PropDPA = DPA_CreateEx( 2, SystemHeap );
if (!PixmapDPA)
PixmapDPA = DPA_CreateEx( 2, SystemHeap );
selectionWindow = owner;
TRACE("Grabbed X selection, owner=(%08x)\n", (unsigned) owner);
}
@ -989,4 +1092,57 @@ END:
}
}
/**************************************************************************
* X11DRV_CLIPBOARD_RegisterPixmapResource
* Registers a Pixmap resource which is to be associated with a property Atom.
* When the property is destroyed we also destroy the Pixmap through the
* PropertyNotify event.
*/
BOOL X11DRV_CLIPBOARD_RegisterPixmapResource( Atom property, Pixmap pixmap )
{
if ( -1 == DPA_InsertPtr( PropDPA, 0, (void*)property ) )
return FALSE;
if ( -1 == DPA_InsertPtr( PixmapDPA, 0, (void*)pixmap ) )
return FALSE;
return TRUE;
}
/**************************************************************************
* X11DRV_CLIPBOARD_FreeResources
*
* Called from EVENT_PropertyNotify() to give us a chance to destroy
* any resources associated with this property.
*/
void X11DRV_CLIPBOARD_FreeResources( Atom property )
{
/* Do a simple linear search to see if we have a Pixmap resource
* associated with this property and release it.
*/
int i;
Pixmap pixmap;
Atom cacheProp = NULL;
for( i = 0; ; i++ )
{
if ( !(cacheProp = ((Atom)DPA_GetPtr(PropDPA, i))) )
break;
if ( cacheProp == property )
{
/* Lookup the associated Pixmap and free it */
pixmap = (Pixmap)DPA_GetPtr(PixmapDPA, i);
TRACE("Releasing pixmap %ld for Property %s\n",
(long)pixmap, TSXGetAtomName(display, cacheProp));
XFreePixmap(display, pixmap);
/* Free the entries from the table */
DPA_DeletePtr(PropDPA, i);
DPA_DeletePtr(PixmapDPA, i);
}
}
}
#endif /* !defined(X_DISPLAY_MISSING) */

View File

@ -2,6 +2,7 @@
* X11 event driver
*
* Copyright 1993 Alexandre Julliard
* 1999 Noel Borthwick
*/
#include "config.h"
@ -79,6 +80,7 @@ static const char * const event_names[] =
"ClientMessage", "MappingNotify"
};
static void CALLBACK EVENT_Flush( ULONG_PTR arg );
static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg );
static void EVENT_ProcessEvent( XEvent *event );
@ -93,8 +95,9 @@ static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
static void EVENT_Expose( HWND hWnd, XExposeEvent *event );
static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event );
static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event );
static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event);
static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
static void EVENT_PropertyNotify( XPropertyEvent *event );
static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
static void EVENT_MapNotify( HWND pWnd, XMapEvent *event );
static void EVENT_UnmapNotify( HWND pWnd, XUnmapEvent *event );
@ -222,14 +225,14 @@ static void EVENT_ProcessEvent( XEvent *event )
}
}
if ( !hWnd && event->xany.window != X11DRV_GetXRootWindow() )
if ( !hWnd && event->xany.window != X11DRV_GetXRootWindow()
&& event->type != PropertyNotify )
ERR_(event)("Got event %s for unknown Window %08lx\n",
event_names[event->type], event->xany.window );
else
TRACE_(event)("Got event %s for hwnd %04x\n",
event_names[event->type], hWnd );
switch(event->type)
{
case KeyPress:
@ -322,7 +325,7 @@ static void EVENT_ProcessEvent( XEvent *event )
case SelectionRequest:
if (!hWnd || bUserRepaintDisabled) return;
EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event );
EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
break;
case SelectionClear:
@ -330,6 +333,10 @@ static void EVENT_ProcessEvent( XEvent *event )
EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
break;
case PropertyNotify:
EVENT_PropertyNotify( (XPropertyEvent *)event );
break;
case ClientMessage:
if (!hWnd || bUserRepaintDisabled) return;
EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
@ -833,191 +840,469 @@ static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event )
}
/***********************************************************************
* EVENT_SelectionRequest_TARGETS
* Service a TARGETS selection request event
*/
static Atom EVENT_SelectionRequest_TARGETS( Window requestor, Atom target, Atom rprop )
{
Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
Atom* targets;
Atom prop;
UINT wFormat;
unsigned long cTargets;
BOOL bHavePixmap;
int xRc;
TRACE_(event)("Request for %s\n", TSXGetAtomName(display, target));
/*
* Count the number of items we wish to expose as selection targets.
* We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
*/
cTargets = CountClipboardFormats() + 1;
if ( CLIPBOARD_IsPresent(CF_DIB) || CLIPBOARD_IsPresent(CF_BITMAP) )
cTargets++;
/* Allocate temp buffer */
targets = (Atom*)HEAP_xalloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
/* Create TARGETS property list (First item in list is TARGETS itself) */
for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
(wFormat = EnumClipboardFormats( wFormat )); )
{
if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
{
/* Scan through what we have so far to avoid duplicates */
int i;
BOOL bExists;
for (i = 0, bExists = FALSE; i < cTargets; i++)
{
if (targets[i] == prop)
{
bExists = TRUE;
break;
}
}
if (!bExists)
{
targets[cTargets++] = prop;
/* Add PIXMAP prop for bitmaps additionally */
if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
&& !bHavePixmap )
{
targets[cTargets++] = XA_PIXMAP;
bHavePixmap = TRUE;
}
}
}
}
#ifdef DEBUG_RUNTIME
{
int i;
for ( i = 0; i < cTargets; i++)
{
if (targets[i])
{
char *itemFmtName = TSXGetAtomName(display, targets[i]);
TRACE_(event)("\tAtom# %d: Type %s\n", i, itemFmtName);
TSXFree(itemFmtName);
}
}
}
#endif
/* Update the X property */
TRACE_(event)("\tUpdating property %s...", TSXGetAtomName(display, rprop));
/* We may want to consider setting the type to xaTargets instead,
* in case some apps expect this instead of XA_ATOM */
xRc = TSXChangeProperty(display, requestor, rprop,
XA_ATOM, 32, PropModeReplace,
(unsigned char *)targets, cTargets);
TRACE_(event)("(Rc=%d)\n", xRc);
HeapFree( GetProcessHeap(), 0, targets );
return rprop;
}
/***********************************************************************
* EVENT_SelectionRequest_STRING
* Service a STRING selection request event
*/
static Atom EVENT_SelectionRequest_STRING( Window requestor, Atom target, Atom rprop )
{
HANDLE16 hText;
LPSTR text;
int size,i,j;
char* lpstr = 0;
char *itemFmtName;
int xRc;
/*
* Map the requested X selection property type atom name to a
* windows clipboard format ID.
*/
itemFmtName = TSXGetAtomName(display, target);
TRACE_(event)("Request for %s (wFormat=%x %s)\n",
itemFmtName, CF_TEXT, CLIPBOARD_GetFormatName(CF_TEXT));
TSXFree(itemFmtName);
if ( !CLIPBOARD_IsPresent(CF_TEXT) )
{
rprop = None;
goto END;
}
hText = GetClipboardData16(CF_TEXT);
text = GlobalLock16(hText);
size = GlobalSize16(hText);
/* remove carriage returns */
lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
for(i=0,j=0; i < size && text[i]; i++ )
{
if( text[i] == '\r' &&
(text[i+1] == '\n' || text[i+1] == '\0') ) continue;
lpstr[j++] = text[i];
}
lpstr[j]='\0';
/* Update the X property */
TRACE_(event)("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
xRc = TSXChangeProperty(display, requestor, rprop,
XA_STRING, 8, PropModeReplace,
lpstr, j);
TRACE_(event)("(Rc=%d)\n", xRc);
GlobalUnlock16(hText);
HeapFree( GetProcessHeap(), 0, lpstr );
END:
return rprop;
}
/***********************************************************************
* EVENT_SelectionRequest_PIXMAP
* Service a PIXMAP selection request event
*/
static Atom EVENT_SelectionRequest_PIXMAP( Window requestor, Atom target, Atom rprop )
{
HANDLE hClipData = 0;
Pixmap pixmap = NULL;
UINT wFormat;
char * itemFmtName;
int xRc;
#if(0)
XSetWindowAttributes win_attr;
XWindowAttributes win_attr_src;
#endif
/*
* Map the requested X selection property type atom name to a
* windows clipboard format ID.
*/
itemFmtName = TSXGetAtomName(display, target);
wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
TRACE_(event)("Request for %s (wFormat=%x %s)\n",
itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
TSXFree(itemFmtName);
hClipData = GetClipboardData(wFormat);
if ( !hClipData )
{
TRACE_(event)("Could not retrieve a Pixmap compatible format from clipboard!\n");
rprop = None; /* Fail the request */
goto END;
}
if (wFormat == CF_DIB)
{
HWND hwnd = GetOpenClipboardWindow();
HDC hdc = GetDC(hwnd);
/* For convert from packed DIB to Pixmap */
pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
ReleaseDC(hdc, hwnd);
}
else if (wFormat == CF_BITMAP)
{
HWND hwnd = GetOpenClipboardWindow();
HDC hdc = GetDC(hwnd);
pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
ReleaseDC(hdc, hwnd);
}
else
{
FIXME_(event)("%s to PIXMAP conversion not yet implemented!\n",
CLIPBOARD_GetFormatName(wFormat));
rprop = None;
goto END;
}
TRACE_(event)("\tUpdating property %s on Window %ld with %s %ld...\n",
TSXGetAtomName(display, rprop), (long)requestor,
TSXGetAtomName(display, target),
pixmap);
/* Store the Pixmap handle in the property */
xRc = TSXChangeProperty(display, requestor, rprop, target,
32, PropModeReplace,
(unsigned char *)&pixmap, 1);
TRACE_(event)("(Rc=%d)\n", xRc);
/* Enable the code below if you want to handle destroying Pixmap resources
* in response to property notify events. Clients like XPaint don't
* appear to be duplicating Pixmaps so they don't like us deleting,
* the resource in response to the property being deleted.
*/
#if(0)
/* Express interest in property notify events so that we can delete the
* pixmap when the client deletes the property atom.
*/
xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
TRACE_(event)("Turning on PropertyChangeEvent notifications from window %ld\n",
(long)requestor);
win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
/* Register the Pixmap we created with the request property Atom.
* When this property is destroyed we also destroy the Pixmap in
* response to the PropertyNotify event.
*/
X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
#endif
END:
return rprop;
}
/***********************************************************************
* EVENT_SelectionRequest_WCF
* Service a Wine Clipboard Format selection request event.
* For <WCF>* data types we simply copy the data to X without conversion.
*/
static Atom EVENT_SelectionRequest_WCF( Window requestor, Atom target, Atom rprop )
{
HANDLE hClipData = 0;
void* lpClipData;
UINT wFormat;
char * itemFmtName;
int cBytes;
int xRc;
/*
* Map the requested X selection property type atom name to a
* windows clipboard format ID.
*/
itemFmtName = TSXGetAtomName(display, target);
wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
TRACE_(event)("Request for %s (wFormat=%x %s)\n",
itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
TSXFree(itemFmtName);
hClipData = GetClipboardData16(wFormat);
if( hClipData && (lpClipData = GlobalLock16(hClipData)) )
{
cBytes = GlobalSize16(hClipData);
TRACE_(event)("\tUpdating property %s, %d bytes...\n",
TSXGetAtomName(display, rprop), cBytes);
xRc = TSXChangeProperty(display, requestor, rprop,
target, 8, PropModeReplace,
(unsigned char *)lpClipData, cBytes);
TRACE_(event)("(Rc=%d)\n", xRc);
GlobalUnlock16(hClipData);
}
else
{
TRACE_(event)("\tCould not retrieve native format!\n");
rprop = None; /* Fail the request */
}
return rprop;
}
/***********************************************************************
* EVENT_SelectionRequest_MULTIPLE
* Service a MULTIPLE selection request event
* rprop contains a list of (target,property) atom pairs.
* The first atom names a target and the second names a property.
* The effect is as if we have received a sequence of SelectionRequest events
* (one for each atom pair) except that:
* 1. We reply with a SelectionNotify only when all the requested conversions
* have been performed.
* 2. If we fail to convert the target named by an atom in the MULTIPLE property,
* we replace the atom in the property by None.
*/
static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
{
Atom rprop;
Atom atype=AnyPropertyType;
int aformat;
unsigned long remain;
Atom* targetPropList=NULL;
unsigned long cTargetPropList = 0;
/* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
/* If the specified property is None the requestor is an obsolete client.
* We support these by using the specified target atom as the reply property.
*/
rprop = pevent->property;
if( rprop == None )
rprop = pevent->target;
if (!rprop)
goto END;
/* Read the MULTIPLE property contents. This should contain a list of
* (target,property) atom pairs.
*/
if(TSXGetWindowProperty(display, pevent->requestor, rprop,
0, 0x3FFF, False, AnyPropertyType, &atype, &aformat,
&cTargetPropList, &remain, (unsigned char**)&targetPropList) != Success)
TRACE_(event)("\tCouldn't read MULTIPLE property\n");
else
{
TRACE_(event)("\tType %s,Format %d,nItems %ld, Remain %ld\n",
TSXGetAtomName(display,atype),aformat,cTargetPropList,remain);
/*
* Make sure we got what we expect.
* NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
* in a MULTIPLE selection request should be of type ATOM_PAIR.
* However some X apps(such as XPaint) are not compliant with this and return
* a user defined atom in atype when XGetWindowProperty is called.
* The data *is* an atom pair but is not denoted as such.
*/
if(aformat == 32 /* atype == xAtomPair */ )
{
int i;
/* Iterate through the ATOM_PAIR list and execute a SelectionRequest
* for each (target,property) pair */
for (i = 0; i < cTargetPropList; i+=2)
{
char *targetName = TSXGetAtomName(display, targetPropList[i]);
char *propName = TSXGetAtomName(display, targetPropList[i+1]);
XSelectionRequestEvent event;
TRACE_(event)("MULTIPLE(%d): Target='%s' Prop='%s'\n", i/2, targetName, propName);
TSXFree(targetName);
TSXFree(propName);
/* We must have a non "None" property to service a MULTIPLE target atom */
if ( !targetPropList[i+1] )
{
TRACE_(event)("\tMULTIPLE(%d): Skipping target with empty property!", i);
continue;
}
/* Set up an XSelectionRequestEvent for this (target,property) pair */
memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
event.target = targetPropList[i];
event.property = targetPropList[i+1];
/* Fire a SelectionRequest, informing the handler that we are processing
* a MULTIPLE selection request event.
*/
EVENT_SelectionRequest( hWnd, &event, TRUE );
}
}
/* Free the list of targets/properties */
TSXFree(targetPropList);
}
END:
return rprop;
}
/***********************************************************************
* EVENT_SelectionRequest
* Process an event selection request event.
* The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
* recursively while servicing a "MULTIPLE" selection target.
*
* Note: We only receive this event when WINE owns the X selection
*/
static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event )
static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
{
XSelectionEvent result;
Atom rprop = None;
Window request = event->requestor;
UINT wFormat;
char * itemFmtName;
BOOL couldOpen = FALSE;
Atom xaClipboard = XInternAtom(display, "CLIPBOARD", False);
Atom xaTargets = XInternAtom(display, "TARGETS", False);
int xRc;
/*
* Map the requested X selection property type atom name to a
* windows clipboard format ID.
*/
itemFmtName = TSXGetAtomName(display, event->target);
wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
TRACE_(event)("Request for %s\n", itemFmtName);
TSXFree(itemFmtName);
Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
Atom xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
/*
* We can only handle the selection request if :
* The selection is PRIMARY or CLIPBOARD,
* AND we can successfully open the clipboard.
* AND we have a request for a TARGETS selection target,
* OR the requested format is available in the clipboard
* The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
* Don't do these checks or open the clipboard while recursively processing MULTIPLE,
* since this has been already done.
*/
if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
|| !(couldOpen = OpenClipboard(hWnd)) )
goto END;
if ( (event->target != xaTargets)
&& ( (0 == wFormat) || !CLIPBOARD_IsPresent(wFormat) ) )
goto END;
if ( !bIsMultiple )
{
if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
|| !(couldOpen = OpenClipboard(hWnd)) )
goto END;
}
/* We can handle the request */
/* If the specified property is None the requestor is an obsolete client.
* We support these by using the specified target atom as the reply property.
*/
rprop = event->property;
if( rprop == None )
rprop = event->target;
if(event->target == xaTargets) /* Return a list of all supported targets */
{
Atom* targets;
Atom prop;
UINT wFormat;
unsigned long cTargets;
BOOL bHavePixmap;
/*
* Count the number of items we wish to expose as selection targets.
* We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
*/
cTargets = CountClipboardFormats() + 1;
if ( CLIPBOARD_IsPresent(CF_DIB) || CLIPBOARD_IsPresent(CF_BITMAP) )
cTargets++;
/* Allocate temp buffer */
targets = (Atom*)HEAP_xalloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
/* Create TARGETS property list (First item in list is TARGETS itself) */
for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
(wFormat = EnumClipboardFormats( wFormat )); )
{
if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
{
/* Scan through what we have so far to avoid duplicates */
int i;
BOOL bExists;
for (i = 0, bExists = FALSE; i < cTargets; i++)
{
if (targets[i] == prop)
{
bExists = TRUE;
break;
}
}
if (!bExists)
{
targets[cTargets++] = prop;
/* Add PIXMAP prop for bitmaps additionally */
if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
&& !bHavePixmap )
{
targets[cTargets++] = XA_PIXMAP;
bHavePixmap = TRUE;
}
}
}
}
#ifdef DEBUG_RUNTIME
{
int i;
for ( i = 0; i < cTargets; i++)
{
if (targets[i])
{
char *itemFmtName = TSXGetAtomName(display, targets[i]);
TRACE_(event)("\tAtom# %d: Type %s\n", i, itemFmtName);
TSXFree(itemFmtName);
}
}
}
#endif
/* Update the X property */
TRACE_(event)("\tUpdating property %s...", TSXGetAtomName(display, rprop));
xRc = TSXChangeProperty(display, request, rprop,
XA_ATOM, 32, PropModeReplace,
(unsigned char *)targets, cTargets);
TRACE_(event)("(Rc=%d)\n", xRc);
HeapFree( GetProcessHeap(), 0, targets );
/* TARGETS selection request */
rprop = EVENT_SelectionRequest_TARGETS( request, event->target, rprop );
}
else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
{
/* MULTIPLE selection request */
rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
}
else if(event->target == XA_STRING) /* treat CF_TEXT as Unix text */
{
HANDLE16 hText;
LPSTR text;
int size,i,j;
char* lpstr = 0;
hText = GetClipboardData16(CF_TEXT);
text = GlobalLock16(hText);
size = GlobalSize16(hText);
/* remove carriage returns */
lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
for(i=0,j=0; i < size && text[i]; i++ )
{
if( text[i] == '\r' &&
(text[i+1] == '\n' || text[i+1] == '\0') ) continue;
lpstr[j++] = text[i];
}
lpstr[j]='\0';
/* Update the X property */
TRACE_(event)("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
xRc = TSXChangeProperty(display, request, rprop,
XA_STRING, 8, PropModeReplace,
lpstr, j);
TRACE_(event)("(Rc=%d)\n", xRc);
GlobalUnlock16(hText);
HeapFree( GetProcessHeap(), 0, lpstr );
/* XA_STRING selection request */
rprop = EVENT_SelectionRequest_STRING( request, event->target, rprop );
}
else if(event->target == XA_PIXMAP) /* Convert DIB's to Pixmaps */
{
FIXME_(event)("DIB to PIXMAP conversion not yet implemented!\n");
rprop = None;
/* XA_PIXMAP selection request */
rprop = EVENT_SelectionRequest_PIXMAP( request, event->target, rprop );
}
else /* For other data types (WCF_*) simply copy the data to X without conversion */
else if(event->target == XA_BITMAP) /* Convert DIB's to 1-bit Pixmaps */
{
HANDLE hClipData = 0;
void* lpClipData;
int cBytes;
hClipData = GetClipboardData16(wFormat);
if( hClipData && (lpClipData = GlobalLock16(hClipData)) )
{
cBytes = GlobalSize16(hClipData);
TRACE_(event)("\tUpdating property %s, %d bytes...\n",
TSXGetAtomName(display, rprop), cBytes);
xRc = TSXChangeProperty(display, request, rprop,
event->target, 8, PropModeReplace,
(unsigned char *)lpClipData, cBytes);
TRACE_(event)("(Rc=%d)\n", xRc);
GlobalUnlock16(hClipData);
}
else
rprop = None; /* Fail the request */
/* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
rprop = EVENT_SelectionRequest_PIXMAP( request, XA_PIXMAP, rprop );
}
else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
{
/* All <WCF> selection requests */
rprop = EVENT_SelectionRequest_WCF( request, event->target, rprop );
}
else
rprop = None; /* Don't support this format */
END:
/* close clipboard only if we opened before */
@ -1026,16 +1311,21 @@ END:
if( rprop == None)
TRACE_(event)("\tRequest ignored\n");
/* reply to sender */
result.type = SelectionNotify;
result.display = display;
result.requestor = request;
result.selection = event->selection;
result.property = rprop;
result.target = event->target;
result.time = event->time;
TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
/* reply to sender
* SelectionNotify should be sent only at the end of a MULTIPLE request
*/
if ( !bIsMultiple )
{
result.type = SelectionNotify;
result.display = display;
result.requestor = request;
result.selection = event->selection;
result.property = rprop;
result.target = event->target;
result.time = event->time;
TRACE_(event)("Sending SelectionNotify event...\n");
TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
}
}
/***********************************************************************
@ -1043,12 +1333,45 @@ END:
*/
static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
{
Atom xaClipboard = XInternAtom(display, "CLIPBOARD", False);
Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
}
/***********************************************************************
* EVENT_PropertyNotify
* We use this to release resources like Pixmaps when a selection
* client no longer needs them.
*/
static void EVENT_PropertyNotify( XPropertyEvent *event )
{
/* Check if we have any resources to free */
TRACE_(event)("Received PropertyNotify event: ");
switch(event->state)
{
case PropertyDelete:
{
TRACE_(event)("\tPropertyDelete for atom %s on window %ld\n",
TSXGetAtomName(event->display, event->atom), (long)event->window);
if (X11DRV_CLIPBOARD_IsSelectionowner())
X11DRV_CLIPBOARD_FreeResources( event->atom );
break;
}
case PropertyNewValue:
{
TRACE_(event)("\tPropertyNewValue for atom %s on window %ld\n\n",
TSXGetAtomName(event->display, event->atom), (long)event->window);
break;
}
default:
break;
}
}
/**********************************************************************
* EVENT_DropFromOffix