Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore_win32 / ecore_win32_dnd_drop_target.cpp
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8
9 #include "ecore_win32_dnd_drop_target.h"
10
11 #include "ecore_win32_private.h"
12
13
14 // structors
15
16 DropTarget::DropTarget(HWND window, Ecore_Win32_Dnd_DropTarget_Callback callback, void *window_obj_ptr)
17   : ref_count_(1)
18   , window_(window)
19   , allow_drop_(false)
20   , drop_callback_(callback)
21   ,drop_callback_ptr_(window_obj_ptr)
22 { }
23
24
25 // IUnknown
26
27 HRESULT DropTarget::QueryInterface(REFIID iid, void **ppvObject)
28 {
29    // check to see what interface has been requested
30    if (iid == IID_IDropTarget || iid == IID_IUnknown)
31    {
32       AddRef();
33       *ppvObject = this;
34       return S_OK;
35    }
36    *ppvObject = 0;
37
38    return E_NOINTERFACE;
39 }
40
41 ULONG DropTarget::AddRef()
42 {
43    return InterlockedIncrement(&ref_count_);
44 }
45
46 ULONG DropTarget::Release()
47 {
48    LONG count = InterlockedDecrement(&ref_count_);
49    if (count == 0)
50    {
51       delete this;
52       return 0;
53    }
54
55    return count;
56 }
57
58
59 // IDropTarget
60
61 HRESULT DropTarget::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
62 {
63    // does the dataobject contain data we want?
64    allow_drop_ = QueryDataObject(pDataObject) &&
65       (drop_callback_ == NULL ||
66       (drop_callback_(drop_callback_ptr_, ECORE_WIN32_DND_EVENT_DRAG_ENTER, pt.x, pt.y, NULL, 0) != 0));
67
68    if (allow_drop_)
69    {
70       // get the dropeffect based on keyboard state
71       *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);
72       SetFocus(window_);
73       //PositionCursor(_hwnd, pt);
74    }
75    else
76       *pdwEffect = DROPEFFECT_NONE;
77    return S_OK;
78 }
79
80 HRESULT DropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
81 {
82    allow_drop_ =
83      (drop_callback_ == NULL) ||
84      (drop_callback_(drop_callback_ptr_, ECORE_WIN32_DND_EVENT_DRAG_OVER, pt.x, pt.y, NULL, 0) != 0);
85
86    if (allow_drop_)
87    {
88       *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);
89       //PositionCursor(m_hWnd, pt);
90    }
91    else
92    {
93       *pdwEffect = DROPEFFECT_NONE;
94    }
95
96    return S_OK;
97 }
98
99 HRESULT DropTarget::DragLeave()
100 {
101    POINT pt;
102
103    GetCursorPos(&pt);
104    if (drop_callback_ != NULL)
105      drop_callback_(drop_callback_ptr_, ECORE_WIN32_DND_EVENT_DRAG_LEAVE, pt.x, pt.y, NULL, 0);
106
107    return S_OK;
108 }
109
110 HRESULT DropTarget::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
111 {
112    if (allow_drop_)
113    {
114       // construct a FORMATETC object
115       FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
116       STGMEDIUM stgmed;
117
118       // See if the dataobject contains any TEXT stored as a HGLOBAL
119       if (pDataObject->QueryGetData(&fmtetc) == S_OK)
120       {
121          // Yippie! the data is there, so go get it!
122          if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK)
123          {
124             // we asked for the data as a HGLOBAL, so access it appropriately
125             PVOID data = GlobalLock(stgmed.hGlobal);
126             UINT size = GlobalSize(stgmed.hGlobal);
127
128             if (drop_callback_ != NULL)
129             {
130                drop_callback_(drop_callback_ptr_,
131                               ECORE_WIN32_DND_EVENT_DROP,
132                               pt.x, pt.y,
133                               data, size);
134             }
135
136             GlobalUnlock(stgmed.hGlobal);
137
138             // release the data using the COM API
139             ReleaseStgMedium(&stgmed);
140          }
141       }
142       *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);
143    }
144    else
145    {
146       *pdwEffect = DROPEFFECT_NONE;
147    }
148
149    return S_OK;
150 }
151
152
153 // internal helper function
154
155 DWORD DropTarget::DropEffect(DWORD grfKeyState, POINTL pt __UNUSED__, DWORD dwAllowed)
156 {
157    DWORD dwEffect = 0;
158
159    // 1. check "pt" -> do we allow a drop at the specified coordinates?
160
161    // 2. work out that the drop-effect should be based on grfKeyState
162    if (grfKeyState & MK_CONTROL)
163    {
164            dwEffect = dwAllowed & DROPEFFECT_COPY;
165    }
166    else if (grfKeyState & MK_SHIFT)
167    {
168            dwEffect = dwAllowed & DROPEFFECT_MOVE;
169    }
170
171    // 3. no key-modifiers were specified (or drop effect not allowed), so
172    //    base the effect on those allowed by the dropsource
173    if (dwEffect == 0)
174    {
175            if (dwAllowed & DROPEFFECT_COPY) dwEffect = DROPEFFECT_COPY;
176            if (dwAllowed & DROPEFFECT_MOVE) dwEffect = DROPEFFECT_MOVE;
177    }
178
179    return dwEffect;
180 }
181
182 bool DropTarget::QueryDataObject(IDataObject *pDataObject)
183 {
184     FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
185
186     // does the data object support CF_TEXT using a HGLOBAL?
187     return pDataObject->QueryGetData(&fmtetc) == S_OK;
188 }
189
190
191 // ecore_win32 private functions
192
193 void *_ecore_win32_dnd_register_drop_window(HWND hwnd,  Ecore_Win32_Dnd_DropTarget_Callback callback, void *ptr)
194 {
195    DropTarget *pDropTarget = new DropTarget(hwnd, callback, ptr);
196
197    if (pDropTarget == NULL)
198      return NULL;
199
200    // acquire a strong lock
201    if (FAILED(CoLockObjectExternal(pDropTarget, TRUE, FALSE)))
202      {
203         delete pDropTarget;
204         return NULL;
205      }
206
207    // tell OLE that the window is a drop target
208    if (FAILED(RegisterDragDrop(hwnd, pDropTarget)))
209      {
210         delete pDropTarget;
211         return NULL;
212      }
213
214    return pDropTarget;
215 }
216
217 void _ecore_win32_dnd_unregister_drop_window(HWND hwnd, void *drop_target)
218 {
219    IDropTarget *pDropTarget = (IDropTarget *)drop_target;
220
221    if (drop_target == NULL)
222      return;
223
224    // remove drag+drop
225    RevokeDragDrop(hwnd);
226
227    // remove the strong lock
228    CoLockObjectExternal(pDropTarget, FALSE, TRUE);
229
230    // release our own reference
231    pDropTarget->Release();
232 }