[PATCH 3/3] winex11.drv: use the clipboard functions and formats to import drag and drop selections

Damjan Jovanovic damjan.jov at gmail.com
Sun May 4 22:33:14 CDT 2014


Use the clipboard formats for importing drag and drop selections,
which de-duplicates a lot of code, allows the drag and drop code to
use INCR for large transfers, and supports dragging and dropping new
types into Wine, such as images.

Damjan Jovanovic

---
 dlls/winex11.drv/clipboard.c |  19 +++
 dlls/winex11.drv/x11drv.h    |   1 +
 dlls/winex11.drv/xdnd.c      | 317 +++----------------------------------------
 3 files changed, 38 insertions(+), 299 deletions(-)

diff --git a/dlls/winex11.drv/clipboard.c b/dlls/winex11.drv/clipboard.c
index acb4e3f..e3508ca 100644
--- a/dlls/winex11.drv/clipboard.c
+++ b/dlls/winex11.drv/clipboard.c
@@ -1698,6 +1698,25 @@ static HANDLE
X11DRV_CLIPBOARD_ImportClipboardData(Display *display, Window w, A


 /**************************************************************************
+ *      X11DRV_CLIPBOARD_ImportSelection
+ *
+ *  Import the X selection into the clipboard format registered for
the given X target.
+ */
+HANDLE X11DRV_CLIPBOARD_ImportSelection(Display *d, Atom target,
Window w, Atom prop, UINT *windowsFormat)
+{
+    WINE_CLIPFORMAT *clipFormat;
+
+    clipFormat = X11DRV_CLIPBOARD_LookupProperty(NULL, target);
+    if (clipFormat)
+    {
+        *windowsFormat = clipFormat->wFormatID;
+        return clipFormat->lpDrvImportFunc(d, w, prop);
+    }
+    return NULL;
+}
+
+
+/**************************************************************************
  X11DRV_CLIPBOARD_ExportClipboardData
  *
  *  Generic export clipboard data routine.
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 7a3374d..bcbfe14 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -238,6 +238,7 @@ extern void X11DRV_XDND_EnterEvent( HWND hWnd,
XClientMessageEvent *event ) DECL
 extern void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent
*event ) DECLSPEC_HIDDEN;
 extern void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent
*event ) DECLSPEC_HIDDEN;
 extern void X11DRV_XDND_LeaveEvent( HWND hWnd, XClientMessageEvent
*event ) DECLSPEC_HIDDEN;
+extern HANDLE X11DRV_CLIPBOARD_ImportSelection(Display *d, Atom
target, Window w, Atom prop, UINT *windowsFormat) DECLSPEC_HIDDEN;

 /**************************************************************************
  * X11 GDI driver
diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c
index e894de0..4d19360 100644
--- a/dlls/winex11.drv/xdnd.c
+++ b/dlls/winex11.drv/xdnd.c
@@ -56,8 +56,7 @@ typedef struct tagXDNDDATA
 {
     int cf_win;
     Atom cf_xdnd;
-    void *data;
-    unsigned int size;
+    HANDLE contents;
     struct list entry;
 } XDNDDATA, *LPXDNDDATA;

@@ -71,17 +70,11 @@ static HWND XDNDLastTargetWnd;
 /* might be an ancestor of XDNDLastTargetWnd */
 static HWND XDNDLastDropTargetWnd;

-static void X11DRV_XDND_InsertXDNDData(int property, int format,
void* data, unsigned int len);
-static int X11DRV_XDND_DeconstructTextURIList(int property, void*
data, int len);
-static int X11DRV_XDND_DeconstructTextPlain(int property, void* data, int len);
-static int X11DRV_XDND_DeconstructTextHTML(int property, void* data, int len);
-static int X11DRV_XDND_MapFormat(unsigned int property, unsigned char
*data, int len);
+static void X11DRV_XDND_InsertXDNDData(int property, int format,
HANDLE contents);
 static void X11DRV_XDND_ResolveProperty(Display *display, Window xwin, Time tm,
     Atom *types, unsigned long *count);
 static void X11DRV_XDND_SendDropFiles(HWND hwnd);
 static void X11DRV_XDND_FreeDragDropOp(void);
-static unsigned int X11DRV_XDND_UnixToDos(char** lpdest, char* lpsrc, int len);
-static WCHAR* X11DRV_XDND_URIToDOS(char *encodedURI);

 static CRITICAL_SECTION xdnd_cs;
 static CRITICAL_SECTION_DEBUG critsect_debug =
@@ -459,11 +452,6 @@ static void X11DRV_XDND_ResolveProperty(Display
*display, Window xwin, Time tm,
     unsigned int i, j;
     BOOL res;
     XEvent xe;
-    Atom acttype;
-    int actfmt;
-    unsigned long bytesret, icount;
-    int entries = 0;
-    unsigned char* data = NULL;
     XDNDDATA *current, *next;
     BOOL haveHDROP = FALSE;

@@ -473,6 +461,9 @@ static void X11DRV_XDND_ResolveProperty(Display
*display, Window xwin, Time tm,

     for (i = 0; i < *count; i++)
     {
+        HANDLE contents;
+        UINT windowsFormat;
+
         TRACE("requesting atom %ld from xwin %ld\n", types[i], xwin);

         if (types[i] == 0)
@@ -495,11 +486,9 @@ static void X11DRV_XDND_ResolveProperty(Display
*display, Window xwin, Time tm,
         if (xe.xselection.property == None)
             continue;

-        XGetWindowProperty(display, xwin, x11drv_atom(XdndTarget), 0,
65535, FALSE,
-            AnyPropertyType, &acttype, &actfmt, &icount, &bytesret, &data);
-
-        entries += X11DRV_XDND_MapFormat(types[i], data,
get_property_size( actfmt, icount ));
-        XFree(data);
+        contents = X11DRV_CLIPBOARD_ImportSelection(display,
types[i], xwin, x11drv_atom(XdndTarget), &windowsFormat);
+        if (contents)
+            X11DRV_XDND_InsertXDNDData(types[i], windowsFormat, contents);
     }

     /* On Windows when there is a CF_HDROP, there are no other CF_ formats.
@@ -520,14 +509,11 @@ static void X11DRV_XDND_ResolveProperty(Display
*display, Window xwin, Time tm,
             if (current->cf_win != CF_HDROP && current->cf_win < CF_MAX)
             {
                 list_remove(&current->entry);
-                HeapFree(GetProcessHeap(), 0, current->data);
+                GlobalFree(current->contents);
                 HeapFree(GetProcessHeap(), 0, current);
-                --entries;
             }
         }
     }
-
-    *count = entries;
 }


@@ -536,7 +522,7 @@ static void X11DRV_XDND_ResolveProperty(Display
*display, Window xwin, Time tm,
  *
  * Cache available XDND property
  */
-static void X11DRV_XDND_InsertXDNDData(int property, int format,
void* data, unsigned int len)
+static void X11DRV_XDND_InsertXDNDData(int property, int format,
HANDLE contents)
 {
     LPXDNDDATA current = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, sizeof(XDNDDATA));

@@ -545,8 +531,7 @@ static void X11DRV_XDND_InsertXDNDData(int
property, int format, void* data, uns
         EnterCriticalSection(&xdnd_cs);
         current->cf_xdnd = property;
         current->cf_win = format;
-        current->data = data;
-        current->size = len;
+        current->contents = contents;
         list_add_tail(&xdndData, &current->entry);
         LeaveCriticalSection(&xdnd_cs);
     }
@@ -554,158 +539,6 @@ static void X11DRV_XDND_InsertXDNDData(int
property, int format, void* data, uns


 /**************************************************************************
- * X11DRV_XDND_MapFormat
- *
- * Map XDND MIME format to windows clipboard format.
- */
-static int X11DRV_XDND_MapFormat(unsigned int property, unsigned char
*data, int len)
-{
-    void* xdata;
-    int count = 0;
-
-    TRACE("%d: %s\n", property, data);
-
-    /* Always include the raw type */
-    xdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
-    memcpy(xdata, data, len);
-    X11DRV_XDND_InsertXDNDData(property, property, xdata, len);
-    count++;
-
-    if (property == x11drv_atom(text_uri_list))
-        count += X11DRV_XDND_DeconstructTextURIList(property, data, len);
-    else if (property == x11drv_atom(text_plain))
-        count += X11DRV_XDND_DeconstructTextPlain(property, data, len);
-    else if (property == x11drv_atom(text_html))
-        count += X11DRV_XDND_DeconstructTextHTML(property, data, len);
-
-    return count;
-}
-
-
-/**************************************************************************
- * X11DRV_XDND_DeconstructTextURIList
- *
- * Interpret text/uri-list data and add records to <dndfmt> linked list
- */
-static int X11DRV_XDND_DeconstructTextURIList(int property, void*
data, int len)
-{
-    char *uriList = data;
-    char *uri;
-    WCHAR *path;
-
-    WCHAR *out = NULL;
-    int size = 0;
-    int capacity = 4096;
-
-    int count = 0;
-    int start = 0;
-    int end = 0;
-
-    out = HeapAlloc(GetProcessHeap(), 0, capacity * sizeof(WCHAR));
-    if (out == NULL)
-        return 0;
-
-    while (end < len)
-    {
-        while (end < len && uriList[end] != '\r')
-            ++end;
-        if (end < (len - 1) && uriList[end+1] != '\n')
-        {
-            WARN("URI list line doesn't end in \\r\\n\n");
-            break;
-        }
-
-        uri = HeapAlloc(GetProcessHeap(), 0, end - start + 1);
-        if (uri == NULL)
-            break;
-        lstrcpynA(uri, &uriList[start], end - start + 1);
-        path = X11DRV_XDND_URIToDOS(uri);
-        TRACE("converted URI %s to DOS path %s\n", debugstr_a(uri),
debugstr_w(path));
-        HeapFree(GetProcessHeap(), 0, uri);
-
-        if (path)
-        {
-            int pathSize = strlenW(path) + 1;
-            if (pathSize > capacity-size)
-            {
-                capacity = 2*capacity + pathSize;
-                out = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
out, (capacity + 1)*sizeof(WCHAR));
-                if (out == NULL)
-                    goto done;
-            }
-            memcpy(&out[size], path, pathSize * sizeof(WCHAR));
-            size += pathSize;
-        done:
-            HeapFree(GetProcessHeap(), 0, path);
-            if (out == NULL)
-                break;
-        }
-
-        start = end + 2;
-        end = start;
-    }
-    if (out && end >= len)
-    {
-        DROPFILES *dropFiles;
-        dropFiles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(DROPFILES) + (size + 1)*sizeof(WCHAR));
-        if (dropFiles)
-        {
-            dropFiles->pFiles = sizeof(DROPFILES);
-            dropFiles->pt.x = XDNDxy.x;
-            dropFiles->pt.y = XDNDxy.y;
-            dropFiles->fNC = 0;
-            dropFiles->fWide = TRUE;
-            out[size] = '\0';
-            memcpy(((char*)dropFiles) + dropFiles->pFiles, out, (size
+ 1)*sizeof(WCHAR));
-            X11DRV_XDND_InsertXDNDData(property, CF_HDROP, dropFiles,
sizeof(DROPFILES) + (size + 1)*sizeof(WCHAR));
-            count = 1;
-        }
-    }
-    HeapFree(GetProcessHeap(), 0, out);
-    return count;
-}
-
-
-/**************************************************************************
- * X11DRV_XDND_DeconstructTextPlain
- *
- * Interpret text/plain Data and add records to <dndfmt> linked list
- */
-static int X11DRV_XDND_DeconstructTextPlain(int property, void* data, int len)
-{
-    char* dostext;
-
-    /* Always supply plain text */
-    X11DRV_XDND_UnixToDos(&dostext, data, len);
-    X11DRV_XDND_InsertXDNDData(property, CF_TEXT, dostext, strlen(dostext));
-
-    TRACE("CF_TEXT (%d): %s\n", CF_TEXT, dostext);
-
-    return 1;
-}
-
-
-/**************************************************************************
- * X11DRV_XDND_DeconstructTextHTML
- *
- * Interpret text/html data and add records to <dndfmt> linked list
- */
-static int X11DRV_XDND_DeconstructTextHTML(int property, void* data, int len)
-{
-    char* dostext;
-
-    X11DRV_XDND_UnixToDos(&dostext, data, len);
-
-    X11DRV_XDND_InsertXDNDData(property,
-        RegisterClipboardFormatA("UniformResourceLocator"), dostext,
strlen(dostext));
-
-    TRACE("UniformResourceLocator: %s\n", dostext);
-
-    return 1;
-}
-
-
-/**************************************************************************
  * X11DRV_XDND_SendDropFiles
  */
 static void X11DRV_XDND_SendDropFiles(HWND hwnd)
@@ -727,14 +560,15 @@ static void X11DRV_XDND_SendDropFiles(HWND hwnd)

     if (found)
     {
-        HGLOBAL dropHandle = GlobalAlloc(GMEM_FIXED, current->size);
+        HGLOBAL dropHandle = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
GlobalSize(current->contents));

         if (dropHandle)
         {
             DROPFILES *lpDrop = GlobalLock(dropHandle);
             lpDrop->pt.x = XDNDxy.x;
             lpDrop->pt.y = XDNDxy.y;
-            memcpy(lpDrop, current->data, current->size);
+            memcpy(lpDrop, GlobalLock(current->contents),
GlobalSize(current->contents));
+            GlobalUnlock(current->contents);
             TRACE("Sending WM_DROPFILES: hWnd(0x%p) %p(%s)\n", hwnd,
                 ((char*)lpDrop) + lpDrop->pFiles,
debugstr_w((WCHAR*)(((char*)lpDrop) + lpDrop->pFiles)));
             GlobalUnlock(dropHandle);
@@ -764,7 +598,7 @@ static void X11DRV_XDND_FreeDragDropOp(void)
     LIST_FOR_EACH_ENTRY_SAFE(current, next, &xdndData, XDNDDATA, entry)
     {
         list_remove(&current->entry);
-        HeapFree(GetProcessHeap(), 0, current->data);
+        GlobalFree(current->contents);
         HeapFree(GetProcessHeap(), 0, current);
     }

@@ -777,122 +611,6 @@ static void X11DRV_XDND_FreeDragDropOp(void)
 }


-
-/**************************************************************************
- * X11DRV_XDND_UnixToDos
- */
-static unsigned int X11DRV_XDND_UnixToDos(char** lpdest, char* lpsrc, int len)
-{
-    int i;
-    unsigned int destlen, lines;
-
-    for (i = 0, lines = 0; i <= len; i++)
-    {
-        if (lpsrc[i] == '\n')
-            lines++;
-    }
-
-    destlen = len + lines + 1;
-
-    if (lpdest)
-    {
-        char* lpstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, destlen);
-        for (i = 0, lines = 0; i <= len; i++)
-        {
-            if (lpsrc[i] == '\n')
-                lpstr[++lines + i] = '\r';
-            lpstr[lines + i] = lpsrc[i];
-        }
-
-        *lpdest = lpstr;
-    }
-
-    return lines;
-}
-
-
-/**************************************************************************
- * X11DRV_XDND_URIToDOS
- */
-static WCHAR* X11DRV_XDND_URIToDOS(char *encodedURI)
-{
-    WCHAR *ret = NULL;
-    int i;
-    int j = 0;
-    char *uri = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
strlen(encodedURI) + 1);
-    if (uri == NULL)
-        return NULL;
-    for (i = 0; encodedURI[i]; ++i)
-    {
-        if (encodedURI[i] == '%')
-        {
-            if (encodedURI[i+1] && encodedURI[i+2])
-            {
-                char buffer[3];
-                int number;
-                buffer[0] = encodedURI[i+1];
-                buffer[1] = encodedURI[i+2];
-                buffer[2] = '\0';
-                sscanf(buffer, "%x", &number);
-                uri[j++] = number;
-                i += 2;
-            }
-            else
-            {
-                WARN("invalid URI encoding in %s\n", debugstr_a(encodedURI));
-                HeapFree(GetProcessHeap(), 0, uri);
-                return NULL;
-            }
-        }
-        else
-            uri[j++] = encodedURI[i];
-    }
-
-    /* Read http://www.freedesktop.org/wiki/Draganddropwarts and cry... */
-    if (strncmp(uri, "file:/", 6) == 0)
-    {
-        if (uri[6] == '/')
-        {
-            if (uri[7] == '/')
-            {
-                /* file:///path/to/file (nautilus, thunar) */
-                ret = wine_get_dos_file_name(&uri[7]);
-            }
-            else if (uri[7])
-            {
-                /* file://hostname/path/to/file (X file drag spec) */
-                char hostname[256];
-                char *path = strchr(&uri[7], '/');
-                if (path)
-                {
-                    *path = '\0';
-                    if (strcmp(&uri[7], "localhost") == 0)
-                    {
-                        *path = '/';
-                        ret = wine_get_dos_file_name(path);
-                    }
-                    else if (gethostname(hostname, sizeof(hostname)) == 0)
-                    {
-                        if (strcmp(hostname, &uri[7]) == 0)
-                        {
-                            *path = '/';
-                            ret = wine_get_dos_file_name(path);
-                        }
-                    }
-                }
-            }
-        }
-        else if (uri[6])
-        {
-            /* file:/path/to/file (konqueror) */
-            ret = wine_get_dos_file_name(&uri[5]);
-        }
-    }
-    HeapFree(GetProcessHeap(), 0, uri);
-    return ret;
-}
-
-
 /**************************************************************************
  * X11DRV_XDND_DescribeClipboardFormat
  */
@@ -985,10 +703,11 @@ static HRESULT WINAPI
XDNDDATAOBJECT_GetData(IDataObject *dataObject,
             if (current->cf_win == formatEtc->cfFormat)
             {
                 pMedium->tymed = TYMED_HGLOBAL;
-                pMedium->u.hGlobal = HeapAlloc(GetProcessHeap(), 0,
current->size);
+                pMedium->u.hGlobal = GlobalAlloc(GMEM_FIXED |
GMEM_ZEROINIT, GlobalSize(current->contents));
                 if (pMedium->u.hGlobal == NULL)
                     return E_OUTOFMEMORY;
-                memcpy(pMedium->u.hGlobal, current->data, current->size);
+                memcpy(pMedium->u.hGlobal,
GlobalLock(current->contents), GlobalSize(current->contents));
+                GlobalUnlock(current->contents);
                 pMedium->pUnkForRelease = 0;
                 return S_OK;
             }
-- 
1.8.5.4



More information about the wine-patches mailing list