From b6030cb26de8c0201a33f59d52322f375786bb3d Mon Sep 17 00:00:00 2001 From: Damjan Jovanovic Date: Wed, 27 Jun 2007 09:50:35 +0200 Subject: [PATCH] winex11.drv: Added better support for the X file drag protocol. --- dlls/winex11.drv/x11drv.h | 1 + dlls/winex11.drv/x11drv_main.c | 3 +- dlls/winex11.drv/xdnd.c | 178 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 180 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 8de2e25492b..c5425820325 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -597,6 +597,7 @@ enum x11drv_atoms XATOM_text_plain, XATOM_text_rtf, XATOM_text_richtext, + XATOM_text_uri_list, NB_XATOMS }; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 15a362484d1..e4c8a879bdc 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -158,7 +158,8 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "text/html", "text/plain", "text/rtf", - "text/richtext" + "text/richtext", + "text/uri-list" }; /*********************************************************************** diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c index f1d6d24e164..59410c56f4f 100644 --- a/dlls/winex11.drv/xdnd.c +++ b/dlls/winex11.drv/xdnd.c @@ -2,6 +2,7 @@ * XDND handler code * * Copyright 2003 Ulrich Czekalla + * Copyright 2007 Damjan Jovanovic * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,6 +27,7 @@ # include #endif #include +#include #include "windef.h" #include "winbase.h" @@ -35,6 +37,7 @@ #include "x11drv.h" #include "shlobj.h" /* DROPFILES */ +#include "wine/unicode.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(xdnd); @@ -56,6 +59,7 @@ static LPXDNDDATA XDNDData = NULL; static POINT XDNDxy = { 0, 0 }; 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); @@ -64,6 +68,7 @@ static void X11DRV_XDND_ResolveProperty(Display *display, Window xwin, Time tm, 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 DROPFILES* X11DRV_XDND_BuildDropFiles(char* filename, unsigned int len, POINT pt); static CRITICAL_SECTION xdnd_cs; @@ -333,7 +338,9 @@ static int X11DRV_XDND_MapFormat(unsigned int property, unsigned char *data, int X11DRV_XDND_InsertXDNDData(property, property, xdata, len); count++; - if (property == x11drv_atom(text_plain)) + 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); @@ -343,6 +350,92 @@ static int X11DRV_XDND_MapFormat(unsigned int property, unsigned char *data, int /************************************************************************** + * 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 = (char*) data; + char *uri; + WCHAR *path; + + char *out = NULL; + int size = 0; + int capacity = 4096; + + int count = 0; + int start = 0; + int end = 0; + + out = HeapAlloc(GetProcessHeap(), 0, capacity); + if (out == NULL) + return 0; + + while (end < len) + { + while (end < len && uriList[end] != '\r') + ++end; + if (end == len) + break; + if (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); + if (out == NULL) + goto done; + } + WideCharToMultiByte(CP_ACP, 0, path, -1, &out[size], pathSize, 0, 0); + 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); + if (dropFiles) + { + dropFiles->pFiles = sizeof(DROPFILES); + dropFiles->pt.x = XDNDxy.x; + dropFiles->pt.y = XDNDxy.y; + dropFiles->fNC = 0; + dropFiles->fWide = FALSE; + out[size] = '\0'; + memcpy(((char*)dropFiles) + dropFiles->pFiles, out, size + 1); + X11DRV_XDND_InsertXDNDData(property, CF_HDROP, dropFiles, sizeof(DROPFILES) + size + 1); + count = 1; + } + } + HeapFree(GetProcessHeap(), 0, out); + return count; +} + + +/************************************************************************** * X11DRV_XDND_DeconstructTextPlain * * Interpret text/plain Data and add records to linked list @@ -566,3 +659,86 @@ static unsigned int X11DRV_XDND_UnixToDos(char** lpdest, char* lpsrc, int len) 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; +} + -- 2.11.4.GIT