From: Damjan Jovanovic Subject: [PATCH 3/7] winex11.drv: use the correct XDND timestamp when converting selections Message-Id: Date: Mon, 25 Apr 2016 03:00:35 +0200 XDND specifies a timestamp in XdndPosition and XdndDrop messages to be used when converting selections, which prevents race conditions over slow X11 connections. Wine is passing the wrong field from the XdndEnter message as the timestamp, and then using CurrentTime instead since that usually doesn't work... Additionally drag sources might only expect their selections to be requested later, in XdndPosition. Rather remember the XdndTypeList atoms obtained from XdndEnter, and then use them with the timestamp obtained from XdndPosition when converting the selections. Signed-off-by: Damjan Jovanovic --- dlls/winex11.drv/xdnd.c | 60 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c index cbc917a..c852d44 100644 --- a/dlls/winex11.drv/xdnd.c +++ b/dlls/winex11.drv/xdnd.c @@ -62,6 +62,9 @@ typedef struct tagXDNDDATA } XDNDDATA, *LPXDNDDATA; static struct list xdndData = LIST_INIT(xdndData); +static Atom *XDNDTypeList = NULL; +static unsigned long XDNDTypeListSize = 0; +static BOOL XDNDResolvedProperties = FALSE; static POINT XDNDxy = { 0, 0 }; static IDataObject XDNDDataObject; static BOOL XDNDAccepted = FALSE; @@ -200,7 +203,6 @@ void X11DRV_XDND_EnterEvent( HWND hWnd, XClientMessageEvent *event ) { int version; Atom *xdndtypes; - unsigned long count = 0; version = (event->data.l[1] & 0xFF000000) >> 24; TRACE("ver(%d) check-XdndTypeList(%ld) data=%ld,%ld,%ld,%ld,%ld\n", @@ -226,36 +228,48 @@ void X11DRV_XDND_EnterEvent( HWND hWnd, XClientMessageEvent *event ) /* Request supported formats from source window */ XGetWindowProperty(event->display, event->data.l[0], x11drv_atom(XdndTypeList), - 0, 65535, FALSE, AnyPropertyType, &acttype, &actfmt, &count, + 0, 65535, FALSE, AnyPropertyType, &acttype, &actfmt, &XDNDTypeListSize, &bytesret, (unsigned char**)&xdndtypes); } else { - count = 3; + XDNDTypeListSize = 3; xdndtypes = (Atom*) &event->data.l[2]; } + if (xdndtypes) + { + XDNDTypeList = HeapAlloc(GetProcessHeap(), 0, XDNDTypeListSize*sizeof(Atom)); + if (XDNDTypeList) + memcpy(XDNDTypeList, xdndtypes, XDNDTypeListSize*sizeof(Atom)); + else + { + ERR("out of memory for XDNDTypeList\n"); + XDNDTypeListSize = 0; + } + if (event->data.l[1] & 1) + XFree(xdndtypes); + } + else + { + ERR("could not read XdndTypeList property from X11 window 0x%lx\n", event->data.l[0]); + XDNDTypeListSize = 0; + } + if (TRACE_ON(xdnd)) { unsigned int i; - for (i = 0; i < count; i++) + for (i = 0; i < XDNDTypeListSize; i++) { - if (xdndtypes[i] != 0) + if (XDNDTypeList[i] != 0) { - char * pn = XGetAtomName(event->display, xdndtypes[i]); - TRACE("XDNDEnterAtom %ld: %s\n", xdndtypes[i], pn); + char * pn = XGetAtomName(event->display, XDNDTypeList[i]); + TRACE("XDNDEnterAtom %ld: %s\n", XDNDTypeList[i], pn); XFree(pn); } } } - - /* Do a one-time data read and cache results */ - X11DRV_XDND_ResolveProperty(event->display, event->window, - event->data.l[1], xdndtypes, count); - - if (event->data.l[1] & 1) - XFree(xdndtypes); } /************************************************************************** @@ -268,6 +282,7 @@ void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) XClientMessageEvent e; int accept = 0; /* Assume we're not accepting */ IDropTarget *dropTarget = NULL; + Time time; DWORD effect; POINTL pointl; HWND targetWindow; @@ -278,8 +293,17 @@ void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) pointl.x = XDNDxy.x; pointl.y = XDNDxy.y; + time = event->data.l[3]; effect = X11DRV_XDND_XdndActionToDROPEFFECT(event->data.l[4]); + /* Do a one-time data read and cache results */ + if (!XDNDResolvedProperties) + { + X11DRV_XDND_ResolveProperty(event->display, event->window, + time, XDNDTypeList, XDNDTypeListSize); + XDNDResolvedProperties = TRUE; + } + if (!XDNDAccepted || XDNDLastTargetWnd != targetWindow) { /* Notify OLE of DragEnter. Result determines if we accept */ @@ -504,8 +528,6 @@ static void X11DRV_XDND_ResolveProperty(Display *display, Window xwin, Time tm, TRACE("count(%ld)\n", count); - X11DRV_XDND_FreeDragDropOp(); /* Clear previously cached data */ - for (i = 0; i < count; i++) { HANDLE contents; @@ -517,7 +539,7 @@ static void X11DRV_XDND_ResolveProperty(Display *display, Window xwin, Time tm, continue; XConvertSelection(display, x11drv_atom(XdndSelection), types[i], - x11drv_atom(XdndTarget), xwin, /*tm*/CurrentTime); + x11drv_atom(XdndTarget), xwin, tm); /* * Wait for SelectionNotify @@ -684,6 +706,10 @@ static void X11DRV_XDND_FreeDragDropOp(void) HeapFree(GetProcessHeap(), 0, current); } + HeapFree(GetProcessHeap(), 0, XDNDTypeList); + XDNDTypeList = NULL; + XDNDTypeListSize = 0; + XDNDResolvedProperties = FALSE; XDNDxy.x = XDNDxy.y = 0; XDNDLastTargetWnd = NULL; XDNDLastDropTargetWnd = NULL;