diff --git a/dlls/winex11.drv/clipboard.c b/dlls/winex11.drv/clipboard.c index dfd09e93d56..727a2a4ffc9 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, @@ -203,6 +208,7 @@ static const struct { 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_ExportClipboardData }, { 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 }, @@ -1005,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 +1567,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 * diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c index 4cd67de0492..3390dad65c6 100644 --- a/dlls/winex11.drv/xdnd.c +++ b/dlls/winex11.drv/xdnd.c @@ -72,13 +72,10 @@ static HWND XDNDLastTargetWnd; static HWND XDNDLastDropTargetWnd; static void X11DRV_XDND_InsertXDNDData(int property, int format, HANDLE contents); -static int X11DRV_XDND_DeconstructTextURIList(int property, void* data, int len); -static void X11DRV_XDND_MapFormat(Display *display, Window xwin, unsigned int property, unsigned char *data, int len); 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 WCHAR* X11DRV_XDND_URIToDOS(char *encodedURI); static CRITICAL_SECTION xdnd_cs; static CRITICAL_SECTION_DEBUG critsect_debug = @@ -456,10 +453,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; - unsigned char* data = NULL; XDNDDATA *current, *next; BOOL haveHDROP = FALSE; @@ -469,6 +462,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) @@ -491,11 +487,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); - - X11DRV_XDND_MapFormat(display, xwin, 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. @@ -545,129 +539,6 @@ static void X11DRV_XDND_InsertXDNDData(int property, int format, HANDLE contents } -/************************************************************************** - * X11DRV_XDND_MapFormat - * - * Map XDND MIME format to windows clipboard format. - */ -static void X11DRV_XDND_MapFormat(Display *display, Window xwin, unsigned int property, unsigned char *data, int len) -{ - HANDLE xdata; - - TRACE("%d: %s\n", property, data); - - /* Always include the raw type */ - xdata = GlobalAlloc(GMEM_FIXED, len); - if (xdata) - { - memcpy(GlobalLock(xdata), data, len); - GlobalUnlock(xdata); - X11DRV_XDND_InsertXDNDData(property, property, xdata); - } - else - ERR("out of memory\n"); - - if (property == x11drv_atom(text_uri_list)) - X11DRV_XDND_DeconstructTextURIList(property, data, len); - else - { - /* use the clipboard import functions for other types */ - HANDLE *contents; - UINT windowsFormat; - contents = X11DRV_CLIPBOARD_ImportSelection(display, property, xwin, x11drv_atom(XdndTarget), &windowsFormat); - if (contents) - X11DRV_XDND_InsertXDNDData(property, windowsFormat, contents); - } -} - - -/************************************************************************** - * X11DRV_XDND_DeconstructTextURIList - * - * Interpret text/uri-list data and add records to 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) - { - HDROP hDrop; - DROPFILES *dropFiles; - hDrop = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(DROPFILES) + (size + 1)*sizeof(WCHAR)); - if (hDrop) - { - dropFiles = GlobalLock(hDrop); - 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)); - GlobalUnlock(hDrop); - X11DRV_XDND_InsertXDNDData(property, CF_HDROP, hDrop); - count = 1; - } - } - HeapFree(GetProcessHeap(), 0, out); - return count; -} - - /************************************************************************** * X11DRV_XDND_SendDropFiles */ @@ -740,88 +611,6 @@ static void X11DRV_XDND_FreeDragDropOp(void) } -/************************************************************************** - * 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 */