1 // This file is part of VSTGUI. It is subject to the license terms
2 // in the LICENSE file found in the top-level directory of this
3 // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
4
5 #include "win32dragging.h"
6 #include "win32support.h"
7 #include "winstring.h"
8 #include "../../cstring.h"
9 #include "../../cdrawcontext.h"
10 #include "../../cvstguitimer.h"
11 #include "win32dll.h"
12 #include <dwmapi.h>
13 #include <shlobj.h>
14
15 #ifdef _MSC_VER
16 #pragma comment(lib, "Dwmapi.lib")
17 #endif
18
19 namespace VSTGUI {
20
21 //-----------------------------------------------------------------------------
22 class Win32DragBitmapWindow
23 {
24 public:
25 Win32DragBitmapWindow (const SharedPointer<CBitmap>& bitmap, CPoint offset);
26 ~Win32DragBitmapWindow () noexcept;
27
28 void updateBitmap (const SharedPointer<CBitmap>& bitmap, CPoint offset);
29 void mouseChanged ();
30 private:
31 static LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
32 LRESULT proc (UINT message, WPARAM wParam, LPARAM lParam);
33
34 void registerWindowClass ();
35 void unregisterWindowClass ();
36
37 void createWindow ();
38 void releaseWindow ();
39 void showWindow ();
40
41 POINT calculateWindowPosition () const;
42 void updateScaleFactor (POINT p);
43 void updateWindowPosition (POINT where);
44 void setAlphaTransparency (float alpha);
45
46 void paint ();
47
48 SharedPointer<CBitmap> bitmap;
49 CPoint offset;
50 UTF8String windowClassName;
51 HWND hwnd {nullptr};
52 CCoord scaleFactor {2.};
53 };
54
55 //-----------------------------------------------------------------------------
56 class Win32MouseObserverWhileDragging
57 {
58 public:
59 using Callback = std::function<void ()>;
60
Win32MouseObserverWhileDragging()61 Win32MouseObserverWhileDragging ()
62 {
63 gInstance = this;
64 mouseHook = SetWindowsHookEx (WH_MOUSE, MouseHookProc, GetInstance (), GetCurrentThreadId ());
65 }
66
~Win32MouseObserverWhileDragging()67 ~Win32MouseObserverWhileDragging () noexcept
68 {
69 if (mouseHook)
70 UnhookWindowsHookEx (mouseHook);
71 gInstance = nullptr;
72 }
73
registerCallback(Callback && c)74 void registerCallback (Callback&& c) { callbacks.emplace_back (std::move (c)); }
75 private:
76 static Win32MouseObserverWhileDragging* gInstance;
MouseHookProc(int nCode,WPARAM wParam,LPARAM lParam)77 static LRESULT CALLBACK MouseHookProc (int nCode, WPARAM wParam, LPARAM lParam)
78 {
79 if (gInstance)
80 {
81 for (auto& c : gInstance->callbacks)
82 c ();
83 }
84 return CallNextHookEx (nullptr, nCode, wParam, lParam);
85 }
86 HHOOK mouseHook {nullptr};
87 std::vector<Callback> callbacks;
88 };
89 Win32MouseObserverWhileDragging* Win32MouseObserverWhileDragging::gInstance = nullptr;
90
91 //-----------------------------------------------------------------------------
Win32DraggingSession(Win32Frame * frame)92 Win32DraggingSession::Win32DraggingSession (Win32Frame* frame)
93 : frame (frame)
94 {
95 }
96
97 //-----------------------------------------------------------------------------
98 Win32DraggingSession::~Win32DraggingSession () noexcept = default;
99
100 //-----------------------------------------------------------------------------
setBitmap(const SharedPointer<CBitmap> & bitmap,CPoint offset)101 bool Win32DraggingSession::setBitmap (const SharedPointer<CBitmap>& bitmap, CPoint offset)
102 {
103 if (!dragBitmapWindow && bitmap)
104 {
105 dragBitmapWindow = std::make_unique<Win32DragBitmapWindow> (bitmap,
106 offset);
107 if (!mouseObserver)
108 mouseObserver = std::make_unique<Win32MouseObserverWhileDragging> ();
109
110 mouseObserver->registerCallback ([&] () { dragBitmapWindow->mouseChanged (); });
111 }
112 if (dragBitmapWindow)
113 {
114 dragBitmapWindow->updateBitmap (bitmap, offset);
115 }
116 return true;
117 }
118
119 //-----------------------------------------------------------------------------
doDrag(const DragDescription & dragDescription,const SharedPointer<IDragCallback> & callback)120 bool Win32DraggingSession::doDrag (const DragDescription& dragDescription, const SharedPointer<IDragCallback>& callback)
121 {
122 auto lastCursor = frame->getLastSetCursor ();
123 frame->setMouseCursor (kCursorNotAllowed);
124
125 if (callback)
126 mouseObserver = std::make_unique<Win32MouseObserverWhileDragging> ();
127
128 if (callback)
129 {
130 CPoint location;
131 frame->getCurrentMousePosition (location);
132 callback->dragWillBegin (this, location);
133
134 if (mouseObserver)
135 {
136 mouseObserver->registerCallback ([callback, location, this] () mutable {
137 CPoint newLocation;
138 frame->getCurrentMousePosition (newLocation);
139 if (newLocation != location)
140 {
141 callback->dragMoved (this, newLocation);
142 location = newLocation;
143 }
144 });
145 }
146 }
147
148 setBitmap (dragDescription.bitmap, dragDescription.bitmapOffset);
149
150 auto dataObject = new Win32DataObject (dragDescription.data);
151 auto dropSource = new Win32DropSource ();
152 DWORD outEffect;
153
154 auto hResult = DoDragDrop (dataObject, dropSource, DROPEFFECT_COPY | DROPEFFECT_MOVE, &outEffect);
155 if (mouseObserver)
156 mouseObserver = nullptr;
157 if (dragBitmapWindow)
158 dragBitmapWindow = nullptr;
159
160 frame->setMouseCursor (lastCursor);
161
162 if (callback)
163 {
164 CPoint location;
165 frame->getCurrentMousePosition (location);
166 if (hResult == DRAGDROP_S_DROP)
167 {
168 if (outEffect == DROPEFFECT_MOVE)
169 callback->dragEnded (this, location, DragOperation::Move);
170 else
171 callback->dragEnded (this, location, DragOperation::Copy);
172 }
173 else
174 {
175 callback->dragEnded (this, location, DragOperation::None);
176 }
177 }
178
179 dataObject->Release ();
180 dropSource->Release ();
181
182 return true;
183 }
184
185 //-----------------------------------------------------------------------------
CDropTarget(Win32Frame * pFrame)186 CDropTarget::CDropTarget (Win32Frame* pFrame)
187 : refCount (0)
188 , pFrame (pFrame)
189 , dragData (nullptr)
190 {
191 }
192
193 //-----------------------------------------------------------------------------
~CDropTarget()194 CDropTarget::~CDropTarget () noexcept
195 {
196 }
197
198 //-----------------------------------------------------------------------------
QueryInterface(REFIID riid,void ** object)199 COM_DECLSPEC_NOTHROW STDMETHODIMP CDropTarget::QueryInterface (REFIID riid, void** object)
200 {
201 if (riid == IID_IDropTarget || riid == IID_IUnknown)
202 {
203 *object = this;
204 AddRef ();
205 return NOERROR;
206 }
207 *object = nullptr;
208 return E_NOINTERFACE;
209 }
210
211 //-----------------------------------------------------------------------------
STDMETHODIMP_(ULONG)212 COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) CDropTarget::AddRef (void)
213 {
214 return static_cast<ULONG> (++refCount);
215 }
216
217 //-----------------------------------------------------------------------------
STDMETHODIMP_(ULONG)218 COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) CDropTarget::Release (void)
219 {
220 refCount--;
221 if (refCount <= 0)
222 {
223 delete this;
224 return 0;
225 }
226 return static_cast<ULONG> (refCount);
227 }
228
229 //-----------------------------------------------------------------------------
DragEnter(IDataObject * dataObject,DWORD keyState,POINTL pt,DWORD * effect)230 COM_DECLSPEC_NOTHROW STDMETHODIMP CDropTarget::DragEnter (IDataObject* dataObject, DWORD keyState, POINTL pt, DWORD* effect)
231 {
232 if (dataObject && pFrame)
233 {
234 dragData = new Win32DataPackage (dataObject);
235
236 DragEventData data;
237 data.drag = dragData;
238 pFrame->getCurrentMousePosition (data.pos);
239 pFrame->getCurrentMouseButtons (data.modifiers);
240 auto result = pFrame->getFrame ()->platformOnDragEnter (data);
241 if (result == DragOperation::Copy)
242 *effect = DROPEFFECT_COPY;
243 else if (result == DragOperation::Move)
244 *effect = DROPEFFECT_MOVE;
245 else
246 *effect = DROPEFFECT_NONE;
247 }
248 else
249 *effect = DROPEFFECT_NONE;
250 return S_OK;
251 }
252
253 //-----------------------------------------------------------------------------
DragOver(DWORD keyState,POINTL pt,DWORD * effect)254 COM_DECLSPEC_NOTHROW STDMETHODIMP CDropTarget::DragOver (DWORD keyState, POINTL pt, DWORD* effect)
255 {
256 if (dragData && pFrame)
257 {
258 DragEventData data;
259 data.drag = dragData;
260 pFrame->getCurrentMousePosition (data.pos);
261 pFrame->getCurrentMouseButtons (data.modifiers);
262 auto result = pFrame->getFrame ()->platformOnDragMove (data);
263 if (result == DragOperation::Copy)
264 *effect = DROPEFFECT_COPY;
265 else if (result == DragOperation::Move)
266 *effect = DROPEFFECT_MOVE;
267 else
268 *effect = DROPEFFECT_NONE;
269 }
270 return S_OK;
271 }
272
273 //-----------------------------------------------------------------------------
DragLeave(void)274 COM_DECLSPEC_NOTHROW STDMETHODIMP CDropTarget::DragLeave (void)
275 {
276 if (dragData && pFrame)
277 {
278 DragEventData data;
279 data.drag = dragData;
280 pFrame->getCurrentMousePosition (data.pos);
281 pFrame->getCurrentMouseButtons (data.modifiers);
282 pFrame->getFrame ()->platformOnDragLeave (data);
283 dragData->forget ();
284 dragData = nullptr;
285 }
286 return S_OK;
287 }
288
289 //-----------------------------------------------------------------------------
Drop(IDataObject * dataObject,DWORD keyState,POINTL pt,DWORD * effect)290 COM_DECLSPEC_NOTHROW STDMETHODIMP CDropTarget::Drop (IDataObject* dataObject, DWORD keyState, POINTL pt, DWORD* effect)
291 {
292 if (dragData && pFrame)
293 {
294 DragEventData data;
295 data.drag = dragData;
296 pFrame->getCurrentMousePosition (data.pos);
297 pFrame->getCurrentMouseButtons (data.modifiers);
298 pFrame->getFrame ()->platformOnDrop (data);
299 dragData->forget ();
300 dragData = nullptr;
301 }
302 return S_OK;
303 }
304
305 //-----------------------------------------------------------------------------
306 // Win32DropSource
307 //-----------------------------------------------------------------------------
QueryInterface(REFIID riid,void ** object)308 COM_DECLSPEC_NOTHROW STDMETHODIMP Win32DropSource::QueryInterface (REFIID riid, void** object)
309 {
310 if (riid == ::IID_IDropSource)
311 {
312 AddRef ();
313 *object = (::IDropSource*)this;
314 return S_OK;
315 }
316 else if (riid == ::IID_IUnknown)
317 {
318 AddRef ();
319 *object = (::IUnknown*)this;
320 return S_OK;
321 }
322 return E_NOINTERFACE;
323 }
324
325 //-----------------------------------------------------------------------------
QueryContinueDrag(BOOL escapePressed,DWORD keyState)326 COM_DECLSPEC_NOTHROW STDMETHODIMP Win32DropSource::QueryContinueDrag (BOOL escapePressed, DWORD keyState)
327 {
328 if (escapePressed)
329 return DRAGDROP_S_CANCEL;
330
331 if ((keyState & (MK_LBUTTON|MK_RBUTTON)) == 0)
332 return DRAGDROP_S_DROP;
333
334 return S_OK;
335 }
336
337 //-----------------------------------------------------------------------------
GiveFeedback(DWORD effect)338 COM_DECLSPEC_NOTHROW STDMETHODIMP Win32DropSource::GiveFeedback (DWORD effect)
339 {
340 return DRAGDROP_S_USEDEFAULTCURSORS;
341 }
342
343 //-----------------------------------------------------------------------------
344 // DataObject
345 //-----------------------------------------------------------------------------
Win32DataObject(IDataPackage * dataPackage)346 Win32DataObject::Win32DataObject (IDataPackage* dataPackage)
347 : dataPackage (dataPackage)
348 {
349 dataPackage->remember ();
350 }
351
352 //-----------------------------------------------------------------------------
~Win32DataObject()353 Win32DataObject::~Win32DataObject () noexcept
354 {
355 dataPackage->forget ();
356 }
357
358 //-----------------------------------------------------------------------------
QueryInterface(REFIID riid,void ** object)359 COM_DECLSPEC_NOTHROW STDMETHODIMP Win32DataObject::QueryInterface (REFIID riid, void** object)
360 {
361 if (riid == ::IID_IDataObject)
362 {
363 AddRef ();
364 *object = (::IDataObject*)this;
365 return S_OK;
366 }
367 else if (riid == ::IID_IUnknown)
368 {
369 AddRef ();
370 *object = (::IUnknown*)this;
371 return S_OK;
372 }
373 return E_NOINTERFACE;
374 }
375
376 //-----------------------------------------------------------------------------
GetData(FORMATETC * format,STGMEDIUM * medium)377 COM_DECLSPEC_NOTHROW STDMETHODIMP Win32DataObject::GetData (FORMATETC* format, STGMEDIUM* medium)
378 {
379 medium->tymed = 0;
380 medium->hGlobal = nullptr;
381 medium->pUnkForRelease = nullptr;
382
383 if (format->cfFormat == CF_TEXT || format->cfFormat == CF_UNICODETEXT)
384 {
385 for (uint32_t i = 0; i < dataPackage->getCount (); i++)
386 {
387 if (dataPackage->getDataType (i) == IDataPackage::kText)
388 {
389 const void* buffer;
390 IDataPackage::Type type;
391 uint32_t bufferSize = dataPackage->getData (i, buffer, type);
392 UTF8StringHelper utf8String (static_cast<const char*> (buffer), bufferSize);
393 SIZE_T size = 0;
394 const void* data = nullptr;
395 if (format->cfFormat == CF_UNICODETEXT)
396 {
397 size = bufferSize * sizeof (WCHAR);
398 data = utf8String.getWideString ();
399 }
400 else
401 {
402 size = bufferSize * sizeof (char);
403 data = buffer;
404 }
405 if (data && size > 0)
406 {
407 HGLOBAL memoryHandle = GlobalAlloc (GMEM_MOVEABLE, size);
408 void* memory = GlobalLock (memoryHandle);
409 if (memory)
410 {
411 memcpy (memory, data, size);
412 GlobalUnlock (memoryHandle);
413 }
414
415 medium->hGlobal = memoryHandle;
416 medium->tymed = TYMED_HGLOBAL;
417 return S_OK;
418 }
419 }
420 }
421 }
422 else if (format->cfFormat == CF_HDROP)
423 {
424 HRESULT result = E_UNEXPECTED;
425 UTF8StringHelper** wideStringFileNames = (UTF8StringHelper**)std::malloc (sizeof (UTF8StringHelper*) * dataPackage->getCount ());
426 memset (wideStringFileNames, 0, sizeof (UTF8StringHelper*) * dataPackage->getCount ());
427 uint32_t fileNamesIndex = 0;
428 uint32_t bufferSizeNeeded = 0;
429 for (uint32_t i = 0; i < dataPackage->getCount (); i++)
430 {
431 if (dataPackage->getDataType (i) == IDataPackage::kFilePath)
432 {
433 const void* buffer;
434 IDataPackage::Type type;
435 dataPackage->getData (i, buffer, type);
436
437 wideStringFileNames[fileNamesIndex] = new UTF8StringHelper ((UTF8StringPtr)buffer);
438 bufferSizeNeeded += static_cast<uint32_t> (wcslen (*wideStringFileNames[fileNamesIndex])) + 1;
439 fileNamesIndex++;
440 }
441 }
442 bufferSizeNeeded++;
443 bufferSizeNeeded *= sizeof (WCHAR);
444 bufferSizeNeeded += sizeof (DROPFILES);
445 HGLOBAL memoryHandle = GlobalAlloc (GMEM_MOVEABLE, bufferSizeNeeded);
446 void* memory = GlobalLock (memoryHandle);
447 if (memory)
448 {
449 DROPFILES* dropFiles = (DROPFILES*)memory;
450 dropFiles->pFiles = sizeof (DROPFILES);
451 dropFiles->pt.x = 0;
452 dropFiles->pt.y = 0;
453 dropFiles->fNC = FALSE;
454 dropFiles->fWide = TRUE;
455 int8_t* memAddr = ((int8_t*)memory) + sizeof (DROPFILES);
456 for (uint32_t i = 0; i < fileNamesIndex; i++)
457 {
458 size_t len = (wcslen (wideStringFileNames[i]->getWideString ()) + 1) * 2;
459 memcpy (memAddr, wideStringFileNames[i]->getWideString (), len);
460 memAddr += len;
461 }
462 *memAddr = 0;
463 memAddr++;
464 *memAddr = 0;
465 memAddr++;
466 GlobalUnlock (memoryHandle);
467 medium->hGlobal = memoryHandle;
468 medium->tymed = TYMED_HGLOBAL;
469 result = S_OK;
470 }
471 for (uint32_t i = 0; i < fileNamesIndex; i++)
472 delete wideStringFileNames[i];
473 std::free (wideStringFileNames);
474 return result;
475 }
476 else if (format->cfFormat == CF_PRIVATEFIRST)
477 {
478 for (uint32_t i = 0; i < dataPackage->getCount (); i++)
479 {
480 if (dataPackage->getDataType (i) == IDataPackage::kBinary)
481 {
482 const void* buffer;
483 IDataPackage::Type type;
484 uint32_t bufferSize = dataPackage->getData (i, buffer, type);
485
486 HGLOBAL memoryHandle = GlobalAlloc (GMEM_MOVEABLE, bufferSize);
487 void* memory = GlobalLock (memoryHandle);
488 if (memory)
489 {
490 memcpy (memory, buffer, bufferSize);
491 GlobalUnlock (memoryHandle);
492 }
493
494 medium->hGlobal = memoryHandle;
495 medium->tymed = TYMED_HGLOBAL;
496 return S_OK;
497 }
498 }
499 }
500
501 return E_UNEXPECTED;
502 }
503
504 //-----------------------------------------------------------------------------
GetDataHere(FORMATETC * format,STGMEDIUM * pmedium)505 COM_DECLSPEC_NOTHROW STDMETHODIMP Win32DataObject::GetDataHere (FORMATETC *format, STGMEDIUM *pmedium)
506 {
507 return E_NOTIMPL;
508 }
509
510 //-----------------------------------------------------------------------------
QueryGetData(FORMATETC * format)511 COM_DECLSPEC_NOTHROW STDMETHODIMP Win32DataObject::QueryGetData (FORMATETC *format)
512 {
513 if (format->cfFormat == CF_TEXT || format->cfFormat == CF_UNICODETEXT)
514 {
515 for (uint32_t i = 0; i < dataPackage->getCount (); i++)
516 {
517 if (dataPackage->getDataType (i) == IDataPackage::kText)
518 return S_OK;
519 }
520 }
521 else if (format->cfFormat == CF_PRIVATEFIRST)
522 {
523 for (uint32_t i = 0; i < dataPackage->getCount (); i++)
524 {
525 if (dataPackage->getDataType (i) == IDataPackage::kBinary)
526 return S_OK;
527 }
528 }
529 else if (format->cfFormat == CF_HDROP)
530 {
531 for (uint32_t i = 0; i < dataPackage->getCount (); i++)
532 {
533 if (dataPackage->getDataType (i) == IDataPackage::kFilePath)
534 return S_OK;
535 }
536 }
537 return DV_E_FORMATETC;
538 }
539
540 //-----------------------------------------------------------------------------
GetCanonicalFormatEtc(FORMATETC * formatIn,FORMATETC * formatOut)541 COM_DECLSPEC_NOTHROW STDMETHODIMP Win32DataObject::GetCanonicalFormatEtc (FORMATETC *formatIn, FORMATETC *formatOut)
542 {
543 return E_NOTIMPL;
544 }
545
546 //-----------------------------------------------------------------------------
SetData(FORMATETC * pformatetc,STGMEDIUM * pmedium,BOOL fRelease)547 COM_DECLSPEC_NOTHROW STDMETHODIMP Win32DataObject::SetData (FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
548 {
549 return E_NOTIMPL;
550 }
551
552 //-----------------------------------------------------------------------------
553 struct Win32DataObjectEnumerator : IEnumFORMATETC, AtomicReferenceCounted
554 {
Win32DataObjectEnumeratorVSTGUI::Win32DataObjectEnumerator555 Win32DataObjectEnumerator (const SharedPointer<IDataPackage>& data) : data (data) {}
556
QueryInterfaceVSTGUI::Win32DataObjectEnumerator557 COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE QueryInterface (REFIID riid, void** object) override
558 {
559 if (riid == ::IID_IEnumFORMATETC)
560 {
561 AddRef ();
562 *object = (::IEnumFORMATETC*)this;
563 return S_OK;
564 }
565 else if (riid == ::IID_IUnknown)
566 {
567 AddRef ();
568 *object = (::IUnknown*)this;
569 return S_OK;
570 }
571 return E_NOINTERFACE;
572 }
573
AddRefVSTGUI::Win32DataObjectEnumerator574 COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE AddRef (void) override
575 {
576 remember ();
577 return static_cast<ULONG> (getNbReference ());
578 }
ReleaseVSTGUI::Win32DataObjectEnumerator579 COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE Release (void) override
580 {
581 ULONG refCount = static_cast<ULONG> (getNbReference ()) - 1;
582 forget ();
583 return refCount;
584 }
585
NextVSTGUI::Win32DataObjectEnumerator586 COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE Next (ULONG celt, FORMATETC* rgelt, ULONG* pceltFetched) override
587 {
588 if (!rgelt)
589 return E_INVALIDARG;
590 const void* buffer;
591 IDataPackage::Type dataType;
592 auto dataSize = data->getData (index++, buffer, dataType);
593 if (dataSize)
594 {
595 if (dataType == IDataPackage::kText)
596 {
597 rgelt->cfFormat = CF_UNICODETEXT;
598 rgelt->ptd = nullptr;
599 rgelt->dwAspect = DVASPECT_CONTENT;
600 rgelt->lindex = -1;
601 rgelt->tymed = TYMED_HGLOBAL;
602 return S_OK;
603 }
604 if (dataType == IDataPackage::kFilePath)
605 {
606 #if DEBUG
607 DebugPrint ("IDataPackage::kFilePath not yet tested!\n");
608 #endif
609 rgelt->cfFormat = CF_HDROP;
610 rgelt->ptd = nullptr;
611 rgelt->dwAspect = DVASPECT_CONTENT;
612 rgelt->lindex = -1;
613 rgelt->tymed = TYMED_HGLOBAL;
614 return S_OK;
615 }
616 }
617 return S_FALSE;
618 }
619
SkipVSTGUI::Win32DataObjectEnumerator620 COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE Skip (ULONG celt) override
621 {
622 if (index + celt >= data->getCount ())
623 return S_FALSE;
624 index += celt;
625 return S_OK;
626 }
627
ResetVSTGUI::Win32DataObjectEnumerator628 COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE Reset (void) override
629 {
630 index = 0;
631 return S_OK;
632 }
633
CloneVSTGUI::Win32DataObjectEnumerator634 COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE Clone (IEnumFORMATETC** ppenum) override
635 {
636 return E_NOTIMPL;
637 }
638
639 SharedPointer<IDataPackage> data;
640 uint32_t index {0};
641 };
642
643 //-----------------------------------------------------------------------------
EnumFormatEtc(DWORD dwDirection,IEnumFORMATETC ** ppenumFormatEtc)644 COM_DECLSPEC_NOTHROW STDMETHODIMP Win32DataObject::EnumFormatEtc (DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc)
645 {
646 if (dwDirection != DATADIR_GET)
647 return E_INVALIDARG;
648
649 auto enumerator = new Win32DataObjectEnumerator (dataPackage);
650 *ppenumFormatEtc = enumerator;
651 return S_OK;
652 }
653
654 //-----------------------------------------------------------------------------
DAdvise(FORMATETC * pformatetc,DWORD advf,IAdviseSink * pAdvSink,DWORD * pdwConnection)655 COM_DECLSPEC_NOTHROW STDMETHODIMP Win32DataObject::DAdvise (FORMATETC* pformatetc, DWORD advf, IAdviseSink* pAdvSink, DWORD* pdwConnection)
656 {
657 return E_NOTIMPL;
658 }
659
660 //-----------------------------------------------------------------------------
DUnadvise(DWORD dwConnection)661 COM_DECLSPEC_NOTHROW STDMETHODIMP Win32DataObject::DUnadvise (DWORD dwConnection)
662 {
663 return E_NOTIMPL;
664 }
665
666 //-----------------------------------------------------------------------------
EnumDAdvise(IEnumSTATDATA ** ppenumAdvise)667 COM_DECLSPEC_NOTHROW STDMETHODIMP Win32DataObject::EnumDAdvise (IEnumSTATDATA** ppenumAdvise)
668 {
669 return E_NOTIMPL;
670 }
671
672 //-----------------------------------------------------------------------------
Win32DragBitmapWindow(const SharedPointer<CBitmap> & bitmap,CPoint offset)673 Win32DragBitmapWindow::Win32DragBitmapWindow (const SharedPointer<CBitmap>& bitmap, CPoint offset)
674 : bitmap (bitmap)
675 , offset (offset)
676 {
677 registerWindowClass ();
678 auto initialWindowPosition = calculateWindowPosition ();
679 updateScaleFactor (initialWindowPosition);
680 createWindow ();
681 setAlphaTransparency (1.f);
682 updateWindowPosition (initialWindowPosition);
683 showWindow ();
684 }
685
686 //-----------------------------------------------------------------------------
~Win32DragBitmapWindow()687 Win32DragBitmapWindow::~Win32DragBitmapWindow () noexcept
688 {
689 releaseWindow ();
690 unregisterWindowClass ();
691 }
692
693 //-----------------------------------------------------------------------------
updateBitmap(const SharedPointer<CBitmap> & bitmap,CPoint offset)694 void Win32DragBitmapWindow::updateBitmap (const SharedPointer<CBitmap>& bitmap, CPoint offset)
695 {
696 this->bitmap = bitmap;
697 this->offset = offset;
698 updateWindowPosition (calculateWindowPosition ());
699 RECT r;
700 GetClientRect (hwnd, &r);
701 InvalidateRect (hwnd, &r, FALSE);
702 }
703
704 //-----------------------------------------------------------------------------
createWindow()705 void Win32DragBitmapWindow::createWindow ()
706 {
707 auto winString = dynamic_cast<WinString*> (windowClassName.getPlatformString ());
708
709 DWORD exStyle = WS_EX_COMPOSITED | WS_EX_TRANSPARENT | WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TOOLWINDOW;
710 DWORD dwStyle = WS_POPUP;
711
712 auto width = static_cast<int> (bitmap->getWidth () * scaleFactor);
713 auto height = static_cast<int> (bitmap->getHeight () * scaleFactor);
714
715 hwnd = CreateWindowEx (exStyle, winString->getWideString (), nullptr, dwStyle, -1000, -1000, width,
716 height, nullptr, nullptr, GetInstance (), nullptr);
717 SetWindowLongPtr (hwnd, GWLP_USERDATA, (__int3264) (LONG_PTR) this);
718
719 MARGINS margin = { -1 };
720 auto res = DwmExtendFrameIntoClientArea (hwnd, &margin);
721 vstgui_assert (res == S_OK);
722 }
723
724 //-----------------------------------------------------------------------------
releaseWindow()725 void Win32DragBitmapWindow::releaseWindow ()
726 {
727 if (hwnd)
728 DestroyWindow (hwnd);
729 }
730
731 //-----------------------------------------------------------------------------
showWindow()732 void Win32DragBitmapWindow::showWindow ()
733 {
734 ShowWindow (hwnd, SW_SHOWNOACTIVATE);
735 }
736
737 //-----------------------------------------------------------------------------
setAlphaTransparency(float alpha)738 void Win32DragBitmapWindow::setAlphaTransparency (float alpha)
739 {
740 if (!hwnd)
741 return;
742 SetLayeredWindowAttributes (hwnd, 0, static_cast<BYTE> (alpha * 255.), LWA_ALPHA);
743 }
744
745 //-----------------------------------------------------------------------------
calculateWindowPosition() const746 POINT Win32DragBitmapWindow::calculateWindowPosition () const
747 {
748 POINT where;
749 GetCursorPos (&where);
750 where.x += static_cast<int> (offset.x * scaleFactor);
751 where.y += static_cast<int> (offset.y * scaleFactor);
752
753 return where;
754 }
755
756 //-----------------------------------------------------------------------------
updateScaleFactor(POINT p)757 void Win32DragBitmapWindow::updateScaleFactor (POINT p)
758 {
759 auto monitor = MonitorFromPoint (p, MONITOR_DEFAULTTONEAREST);
760 UINT dpiX, dpiY;
761 HiDPISupport::instance ().getDPIForMonitor (monitor, HiDPISupport::MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
762 vstgui_assert (dpiX == dpiY);
763
764 scaleFactor = static_cast<CCoord> (dpiX) / 96.;
765 }
766
767 //-----------------------------------------------------------------------------
updateWindowPosition(POINT where)768 void Win32DragBitmapWindow::updateWindowPosition (POINT where)
769 {
770 auto width = bitmap ? static_cast<int> (bitmap->getWidth () * scaleFactor) : 0;
771 auto height = bitmap ? static_cast<int> (bitmap->getHeight () * scaleFactor) : 0;
772
773 SetWindowPos (hwnd, nullptr, where.x, where.y, width, height, SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOZORDER);
774 }
775
776 //-----------------------------------------------------------------------------
paint()777 void Win32DragBitmapWindow::paint ()
778 {
779 PAINTSTRUCT ps;
780 HDC hdc = BeginPaint (hwnd, &ps);
781
782 RECT clientRect;
783 GetClientRect (hwnd, &clientRect);
784
785 CRect rect;
786 rect.setWidth (clientRect.right - clientRect.left);
787 rect.setHeight (clientRect.bottom - clientRect.top);
788
789 if (auto drawContext = owned (createDrawContext (hwnd, hdc, rect)))
790 {
791 drawContext->beginDraw ();
792
793 drawContext->clearRect (rect);
794 drawContext->setGlobalAlpha (0.9f);
795 CDrawContext::Transform t (*drawContext, CGraphicsTransform ().scale (scaleFactor, scaleFactor));
796 bitmap->draw (drawContext, rect);
797
798 drawContext->endDraw ();
799 }
800 EndPaint (hwnd, &ps);
801 }
802
803 //-----------------------------------------------------------------------------
proc(UINT message,WPARAM wParam,LPARAM lParam)804 LRESULT Win32DragBitmapWindow::proc (UINT message, WPARAM wParam, LPARAM lParam)
805 {
806 switch (message)
807 {
808 case WM_DPICHANGED:
809 {
810 scaleFactor = static_cast<CCoord> (HIWORD (wParam)) / 96.;
811 updateWindowPosition (calculateWindowPosition ());
812 break;
813 }
814 case WM_GETMINMAXINFO:
815 {
816 auto minMax = reinterpret_cast<MINMAXINFO*> (lParam);
817 minMax->ptMinTrackSize.x = 1;
818 minMax->ptMinTrackSize.y = 1;
819 break;
820 }
821 case WM_ERASEBKGND:
822 {
823 return 0;
824 }
825 case WM_PAINT:
826 {
827 paint ();
828 return 0;
829 }
830 case WM_NCCALCSIZE:
831 {
832 return 0;
833 }
834 case WM_NCHITTEST:
835 {
836 return 0;
837 }
838 }
839 return DefWindowProc (hwnd, message, wParam, lParam);
840 }
841
842 //-----------------------------------------------------------------------------
mouseChanged()843 void Win32DragBitmapWindow::mouseChanged ()
844 {
845 updateWindowPosition (calculateWindowPosition ());
846 }
847
848 //-----------------------------------------------------------------------------
WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)849 LRESULT CALLBACK Win32DragBitmapWindow::WndProc (HWND hWnd, UINT message, WPARAM wParam,
850 LPARAM lParam)
851 {
852 auto window = reinterpret_cast<Win32DragBitmapWindow*> ((LONG_PTR)GetWindowLongPtr (hWnd, GWLP_USERDATA));
853 if (window)
854 return window->proc (message, wParam, lParam);
855 return DefWindowProc (hWnd, message, wParam, lParam);
856 }
857
858 //-----------------------------------------------------------------------------
registerWindowClass()859 void Win32DragBitmapWindow::registerWindowClass ()
860 {
861 char tmp[32];
862 sprintf_s (tmp, 32, "%p", this);
863 windowClassName = "VSTGUI DragBitmap Window ";
864 windowClassName += tmp;
865
866 auto winString = dynamic_cast<WinString*> (windowClassName.getPlatformString ());
867
868 WNDCLASSEX wcex {};
869
870 wcex.cbSize = sizeof (WNDCLASSEX);
871
872 wcex.style = 0;
873 wcex.lpfnWndProc = WndProc;
874 wcex.hInstance = GetInstance ();
875 wcex.hCursor = LoadCursor (GetInstance (), IDC_ARROW);
876 wcex.hbrBackground = nullptr;
877 wcex.lpszClassName = winString->getWideString ();
878
879 RegisterClassEx (&wcex);
880 }
881
882 //-----------------------------------------------------------------------------
unregisterWindowClass()883 void Win32DragBitmapWindow::unregisterWindowClass ()
884 {
885 auto winString = dynamic_cast<WinString*> (windowClassName.getPlatformString ());
886 UnregisterClass (winString->getWideString (), GetInstance ());
887 }
888
889 } // VSTGUI
890