[PATCH 2/3] winex11.drv: copy and paste files to/from X11 apps

Damjan Jovanovic damjan.jov at gmail.com
Sun May 4 22:29:54 CDT 2014


Import and export HDROP as text/uri-list, so we can copy and paste
files bidirectionally between X11 apps and Wine apps. This patch is
based on the import functions from xdnd.c, which are deleted from
there in the next patch.

---
 dlls/winex11.drv/clipboard.c | 306 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 305 insertions(+), 1 deletion(-)

diff --git a/dlls/winex11.drv/clipboard.c b/dlls/winex11.drv/clipboard.c
index 730b6c9..acb4e3f 100644
--- a/dlls/winex11.drv/clipboard.c
+++ b/dlls/winex11.drv/clipboard.c
@@ -5,6 +5,7 @@
  *     1996 Alex Korobka
  *     1999 Noel Borthwick
  *           2003 Ulrich Czekalla for CodeWeavers
+ *           2014 Damjan Jovanovic
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -78,6 +79,9 @@

 #include "windef.h"
 #include "winbase.h"
+#include "shlobj.h"
+#include "shellapi.h"
+#include "shlwapi.h"
 #include "x11drv.h"
 #include "wine/list.h"
 #include "wine/debug.h"
@@ -144,6 +148,7 @@ static HANDLE
X11DRV_CLIPBOARD_ImportImageBmp(Display *d, Window w, Atom prop);
 static HANDLE X11DRV_CLIPBOARD_ImportXAString(Display *d, Window w, Atom prop);
 static HANDLE X11DRV_CLIPBOARD_ImportUTF8(Display *d, Window w, Atom prop);
 static HANDLE X11DRV_CLIPBOARD_ImportCompoundText(Display *d, Window
w, Atom prop);
+static HANDLE X11DRV_CLIPBOARD_ImportTextUriList(Display *display,
Window w, Atom prop);
 static HANDLE X11DRV_CLIPBOARD_ExportClipboardData(Display *display,
Window requestor, Atom aTarget,
     Atom rprop, LPWINE_CLIPDATA lpData, LPDWORD lpBytes);
 static HANDLE X11DRV_CLIPBOARD_ExportString(Display *display, Window
requestor, Atom aTarget,
@@ -158,6 +163,8 @@ static HANDLE
X11DRV_CLIPBOARD_ExportEnhMetaFile(Display *display, Window reques
     Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
 static HANDLE X11DRV_CLIPBOARD_ExportTextHtml(Display *display,
Window requestor, Atom aTarget,
     Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
+static HANDLE X11DRV_CLIPBOARD_ExportHDROP(Display *display, Window
requestor, Atom aTarget,
+    Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
 static WINE_CLIPFORMAT *X11DRV_CLIPBOARD_InsertClipboardFormat(UINT
id, Atom prop);
 static BOOL X11DRV_CLIPBOARD_RenderSynthesizedText(Display *display,
UINT wFormatID);
 static void X11DRV_CLIPBOARD_FreeData(LPWINE_CLIPDATA lpData);
@@ -201,7 +208,7 @@ static const struct
     /* If UTF8_STRING is not available, attempt COMPOUND_TEXT */
     { CF_UNICODETEXT, XATOM_COMPOUND_TEXT,
X11DRV_CLIPBOARD_ImportCompoundText, X11DRV_CLIPBOARD_ExportString },
     { CF_ENHMETAFILE, XATOM_WCF_ENHMETAFILE,
X11DRV_CLIPBOARD_ImportEnhMetaFile, X11DRV_CLIPBOARD_ExportEnhMetaFile
},
-    { CF_HDROP, XATOM_WCF_HDROP,
X11DRV_CLIPBOARD_ImportClipboardData,
X11DRV_CLIPBOARD_ExportClipboardData },
+    { CF_HDROP, XATOM_text_uri_list,
X11DRV_CLIPBOARD_ImportTextUriList, X11DRV_CLIPBOARD_ExportHDROP },
     { CF_LOCALE, XATOM_WCF_LOCALE,
X11DRV_CLIPBOARD_ImportClipboardData,
X11DRV_CLIPBOARD_ExportClipboardData },
     { CF_DIBV5, XATOM_WCF_DIBV5,
X11DRV_CLIPBOARD_ImportClipboardData,
X11DRV_CLIPBOARD_ExportClipboardData },
     { CF_OWNERDISPLAY, XATOM_WCF_OWNERDISPLAY,
X11DRV_CLIPBOARD_ImportClipboardData,
X11DRV_CLIPBOARD_ExportClipboardData },
@@ -1004,6 +1011,90 @@ static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp)
 }


+/***********************************************************************
+ *           uri_to_dos
+ *
+ *  Converts a text/uri-list URI to DOS filename.
+ */
+static WCHAR* uri_to_dos(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_CLIPBOARD_RenderSynthesizedDIB
  *
@@ -1477,6 +1568,92 @@ static HANDLE
X11DRV_CLIPBOARD_ImportEnhMetaFile(Display *display, Window w, Ato


 /**************************************************************************
+ *      X11DRV_CLIPBOARD_ImportTextUriList
+ *
+ *  Import text/uri-list.
+ */
+static HANDLE X11DRV_CLIPBOARD_ImportTextUriList(Display *display,
Window w, Atom prop)
+{
+    char *uriList;
+    unsigned long len;
+    char *uri;
+    WCHAR *path;
+    WCHAR *out = NULL;
+    int size = 0;
+    int capacity = 4096;
+    int start = 0;
+    int end = 0;
+    HANDLE handle = NULL;
+
+    if (!X11DRV_CLIPBOARD_ReadProperty(display, w, prop,
(LPBYTE*)&uriList, &len))
+        return 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 = uri_to_dos(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;
+        handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
sizeof(DROPFILES) + (size + 1)*sizeof(WCHAR));
+        if (handle)
+        {
+            dropFiles = (DROPFILES*) GlobalLock(handle);
+            dropFiles->pFiles = sizeof(DROPFILES);
+            dropFiles->pt.x = 0;
+            dropFiles->pt.y = 0;
+            dropFiles->fNC = 0;
+            dropFiles->fWide = TRUE;
+            out[size] = '\0';
+            memcpy(((char*)dropFiles) + dropFiles->pFiles, out, (size
+ 1)*sizeof(WCHAR));
+            GlobalUnlock(handle);
+        }
+    }
+    HeapFree(GetProcessHeap(), 0, out);
+    return handle;
+}
+
+
+/**************************************************************************
  * X11DRV_ImportClipbordaData
  *
  *  Generic import clipboard data routine.
@@ -1984,6 +2161,133 @@ end:


 /**************************************************************************
+ *      X11DRV_CLIPBOARD_ExportHDROP
+ *
+ *  Export CF_HDROP format to text/uri-list.
+ */
+static HANDLE X11DRV_CLIPBOARD_ExportHDROP(Display *display, Window
requestor, Atom aTarget,
+    Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
+{
+    HDROP hDrop;
+    UINT i;
+    UINT numFiles;
+    UINT totalSize = 0;
+    HGLOBAL hClipData = NULL;
+    char *text_uri_list = NULL;
+    char *next;
+    BOOLEAN succeeded = FALSE;
+
+    *lpBytes = 0;
+
+    if (!X11DRV_CLIPBOARD_RenderFormat(display, lpdata))
+    {
+        ERR("Failed to export %04x format\n", lpdata->wFormatID);
+        return 0;
+    }
+
+    hDrop = (HDROP) lpdata->hData;
+    numFiles = DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0);
+
+    for (i = 0; i < numFiles; i++)
+    {
+        UINT dosFilenameSize;
+        WCHAR *dosFilename;
+        succeeded = FALSE;
+        dosFilenameSize = 1 + DragQueryFileW(hDrop, i, NULL, 0);
+        dosFilename = HeapAlloc(GetProcessHeap(), 0,
dosFilenameSize*sizeof(WCHAR));
+        if (dosFilename)
+        {
+            char *unixFilename;
+            DragQueryFileW(hDrop, i, dosFilename, dosFilenameSize);
+            unixFilename = wine_get_unix_file_name(dosFilename);
+            if (unixFilename)
+            {
+                totalSize += 8 + /* file:/// */
+                        3*(lstrlenA(unixFilename) - 1); /* "%xy" per
char except first '/' */
+                succeeded = TRUE;
+                HeapFree(GetProcessHeap(), 0, unixFilename);
+            }
+            HeapFree(GetProcessHeap(), 0, dosFilename);
+        }
+        if (!succeeded)
+        {
+            ERR("out of memory\n");
+            goto end;
+        }
+    }
+    totalSize += 2 * numFiles; /* "\r\n" */
+    hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, totalSize);
+    if (hClipData == NULL)
+    {
+        ERR("out of memory\n");
+        succeeded = FALSE;
+        goto end;
+    }
+    text_uri_list = (char*) GlobalLock(hClipData);
+    next = text_uri_list;
+    for (i = 0; i < numFiles; i++)
+    {
+        UINT dosFilenameSize;
+        WCHAR *dosFilename;
+        succeeded = FALSE;
+        dosFilenameSize = 1 + DragQueryFileW(hDrop, i, NULL, 0);
+        dosFilename = HeapAlloc(GetProcessHeap(), 0,
dosFilenameSize*sizeof(WCHAR));
+        if (dosFilename)
+        {
+            char *unixFilename;
+            DragQueryFileW(hDrop, i, dosFilename, dosFilenameSize);
+            unixFilename = wine_get_unix_file_name(dosFilename);
+            if (unixFilename)
+            {
+                static const char *hex_table = "0123456789abcdef";
+                UINT u;
+                *next++ = 'f';
+                *next++ = 'i';
+                *next++ = 'l';
+                *next++ = 'e';
+                *next++ = ':';
+                *next++ = '/';
+                *next++ = '/';
+                *next++ = '/';
+                /* URL encode everything - unnecessary, but
easier/lighter than linking in shlwapi, and can't hurt */
+                for (u = 1; unixFilename[u]; u++) {
+                    *next++ = '%';
+                    *next++ = hex_table[unixFilename[u] >> 4];
+                    *next++ = hex_table[unixFilename[u] & 0xf];
+                }
+                *next++ = '\r';
+                *next++ = '\n';
+                succeeded = TRUE;
+                HeapFree(GetProcessHeap(), 0, unixFilename);
+            }
+            HeapFree(GetProcessHeap(), 0, dosFilename);
+        }
+        if (!succeeded)
+        {
+            ERR("out of memory\n");
+            goto end;
+        }
+    }
+
+end:
+    if (succeeded)
+    {
+        GlobalUnlock(hClipData);
+        *lpBytes = GlobalSize(hClipData);
+        return hClipData;
+    }
+    else
+    {
+        if (text_uri_list)
+            GlobalUnlock(hClipData);
+        GlobalFree(hClipData);
+        *lpBytes = 0;
+        return 0;
+    }
+}
+
+
+/**************************************************************************
  * X11DRV_CLIPBOARD_QueryTargets
  */
 static BOOL X11DRV_CLIPBOARD_QueryTargets(Display *display, Window w,
Atom selection,
-- 
1.8.5.4



More information about the wine-patches mailing list