Blender V4.3
GHOST_DropTargetWin32.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10#include "GHOST_Debug.hh"
11#include <shellapi.h>
12
13#include "utf_winfunc.hh"
14#include "utfconv.hh"
15
16#ifdef WITH_GHOST_DEBUG
17/* utility */
18void printLastError(void);
19#endif /* WITH_GHOST_DEBUG */
20
22 : m_window(window), m_system(system)
23{
24 m_cRef = 1;
25 m_hWnd = window->getHWND();
26 m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
27}
28
30
31/*
32 * IUnknown::QueryInterface
33 */
34HRESULT __stdcall GHOST_DropTargetWin32::QueryInterface(REFIID riid, void **ppv_obj)
35{
36
37 if (!ppv_obj) {
38 return E_INVALIDARG;
39 }
40 *ppv_obj = nullptr;
41
42 if (riid == IID_IUnknown || riid == IID_IDropTarget) {
43 AddRef();
44 *ppv_obj = (void *)this;
45 return S_OK;
46 }
47 *ppv_obj = nullptr;
48 return E_NOINTERFACE;
49}
50
51/*
52 * IUnknown::AddRef
53 */
54
55ULONG __stdcall GHOST_DropTargetWin32::AddRef(void)
56{
57 return ::InterlockedIncrement(&m_cRef);
58}
59
60/*
61 * IUnknown::Release
62 */
63ULONG __stdcall GHOST_DropTargetWin32::Release(void)
64{
65 ULONG refs = ::InterlockedDecrement(&m_cRef);
66
67 if (refs == 0) {
68 delete this;
69 return 0;
70 }
71 else {
72 return refs;
73 }
74}
75
76/*
77 * Implementation of IDropTarget::DragEnter
78 */
79HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *p_data_object,
80 DWORD /*grf_key_state*/,
81 POINTL pt,
82 DWORD *pdw_effect)
83{
84 /* We accept all drop by default. */
85 m_window->setAcceptDragOperation(true);
86 *pdw_effect = DROPEFFECT_NONE;
87
88 m_draggedObjectType = getGhostType(p_data_object);
89 m_system->pushDragDropEvent(
90 GHOST_kEventDraggingEntered, m_draggedObjectType, m_window, pt.x, pt.y, nullptr);
91 return S_OK;
92}
93
94/*
95 * Implementation of IDropTarget::DragOver
96 */
97HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD /*grf_key_state*/,
98 POINTL pt,
99 DWORD *pdw_effect)
100{
101 if (m_window->canAcceptDragOperation()) {
102 *pdw_effect = allowedDropEffect(*pdw_effect);
103 }
104 else {
105 *pdw_effect = DROPEFFECT_NONE;
106 /* XXX Uncomment to test drop. Drop will not be called if `pdw_effect == DROPEFFECT_NONE`. */
107 // *pdw_effect = DROPEFFECT_COPY;
108 }
109 m_system->pushDragDropEvent(
110 GHOST_kEventDraggingUpdated, m_draggedObjectType, m_window, pt.x, pt.y, nullptr);
111 return S_OK;
112}
113
114/*
115 * Implementation of IDropTarget::DragLeave
116 */
117HRESULT __stdcall GHOST_DropTargetWin32::DragLeave(void)
118{
119 m_system->pushDragDropEvent(
120 GHOST_kEventDraggingExited, m_draggedObjectType, m_window, 0, 0, nullptr);
121 m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
122 return S_OK;
123}
124
125/* Implementation of IDropTarget::Drop
126 * This function will not be called if pdw_effect is set to DROPEFFECT_NONE in
127 * the implementation of IDropTarget::DragOver
128 */
129HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject *p_data_object,
130 DWORD /*grf_key_state*/,
131 POINTL pt,
132 DWORD *pdw_effect)
133{
134 void *data = getGhostData(p_data_object);
135 if (m_window->canAcceptDragOperation()) {
136 *pdw_effect = allowedDropEffect(*pdw_effect);
137 }
138 else {
139 *pdw_effect = DROPEFFECT_NONE;
140 }
141 if (data) {
142 m_system->pushDragDropEvent(
143 GHOST_kEventDraggingDropDone, m_draggedObjectType, m_window, pt.x, pt.y, data);
144 }
145 m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
146 return S_OK;
147}
148
149/*
150 * Helpers
151 */
152
153DWORD GHOST_DropTargetWin32::allowedDropEffect(DWORD dw_allowed)
154{
155 DWORD dw_effect = DROPEFFECT_NONE;
156 if (dw_allowed & DROPEFFECT_COPY) {
157 dw_effect = DROPEFFECT_COPY;
158 }
159 return dw_effect;
160}
161
162GHOST_TDragnDropTypes GHOST_DropTargetWin32::getGhostType(IDataObject *p_data_object)
163{
164 /* Text
165 * NOTE: Unicode text is available as CF_TEXT too, the system can do the
166 * conversion, but we do the conversion our self with #WC_NO_BEST_FIT_CHARS.
167 */
168 FORMATETC fmtetc = {CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
169 if (p_data_object->QueryGetData(&fmtetc) == S_OK) {
171 }
172
173 /* Files-names. */
174 fmtetc.cfFormat = CF_HDROP;
175 if (p_data_object->QueryGetData(&fmtetc) == S_OK) {
177 }
178
180}
181
182void *GHOST_DropTargetWin32::getGhostData(IDataObject *p_data_object)
183{
184 GHOST_TDragnDropTypes type = getGhostType(p_data_object);
185 switch (type) {
187 return getDropDataAsFilenames(p_data_object);
189 return getDropDataAsString(p_data_object);
191 // return getDropDataAsBitmap(p_data_object);
192 break;
193 default:
194#ifdef WITH_GHOST_DEBUG
195 ::printf("\nGHOST_kDragnDropTypeUnknown");
196#endif /* WITH_GHOST_DEBUG */
197 return nullptr;
198 }
199 return nullptr;
200}
201
202void *GHOST_DropTargetWin32::getDropDataAsFilenames(IDataObject *p_data_object)
203{
204 GHOST_TStringArray *str_array = nullptr;
205 FORMATETC fmtetc = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
206
207 /* Check if data-object supplies the format we want.
208 * Double checking here, first in #getGhostType. */
209 if (p_data_object->QueryGetData(&fmtetc) == S_OK) {
210 STGMEDIUM stgmed;
211 if (p_data_object->GetData(&fmtetc, &stgmed) == S_OK) {
212 const HDROP hdrop = (HDROP)::GlobalLock(stgmed.hGlobal);
213
214 const uint totfiles = ::DragQueryFileW(hdrop, -1, nullptr, 0);
215 if (totfiles) {
216 str_array = (GHOST_TStringArray *)::malloc(sizeof(GHOST_TStringArray));
217 str_array->count = 0;
218 str_array->strings = (uint8_t **)::malloc(totfiles * sizeof(uint8_t *));
219
220 for (uint nfile = 0; nfile < totfiles; nfile++) {
221 WCHAR fpath[MAX_PATH];
222 if (::DragQueryFileW(hdrop, nfile, fpath, MAX_PATH) > 0) {
223 char *temp_path;
224 if (!(temp_path = alloc_utf_8_from_16(fpath, 0))) {
225 /* Just ignore paths that could not be converted verbatim. */
226 continue;
227 }
228 str_array->strings[str_array->count++] = (uint8_t *)temp_path;
229 }
230 }
231 }
232 /* Free up memory. */
233 ::GlobalUnlock(stgmed.hGlobal);
234 ::ReleaseStgMedium(&stgmed);
235 }
236 }
237 return str_array;
238}
239
240void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *p_data_object)
241{
242 char *tmp_string;
243 FORMATETC fmtetc = {CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
244 STGMEDIUM stgmed;
245
246 /* Try unicode first.
247 * Check if data-object supplies the format we want. */
248 if (p_data_object->QueryGetData(&fmtetc) == S_OK) {
249 if (p_data_object->GetData(&fmtetc, &stgmed) == S_OK) {
250 LPCWSTR wstr = (LPCWSTR)::GlobalLock(stgmed.hGlobal);
251
252 tmp_string = alloc_utf_8_from_16((wchar_t *)wstr, 0);
253
254 /* Free memory. */
255 ::GlobalUnlock(stgmed.hGlobal);
256 ::ReleaseStgMedium(&stgmed);
257
258#ifdef WITH_GHOST_DEBUG
259 if (tmp_string) {
260 ::printf("\n<converted droped unicode string>\n%s\n</droped converted unicode string>\n",
261 tmp_string);
262 }
263#endif /* WITH_GHOST_DEBUG */
264 return tmp_string;
265 }
266 }
267
268 fmtetc.cfFormat = CF_TEXT;
269
270 if (p_data_object->QueryGetData(&fmtetc) == S_OK) {
271 if (p_data_object->GetData(&fmtetc, &stgmed) == S_OK) {
272 char *str = (char *)::GlobalLock(stgmed.hGlobal);
273 int str_size = ::strlen(str) + 1;
274
275 tmp_string = (char *)::malloc(str_size);
276 if (tmp_string) {
277 ::memcpy(tmp_string, str, str_size);
278 }
279 /* Free memory. */
280 ::GlobalUnlock(stgmed.hGlobal);
281 ::ReleaseStgMedium(&stgmed);
282
283 return tmp_string;
284 }
285 }
286
287 return nullptr;
288}
289
290int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char *&out)
291{
292 int size;
293 out = nullptr; /* caller should free if != nullptr */
294
295 /* Get the required size. */
296 size = ::WideCharToMultiByte(CP_ACP, /* System Default Codepage */
297 0x00000400, /* WC_NO_BEST_FIT_CHARS */
298 in,
299 -1, /* -1 null terminated, makes output null terminated too. */
300 nullptr,
301 0,
302 nullptr,
303 nullptr);
304
305 if (!size) {
306#ifdef WITH_GHOST_DEBUG
307 ::printLastError();
308#endif /* WITH_GHOST_DEBUG */
309 return 0;
310 }
311
312 out = (char *)::malloc(size);
313 if (!out) {
314 ::printf("\nmalloc failed!!!");
315 return 0;
316 }
317
318 size = ::WideCharToMultiByte(CP_ACP, 0x00000400, in, -1, (LPSTR)out, size, nullptr, nullptr);
319
320 if (!size) {
321#ifdef WITH_GHOST_DEBUG
322 ::printLastError();
323#endif /* WITH_GHOST_DEBUG */
324 ::free(out);
325 out = nullptr;
326 }
327 return size;
328}
329
330#ifdef WITH_GHOST_DEBUG
331void printLastError(void)
332{
333 LPTSTR s;
334 DWORD err;
335
336 err = GetLastError();
337 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
338 nullptr,
339 err,
340 0,
341 (LPTSTR)&s,
342 0,
343 nullptr))
344 {
345 printf("\nLastError: (%d) %s\n", int(err), s);
346 LocalFree(s);
347 }
348}
349#endif /* WITH_GHOST_DEBUG */
void BLI_kdtree_nd_ free(KDTree *tree)
unsigned int uint
@ GHOST_kEventDraggingDropDone
@ GHOST_kEventDraggingExited
@ GHOST_kEventDraggingUpdated
@ GHOST_kEventDraggingEntered
GHOST_TDragnDropTypes
@ GHOST_kDragnDropTypeUnknown
@ GHOST_kDragnDropTypeFilenames
@ GHOST_kDragnDropTypeBitmap
@ GHOST_kDragnDropTypeString
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
HRESULT __stdcall QueryInterface(REFIID riid, void **ppv_obj)
HRESULT __stdcall DragEnter(IDataObject *p_data_object, DWORD grf_key_state, POINTL pt, DWORD *pdw_effect)
HRESULT __stdcall DragLeave()
HRESULT __stdcall Drop(IDataObject *p_data_object, DWORD grf_key_state, POINTL pt, DWORD *pdw_effect)
GHOST_DropTargetWin32(GHOST_WindowWin32 *window, GHOST_SystemWin32 *system)
HRESULT __stdcall DragOver(DWORD grf_key_state, POINTL pt, DWORD *pdw_effect)
static GHOST_TSuccess pushDragDropEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType, GHOST_WindowWin32 *window, int mouseX, int mouseY, void *data)
bool canAcceptDragOperation() const override
void setAcceptDragOperation(bool canAccept) override
#define printf
#define str(s)
unsigned char uint8_t
Definition stdint.h:78
char * alloc_utf_8_from_16(const wchar_t *in16, size_t add)
Definition utfconv.cc:280