Blender  V2.93
GHOST_DropTargetWin32.cpp
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include "GHOST_DropTargetWin32.h"
25 #include "GHOST_Debug.h"
26 #include <shellapi.h>
27 
28 #include "utf_winfunc.h"
29 #include "utfconv.h"
30 
31 #ifdef WITH_GHOST_DEBUG
32 // utility
33 void printLastError(void);
34 #endif // WITH_GHOST_DEBUG
35 
37  : m_window(window), m_system(system)
38 {
39  m_cRef = 1;
40  m_hWnd = window->getHWND();
41  m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
42 }
43 
45 {
46 }
47 
48 /*
49  * IUnknown::QueryInterface
50  */
51 HRESULT __stdcall GHOST_DropTargetWin32::QueryInterface(REFIID riid, void **ppvObj)
52 {
53 
54  if (!ppvObj)
55  return E_INVALIDARG;
56  *ppvObj = NULL;
57 
58  if (riid == IID_IUnknown || riid == IID_IDropTarget) {
59  AddRef();
60  *ppvObj = (void *)this;
61  return S_OK;
62  }
63  else {
64  *ppvObj = NULL;
65  return E_NOINTERFACE;
66  }
67 }
68 
69 /*
70  * IUnknown::AddRef
71  */
72 
73 ULONG __stdcall GHOST_DropTargetWin32::AddRef(void)
74 {
75  return ::InterlockedIncrement(&m_cRef);
76 }
77 
78 /*
79  * IUnknown::Release
80  */
81 ULONG __stdcall GHOST_DropTargetWin32::Release(void)
82 {
83  ULONG refs = ::InterlockedDecrement(&m_cRef);
84 
85  if (refs == 0) {
86  delete this;
87  return 0;
88  }
89  else {
90  return refs;
91  }
92 }
93 
94 /*
95  * Implementation of IDropTarget::DragEnter
96  */
97 HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *pDataObject,
98  DWORD grfKeyState,
99  POINTL pt,
100  DWORD *pdwEffect)
101 {
102  // we accept all drop by default
103  m_window->setAcceptDragOperation(true);
104  *pdwEffect = DROPEFFECT_NONE;
105 
106  m_draggedObjectType = getGhostType(pDataObject);
107  m_system->pushDragDropEvent(
108  GHOST_kEventDraggingEntered, m_draggedObjectType, m_window, pt.x, pt.y, NULL);
109  return S_OK;
110 }
111 
112 /*
113  * Implementation of IDropTarget::DragOver
114  */
115 HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
116 {
117  if (m_window->canAcceptDragOperation()) {
118  *pdwEffect = allowedDropEffect(*pdwEffect);
119  }
120  else {
121  *pdwEffect = DROPEFFECT_NONE;
122  // XXX Uncomment to test drop. Drop will not be called if pdwEffect == DROPEFFECT_NONE.
123  // *pdwEffect = DROPEFFECT_COPY;
124  }
125  m_system->pushDragDropEvent(
126  GHOST_kEventDraggingUpdated, m_draggedObjectType, m_window, pt.x, pt.y, NULL);
127  return S_OK;
128 }
129 
130 /*
131  * Implementation of IDropTarget::DragLeave
132  */
133 HRESULT __stdcall GHOST_DropTargetWin32::DragLeave(void)
134 {
135  m_system->pushDragDropEvent(
136  GHOST_kEventDraggingExited, m_draggedObjectType, m_window, 0, 0, NULL);
137  m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
138  return S_OK;
139 }
140 
141 /* Implementation of IDropTarget::Drop
142  * This function will not be called if pdwEffect is set to DROPEFFECT_NONE in
143  * the implementation of IDropTarget::DragOver
144  */
145 HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject *pDataObject,
146  DWORD grfKeyState,
147  POINTL pt,
148  DWORD *pdwEffect)
149 {
150  void *data = getGhostData(pDataObject);
151  if (m_window->canAcceptDragOperation()) {
152  *pdwEffect = allowedDropEffect(*pdwEffect);
153  }
154  else {
155  *pdwEffect = DROPEFFECT_NONE;
156  }
157  if (data)
158  m_system->pushDragDropEvent(
159  GHOST_kEventDraggingDropDone, m_draggedObjectType, m_window, pt.x, pt.y, data);
160 
161  m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
162  return S_OK;
163 }
164 
165 /*
166  * Helpers
167  */
168 
169 DWORD GHOST_DropTargetWin32::allowedDropEffect(DWORD dwAllowed)
170 {
171  DWORD dwEffect = DROPEFFECT_NONE;
172  if (dwAllowed & DROPEFFECT_COPY)
173  dwEffect = DROPEFFECT_COPY;
174 
175  return dwEffect;
176 }
177 
178 GHOST_TDragnDropTypes GHOST_DropTargetWin32::getGhostType(IDataObject *pDataObject)
179 {
180  /* Text
181  * NOTE: Unicode text is available as CF_TEXT too, the system can do the
182  * conversion, but we do the conversion our self with #WC_NO_BEST_FIT_CHARS.
183  */
184  FORMATETC fmtetc = {CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
185  if (pDataObject->QueryGetData(&fmtetc) == S_OK) {
187  }
188 
189  // Filesnames
190  fmtetc.cfFormat = CF_HDROP;
191  if (pDataObject->QueryGetData(&fmtetc) == S_OK) {
193  }
194 
196 }
197 
198 void *GHOST_DropTargetWin32::getGhostData(IDataObject *pDataObject)
199 {
200  GHOST_TDragnDropTypes type = getGhostType(pDataObject);
201  switch (type) {
203  return getDropDataAsFilenames(pDataObject);
204  break;
206  return getDropDataAsString(pDataObject);
207  break;
209  // return getDropDataAsBitmap(pDataObject);
210  break;
211  default:
212 #ifdef WITH_GHOST_DEBUG
213  ::printf("\nGHOST_kDragnDropTypeUnknown");
214 #endif // WITH_GHOST_DEBUG
215  return NULL;
216  break;
217  }
218  return NULL;
219 }
220 
221 void *GHOST_DropTargetWin32::getDropDataAsFilenames(IDataObject *pDataObject)
222 {
223  UINT totfiles, nvalid = 0;
224  WCHAR fpath[MAX_PATH];
225  char *temp_path;
226  GHOST_TStringArray *strArray = NULL;
227  FORMATETC fmtetc = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
228  STGMEDIUM stgmed;
229  HDROP hdrop;
230 
231  // Check if dataobject supplies the format we want.
232  // Double checking here, first in getGhostType.
233  if (pDataObject->QueryGetData(&fmtetc) == S_OK) {
234  if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK) {
235  hdrop = (HDROP)::GlobalLock(stgmed.hGlobal);
236 
237  totfiles = ::DragQueryFileW(hdrop, -1, NULL, 0);
238  if (!totfiles) {
239  ::GlobalUnlock(stgmed.hGlobal);
240  return NULL;
241  }
242 
243  strArray = (GHOST_TStringArray *)::malloc(sizeof(GHOST_TStringArray));
244  strArray->count = 0;
245  strArray->strings = (GHOST_TUns8 **)::malloc(totfiles * sizeof(GHOST_TUns8 *));
246 
247  for (UINT nfile = 0; nfile < totfiles; nfile++) {
248  if (::DragQueryFileW(hdrop, nfile, fpath, MAX_PATH) > 0) {
249  if (!(temp_path = alloc_utf_8_from_16(fpath, 0))) {
250  continue;
251  }
252  // Just ignore paths that could not be converted verbatim.
253 
254  strArray->strings[nvalid] = (GHOST_TUns8 *)temp_path;
255  strArray->count = nvalid + 1;
256  nvalid++;
257  }
258  }
259  // Free up memory.
260  ::GlobalUnlock(stgmed.hGlobal);
261  ::ReleaseStgMedium(&stgmed);
262 
263  return strArray;
264  }
265  }
266  return NULL;
267 }
268 
269 void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject)
270 {
271  char *tmp_string;
272  FORMATETC fmtetc = {CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
273  STGMEDIUM stgmed;
274 
275  // Try unicode first.
276  // Check if dataobject supplies the format we want.
277  if (pDataObject->QueryGetData(&fmtetc) == S_OK) {
278  if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK) {
279  LPCWSTR wstr = (LPCWSTR)::GlobalLock(stgmed.hGlobal);
280  if (!(tmp_string = alloc_utf_8_from_16((wchar_t *)wstr, 0))) {
281  ::GlobalUnlock(stgmed.hGlobal);
282  return NULL;
283  }
284  // Free memory
285  ::GlobalUnlock(stgmed.hGlobal);
286  ::ReleaseStgMedium(&stgmed);
287 #ifdef WITH_GHOST_DEBUG
288  ::printf("\n<converted droped unicode string>\n%s\n</droped converted unicode string>\n",
289  tmp_string);
290 #endif // WITH_GHOST_DEBUG
291  return tmp_string;
292  }
293  }
294 
295  fmtetc.cfFormat = CF_TEXT;
296 
297  if (pDataObject->QueryGetData(&fmtetc) == S_OK) {
298  if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK) {
299  char *str = (char *)::GlobalLock(stgmed.hGlobal);
300 
301  tmp_string = (char *)::malloc(::strlen(str) + 1);
302  if (!tmp_string) {
303  ::GlobalUnlock(stgmed.hGlobal);
304  return NULL;
305  }
306 
307  if (!::strcpy(tmp_string, str)) {
308  ::free(tmp_string);
309  ::GlobalUnlock(stgmed.hGlobal);
310  return NULL;
311  }
312  // Free memory
313  ::GlobalUnlock(stgmed.hGlobal);
314  ::ReleaseStgMedium(&stgmed);
315 
316  return tmp_string;
317  }
318  }
319 
320  return NULL;
321 }
322 
323 int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char *&out)
324 {
325  int size;
326  out = NULL; // caller should free if != NULL
327 
328  // Get the required size.
329  size = ::WideCharToMultiByte(CP_ACP, // System Default Codepage
330  0x00000400, // WC_NO_BEST_FIT_CHARS
331  in,
332  -1, //-1 null terminated, makes output null terminated too.
333  NULL,
334  0,
335  NULL,
336  NULL);
337 
338  if (!size) {
339 #ifdef WITH_GHOST_DEBUG
340  ::printLastError();
341 #endif // WITH_GHOST_DEBUG
342  return 0;
343  }
344 
345  out = (char *)::malloc(size);
346  if (!out) {
347  ::printf("\nmalloc failed!!!");
348  return 0;
349  }
350 
351  size = ::WideCharToMultiByte(CP_ACP, 0x00000400, in, -1, (LPSTR)out, size, NULL, NULL);
352 
353  if (!size) {
354 #ifdef WITH_GHOST_DEBUG
355  ::printLastError();
356 #endif // WITH_GHOST_DEBUG
357  ::free(out);
358  out = NULL;
359  }
360  return size;
361 }
362 
363 #ifdef WITH_GHOST_DEBUG
364 void printLastError(void)
365 {
366  LPTSTR s;
367  DWORD err;
368 
369  err = GetLastError();
370  if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
371  NULL,
372  err,
373  0,
374  (LPTSTR)&s,
375  0,
376  NULL)) {
377  printf("\nLastError: (%d) %s\n", (int)err, s);
378  LocalFree(s);
379  }
380 }
381 #endif // WITH_GHOST_DEBUG
void BLI_kdtree_nd_() free(KDTree *tree)
Definition: kdtree_impl.h:116
@ GHOST_kEventDraggingDropDone
Definition: GHOST_Types.h:208
@ GHOST_kEventDraggingExited
Definition: GHOST_Types.h:207
@ GHOST_kEventDraggingUpdated
Definition: GHOST_Types.h:206
@ GHOST_kEventDraggingEntered
Definition: GHOST_Types.h:205
GHOST_TDragnDropTypes
Definition: GHOST_Types.h:477
@ GHOST_kDragnDropTypeUnknown
Definition: GHOST_Types.h:478
@ GHOST_kDragnDropTypeFilenames
Definition: GHOST_Types.h:479
@ GHOST_kDragnDropTypeBitmap
Definition: GHOST_Types.h:481
@ GHOST_kDragnDropTypeString
Definition: GHOST_Types.h:480
unsigned char GHOST_TUns8
Definition: GHOST_Types.h:60
typedef UINT
_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 FT_Error err
Definition: freetypefont.c:52
GHOST_TUns8 ** strings
Definition: GHOST_Types.h:513
char * alloc_utf_8_from_16(const wchar_t *in16, size_t add)
Definition: utfconv.c:285