forked from enlightenment/efl
Patch by Dmitriy Mazovka:
add drag'n drop support in ecore_win32 (reworked) (missing files) SVN revision: 37890
This commit is contained in:
parent
6a06a92ac8
commit
1a897239c7
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "Ecore_Win32.h"
|
||||
#include "ecore_win32_private.h"
|
||||
|
||||
|
||||
static int _ecore_win32_dnd_init_count = 0;
|
||||
|
||||
static HANDLE DataToHandle(const char *data, int size)
|
||||
{
|
||||
char *ptr;
|
||||
ptr = (char *)GlobalAlloc(GMEM_FIXED, size);
|
||||
memcpy(ptr, data, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ecore_win32_dnd_init()
|
||||
{
|
||||
if (_ecore_win32_dnd_init_count > 0)
|
||||
{
|
||||
_ecore_win32_dnd_init_count++;
|
||||
return _ecore_win32_dnd_init_count;
|
||||
}
|
||||
|
||||
if (OleInitialize(NULL) != S_OK)
|
||||
return 0;
|
||||
|
||||
_ecore_win32_dnd_init_count++;
|
||||
|
||||
return _ecore_win32_dnd_init_count;
|
||||
}
|
||||
|
||||
int ecore_win32_dnd_shutdown()
|
||||
{
|
||||
_ecore_win32_dnd_init_count--;
|
||||
if (_ecore_win32_dnd_init_count > 0) return _ecore_win32_dnd_init_count;
|
||||
|
||||
OleUninitialize();
|
||||
|
||||
if (_ecore_win32_dnd_init_count < 0) _ecore_win32_dnd_init_count = 0;
|
||||
|
||||
return _ecore_win32_dnd_init_count;
|
||||
}
|
||||
|
||||
int ecore_win32_dnd_begin(const char *data,
|
||||
int size)
|
||||
{
|
||||
if (data == NULL)
|
||||
return 0;
|
||||
if (size < 0)
|
||||
size = strlen(data) + 1;
|
||||
|
||||
IDataObject *pDataObject = NULL;
|
||||
IDropSource *pDropSource = NULL;
|
||||
|
||||
FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||||
STGMEDIUM stgmed = { TYMED_HGLOBAL, { 0 }, 0 };
|
||||
|
||||
stgmed.hGlobal = DataToHandle(data, size);
|
||||
|
||||
int res = 0;
|
||||
|
||||
// create the data object
|
||||
pDataObject = (IDataObject *)_ecore_win32_dnd_data_object_new((void *)&fmtetc,
|
||||
(void *)&stgmed,
|
||||
1);
|
||||
pDropSource = (IDropSource *)_ecore_win32_dnd_drop_source_new();
|
||||
|
||||
if (pDataObject && pDropSource)
|
||||
{
|
||||
DWORD dwResult;
|
||||
DWORD dwEffect = DROPEFFECT_COPY;
|
||||
|
||||
// do the drag-drop!
|
||||
dwResult = DoDragDrop(pDataObject, pDropSource, DROPEFFECT_COPY, &dwEffect);
|
||||
|
||||
// finished. Check the return values to see if we need to do anything else
|
||||
if (dwResult == DRAGDROP_S_DROP)
|
||||
{
|
||||
//printf(">>> \"%s\" Dropped <<<\n", str);
|
||||
if(dwEffect == DROPEFFECT_MOVE)
|
||||
{
|
||||
// remove the data we just dropped from active document
|
||||
}
|
||||
}
|
||||
//else if (dwResult == DRAGDROP_S_CANCEL)
|
||||
// printf("DND cancelled\n");
|
||||
//else
|
||||
// printf("DND error\n");
|
||||
|
||||
res = 1;
|
||||
}
|
||||
|
||||
_ecore_win32_dnd_data_object_free(pDataObject);
|
||||
_ecore_win32_dnd_drop_source_free(pDropSource);
|
||||
|
||||
// cleanup
|
||||
ReleaseStgMedium(&stgmed);
|
||||
return (int)res;
|
||||
}
|
||||
|
||||
int ecore_win32_dnd_register_drop_target(Ecore_Win32_Window *window,
|
||||
Ecore_Win32_Dnd_DropTarget_Callback callback)
|
||||
{
|
||||
if (window == NULL)
|
||||
return 0;
|
||||
|
||||
struct _Ecore_Win32_Window *wnd = (struct _Ecore_Win32_Window *)window;
|
||||
wnd->dnd_drop_target = _ecore_win32_dnd_register_drop_window(wnd->window,
|
||||
callback,
|
||||
(void *)wnd);
|
||||
return (int)(wnd->dnd_drop_target != NULL);
|
||||
}
|
||||
|
||||
void ecore_win32_dnd_unregister_drop_target(Ecore_Win32_Window *window)
|
||||
{
|
||||
if (window == NULL)
|
||||
return;
|
||||
|
||||
struct _Ecore_Win32_Window *wnd = (struct _Ecore_Win32_Window *)window;
|
||||
if (wnd->dnd_drop_target != NULL)
|
||||
_ecore_win32_dnd_unregister_drop_window(wnd->window, wnd->dnd_drop_target);
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include <ole2.h>
|
||||
|
||||
#include "Ecore_Win32.h"
|
||||
#include "ecore_win32_private.h"
|
||||
|
||||
#include "ecore_win32_dnd_enumformatetc.h"
|
||||
#include "ecore_win32_dnd_data_object.h"
|
||||
|
||||
|
||||
static HGLOBAL DupGlobalMem(HGLOBAL hMem)
|
||||
{
|
||||
DWORD len = (DWORD)GlobalSize(hMem);
|
||||
PVOID source = GlobalLock(hMem);
|
||||
PVOID dest = GlobalAlloc(GMEM_FIXED, len);
|
||||
memcpy(dest, source, len);
|
||||
GlobalUnlock(hMem);
|
||||
return dest;
|
||||
}
|
||||
|
||||
// structors
|
||||
|
||||
DataObject::DataObject(FORMATETC *fmtetc, STGMEDIUM *stgmed, int count)
|
||||
{
|
||||
assert(fmtetc != NULL);
|
||||
assert(stgmed != NULL);
|
||||
assert(count > 0);
|
||||
|
||||
// reference count must ALWAYS start at 1
|
||||
ref_count_ = 1;
|
||||
formats_num_ = count;
|
||||
|
||||
format_etc_ = new FORMATETC[count];
|
||||
stg_medium_ = new STGMEDIUM[count];
|
||||
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
format_etc_[i] = fmtetc[i];
|
||||
stg_medium_[i] = stgmed[i];
|
||||
}
|
||||
}
|
||||
|
||||
DataObject::~DataObject()
|
||||
{
|
||||
delete[] format_etc_;
|
||||
delete[] stg_medium_;
|
||||
}
|
||||
|
||||
|
||||
// IUnknown
|
||||
|
||||
HRESULT DataObject::QueryInterface(REFIID iid, void **ppvObject)
|
||||
{
|
||||
// check to see what interface has been requested
|
||||
if ((iid == IID_IDataObject) || (iid == IID_IUnknown))
|
||||
{
|
||||
AddRef();
|
||||
*ppvObject = this;
|
||||
return S_OK;
|
||||
}
|
||||
*ppvObject = 0;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG DataObject::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&ref_count_);
|
||||
}
|
||||
|
||||
ULONG DataObject::Release()
|
||||
{
|
||||
LONG count = InterlockedDecrement(&ref_count_);
|
||||
if(count == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// IDataObject
|
||||
|
||||
HRESULT DataObject::GetData(FORMATETC *pFormatEtc, STGMEDIUM *pMedium)
|
||||
{
|
||||
assert(pMedium != NULL);
|
||||
int idx;
|
||||
|
||||
// try to match the specified FORMATETC with one of our supported formats
|
||||
if((idx = lookup_format_etc(pFormatEtc)) == -1)
|
||||
return DV_E_FORMATETC;
|
||||
|
||||
// found a match - transfer data into supplied storage medium
|
||||
pMedium->tymed = format_etc_[idx].tymed;
|
||||
pMedium->pUnkForRelease = 0;
|
||||
|
||||
// copy the data into the caller's storage medium
|
||||
switch(format_etc_[idx].tymed)
|
||||
{
|
||||
case TYMED_HGLOBAL:
|
||||
pMedium->hGlobal = DupGlobalMem(stg_medium_[idx].hGlobal);
|
||||
break;
|
||||
|
||||
default:
|
||||
return DV_E_FORMATETC;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT DataObject::GetDataHere(FORMATETC *pFormatEtc, STGMEDIUM *pmedium)
|
||||
{
|
||||
return DATA_E_FORMATETC;
|
||||
}
|
||||
|
||||
HRESULT DataObject::QueryGetData(FORMATETC *pFormatEtc)
|
||||
{
|
||||
return (lookup_format_etc(pFormatEtc) == -1) ? DV_E_FORMATETC : S_OK;
|
||||
}
|
||||
|
||||
HRESULT DataObject::GetCanonicalFormatEtc(FORMATETC *pFormatEct, FORMATETC *pFormatEtcOut)
|
||||
{
|
||||
// Apparently we have to set this field to NULL even though we don't do anything else
|
||||
pFormatEtcOut->ptd = NULL;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT DataObject::SetData(FORMATETC *pFormatEtc, STGMEDIUM *pMedium, BOOL fRelease)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT DataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc)
|
||||
{
|
||||
// only the get direction is supported for OLE
|
||||
if(dwDirection == DATADIR_GET)
|
||||
{
|
||||
// for Win2k+ you can use the SHCreateStdEnumFmtEtc API call, however
|
||||
// to support all Windows platforms we need to implement IEnumFormatEtc ourselves.
|
||||
return CreateEnumFormatEtc(formats_num_, format_etc_, ppEnumFormatEtc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// the direction specified is not supported for drag+drop
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT DataObject::DAdvise(FORMATETC *pFormatEtc, DWORD advf, IAdviseSink *, DWORD *)
|
||||
{
|
||||
return OLE_E_ADVISENOTSUPPORTED;
|
||||
}
|
||||
|
||||
HRESULT DataObject::DUnadvise(DWORD dwConnection)
|
||||
{
|
||||
return OLE_E_ADVISENOTSUPPORTED;
|
||||
}
|
||||
|
||||
HRESULT DataObject::EnumDAdvise(IEnumSTATDATA **ppEnumAdvise)
|
||||
{
|
||||
return OLE_E_ADVISENOTSUPPORTED;
|
||||
}
|
||||
|
||||
// internal helper function
|
||||
|
||||
int DataObject::lookup_format_etc(FORMATETC *pFormatEtc)
|
||||
{
|
||||
// check each of our formats in turn to see if one matches
|
||||
for(int i = 0; i < formats_num_; i++)
|
||||
{
|
||||
if((format_etc_[i].tymed & pFormatEtc->tymed) &&
|
||||
(format_etc_[i].cfFormat == pFormatEtc->cfFormat) &&
|
||||
(format_etc_[i].dwAspect == pFormatEtc->dwAspect))
|
||||
{
|
||||
// return index of stored format
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// error, format not found
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *_ecore_win32_dnd_data_object_new(void *fmtetc, void *stgmeds, int count)
|
||||
{
|
||||
IDataObject *object = new DataObject((FORMATETC *)fmtetc, (STGMEDIUM *)stgmeds, (UINT)count);
|
||||
assert(object != NULL);
|
||||
return object;
|
||||
}
|
||||
|
||||
void _ecore_win32_dnd_data_object_free(void *data_object)
|
||||
{
|
||||
if (!data_object)
|
||||
return;
|
||||
|
||||
IDataObject *object = (IDataObject *)data_object;
|
||||
object->Release();
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef __ECORE_WIN32_DND_DATA_OBJECT_H__
|
||||
#define __ECORE_WIN32_DND_DATA_OBJECT_H__
|
||||
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include <objbase.h>
|
||||
|
||||
|
||||
class DataObject : public IDataObject
|
||||
{
|
||||
private:
|
||||
|
||||
LONG ref_count_;
|
||||
int formats_num_;
|
||||
FORMATETC *format_etc_;
|
||||
STGMEDIUM *stg_medium_;
|
||||
|
||||
private: // internal helper function
|
||||
|
||||
int lookup_format_etc(FORMATETC *format_etc);
|
||||
|
||||
public: // structors
|
||||
|
||||
DataObject(FORMATETC *fmtetc, STGMEDIUM *stgmed, int count);
|
||||
~DataObject();
|
||||
|
||||
public: // IUnknown
|
||||
|
||||
HRESULT __stdcall QueryInterface(REFIID iid, void **ppvObject);
|
||||
ULONG __stdcall AddRef();
|
||||
ULONG __stdcall Release();
|
||||
|
||||
public: // IDataObject
|
||||
|
||||
HRESULT __stdcall GetData(FORMATETC *pFormatEtc, STGMEDIUM *pmedium);
|
||||
HRESULT __stdcall GetDataHere(FORMATETC *pFormatEtc, STGMEDIUM *pmedium);
|
||||
HRESULT __stdcall QueryGetData(FORMATETC *pFormatEtc);
|
||||
HRESULT __stdcall GetCanonicalFormatEtc(FORMATETC *pFormatEct, FORMATETC *pFormatEtcOut);
|
||||
HRESULT __stdcall SetData(FORMATETC *pFormatEtc, STGMEDIUM *pMedium, BOOL fRelease);
|
||||
HRESULT __stdcall EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc);
|
||||
HRESULT __stdcall DAdvise(FORMATETC *pFormatEtc, DWORD advf, IAdviseSink *, DWORD *);
|
||||
HRESULT __stdcall DUnadvise(DWORD dwConnection);
|
||||
HRESULT __stdcall EnumDAdvise(IEnumSTATDATA **ppEnumAdvise);
|
||||
};
|
||||
|
||||
|
||||
#endif /* __ECORE_WIN32_DND_DATA_OBJECT_H__ */
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "ecore_win32_dnd_drop_source.h"
|
||||
|
||||
#include "ecore_win32_private.h"
|
||||
|
||||
// structors
|
||||
|
||||
// reference count must ALWAYS start at 1
|
||||
DropSource::DropSource() : ref_count_(1)
|
||||
{ }
|
||||
|
||||
|
||||
// IUnknown
|
||||
|
||||
HRESULT DropSource::QueryInterface(REFIID iid, void **ppvObject)
|
||||
{
|
||||
// check to see what interface has been requested
|
||||
if (iid == IID_IDropSource || iid == IID_IUnknown)
|
||||
{
|
||||
AddRef();
|
||||
*ppvObject = this;
|
||||
return S_OK;
|
||||
}
|
||||
*ppvObject = 0;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG DropSource::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&ref_count_);
|
||||
}
|
||||
|
||||
ULONG DropSource::Release()
|
||||
{
|
||||
LONG count = InterlockedDecrement(&ref_count_);
|
||||
if(count == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// IDropSource
|
||||
|
||||
HRESULT DropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
|
||||
{
|
||||
// if the Escape key has been pressed since the last call, cancel the drop
|
||||
if(fEscapePressed == TRUE)
|
||||
return DRAGDROP_S_CANCEL;
|
||||
|
||||
// if the LeftMouse button has been released, then do the drop!
|
||||
if((grfKeyState & MK_LBUTTON) == 0)
|
||||
return DRAGDROP_S_DROP;
|
||||
|
||||
// continue with the drag-drop
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT DropSource::GiveFeedback(DWORD dwEffect)
|
||||
{
|
||||
return DRAGDROP_S_USEDEFAULTCURSORS;
|
||||
}
|
||||
|
||||
|
||||
// ecore_win32 private functions
|
||||
|
||||
void *_ecore_win32_dnd_drop_source_new()
|
||||
{
|
||||
IDropSource *object = new DropSource();
|
||||
assert(object != NULL);
|
||||
return object;
|
||||
}
|
||||
|
||||
void _ecore_win32_dnd_drop_source_free(void *drop_source)
|
||||
{
|
||||
if (!drop_source)
|
||||
return;
|
||||
|
||||
IDropSource *object = (IDropSource *)drop_source;
|
||||
object->Release();
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef __ECORE_WIN32_DND_DROP_SOURCE_H__
|
||||
#define __ECORE_WIN32_DND_DROP_SOURCE_H__
|
||||
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include <ole2.h>
|
||||
|
||||
#include "Ecore_Win32.h"
|
||||
|
||||
|
||||
class DropSource : public IDropSource
|
||||
{
|
||||
private:
|
||||
|
||||
LONG ref_count_;
|
||||
|
||||
public: // structors
|
||||
|
||||
DropSource();
|
||||
|
||||
public: // IUnknown
|
||||
|
||||
HRESULT __stdcall QueryInterface(REFIID iid, void ** ppvObject);
|
||||
ULONG __stdcall AddRef();
|
||||
ULONG __stdcall Release();
|
||||
|
||||
public: // IDropSource
|
||||
|
||||
HRESULT __stdcall QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
|
||||
HRESULT __stdcall GiveFeedback(DWORD dwEffect);
|
||||
};
|
||||
|
||||
|
||||
#endif /* __ECORE_WIN32_DND_DROP_SOURCE_H__ */
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "ecore_win32_dnd_drop_target.h"
|
||||
|
||||
#include "ecore_win32_private.h"
|
||||
|
||||
|
||||
// structors
|
||||
|
||||
DropTarget::DropTarget(HWND window, Ecore_Win32_Dnd_DropTarget_Callback callback, void *window_obj_ptr)
|
||||
: ref_count_(1)
|
||||
, window_(window)
|
||||
, allow_drop_(false)
|
||||
, drop_callback_(callback)
|
||||
,drop_callback_ptr_(window_obj_ptr)
|
||||
{ }
|
||||
|
||||
|
||||
// IUnknown
|
||||
|
||||
HRESULT DropTarget::QueryInterface(REFIID iid, void **ppvObject)
|
||||
{
|
||||
// check to see what interface has been requested
|
||||
if (iid == IID_IDropTarget || iid == IID_IUnknown)
|
||||
{
|
||||
AddRef();
|
||||
*ppvObject = this;
|
||||
return S_OK;
|
||||
}
|
||||
*ppvObject = 0;
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG DropTarget::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&ref_count_);
|
||||
}
|
||||
|
||||
ULONG DropTarget::Release()
|
||||
{
|
||||
LONG count = InterlockedDecrement(&ref_count_);
|
||||
if (count == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// IDropTarget
|
||||
|
||||
HRESULT DropTarget::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
|
||||
{
|
||||
// does the dataobject contain data we want?
|
||||
allow_drop_ = QueryDataObject(pDataObject) &&
|
||||
(drop_callback_ == NULL ||
|
||||
(drop_callback_(drop_callback_ptr_, ECORE_WIN32_DND_EVENT_DRAG_ENTER, pt.x, pt.y, NULL, 0) != 0));
|
||||
|
||||
if (allow_drop_)
|
||||
{
|
||||
// get the dropeffect based on keyboard state
|
||||
*pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);
|
||||
SetFocus(window_);
|
||||
//PositionCursor(_hwnd, pt);
|
||||
}
|
||||
else
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT DropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
|
||||
{
|
||||
allow_drop_ =
|
||||
(drop_callback_ == NULL) ||
|
||||
(drop_callback_(drop_callback_ptr_, ECORE_WIN32_DND_EVENT_DRAG_OVER, pt.x, pt.y, NULL, 0) != 0);
|
||||
|
||||
if (allow_drop_)
|
||||
{
|
||||
*pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);
|
||||
//PositionCursor(m_hWnd, pt);
|
||||
}
|
||||
else
|
||||
{
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT DropTarget::DragLeave()
|
||||
{
|
||||
POINT pt;
|
||||
|
||||
GetCursorPos(&pt);
|
||||
if (drop_callback_ != NULL)
|
||||
drop_callback_(drop_callback_ptr_, ECORE_WIN32_DND_EVENT_DRAG_LEAVE, pt.x, pt.y, NULL, 0);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT DropTarget::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
|
||||
{
|
||||
if (allow_drop_)
|
||||
{
|
||||
// construct a FORMATETC object
|
||||
FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||||
STGMEDIUM stgmed;
|
||||
|
||||
// See if the dataobject contains any TEXT stored as a HGLOBAL
|
||||
if (pDataObject->QueryGetData(&fmtetc) == S_OK)
|
||||
{
|
||||
// Yippie! the data is there, so go get it!
|
||||
if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK)
|
||||
{
|
||||
// we asked for the data as a HGLOBAL, so access it appropriately
|
||||
PVOID data = GlobalLock(stgmed.hGlobal);
|
||||
UINT size = GlobalSize(stgmed.hGlobal);
|
||||
|
||||
if (drop_callback_ != NULL)
|
||||
{
|
||||
drop_callback_(drop_callback_ptr_,
|
||||
ECORE_WIN32_DND_EVENT_DROP,
|
||||
pt.x, pt.y,
|
||||
data, size);
|
||||
}
|
||||
|
||||
GlobalUnlock(stgmed.hGlobal);
|
||||
|
||||
// release the data using the COM API
|
||||
ReleaseStgMedium(&stgmed);
|
||||
}
|
||||
}
|
||||
*pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);
|
||||
}
|
||||
else
|
||||
{
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// internal helper function
|
||||
|
||||
DWORD DropTarget::DropEffect(DWORD grfKeyState, POINTL pt, DWORD dwAllowed)
|
||||
{
|
||||
DWORD dwEffect = 0;
|
||||
|
||||
// 1. check "pt" -> do we allow a drop at the specified coordinates?
|
||||
|
||||
// 2. work out that the drop-effect should be based on grfKeyState
|
||||
if (grfKeyState & MK_CONTROL)
|
||||
{
|
||||
dwEffect = dwAllowed & DROPEFFECT_COPY;
|
||||
}
|
||||
else if (grfKeyState & MK_SHIFT)
|
||||
{
|
||||
dwEffect = dwAllowed & DROPEFFECT_MOVE;
|
||||
}
|
||||
|
||||
// 3. no key-modifiers were specified (or drop effect not allowed), so
|
||||
// base the effect on those allowed by the dropsource
|
||||
if (dwEffect == 0)
|
||||
{
|
||||
if (dwAllowed & DROPEFFECT_COPY) dwEffect = DROPEFFECT_COPY;
|
||||
if (dwAllowed & DROPEFFECT_MOVE) dwEffect = DROPEFFECT_MOVE;
|
||||
}
|
||||
|
||||
return dwEffect;
|
||||
}
|
||||
|
||||
bool DropTarget::QueryDataObject(IDataObject *pDataObject)
|
||||
{
|
||||
FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||||
|
||||
// does the data object support CF_TEXT using a HGLOBAL?
|
||||
return pDataObject->QueryGetData(&fmtetc) == S_OK;
|
||||
}
|
||||
|
||||
|
||||
// ecore_win32 private functions
|
||||
|
||||
void *_ecore_win32_dnd_register_drop_window(HWND hwnd, Ecore_Win32_Dnd_DropTarget_Callback callback, void *ptr)
|
||||
{
|
||||
DropTarget *pDropTarget = new DropTarget(hwnd, callback, ptr);
|
||||
|
||||
if (pDropTarget == NULL)
|
||||
return NULL;
|
||||
|
||||
// acquire a strong lock
|
||||
if (FAILED(CoLockObjectExternal(pDropTarget, TRUE, FALSE)))
|
||||
{
|
||||
delete pDropTarget;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// tell OLE that the window is a drop target
|
||||
if (FAILED(RegisterDragDrop(hwnd, pDropTarget)))
|
||||
{
|
||||
delete pDropTarget;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pDropTarget;
|
||||
}
|
||||
|
||||
void _ecore_win32_dnd_unregister_drop_window(HWND hwnd, void *drop_target)
|
||||
{
|
||||
IDropTarget *pDropTarget = (IDropTarget *)drop_target;
|
||||
|
||||
if (drop_target == NULL)
|
||||
return;
|
||||
|
||||
// remove drag+drop
|
||||
RevokeDragDrop(hwnd);
|
||||
|
||||
// remove the strong lock
|
||||
CoLockObjectExternal(pDropTarget, FALSE, TRUE);
|
||||
|
||||
// release our own reference
|
||||
pDropTarget->Release();
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef __ECORE_WIN32_DND_DROP_TARGET_H__
|
||||
#define __ECORE_WIN32_DND_DROP_TARGET_H__
|
||||
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include <ole2.h>
|
||||
|
||||
#include "Ecore_Win32.h"
|
||||
|
||||
|
||||
class DropTarget : public IDropTarget
|
||||
{
|
||||
private:
|
||||
|
||||
LONG ref_count_;
|
||||
HWND window_;
|
||||
bool allow_drop_;
|
||||
Ecore_Win32_Dnd_DropTarget_Callback drop_callback_;
|
||||
void *drop_callback_ptr_;
|
||||
|
||||
private: // internal helper function
|
||||
|
||||
DWORD DropEffect(DWORD grfKeyState, POINTL pt, DWORD dwAllowed);
|
||||
bool QueryDataObject(IDataObject *pDataObject);
|
||||
|
||||
public: // structors
|
||||
|
||||
DropTarget(HWND hwnd, Ecore_Win32_Dnd_DropTarget_Callback callback, void *window_obj_ptr);
|
||||
|
||||
public: // IUnknown
|
||||
|
||||
HRESULT __stdcall QueryInterface(REFIID iid, void ** ppvObject);
|
||||
ULONG __stdcall AddRef();
|
||||
ULONG __stdcall Release();
|
||||
|
||||
public: // IDropTarget
|
||||
|
||||
HRESULT __stdcall DragEnter(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
|
||||
HRESULT __stdcall DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
|
||||
HRESULT __stdcall DragLeave();
|
||||
HRESULT __stdcall Drop(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
|
||||
};
|
||||
|
||||
|
||||
#endif /* __ECORE_WIN32_DND_DROP_TARGET_H__ */
|
|
@ -0,0 +1,157 @@
|
|||
|
||||
#include <ole2.h>
|
||||
|
||||
#include "ecore_win32_dnd_enumformatetc.h"
|
||||
|
||||
|
||||
// structors
|
||||
|
||||
CEnumFormatEtc::CEnumFormatEtc(FORMATETC *format_etc, int formats_num)
|
||||
: ref_count_(1)
|
||||
, index_(0)
|
||||
, formats_num_(formats_num)
|
||||
, format_etc_(new FORMATETC[formats_num])
|
||||
{
|
||||
// make a new copy of each FORMATETC structure
|
||||
for (unsigned int i = 0; i < formats_num_; i++)
|
||||
{
|
||||
DeepCopyFormatEtc(&format_etc_[i], &format_etc[i]);
|
||||
}
|
||||
}
|
||||
|
||||
CEnumFormatEtc::~CEnumFormatEtc()
|
||||
{
|
||||
if (format_etc_)
|
||||
{
|
||||
// first free any DVTARGETDEVICE structures
|
||||
for (ULONG i = 0; i < formats_num_; i++)
|
||||
{
|
||||
if (format_etc_[i].ptd)
|
||||
CoTaskMemFree(format_etc_[i].ptd);
|
||||
}
|
||||
|
||||
// now free the main array
|
||||
delete[] format_etc_;
|
||||
}
|
||||
}
|
||||
|
||||
// IUnknown
|
||||
|
||||
ULONG __stdcall CEnumFormatEtc::AddRef(void)
|
||||
{
|
||||
// increment object reference count
|
||||
return InterlockedIncrement(&ref_count_);
|
||||
}
|
||||
|
||||
ULONG __stdcall CEnumFormatEtc::Release(void)
|
||||
{
|
||||
// decrement object reference count
|
||||
LONG count = InterlockedDecrement(&ref_count_);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT __stdcall CEnumFormatEtc::QueryInterface(REFIID iid, void **ppvObject)
|
||||
{
|
||||
// check to see what interface has been requested
|
||||
if ((iid == IID_IEnumFORMATETC) || (iid == IID_IUnknown))
|
||||
{
|
||||
AddRef();
|
||||
*ppvObject = this;
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppvObject = 0;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
// IEnumFormatEtc
|
||||
|
||||
HRESULT CEnumFormatEtc::Reset(void)
|
||||
{
|
||||
index_ = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CEnumFormatEtc::Skip(ULONG celt)
|
||||
{
|
||||
index_ += celt;
|
||||
return (index_ <= formats_num_) ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT CEnumFormatEtc::Clone(IEnumFORMATETC **ppEnumFormatEtc)
|
||||
{
|
||||
HRESULT hResult;
|
||||
|
||||
// make a duplicate enumerator
|
||||
hResult = CreateEnumFormatEtc(formats_num_, format_etc_, ppEnumFormatEtc);
|
||||
|
||||
if (hResult == S_OK)
|
||||
{
|
||||
// manually set the index state
|
||||
((CEnumFormatEtc *)*ppEnumFormatEtc)->index_ = index_;
|
||||
}
|
||||
|
||||
return hResult;
|
||||
}
|
||||
|
||||
HRESULT CEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG *pceltFetched)
|
||||
{
|
||||
ULONG copied = 0;
|
||||
|
||||
// validate arguments
|
||||
if ((celt == 0) || (pFormatEtc == 0))
|
||||
return E_INVALIDARG;
|
||||
|
||||
// copy the FORMATETC structures into the caller's buffer
|
||||
while (index_ < formats_num_ && copied < celt)
|
||||
{
|
||||
DeepCopyFormatEtc(&pFormatEtc[copied], &format_etc_[index_]);
|
||||
copied++;
|
||||
index_++;
|
||||
}
|
||||
|
||||
// store result
|
||||
if (pceltFetched != 0)
|
||||
*pceltFetched = copied;
|
||||
|
||||
// did we copy all that was requested?
|
||||
return (copied == celt) ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
// external functions
|
||||
|
||||
void DeepCopyFormatEtc(FORMATETC *dest, FORMATETC *source)
|
||||
{
|
||||
// copy the source FORMATETC into dest
|
||||
*dest = *source;
|
||||
|
||||
if (source->ptd)
|
||||
{
|
||||
// allocate memory for the DVTARGETDEVICE if necessary
|
||||
dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE));
|
||||
|
||||
// copy the contents of the source DVTARGETDEVICE into dest->ptd
|
||||
*(dest->ptd) = *(source->ptd);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CreateEnumFormatEtc(UINT cfmt, FORMATETC *afmt, IEnumFORMATETC **ppEnumFormatEtc)
|
||||
{
|
||||
if((cfmt == 0) || (afmt == 0) || (ppEnumFormatEtc == 0))
|
||||
return E_INVALIDARG;
|
||||
|
||||
*ppEnumFormatEtc = new CEnumFormatEtc(afmt, cfmt);
|
||||
|
||||
return (*ppEnumFormatEtc) ? S_OK : E_OUTOFMEMORY;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef __ECORE_WIN32_DND_ENUMFORMATETC_H__
|
||||
#define __ECORE_WIN32_DND_ENUMFORMATETC_H__
|
||||
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include <objbase.h>
|
||||
|
||||
|
||||
class CEnumFormatEtc : public IEnumFORMATETC
|
||||
{
|
||||
private:
|
||||
|
||||
LONG ref_count_; // Reference count for this COM interface
|
||||
ULONG index_; // current enumerator index
|
||||
ULONG formats_num_; // number of FORMATETC members
|
||||
FORMATETC *format_etc_; // array of FORMATETC objects
|
||||
|
||||
public: // structors
|
||||
|
||||
CEnumFormatEtc(FORMATETC *pFormatEtc, int nNumFormats);
|
||||
|
||||
~CEnumFormatEtc();
|
||||
|
||||
public: // IUnknown
|
||||
|
||||
HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject);
|
||||
|
||||
ULONG __stdcall AddRef (void);
|
||||
|
||||
ULONG __stdcall Release (void);
|
||||
|
||||
public: // IEnumFormatEtc
|
||||
|
||||
HRESULT __stdcall Next (ULONG celt, FORMATETC * rgelt, ULONG * pceltFetched);
|
||||
|
||||
HRESULT __stdcall Skip (ULONG celt);
|
||||
|
||||
HRESULT __stdcall Reset (void);
|
||||
|
||||
HRESULT __stdcall Clone (IEnumFORMATETC ** ppEnumFormatEtc);
|
||||
};
|
||||
|
||||
void DeepCopyFormatEtc(FORMATETC *dest, FORMATETC *source);
|
||||
|
||||
HRESULT CreateEnumFormatEtc(UINT cfmt, FORMATETC *afmt, IEnumFORMATETC **ppEnumFormatEtc);
|
||||
|
||||
|
||||
#endif /* __ECORE_WIN32_DND_ENUMFORMATETC_H__ */
|
Loading…
Reference in New Issue