395 lines
9.7 KiB
C++
395 lines
9.7 KiB
C++
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): none yet.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
/** \file ghost/intern/GHOST_DropTargetWin32.cpp
|
|
* \ingroup GHOST
|
|
*/
|
|
|
|
|
|
#include "GHOST_Debug.h"
|
|
#include "GHOST_DropTargetWin32.h"
|
|
#include <shellapi.h>
|
|
|
|
#include "utf_winfunc.h"
|
|
#include "utfconv.h"
|
|
|
|
#ifdef GHOST_DEBUG
|
|
// utility
|
|
void printLastError(void);
|
|
#endif // GHOST_DEBUG
|
|
|
|
|
|
GHOST_DropTargetWin32::GHOST_DropTargetWin32(
|
|
GHOST_WindowWin32 *window,
|
|
GHOST_SystemWin32 *system)
|
|
: m_window(window),
|
|
m_system(system)
|
|
{
|
|
m_cRef = 1;
|
|
m_hWnd = window->getHWND();
|
|
m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
|
|
}
|
|
|
|
GHOST_DropTargetWin32::~GHOST_DropTargetWin32()
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
* IUnknown::QueryInterface
|
|
*/
|
|
HRESULT __stdcall GHOST_DropTargetWin32::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
|
|
if (!ppvObj)
|
|
return E_INVALIDARG;
|
|
*ppvObj = NULL;
|
|
|
|
if (riid == IID_IUnknown || riid == IID_IDropTarget) {
|
|
AddRef();
|
|
*ppvObj = (void *)this;
|
|
return S_OK;
|
|
}
|
|
else {
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* IUnknown::AddRef
|
|
*/
|
|
|
|
ULONG __stdcall GHOST_DropTargetWin32::AddRef(void)
|
|
{
|
|
return ::InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
/*
|
|
* IUnknown::Release
|
|
*/
|
|
ULONG __stdcall GHOST_DropTargetWin32::Release(void)
|
|
{
|
|
ULONG refs = ::InterlockedDecrement(&m_cRef);
|
|
|
|
if (refs == 0) {
|
|
delete this;
|
|
return 0;
|
|
}
|
|
else {
|
|
return refs;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Implementation of IDropTarget::DragEnter
|
|
*/
|
|
HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
|
|
{
|
|
// we accept all drop by default
|
|
m_window->setAcceptDragOperation(true);
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
m_draggedObjectType = getGhostType(pDataObject);
|
|
m_system->pushDragDropEvent(GHOST_kEventDraggingEntered, m_draggedObjectType, m_window, pt.x, pt.y, NULL);
|
|
return S_OK;
|
|
}
|
|
|
|
/*
|
|
* Implementation of IDropTarget::DragOver
|
|
*/
|
|
HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
|
|
{
|
|
if (m_window->canAcceptDragOperation()) {
|
|
*pdwEffect = allowedDropEffect(*pdwEffect);
|
|
}
|
|
else {
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
// *pdwEffect = DROPEFFECT_COPY; // XXX Uncomment to test drop. Drop will not be called if pdwEffect == DROPEFFECT_NONE.
|
|
}
|
|
m_system->pushDragDropEvent(GHOST_kEventDraggingUpdated, m_draggedObjectType, m_window, pt.x, pt.y, NULL);
|
|
return S_OK;
|
|
}
|
|
|
|
/*
|
|
* Implementation of IDropTarget::DragLeave
|
|
*/
|
|
HRESULT __stdcall GHOST_DropTargetWin32::DragLeave(void)
|
|
{
|
|
m_system->pushDragDropEvent(GHOST_kEventDraggingExited, m_draggedObjectType, m_window, 0, 0, NULL);
|
|
m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
|
|
return S_OK;
|
|
}
|
|
|
|
/* Implementation of IDropTarget::Drop
|
|
* This function will not be called if pdwEffect is set to DROPEFFECT_NONE in
|
|
* the implementation of IDropTarget::DragOver
|
|
*/
|
|
HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
|
|
{
|
|
void *data = getGhostData(pDataObject);
|
|
if (m_window->canAcceptDragOperation()) {
|
|
*pdwEffect = allowedDropEffect(*pdwEffect);
|
|
|
|
}
|
|
else {
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
}
|
|
if (data)
|
|
m_system->pushDragDropEvent(GHOST_kEventDraggingDropDone, m_draggedObjectType, m_window, pt.x, pt.y, data);
|
|
|
|
m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
|
|
return S_OK;
|
|
}
|
|
|
|
/*
|
|
* Helpers
|
|
*/
|
|
|
|
DWORD GHOST_DropTargetWin32::allowedDropEffect(DWORD dwAllowed)
|
|
{
|
|
DWORD dwEffect = DROPEFFECT_NONE;
|
|
if (dwAllowed & DROPEFFECT_COPY)
|
|
dwEffect = DROPEFFECT_COPY;
|
|
|
|
return dwEffect;
|
|
}
|
|
|
|
GHOST_TDragnDropTypes GHOST_DropTargetWin32::getGhostType(IDataObject *pDataObject)
|
|
{
|
|
/* Text
|
|
* Note: Unicode text is available as CF_TEXT too, the system can do the
|
|
* conversion, but we do the conversion ourself with WC_NO_BEST_FIT_CHARS.
|
|
*/
|
|
FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
|
if (pDataObject->QueryGetData(&fmtetc) == S_OK) {
|
|
return GHOST_kDragnDropTypeString;
|
|
}
|
|
|
|
// Filesnames
|
|
fmtetc.cfFormat = CF_HDROP;
|
|
if (pDataObject->QueryGetData(&fmtetc) == S_OK) {
|
|
return GHOST_kDragnDropTypeFilenames;
|
|
}
|
|
|
|
return GHOST_kDragnDropTypeUnknown;
|
|
}
|
|
|
|
void *GHOST_DropTargetWin32::getGhostData(IDataObject *pDataObject)
|
|
{
|
|
GHOST_TDragnDropTypes type = getGhostType(pDataObject);
|
|
switch (type) {
|
|
case GHOST_kDragnDropTypeFilenames:
|
|
return getDropDataAsFilenames(pDataObject);
|
|
break;
|
|
case GHOST_kDragnDropTypeString:
|
|
return getDropDataAsString(pDataObject);
|
|
break;
|
|
case GHOST_kDragnDropTypeBitmap:
|
|
//return getDropDataAsBitmap(pDataObject);
|
|
break;
|
|
default:
|
|
#ifdef GHOST_DEBUG
|
|
::printf("\nGHOST_kDragnDropTypeUnknown");
|
|
#endif // GHOST_DEBUG
|
|
return NULL;
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void *GHOST_DropTargetWin32::getDropDataAsFilenames(IDataObject *pDataObject)
|
|
{
|
|
UINT totfiles, nvalid = 0;
|
|
WCHAR fpath[MAX_PATH];
|
|
char *temp_path;
|
|
GHOST_TStringArray *strArray = NULL;
|
|
FORMATETC fmtetc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
|
STGMEDIUM stgmed;
|
|
HDROP hdrop;
|
|
|
|
// Check if dataobject supplies the format we want.
|
|
// Double checking here, first in getGhostType.
|
|
if (pDataObject->QueryGetData(&fmtetc) == S_OK) {
|
|
if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK) {
|
|
hdrop = (HDROP) ::GlobalLock(stgmed.hGlobal);
|
|
|
|
totfiles = ::DragQueryFileW(hdrop, -1, NULL, 0);
|
|
if (!totfiles) {
|
|
::GlobalUnlock(stgmed.hGlobal);
|
|
return NULL;
|
|
}
|
|
|
|
strArray = (GHOST_TStringArray *) ::malloc(sizeof(GHOST_TStringArray));
|
|
strArray->count = 0;
|
|
strArray->strings = (GHOST_TUns8 **) ::malloc(totfiles * sizeof(GHOST_TUns8 *));
|
|
|
|
for (UINT nfile = 0; nfile < totfiles; nfile++) {
|
|
if (::DragQueryFileW(hdrop, nfile, fpath, MAX_PATH) > 0) {
|
|
if (!(temp_path = alloc_utf_8_from_16(fpath, 0)) ) {
|
|
continue;
|
|
}
|
|
// Just ignore paths that could not be converted verbatim.
|
|
|
|
strArray->strings[nvalid] = (GHOST_TUns8 *) temp_path;
|
|
strArray->count = nvalid + 1;
|
|
nvalid++;
|
|
}
|
|
}
|
|
// Free up memory.
|
|
::GlobalUnlock(stgmed.hGlobal);
|
|
::ReleaseStgMedium(&stgmed);
|
|
|
|
return strArray;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject)
|
|
{
|
|
char *tmp_string;
|
|
FORMATETC fmtetc = { CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
|
STGMEDIUM stgmed;
|
|
|
|
// Try unicode first.
|
|
// Check if dataobject supplies the format we want.
|
|
if (pDataObject->QueryGetData(&fmtetc) == S_OK) {
|
|
if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK) {
|
|
LPCWSTR wstr = (LPCWSTR) ::GlobalLock(stgmed.hGlobal);
|
|
if (!(tmp_string = alloc_utf_8_from_16((wchar_t *)wstr, 0)) ) {
|
|
::GlobalUnlock(stgmed.hGlobal);
|
|
return NULL;
|
|
}
|
|
// Free memory
|
|
::GlobalUnlock(stgmed.hGlobal);
|
|
::ReleaseStgMedium(&stgmed);
|
|
#ifdef GHOST_DEBUG
|
|
::printf("\n<converted droped unicode string>\n%s\n</droped converted unicode string>\n", tmp_string);
|
|
#endif // GHOST_DEBUG
|
|
return tmp_string;
|
|
}
|
|
}
|
|
|
|
fmtetc.cfFormat = CF_TEXT;
|
|
|
|
if (pDataObject->QueryGetData(&fmtetc) == S_OK) {
|
|
if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK) {
|
|
char *str = (char *)::GlobalLock(stgmed.hGlobal);
|
|
|
|
tmp_string = (char *)::malloc(::strlen(str) + 1);
|
|
if (!tmp_string) {
|
|
::GlobalUnlock(stgmed.hGlobal);
|
|
return NULL;
|
|
}
|
|
|
|
if (!::strcpy(tmp_string, str) ) {
|
|
::free(tmp_string);
|
|
::GlobalUnlock(stgmed.hGlobal);
|
|
return NULL;
|
|
}
|
|
// Free memory
|
|
::GlobalUnlock(stgmed.hGlobal);
|
|
::ReleaseStgMedium(&stgmed);
|
|
|
|
return tmp_string;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char * &out)
|
|
{
|
|
int size;
|
|
out = NULL; //caller should free if != NULL
|
|
|
|
// Get the required size.
|
|
size = ::WideCharToMultiByte(CP_ACP, //System Default Codepage
|
|
0x00000400, // WC_NO_BEST_FIT_CHARS
|
|
in,
|
|
-1, //-1 null terminated, makes output null terminated too.
|
|
NULL,
|
|
0,
|
|
NULL, NULL
|
|
);
|
|
|
|
if (!size) {
|
|
#ifdef GHOST_DEBUG
|
|
::printLastError();
|
|
#endif // GHOST_DEBUG
|
|
return 0;
|
|
}
|
|
|
|
out = (char *)::malloc(size);
|
|
if (!out) {
|
|
::printf("\nmalloc failed!!!");
|
|
return 0;
|
|
}
|
|
|
|
size = ::WideCharToMultiByte(CP_ACP,
|
|
0x00000400,
|
|
in,
|
|
-1,
|
|
(LPSTR) out,
|
|
size,
|
|
NULL, NULL
|
|
);
|
|
|
|
if (!size) {
|
|
#ifdef GHOST_DEBUG
|
|
::printLastError();
|
|
#endif //GHOST_DEBUG
|
|
::free(out);
|
|
out = NULL;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
#ifdef GHOST_DEBUG
|
|
void printLastError(void)
|
|
{
|
|
LPTSTR s;
|
|
DWORD err;
|
|
|
|
err = GetLastError();
|
|
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
err,
|
|
0,
|
|
(LPTSTR)&s,
|
|
0,
|
|
NULL))
|
|
{
|
|
printf("\nLastError: (%d) %s\n", (int)err, s);
|
|
LocalFree(s);
|
|
}
|
|
}
|
|
#endif // GHOST_DEBUG
|