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 "win32frame.h"
6
7 #if WINDOWS
8
9 #include <commctrl.h>
10 #include <cmath>
11 #include <windowsx.h>
12 #include "direct2d/d2ddrawcontext.h"
13 #include "direct2d/d2dbitmap.h"
14 #include "direct2d/d2dgraphicspath.h"
15 #include "win32textedit.h"
16 #include "win32optionmenu.h"
17 #include "win32support.h"
18 #include "win32datapackage.h"
19 #include "win32dragging.h"
20 #include "../common/genericoptionmenu.h"
21 #include "../../cdropsource.h"
22 #include "../../cgradient.h"
23
24 #if VSTGUI_OPENGL_SUPPORT
25 #include "win32openglview.h"
26 #endif
27
28 // windows libraries VSTGUI depends on
29 #ifdef _MSC_VER
30 #pragma comment(lib, "Shlwapi.lib")
31 #endif
32
33 namespace VSTGUI {
34
35 #define DEBUG_DRAWING 0
36
37 //-----------------------------------------------------------------------------
38 static TCHAR gClassName[100];
39 static bool bSwapped_mouse_buttons = false;
40
41 //-----------------------------------------------------------------------------
createPlatformFrame(IPlatformFrameCallback * frame,const CRect & size,void * parent,PlatformType parentType,IPlatformFrameConfig * config)42 IPlatformFrame* IPlatformFrame::createPlatformFrame (IPlatformFrameCallback* frame, const CRect& size, void* parent, PlatformType parentType, IPlatformFrameConfig* config)
43 {
44 return new Win32Frame (frame, size, (HWND)parent, parentType);
45 }
46
47 //-----------------------------------------------------------------------------
isParentLayered(HWND parent)48 static bool isParentLayered (HWND parent)
49 {
50 WINDOWINFO info;
51 info.cbSize = sizeof (info);
52 while (parent)
53 {
54 if (GetWindowInfo (parent, &info))
55 {
56 if (info.dwStyle & WS_CHILD)
57 parent = GetParent (parent);
58 else
59 break;
60 }
61 }
62 if (parent)
63 {
64 if (info.dwExStyle & WS_EX_LAYERED)
65 return true;
66 }
67 return false;
68 }
69
70 //-----------------------------------------------------------------------------
Win32Frame(IPlatformFrameCallback * frame,const CRect & size,HWND parent,PlatformType parentType)71 Win32Frame::Win32Frame (IPlatformFrameCallback* frame, const CRect& size, HWND parent, PlatformType parentType)
72 : IPlatformFrame (frame)
73 , parentWindow (parent)
74 , windowHandle (nullptr)
75 , tooltipWindow (nullptr)
76 , oldFocusWindow (nullptr)
77 , backBuffer (nullptr)
78 , deviceContext (nullptr)
79 , inPaint (false)
80 , mouseInside (false)
81 , updateRegionList (nullptr)
82 , updateRegionListSize (0)
83 {
84 useD2D ();
85 if (parentType == PlatformType::kHWNDTopLevel)
86 {
87 windowHandle = parent;
88 parentWindow = nullptr;
89 RegisterDragDrop (windowHandle, new CDropTarget (this));
90 }
91 else
92 {
93 initWindowClass ();
94
95 DWORD style = isParentLayered (parent) ? WS_EX_TRANSPARENT : 0;
96 windowHandle = CreateWindowEx (style, gClassName, TEXT("Window"),
97 WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
98 0, 0, (int)size.getWidth (), (int)size.getHeight (),
99 parentWindow, NULL, GetInstance (), NULL);
100
101 if (windowHandle)
102 {
103 SetWindowLongPtr (windowHandle, GWLP_USERDATA, (__int3264)(LONG_PTR)this);
104 RegisterDragDrop (windowHandle, new CDropTarget (this));
105 }
106 }
107 setMouseCursor (kCursorDefault);
108 }
109
110 //-----------------------------------------------------------------------------
~Win32Frame()111 Win32Frame::~Win32Frame () noexcept
112 {
113 if (updateRegionList)
114 std::free (updateRegionList);
115 if (deviceContext)
116 deviceContext->forget ();
117 if (tooltipWindow)
118 DestroyWindow (tooltipWindow);
119 if (backBuffer)
120 backBuffer->forget ();
121 if (windowHandle)
122 RevokeDragDrop (windowHandle);
123 if (parentWindow)
124 {
125 if (windowHandle)
126 {
127 SetWindowLongPtr (windowHandle, GWLP_USERDATA, (LONG_PTR)NULL);
128 DestroyWindow (windowHandle);
129 }
130 destroyWindowClass ();
131 }
132
133 unuseD2D ();
134 }
135
136 //-----------------------------------------------------------------------------
137 int32_t Win32Frame::gUseCount = 0;
138
139 //-----------------------------------------------------------------------------
initWindowClass()140 void Win32Frame::initWindowClass ()
141 {
142 gUseCount++;
143 if (gUseCount == 1)
144 {
145 OleInitialize (0);
146
147 VSTGUI_SPRINTF (gClassName, TEXT("VSTGUI%p"), GetInstance ());
148
149 WNDCLASS windowClass;
150 windowClass.style = CS_GLOBALCLASS | CS_DBLCLKS;//|CS_OWNDC; // add Private-DC constant
151
152 windowClass.lpfnWndProc = WindowProc;
153 windowClass.cbClsExtra = 0;
154 windowClass.cbWndExtra = 0;
155 windowClass.hInstance = GetInstance ();
156 windowClass.hIcon = nullptr;
157
158 windowClass.hCursor = LoadCursor (NULL, IDC_ARROW);
159 #if DEBUG_DRAWING
160 windowClass.hbrBackground = GetSysColorBrush (COLOR_BTNFACE);
161 #else
162 windowClass.hbrBackground = nullptr;
163 #endif
164 windowClass.lpszMenuName = nullptr;
165 windowClass.lpszClassName = gClassName;
166 RegisterClass (&windowClass);
167
168 bSwapped_mouse_buttons = GetSystemMetrics (SM_SWAPBUTTON) > 0;
169 }
170 }
171
172 //-----------------------------------------------------------------------------
destroyWindowClass()173 void Win32Frame::destroyWindowClass ()
174 {
175 gUseCount--;
176 if (gUseCount == 0)
177 {
178 UnregisterClass (gClassName, GetInstance ());
179 OleUninitialize ();
180 }
181 }
182
183 //-----------------------------------------------------------------------------
initTooltip()184 void Win32Frame::initTooltip ()
185 {
186 if (tooltipWindow == nullptr && windowHandle)
187 {
188 TOOLINFO ti;
189 // Create the ToolTip control.
190 HWND hwndTT = CreateWindow (TOOLTIPS_CLASS, TEXT(""),
191 WS_POPUP,
192 CW_USEDEFAULT, CW_USEDEFAULT,
193 CW_USEDEFAULT, CW_USEDEFAULT,
194 NULL, (HMENU)NULL, GetInstance (),
195 NULL);
196
197 // Prepare TOOLINFO structure for use as tracking ToolTip.
198 ti.cbSize = sizeof(TOOLINFO);
199 ti.uFlags = TTF_SUBCLASS;
200 ti.hwnd = (HWND)windowHandle;
201 ti.uId = (UINT)0;
202 ti.hinst = GetInstance ();
203 ti.lpszText = const_cast<TCHAR*> (TEXT("This is a tooltip"));
204 ti.rect.left = ti.rect.top = ti.rect.bottom = ti.rect.right = 0;
205
206 // Add the tool to the control
207 if (!SendMessage (hwndTT, TTM_ADDTOOL, 0, (LPARAM)&ti))
208 {
209 DestroyWindow (hwndTT);
210 return;
211 }
212
213 tooltipWindow = hwndTT;
214 }
215 }
216
217 //-----------------------------------------------------------------------------
getOuterWindow() const218 HWND Win32Frame::getOuterWindow () const
219 {
220 int diffWidth, diffHeight;
221 RECT rctTempWnd, rctPluginWnd;
222 HWND hTempWnd = windowHandle;
223 GetWindowRect (hTempWnd, &rctPluginWnd);
224
225 while (hTempWnd != NULL)
226 {
227 // Looking for caption bar
228 if (GetWindowLong (hTempWnd, GWL_STYLE) & WS_CAPTION)
229 return hTempWnd;
230
231 // Looking for last parent
232 if (!GetParent (hTempWnd))
233 return hTempWnd;
234
235 // get difference between plugin-window and current parent
236 GetWindowRect (GetParent (hTempWnd), &rctTempWnd);
237
238 diffWidth = (rctTempWnd.right - rctTempWnd.left) - (rctPluginWnd.right - rctPluginWnd.left);
239 diffHeight = (rctTempWnd.bottom - rctTempWnd.top) - (rctPluginWnd.bottom - rctPluginWnd.top);
240
241 // Looking for size mismatch
242 if ((abs (diffWidth) > 60) || (abs (diffHeight) > 60)) // parent belongs to host
243 return (hTempWnd);
244
245 if (diffWidth < 0)
246 diffWidth = 0;
247 if (diffHeight < 0)
248 diffHeight = 0;
249
250 // get the next parent window
251 hTempWnd = GetParent (hTempWnd);
252 }
253
254 return NULL;
255 }
256
257 // IPlatformFrame
258 //-----------------------------------------------------------------------------
getGlobalPosition(CPoint & pos) const259 bool Win32Frame::getGlobalPosition (CPoint& pos) const
260 {
261 RECT r;
262 GetWindowRect (windowHandle, &r);
263 pos.x = r.left;
264 pos.y = r.top;
265 return true;
266 }
267
268 //-----------------------------------------------------------------------------
setSize(const CRect & newSize)269 bool Win32Frame::setSize (const CRect& newSize)
270 {
271 if (deviceContext)
272 {
273 deviceContext->forget ();
274 deviceContext = nullptr;
275 }
276 if (backBuffer)
277 {
278 backBuffer->forget ();
279 backBuffer = createOffscreenContext (newSize.getWidth (), newSize.getHeight ());
280 }
281 if (!parentWindow)
282 return true;
283 SetWindowPos (windowHandle, HWND_TOP, (int)newSize.left, (int)newSize.top, (int)newSize.getWidth (), (int)newSize.getHeight (), SWP_NOZORDER|SWP_NOCOPYBITS|SWP_NOREDRAW|SWP_DEFERERASE);
284 invalidRect (newSize);
285 return true;
286 }
287
288 //-----------------------------------------------------------------------------
getSize(CRect & size) const289 bool Win32Frame::getSize (CRect& size) const
290 {
291 RECT r;
292 GetWindowRect (windowHandle, &r);
293 POINT p;
294 p.x = r.left;
295 p.y = r.top;
296 MapWindowPoints (HWND_DESKTOP, windowHandle, &p, 1);
297 MapWindowPoints (windowHandle, GetParent (windowHandle), &p, 1);
298 size.left = p.x;
299 size.top = p.y;
300 size.right = p.x + (r.right - r.left);
301 size.bottom = p.y + (r.bottom - r.top);
302 return true;
303 }
304
305 //-----------------------------------------------------------------------------
getCurrentMousePosition(CPoint & mousePosition) const306 bool Win32Frame::getCurrentMousePosition (CPoint& mousePosition) const
307 {
308 POINT _where;
309 GetCursorPos (&_where);
310 mousePosition (static_cast<CCoord> (_where.x), static_cast<CCoord> (_where.y));
311 if (auto hwnd = getHWND ())
312 {
313 ScreenToClient (hwnd, &_where);
314 mousePosition (static_cast<CCoord> (_where.x), static_cast<CCoord> (_where.y));
315 return true;
316 }
317 return false;
318 }
319
320 //-----------------------------------------------------------------------------
getCurrentMouseButtons(CButtonState & buttons) const321 bool Win32Frame::getCurrentMouseButtons (CButtonState& buttons) const
322 {
323 if (GetAsyncKeyState (VK_LBUTTON) < 0)
324 buttons |= (bSwapped_mouse_buttons ? kRButton : kLButton);
325 if (GetAsyncKeyState (VK_MBUTTON) < 0)
326 buttons |= kMButton;
327 if (GetAsyncKeyState (VK_RBUTTON) < 0)
328 buttons |= (bSwapped_mouse_buttons ? kLButton : kRButton);
329 if (GetAsyncKeyState (VK_SHIFT) < 0)
330 buttons |= kShift;
331 if (GetAsyncKeyState (VK_CONTROL) < 0)
332 buttons |= kControl;
333 if (GetAsyncKeyState (VK_MENU) < 0)
334 buttons |= kAlt;
335 return true;
336 }
337
338 //-----------------------------------------------------------------------------
setMouseCursor(CCursorType type)339 bool Win32Frame::setMouseCursor (CCursorType type)
340 {
341 HCURSOR cursor = nullptr;
342 switch (type)
343 {
344 case kCursorWait:
345 cursor = LoadCursor (nullptr, IDC_WAIT);
346 break;
347 case kCursorHSize:
348 cursor = LoadCursor (nullptr, IDC_SIZEWE);
349 break;
350 case kCursorVSize:
351 cursor = LoadCursor (nullptr, IDC_SIZENS);
352 break;
353 case kCursorNESWSize:
354 cursor = LoadCursor (nullptr, IDC_SIZENESW);
355 break;
356 case kCursorNWSESize:
357 cursor = LoadCursor (nullptr, IDC_SIZENWSE);
358 break;
359 case kCursorSizeAll:
360 cursor = LoadCursor (nullptr, IDC_SIZEALL);
361 break;
362 case kCursorNotAllowed:
363 cursor = LoadCursor (nullptr, IDC_NO);
364 break;
365 case kCursorHand:
366 cursor = LoadCursor (nullptr, IDC_HAND);
367 break;
368 default:
369 cursor = LoadCursor (nullptr, IDC_ARROW);
370 break;
371 }
372 lastSetCursor = type;
373 SetClassLongPtr (getPlatformWindow (), GCLP_HCURSOR, (__int3264)(LONG_PTR)(cursor));
374 return true;
375 }
376
377 //-----------------------------------------------------------------------------
invalidRect(const CRect & rect)378 bool Win32Frame::invalidRect (const CRect& rect)
379 {
380 if (inPaint)
381 return false;
382 if (!rect.isEmpty ())
383 {
384 RECT r = {(LONG)rect.left, (LONG)rect.top, (LONG)ceil (rect.right), (LONG)ceil (rect.bottom)};
385 InvalidateRect (windowHandle, &r, true);
386 }
387 return true;
388 }
389
390 //-----------------------------------------------------------------------------
scrollRect(const CRect & src,const CPoint & distance)391 bool Win32Frame::scrollRect (const CRect& src, const CPoint& distance)
392 {
393 return false;
394 }
395
396 //-----------------------------------------------------------------------------
getTicks()397 uint32_t IPlatformFrame::getTicks ()
398 {
399 return (uint32_t)GetTickCount ();
400 }
401
402 //-----------------------------------------------------------------------------
showTooltip(const CRect & rect,const char * utf8Text)403 bool Win32Frame::showTooltip (const CRect& rect, const char* utf8Text)
404 {
405 initTooltip ();
406 if (tooltipWindow)
407 {
408 std::string str (utf8Text);
409 size_t pos = 0;
410 while ((pos = str.find ("\\n", pos)) != std::string::npos)
411 {
412 str.erase (pos, 2);
413 str.insert (pos, "\r\n");
414 }
415 UTF8StringHelper tooltipText (str.data ());
416 RECT rc;
417 rc.left = (LONG)rect.left;
418 rc.top = (LONG)rect.top;
419 rc.right = (LONG)rect.right;
420 rc.bottom = (LONG)rect.bottom;
421 TOOLINFO ti = {};
422 ti.cbSize = sizeof(TOOLINFO);
423 ti.hwnd = windowHandle;
424 ti.uId = 0;
425 ti.rect = rc;
426 ti.lpszText = (TCHAR*)(const TCHAR*)tooltipText;
427 SendMessage (tooltipWindow, TTM_SETMAXTIPWIDTH, 0, 0);
428 SendMessage (tooltipWindow, TTM_SETDELAYTIME, 0, 2000);
429 SendMessage (tooltipWindow, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
430 SendMessage (tooltipWindow, TTM_NEWTOOLRECT, 0, (LPARAM)&ti);
431 SendMessage (tooltipWindow, TTM_POPUP, 0, 0);
432 return true;
433 }
434 return false;
435 }
436
437 //-----------------------------------------------------------------------------
hideTooltip()438 bool Win32Frame::hideTooltip ()
439 {
440 if (tooltipWindow)
441 {
442 TOOLINFO ti = {};
443 ti.cbSize = sizeof(TOOLINFO);
444 ti.hwnd = windowHandle;
445 ti.uId = 0;
446 ti.lpszText = nullptr;
447 SendMessage (tooltipWindow, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
448 SendMessage (tooltipWindow, TTM_POP, 0, 0);
449 }
450 return false;
451 }
452
453 //-----------------------------------------------------------------------------
createPlatformTextEdit(IPlatformTextEditCallback * textEdit)454 SharedPointer<IPlatformTextEdit> Win32Frame::createPlatformTextEdit (IPlatformTextEditCallback* textEdit)
455 {
456 return owned<IPlatformTextEdit> (new Win32TextEdit (windowHandle, textEdit));
457 }
458
459 //-----------------------------------------------------------------------------
createPlatformOptionMenu()460 SharedPointer<IPlatformOptionMenu> Win32Frame::createPlatformOptionMenu ()
461 {
462 if (genericOptionMenuTheme)
463 {
464 CButtonState buttons;
465 getCurrentMouseButtons (buttons);
466 return makeOwned<GenericOptionMenu> (dynamic_cast<CFrame*> (frame), buttons,
467 *genericOptionMenuTheme.get ());
468 }
469 return owned<IPlatformOptionMenu> (new Win32OptionMenu (windowHandle));
470 }
471
472 #if VSTGUI_OPENGL_SUPPORT
473 //-----------------------------------------------------------------------------
createPlatformOpenGLView()474 SharedPointer<IPlatformOpenGLView> Win32Frame::createPlatformOpenGLView ()
475 {
476 return owned<IPlatformOpenGLView> (new Win32OpenGLView (this));
477 }
478 #endif
479
480 //-----------------------------------------------------------------------------
createOffscreenContext(CCoord width,CCoord height,double scaleFactor)481 SharedPointer<COffscreenContext> Win32Frame::createOffscreenContext (CCoord width, CCoord height, double scaleFactor)
482 {
483 D2DBitmap* bitmap = new D2DBitmap (CPoint (width * scaleFactor, height * scaleFactor));
484 bitmap->setScaleFactor (scaleFactor);
485 auto context = owned<COffscreenContext> (new D2DDrawContext (bitmap));
486 bitmap->forget ();
487 return context;
488 }
489
490 #if VSTGUI_ENABLE_DEPRECATED_METHODS
491 class Win32LegacyDragSupport final : virtual public DragCallbackAdapter, virtual public NonAtomicReferenceCounted
492 {
493 public:
dragEnded(IDraggingSession *,CPoint,DragOperation r)494 void dragEnded (IDraggingSession*, CPoint, DragOperation r) final { result = r; }
495 DragOperation result {DragOperation::None};
496 };
497
498 //------------------------------------------------------------------------------------
doDrag(IDataPackage * source,const CPoint & offset,CBitmap * dragBitmap)499 DragResult Win32Frame::doDrag (IDataPackage* source, const CPoint& offset, CBitmap* dragBitmap)
500 {
501 Win32LegacyDragSupport dragSupport;
502
503 Win32DraggingSession session (this);
504 if (session.doDrag (DragDescription (source, offset, dragBitmap), &dragSupport))
505 {
506 switch (dragSupport.result)
507 {
508 case DragOperation::Copy: return kDragCopied;
509 case DragOperation::Move: return kDragMoved;
510 case DragOperation::None: return kDragRefused;
511 }
512 }
513 return kDragRefused;
514 }
515 #endif
516
517 //-----------------------------------------------------------------------------
doDrag(const DragDescription & dragDescription,const SharedPointer<IDragCallback> & callback)518 bool Win32Frame::doDrag (const DragDescription& dragDescription, const SharedPointer<IDragCallback>& callback)
519 {
520 Win32DraggingSession session (this);
521 return session.doDrag (dragDescription, callback);
522 }
523
524 //-----------------------------------------------------------------------------
setClipboard(const SharedPointer<IDataPackage> & data)525 void Win32Frame::setClipboard (const SharedPointer<IDataPackage>& data)
526 {
527 auto dataObject = makeOwned<Win32DataObject> (data);
528 auto hr = OleSetClipboard (dataObject);
529 if (hr != S_OK)
530 {
531 #if DEBUG
532 DebugPrint ("Setting clipboard failed!\n");
533 #endif
534 }
535 }
536
537 //-----------------------------------------------------------------------------
getClipboard()538 SharedPointer<IDataPackage> Win32Frame::getClipboard ()
539 {
540 IDataObject* dataObject = nullptr;;
541 if (OleGetClipboard (&dataObject) != S_OK)
542 return nullptr;
543 return makeOwned<Win32DataPackage> (dataObject);
544 }
545
546 //-----------------------------------------------------------------------------
onFrameClosed()547 void Win32Frame::onFrameClosed ()
548 {
549 frame = nullptr;
550 }
551
552 //-----------------------------------------------------------------------------
setupGenericOptionMenu(bool use,GenericOptionMenuTheme * theme)553 bool Win32Frame::setupGenericOptionMenu (bool use, GenericOptionMenuTheme* theme)
554 {
555 if (!use)
556 {
557 genericOptionMenuTheme = nullptr;
558 }
559 else
560 {
561 if (theme)
562 genericOptionMenuTheme = std::unique_ptr<GenericOptionMenuTheme> (new GenericOptionMenuTheme (*theme));
563 else
564 genericOptionMenuTheme = std::unique_ptr<GenericOptionMenuTheme> (new GenericOptionMenuTheme);
565 }
566 return true;
567 }
568
569 //-----------------------------------------------------------------------------
paint(HWND hwnd)570 void Win32Frame::paint (HWND hwnd)
571 {
572 HRGN rgn = CreateRectRgn (0, 0, 0, 0);
573 if (GetUpdateRgn (hwnd, rgn, false) == NULLREGION)
574 {
575 DeleteObject (rgn);
576 return;
577 }
578
579 inPaint = true;
580
581 PAINTSTRUCT ps;
582 HDC hdc = BeginPaint (hwnd, &ps);
583
584 if (hdc)
585 {
586 CRect updateRect ((CCoord)ps.rcPaint.left, (CCoord)ps.rcPaint.top, (CCoord)ps.rcPaint.right, (CCoord)ps.rcPaint.bottom);
587 CRect frameSize;
588 getSize (frameSize);
589 frameSize.offset (-frameSize.left, -frameSize.top);
590 if (deviceContext == nullptr)
591 deviceContext = createDrawContext (hwnd, hdc, frameSize);
592 if (deviceContext)
593 {
594 deviceContext->setClipRect (updateRect);
595
596 CDrawContext* drawContext = backBuffer ? backBuffer : deviceContext;
597 drawContext->beginDraw ();
598 DWORD len = GetRegionData (rgn, 0, NULL);
599 if (len)
600 {
601 if (len > updateRegionListSize)
602 {
603 if (updateRegionList)
604 std::free (updateRegionList);
605 updateRegionListSize = len;
606 updateRegionList = (RGNDATA*) std::malloc (updateRegionListSize);
607 }
608 GetRegionData (rgn, len, updateRegionList);
609 if (updateRegionList->rdh.nCount > 1)
610 {
611 std::vector<CRect> dirtyRects;
612 dirtyRects.reserve (updateRegionList->rdh.nCount);
613 RECT* rp = (RECT*)updateRegionList->Buffer;
614 dirtyRects.emplace_back (CRect (rp->left, rp->top, rp->right, rp->bottom));
615 ++rp;
616 for (uint32_t i = 1; i < updateRegionList->rdh.nCount; ++i, ++rp)
617 {
618 CRect ur (rp->left, rp->top, rp->right, rp->bottom);
619 auto mustAdd = true;
620 for (auto& r : dirtyRects)
621 {
622 auto cr = ur;
623 cr.unite (r);
624 if (cr.getWidth () * cr.getHeight () ==
625 ur.getWidth () * ur.getHeight () + r.getWidth () * r.getHeight ())
626 {
627 r = cr;
628 mustAdd = false;
629 break;
630 }
631 }
632 if (mustAdd)
633 dirtyRects.emplace_back (ur);
634 }
635 for (auto& updateRect : dirtyRects)
636 {
637 drawContext->clearRect (updateRect);
638 getFrame ()->platformDrawRect (drawContext, updateRect);
639 }
640 }
641 else
642 {
643 drawContext->clearRect (updateRect);
644 getFrame ()->platformDrawRect (drawContext, updateRect);
645 }
646 }
647 drawContext->endDraw ();
648 if (backBuffer)
649 {
650 deviceContext->beginDraw ();
651 deviceContext->clearRect (updateRect);
652 backBuffer->copyFrom (deviceContext, updateRect, CPoint (updateRect.left, updateRect.top));
653 deviceContext->endDraw ();
654 }
655 }
656 }
657
658 EndPaint (hwnd, &ps);
659 DeleteObject (rgn);
660
661 inPaint = false;
662 }
663
translateWinVirtualKey(WPARAM winVKey)664 static unsigned char translateWinVirtualKey (WPARAM winVKey)
665 {
666 switch (winVKey)
667 {
668 case VK_BACK: return VKEY_BACK;
669 case VK_TAB: return VKEY_TAB;
670 case VK_CLEAR: return VKEY_CLEAR;
671 case VK_RETURN: return VKEY_RETURN;
672 case VK_PAUSE: return VKEY_PAUSE;
673 case VK_ESCAPE: return VKEY_ESCAPE;
674 case VK_SPACE: return VKEY_SPACE;
675 // TODO: case VK_NEXT: return VKEY_NEXT;
676 case VK_END: return VKEY_END;
677 case VK_HOME: return VKEY_HOME;
678 case VK_LEFT: return VKEY_LEFT;
679 case VK_RIGHT: return VKEY_RIGHT;
680 case VK_UP: return VKEY_UP;
681 case VK_DOWN: return VKEY_DOWN;
682 case VK_PRIOR: return VKEY_PAGEUP;
683 case VK_NEXT: return VKEY_PAGEDOWN;
684 case VK_SELECT: return VKEY_SELECT;
685 case VK_PRINT: return VKEY_PRINT;
686 case VK_SNAPSHOT: return VKEY_SNAPSHOT;
687 case VK_INSERT: return VKEY_INSERT;
688 case VK_DELETE: return VKEY_DELETE;
689 case VK_HELP: return VKEY_HELP;
690 case VK_NUMPAD0: return VKEY_NUMPAD0;
691 case VK_NUMPAD1: return VKEY_NUMPAD1;
692 case VK_NUMPAD2: return VKEY_NUMPAD2;
693 case VK_NUMPAD3: return VKEY_NUMPAD3;
694 case VK_NUMPAD4: return VKEY_NUMPAD4;
695 case VK_NUMPAD5: return VKEY_NUMPAD5;
696 case VK_NUMPAD6: return VKEY_NUMPAD6;
697 case VK_NUMPAD7: return VKEY_NUMPAD7;
698 case VK_NUMPAD8: return VKEY_NUMPAD8;
699 case VK_NUMPAD9: return VKEY_NUMPAD9;
700 case VK_MULTIPLY: return VKEY_MULTIPLY;
701 case VK_ADD: return VKEY_ADD;
702 case VK_SEPARATOR: return VKEY_SEPARATOR;
703 case VK_SUBTRACT: return VKEY_SUBTRACT;
704 case VK_DECIMAL: return VKEY_DECIMAL;
705 case VK_DIVIDE: return VKEY_DIVIDE;
706 case VK_F1: return VKEY_F1;
707 case VK_F2: return VKEY_F2;
708 case VK_F3: return VKEY_F3;
709 case VK_F4: return VKEY_F4;
710 case VK_F5: return VKEY_F5;
711 case VK_F6: return VKEY_F6;
712 case VK_F7: return VKEY_F7;
713 case VK_F8: return VKEY_F8;
714 case VK_F9: return VKEY_F9;
715 case VK_F10: return VKEY_F10;
716 case VK_F11: return VKEY_F11;
717 case VK_F12: return VKEY_F12;
718 case VK_NUMLOCK: return VKEY_NUMLOCK;
719 case VK_SCROLL: return VKEY_SCROLL;
720 case VK_SHIFT: return VKEY_SHIFT;
721 case VK_CONTROL: return VKEY_CONTROL;
722 case VK_MENU: return VKEY_ALT;
723 case VKEY_EQUALS: return VKEY_EQUALS;
724 }
725 return 0;
726 }
727
728 //-----------------------------------------------------------------------------
proc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)729 LONG_PTR WINAPI Win32Frame::proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
730 {
731 if (getFrame () == nullptr)
732 return DefWindowProc (hwnd, message, wParam, lParam);
733
734 SharedPointer<Win32Frame> lifeGuard (this);
735 IPlatformFrameCallback* pFrame = getFrame ();
736 bool doubleClick = false;
737
738 switch (message)
739 {
740 case WM_MOUSEWHEEL:
741 {
742 CButtonState buttons = 0;
743 if (GetAsyncKeyState (VK_SHIFT) < 0)
744 buttons |= kShift;
745 if (GetAsyncKeyState (VK_CONTROL) < 0)
746 buttons |= kControl;
747 if (GetAsyncKeyState (VK_MENU) < 0)
748 buttons |= kAlt;
749 short zDelta = (short) GET_WHEEL_DELTA_WPARAM(wParam);
750 POINT p {GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam)};
751 ScreenToClient (windowHandle, &p);
752 CPoint where (p.x, p.y);
753 if (pFrame->platformOnMouseWheel (where, kMouseWheelAxisY, ((float)zDelta / WHEEL_DELTA), buttons))
754 return 0;
755 break;
756 }
757 case WM_MOUSEHWHEEL: // new since vista
758 {
759 CButtonState buttons = 0;
760 if (GetAsyncKeyState (VK_SHIFT) < 0)
761 buttons |= kShift;
762 if (GetAsyncKeyState (VK_CONTROL) < 0)
763 buttons |= kControl;
764 if (GetAsyncKeyState (VK_MENU) < 0)
765 buttons |= kAlt;
766 short zDelta = (short) GET_WHEEL_DELTA_WPARAM(wParam);
767 POINT p {GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam)};
768 ScreenToClient (windowHandle, &p);
769 CPoint where (p.x, p.y);
770 if (pFrame->platformOnMouseWheel (where, kMouseWheelAxisX, ((float)-zDelta / WHEEL_DELTA), buttons))
771 return 0;
772 break;
773 }
774 case WM_CTLCOLOREDIT:
775 {
776 Win32TextEdit* win32TextEdit = (Win32TextEdit*)(LONG_PTR) GetWindowLongPtr ((HWND)lParam, GWLP_USERDATA);
777 if (win32TextEdit)
778 {
779 CColor fontColor = win32TextEdit->getTextEdit ()->platformGetFontColor ();
780 SetTextColor ((HDC) wParam, RGB (fontColor.red, fontColor.green, fontColor.blue));
781 #if 1 // TODO: I don't know why the transparent part does not work anymore. Needs more investigation.
782 CColor backColor = win32TextEdit->getTextEdit ()->platformGetBackColor ();
783 SetBkColor ((HDC) wParam, RGB (backColor.red, backColor.green, backColor.blue));
784 return (LRESULT)(win32TextEdit->getPlatformBackColor ());
785 #else
786 SetBkMode ((HDC)wParam, TRANSPARENT);
787 return (LRESULT) ::GetStockObject (HOLLOW_BRUSH);
788 #endif
789 }
790 break;
791 }
792
793 case WM_PAINT:
794 {
795 paint (hwnd);
796 return 0;
797 }
798
799 case WM_RBUTTONDBLCLK:
800 case WM_MBUTTONDBLCLK:
801 case WM_LBUTTONDBLCLK:
802 case WM_XBUTTONDBLCLK:
803 doubleClick = true;
804 case WM_RBUTTONDOWN:
805 case WM_MBUTTONDOWN:
806 case WM_LBUTTONDOWN:
807 case WM_XBUTTONDOWN:
808 {
809 CButtonState buttons = 0;
810 if (wParam & MK_LBUTTON)
811 buttons |= kLButton;
812 if (wParam & MK_RBUTTON)
813 buttons |= kRButton;
814 if (wParam & MK_MBUTTON)
815 buttons |= kMButton;
816 if (wParam & MK_XBUTTON1)
817 buttons |= kButton4;
818 if (wParam & MK_XBUTTON2)
819 buttons |= kButton5;
820 if (wParam & MK_CONTROL)
821 buttons |= kControl;
822 if (wParam & MK_SHIFT)
823 buttons |= kShift;
824 if (GetAsyncKeyState (VK_MENU) < 0)
825 buttons |= kAlt;
826 if (doubleClick)
827 buttons |= kDoubleClick;
828 HWND oldFocus = SetFocus(getPlatformWindow());
829 if(oldFocus != hwnd)
830 oldFocusWindow = oldFocus;
831
832 CPoint where (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam));
833 if (pFrame->platformOnMouseDown (where, buttons) == kMouseEventHandled && getPlatformWindow ())
834 SetCapture (getPlatformWindow ());
835 return 0;
836 }
837 case WM_MOUSELEAVE:
838 {
839 CPoint where;
840 getCurrentMousePosition (where);
841 CButtonState buttons;
842 getCurrentMouseButtons (buttons);
843 pFrame->platformOnMouseExited (where, buttons);
844 mouseInside = false;
845 return 0;
846 }
847 case WM_MOUSEMOVE:
848 {
849 CButtonState buttons = 0;
850 if (wParam & MK_LBUTTON)
851 buttons |= kLButton;
852 if (wParam & MK_RBUTTON)
853 buttons |= kRButton;
854 if (wParam & MK_MBUTTON)
855 buttons |= kMButton;
856 if (wParam & MK_XBUTTON1)
857 buttons |= kButton4;
858 if (wParam & MK_XBUTTON2)
859 buttons |= kButton5;
860 if (wParam & MK_CONTROL)
861 buttons |= kControl;
862 if (wParam & MK_SHIFT)
863 buttons |= kShift;
864 if (GetAsyncKeyState (VK_MENU) < 0)
865 buttons |= kAlt;
866 if (!mouseInside)
867 {
868 // this makes sure that WM_MOUSELEAVE will be generated by the system
869 mouseInside = true;
870 TRACKMOUSEEVENT tme = {};
871 tme.cbSize = sizeof (tme);
872 tme.dwFlags = TME_LEAVE;
873 tme.hwndTrack = windowHandle;
874 TrackMouseEvent (&tme);
875 }
876 CPoint where (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam));
877 pFrame->platformOnMouseMoved (where, buttons);
878 return 0;
879 }
880 case WM_LBUTTONUP:
881 case WM_RBUTTONUP:
882 case WM_MBUTTONUP:
883 case WM_XBUTTONUP:
884 {
885 CButtonState buttons = 0;
886 if (message & MK_LBUTTON || message == WM_LBUTTONUP)
887 buttons |= kLButton;
888 if (wParam & MK_RBUTTON || message == WM_RBUTTONUP)
889 buttons |= kRButton;
890 if (wParam & MK_MBUTTON || message == WM_MBUTTONUP)
891 buttons |= kMButton;
892 if (wParam & MK_XBUTTON1)
893 buttons |= kButton4;
894 if (wParam & MK_XBUTTON2)
895 buttons |= kButton5;
896 if (wParam & MK_CONTROL)
897 buttons |= kControl;
898 if (wParam & MK_SHIFT)
899 buttons |= kShift;
900 if (GetAsyncKeyState (VK_MENU) < 0)
901 buttons |= kAlt;
902 CPoint where (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam));
903 pFrame->platformOnMouseUp (where, buttons);
904 ReleaseCapture ();
905 return 0;
906 }
907 case WM_KEYDOWN:
908 {
909 VstKeyCode key {};
910 if (GetAsyncKeyState (VK_SHIFT) < 0)
911 key.modifier |= MODIFIER_SHIFT;
912 if (GetAsyncKeyState (VK_CONTROL) < 0)
913 key.modifier |= MODIFIER_CONTROL;
914 if (GetAsyncKeyState (VK_MENU) < 0)
915 key.modifier |= MODIFIER_ALTERNATE;
916 key.virt = translateWinVirtualKey (wParam);
917 key.character = MapVirtualKey (static_cast<UINT> (wParam), MAPVK_VK_TO_CHAR);
918 if (key.virt || key.character)
919 {
920 key.character = std::tolower (key.character);
921 if (pFrame->platformOnKeyDown (key))
922 return 0;
923 }
924
925 if (IsWindow (oldFocusWindow))
926 {
927 auto oldProc = reinterpret_cast<WNDPROC> (GetWindowLongPtr (oldFocusWindow, GWLP_WNDPROC));
928 if (oldProc && oldProc != WindowProc)
929 return CallWindowProc (oldProc, oldFocusWindow, message, wParam, lParam);
930 }
931 break;
932 }
933 case WM_KEYUP:
934 {
935 VstKeyCode key {};
936 if (GetAsyncKeyState (VK_SHIFT) < 0)
937 key.modifier |= MODIFIER_SHIFT;
938 if (GetAsyncKeyState (VK_CONTROL) < 0)
939 key.modifier |= MODIFIER_CONTROL;
940 if (GetAsyncKeyState (VK_MENU) < 0)
941 key.modifier |= MODIFIER_ALTERNATE;
942 key.virt = translateWinVirtualKey (wParam);
943 key.character = MapVirtualKey (static_cast<UINT> (wParam), MAPVK_VK_TO_CHAR);
944 if (key.virt || key.character)
945 {
946 if (pFrame->platformOnKeyUp (key))
947 return 0;
948 }
949
950 if (IsWindow (oldFocusWindow))
951 {
952 auto oldProc = reinterpret_cast<WNDPROC> (GetWindowLongPtr (oldFocusWindow, GWLP_WNDPROC));
953 if (oldProc && oldProc != WindowProc)
954 return CallWindowProc (oldProc, oldFocusWindow, message, wParam, lParam);
955 }
956 break;
957 }
958 case WM_SETFOCUS:
959 {
960 pFrame->platformOnActivate (true);
961 break;
962 }
963 case WM_KILLFOCUS:
964 {
965 oldFocusWindow = nullptr;
966
967 HWND focusWindow = GetFocus ();
968 if (GetParent (focusWindow) != windowHandle)
969 pFrame->platformOnActivate (false);
970 break;
971 }
972 case WM_DESTROY:
973 {
974 #if DEBUG
975 DebugPrint ("This sometimes happens, only when we are currently processing a mouse down event and via a callback into the host the window gets destroyed. Otherwise this should never get called. We are the owner of the window and we are responsible of destroying it.\n");
976 #endif
977 if (parentWindow)
978 windowHandle = nullptr;
979 break;
980 }
981 case WM_ERASEBKGND:
982 {
983 return 1; // don't draw background
984 }
985 case WM_COMMAND:
986 {
987 if (HIWORD (wParam) == EN_CHANGE)
988 {
989 // text control changes will be forwarded to the text control window proc
990 HWND controlWindow = (HWND)lParam;
991 WINDOWSPROC textEditWindowProc = (WINDOWSPROC)(LONG_PTR)GetWindowLongPtr (controlWindow, GWLP_WNDPROC);
992 if (textEditWindowProc)
993 {
994 textEditWindowProc (controlWindow, WM_COMMAND, wParam, lParam);
995 }
996 }
997 break;
998 }
999 }
1000 return DefWindowProc (hwnd, message, wParam, lParam);
1001 }
1002
1003 //-----------------------------------------------------------------------------
WindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)1004 LONG_PTR WINAPI Win32Frame::WindowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1005 {
1006 Win32Frame* win32Frame = (Win32Frame*)(LONG_PTR)GetWindowLongPtr (hwnd, GWLP_USERDATA);
1007 if (win32Frame)
1008 {
1009 return win32Frame->proc (hwnd, message, wParam, lParam);
1010 }
1011 return DefWindowProc (hwnd, message, wParam, lParam);
1012 }
1013
1014 //-----------------------------------------------------------------------------
create(const ColorStopMap & colorStopMap)1015 CGradient* CGradient::create (const ColorStopMap& colorStopMap)
1016 {
1017 return new CGradient (colorStopMap);
1018 }
1019
1020 } // VSTGUI
1021
1022 #endif // WINDOWS
1023