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