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 "../../cdropsource.h"
21 #include "../../cgradient.h"
22
23 #if VSTGUI_OPENGL_SUPPORT
24 #include "win32openglview.h"
25 #endif
26
27 // windows libraries VSTGUI depends on
28 #ifdef _MSC_VER
29 #pragma comment(lib, "Shlwapi.lib")
30 #endif
31
32 namespace VSTGUI {
33
34 #define DEBUG_DRAWING 0
35
36 //-----------------------------------------------------------------------------
37 static TCHAR gClassName[100];
38 static bool bSwapped_mouse_buttons = false;
39
40 //-----------------------------------------------------------------------------
createPlatformFrame(IPlatformFrameCallback * frame,const CRect & size,void * parent,PlatformType parentType,IPlatformFrameConfig * config)41 IPlatformFrame* IPlatformFrame::createPlatformFrame (IPlatformFrameCallback* frame, const CRect& size, void* parent, PlatformType parentType, IPlatformFrameConfig* config)
42 {
43 return new Win32Frame (frame, size, (HWND)parent, parentType);
44 }
45
46 //-----------------------------------------------------------------------------
isParentLayered(HWND parent)47 static bool isParentLayered (HWND parent)
48 {
49 WINDOWINFO info;
50 info.cbSize = sizeof (info);
51 while (parent)
52 {
53 if (GetWindowInfo (parent, &info))
54 {
55 if (info.dwStyle & WS_CHILD)
56 parent = GetParent (parent);
57 else
58 break;
59 }
60 }
61 if (parent)
62 {
63 if (info.dwExStyle & WS_EX_LAYERED)
64 return true;
65 }
66 return false;
67 }
68
69 //-----------------------------------------------------------------------------
Win32Frame(IPlatformFrameCallback * frame,const CRect & size,HWND parent,PlatformType parentType)70 Win32Frame::Win32Frame (IPlatformFrameCallback* frame, const CRect& size, HWND parent, PlatformType parentType)
71 : IPlatformFrame (frame)
72 , parentWindow (parent)
73 , windowHandle (0)
74 , tooltipWindow (0)
75 , oldFocusWindow (0)
76 , backBuffer (0)
77 , deviceContext (0)
78 , inPaint (false)
79 , mouseInside (false)
80 , updateRegionList (0)
81 , updateRegionListSize (0)
82 , isTouchActive(false)
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 = 0;
157
158 windowClass.hCursor = LoadCursor (NULL, IDC_ARROW);
159 #if DEBUG_DRAWING
160 windowClass.hbrBackground = GetSysColorBrush (COLOR_BTNFACE);
161 #else
162 windowClass.hbrBackground = 0;
163 #endif
164 windowClass.lpszMenuName = 0;
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 == 0 && 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 = 0;
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 = 0;
342 switch (type)
343 {
344 case kCursorWait:
345 cursor = LoadCursor (0, IDC_WAIT);
346 break;
347 case kCursorHSize:
348 cursor = LoadCursor (0, IDC_SIZEWE);
349 break;
350 case kCursorVSize:
351 cursor = LoadCursor (0, IDC_SIZENS);
352 break;
353 case kCursorNESWSize:
354 cursor = LoadCursor (0, IDC_SIZENESW);
355 break;
356 case kCursorNWSESize:
357 cursor = LoadCursor (0, IDC_SIZENWSE);
358 break;
359 case kCursorSizeAll:
360 cursor = LoadCursor (0, IDC_SIZEALL);
361 break;
362 case kCursorNotAllowed:
363 cursor = LoadCursor (0, IDC_NO);
364 break;
365 case kCursorHand:
366 cursor = LoadCursor (0, IDC_HAND);
367 break;
368 default:
369 cursor = LoadCursor (0, 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.c_str ());
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 = {0};
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 = {0};
443 ti.cbSize = sizeof(TOOLINFO);
444 ti.hwnd = windowHandle;
445 ti.uId = 0;
446 ti.lpszText = 0;
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 inPopup = true;
463 return owned<IPlatformOptionMenu> (new Win32OptionMenu (windowHandle));
464 }
465
466 #if VSTGUI_OPENGL_SUPPORT
467 //-----------------------------------------------------------------------------
createPlatformOpenGLView()468 SharedPointer<IPlatformOpenGLView> Win32Frame::createPlatformOpenGLView ()
469 {
470 return owned<IPlatformOpenGLView> (new Win32OpenGLView (this));
471 }
472 #endif
473
474 //-----------------------------------------------------------------------------
createOffscreenContext(CCoord width,CCoord height,double scaleFactor)475 SharedPointer<COffscreenContext> Win32Frame::createOffscreenContext (CCoord width, CCoord height, double scaleFactor)
476 {
477 D2DBitmap* bitmap = new D2DBitmap (CPoint (width * scaleFactor, height * scaleFactor));
478 bitmap->setScaleFactor (scaleFactor);
479 auto context = owned<COffscreenContext> (new D2DDrawContext (bitmap));
480 bitmap->forget ();
481 return context;
482 }
483
484 #if VSTGUI_ENABLE_DEPRECATED_METHODS
485 class Win32LegacyDragSupport : virtual public DragCallbackAdapter, virtual public NonAtomicReferenceCounted
486 {
487 public:
dragEnded(IDraggingSession *,CPoint,DragOperation r)488 void dragEnded (IDraggingSession*, CPoint, DragOperation r) final { result = r; }
489 DragOperation result {DragOperation::None};
490 };
491
492 //------------------------------------------------------------------------------------
doDrag(IDataPackage * source,const CPoint & offset,CBitmap * dragBitmap)493 DragResult Win32Frame::doDrag (IDataPackage* source, const CPoint& offset, CBitmap* dragBitmap)
494 {
495 Win32LegacyDragSupport dragSupport;
496
497 Win32DraggingSession session (this);
498 if (session.doDrag (DragDescription (source, offset, dragBitmap), &dragSupport))
499 {
500 switch (dragSupport.result)
501 {
502 case DragOperation::Copy: return kDragCopied;
503 case DragOperation::Move: return kDragMoved;
504 case DragOperation::None: return kDragRefused;
505 }
506 }
507 return kDragRefused;
508 }
509 #endif
510
511 //-----------------------------------------------------------------------------
doDrag(const DragDescription & dragDescription,const SharedPointer<IDragCallback> & callback)512 bool Win32Frame::doDrag (const DragDescription& dragDescription, const SharedPointer<IDragCallback>& callback)
513 {
514 Win32DraggingSession session (this);
515 return session.doDrag (dragDescription, callback);
516 }
517
518 //-----------------------------------------------------------------------------
setClipboard(const SharedPointer<IDataPackage> & data)519 void Win32Frame::setClipboard (const SharedPointer<IDataPackage>& data)
520 {
521 auto dataObject = makeOwned<Win32DataObject> (data);
522 auto hr = OleSetClipboard (dataObject);
523 if (hr != S_OK)
524 {
525 #if DEBUG
526 DebugPrint ("Setting clipboard failed!\n");
527 #endif
528 }
529 }
530
531 //-----------------------------------------------------------------------------
getClipboard()532 SharedPointer<IDataPackage> Win32Frame::getClipboard ()
533 {
534 IDataObject* dataObject = nullptr;;
535 if (OleGetClipboard (&dataObject) != S_OK)
536 return nullptr;
537 return makeOwned<Win32DataPackage> (dataObject);
538 }
539
540 //-----------------------------------------------------------------------------
onFrameClosed()541 void Win32Frame::onFrameClosed ()
542 {
543 frame = nullptr;
544 }
545
546 //-----------------------------------------------------------------------------
paint(HWND hwnd)547 void Win32Frame::paint (HWND hwnd)
548 {
549 HRGN rgn = CreateRectRgn (0, 0, 0, 0);
550 if (GetUpdateRgn (hwnd, rgn, false) == NULLREGION)
551 {
552 DeleteObject (rgn);
553 return;
554 }
555
556 inPaint = true;
557
558 PAINTSTRUCT ps;
559 HDC hdc = BeginPaint (hwnd, &ps);
560
561 if (hdc)
562 {
563 CRect updateRect ((CCoord)ps.rcPaint.left, (CCoord)ps.rcPaint.top, (CCoord)ps.rcPaint.right, (CCoord)ps.rcPaint.bottom);
564 CRect frameSize;
565 getSize (frameSize);
566 frameSize.offset (-frameSize.left, -frameSize.top);
567 if (deviceContext == 0)
568 deviceContext = createDrawContext (hwnd, hdc, frameSize);
569 if (deviceContext)
570 {
571 deviceContext->setClipRect (updateRect);
572
573 CDrawContext* drawContext = backBuffer ? backBuffer : deviceContext;
574 drawContext->beginDraw ();
575 DWORD len = GetRegionData (rgn, 0, NULL);
576 if (len)
577 {
578 if (len > updateRegionListSize)
579 {
580 if (updateRegionList)
581 std::free (updateRegionList);
582 updateRegionListSize = len;
583 updateRegionList = (RGNDATA*) std::malloc (updateRegionListSize);
584 }
585 GetRegionData (rgn, len, updateRegionList);
586 if (updateRegionList->rdh.nCount > 0)
587 {
588 RECT* rp = (RECT*)updateRegionList->Buffer;
589 for (uint32_t i = 0; i < updateRegionList->rdh.nCount; i++)
590 {
591 CRect ur (rp->left, rp->top, rp->right, rp->bottom);
592 paintRect = ur;
593 drawContext->clearRect (ur);
594 getFrame ()->platformDrawRect (drawContext, ur);
595 rp++;
596 }
597 }
598 else
599 {
600 getFrame ()->platformDrawRect (drawContext, updateRect);
601 }
602 }
603 drawContext->endDraw ();
604 if (backBuffer)
605 {
606 deviceContext->beginDraw ();
607 deviceContext->clearRect (updateRect);
608 backBuffer->copyFrom (deviceContext, updateRect, CPoint (updateRect.left, updateRect.top));
609 deviceContext->endDraw ();
610 }
611 }
612 }
613
614 EndPaint (hwnd, &ps);
615 DeleteObject (rgn);
616
617 inPaint = false;
618 }
619
translateWinVirtualKey(WPARAM winVKey)620 static unsigned char translateWinVirtualKey (WPARAM winVKey)
621 {
622 switch (winVKey)
623 {
624 case VK_BACK: return VKEY_BACK;
625 case VK_TAB: return VKEY_TAB;
626 case VK_CLEAR: return VKEY_CLEAR;
627 case VK_RETURN: return VKEY_RETURN;
628 case VK_PAUSE: return VKEY_PAUSE;
629 case VK_ESCAPE: return VKEY_ESCAPE;
630 case VK_SPACE: return VKEY_SPACE;
631 // TODO: case VK_NEXT: return VKEY_NEXT;
632 case VK_END: return VKEY_END;
633 case VK_HOME: return VKEY_HOME;
634 case VK_LEFT: return VKEY_LEFT;
635 case VK_RIGHT: return VKEY_RIGHT;
636 case VK_UP: return VKEY_UP;
637 case VK_DOWN: return VKEY_DOWN;
638 case VK_PRIOR: return VKEY_PAGEUP;
639 case VK_NEXT: return VKEY_PAGEDOWN;
640 case VK_SELECT: return VKEY_SELECT;
641 case VK_PRINT: return VKEY_PRINT;
642 case VK_SNAPSHOT: return VKEY_SNAPSHOT;
643 case VK_INSERT: return VKEY_INSERT;
644 case VK_DELETE: return VKEY_DELETE;
645 case VK_HELP: return VKEY_HELP;
646 case VK_NUMPAD0: return VKEY_NUMPAD0;
647 case VK_NUMPAD1: return VKEY_NUMPAD1;
648 case VK_NUMPAD2: return VKEY_NUMPAD2;
649 case VK_NUMPAD3: return VKEY_NUMPAD3;
650 case VK_NUMPAD4: return VKEY_NUMPAD4;
651 case VK_NUMPAD5: return VKEY_NUMPAD5;
652 case VK_NUMPAD6: return VKEY_NUMPAD6;
653 case VK_NUMPAD7: return VKEY_NUMPAD7;
654 case VK_NUMPAD8: return VKEY_NUMPAD8;
655 case VK_NUMPAD9: return VKEY_NUMPAD9;
656 case VK_MULTIPLY: return VKEY_MULTIPLY;
657 case VK_ADD: return VKEY_ADD;
658 case VK_SEPARATOR: return VKEY_SEPARATOR;
659 case VK_SUBTRACT: return VKEY_SUBTRACT;
660 case VK_DECIMAL: return VKEY_DECIMAL;
661 case VK_DIVIDE: return VKEY_DIVIDE;
662 case VK_F1: return VKEY_F1;
663 case VK_F2: return VKEY_F2;
664 case VK_F3: return VKEY_F3;
665 case VK_F4: return VKEY_F4;
666 case VK_F5: return VKEY_F5;
667 case VK_F6: return VKEY_F6;
668 case VK_F7: return VKEY_F7;
669 case VK_F8: return VKEY_F8;
670 case VK_F9: return VKEY_F9;
671 case VK_F10: return VKEY_F10;
672 case VK_F11: return VKEY_F11;
673 case VK_F12: return VKEY_F12;
674 case VK_NUMLOCK: return VKEY_NUMLOCK;
675 case VK_SCROLL: return VKEY_SCROLL;
676 case VK_SHIFT: return VKEY_SHIFT;
677 case VK_CONTROL: return VKEY_CONTROL;
678 case VK_MENU: return VKEY_ALT;
679 case VKEY_EQUALS: return VKEY_EQUALS;
680 }
681 return 0;
682 }
683
684 //-----------------------------------------------------------------------------
proc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)685 LONG_PTR WINAPI Win32Frame::proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
686 {
687 if (getFrame () == nullptr)
688 return DefWindowProc (hwnd, message, wParam, lParam);
689
690 SharedPointer<Win32Frame> lifeGuard (this);
691 IPlatformFrameCallback* pFrame = getFrame ();
692 bool doubleClick = false;
693
694 #define WM_POINTERDOWN 0x0246
695 #define WM_POINTERUP 0x0247
696 #define WM_POINTERROUTEDRELEASED 0x0253
697 #define WM_POINTERCAPTURECHANGED 0x024C
698
699 switch (message)
700 {
701 case WM_POINTERDOWN:
702 {
703 isTouchActive = true;
704 break;
705 }
706 case WM_POINTERUP:
707 case WM_POINTERROUTEDRELEASED:
708 case WM_POINTERCAPTURECHANGED:
709 {
710 isTouchActive = false;
711 break;
712 }
713 case WM_MOUSEWHEEL:
714 {
715 CButtonState buttons = 0;
716 if (GetAsyncKeyState (VK_SHIFT) < 0)
717 buttons |= kShift;
718 if (GetAsyncKeyState (VK_CONTROL) < 0)
719 buttons |= kControl;
720 if (GetAsyncKeyState (VK_MENU) < 0)
721 buttons |= kAlt;
722 short zDelta = (short) GET_WHEEL_DELTA_WPARAM(wParam);
723 POINT p {GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam)};
724 ScreenToClient (windowHandle, &p);
725 CPoint where (p.x, p.y);
726 pFrame->platformOnMouseWheel (where, kMouseWheelAxisY, ((float)zDelta / WHEEL_DELTA), buttons);
727 break;
728 }
729 case WM_MOUSEHWHEEL: // new since vista
730 {
731 CButtonState buttons = 0;
732 if (GetAsyncKeyState (VK_SHIFT) < 0)
733 buttons |= kShift;
734 if (GetAsyncKeyState (VK_CONTROL) < 0)
735 buttons |= kControl;
736 if (GetAsyncKeyState (VK_MENU) < 0)
737 buttons |= kAlt;
738 short zDelta = (short) GET_WHEEL_DELTA_WPARAM(wParam);
739 POINT p {GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam)};
740 ScreenToClient (windowHandle, &p);
741 CPoint where (p.x, p.y);
742 pFrame->platformOnMouseWheel (where, kMouseWheelAxisX, ((float)-zDelta / WHEEL_DELTA), buttons);
743 break;
744 }
745 case WM_CTLCOLOREDIT:
746 {
747 Win32TextEdit* win32TextEdit = (Win32TextEdit*)(LONG_PTR) GetWindowLongPtr ((HWND)lParam, GWLP_USERDATA);
748 if (win32TextEdit)
749 {
750 CColor fontColor = win32TextEdit->getTextEdit ()->platformGetFontColor ();
751 SetTextColor ((HDC) wParam, RGB (fontColor.red, fontColor.green, fontColor.blue));
752 #if 1 // TODO: I don't know why the transparent part does not work anymore. Needs more investigation.
753 CColor backColor = win32TextEdit->getTextEdit ()->platformGetBackColor ();
754 SetBkColor ((HDC) wParam, RGB (backColor.red, backColor.green, backColor.blue));
755 return (LRESULT)(win32TextEdit->getPlatformBackColor ());
756 #else
757 SetBkMode ((HDC)wParam, TRANSPARENT);
758 return (LRESULT) ::GetStockObject (HOLLOW_BRUSH);
759 #endif
760 }
761 break;
762 }
763
764 case WM_PAINT:
765 {
766 paint (hwnd);
767 return 0;
768 }
769
770 case WM_RBUTTONDBLCLK:
771 case WM_MBUTTONDBLCLK:
772 case WM_LBUTTONDBLCLK:
773 case WM_XBUTTONDBLCLK:
774 doubleClick = true;
775 case WM_RBUTTONDOWN:
776 case WM_MBUTTONDOWN:
777 case WM_LBUTTONDOWN:
778 case WM_XBUTTONDOWN:
779 {
780 CButtonState buttons = 0;
781 if (wParam & MK_LBUTTON)
782 buttons |= kLButton;
783 if (wParam & MK_RBUTTON)
784 buttons |= kRButton;
785 if (wParam & MK_MBUTTON)
786 buttons |= kMButton;
787 if (wParam & MK_XBUTTON1)
788 buttons |= kButton4;
789 if (wParam & MK_XBUTTON2)
790 buttons |= kButton5;
791 if (wParam & MK_CONTROL)
792 buttons |= kControl;
793 if (wParam & MK_SHIFT)
794 buttons |= kShift;
795 if (GetAsyncKeyState (VK_MENU) < 0)
796 buttons |= kAlt;
797 if (doubleClick)
798 buttons |= kDoubleClick;
799 HWND oldFocus = SetFocus(getPlatformWindow());
800 if(oldFocus != hwnd)
801 oldFocusWindow = oldFocus;
802 if (isTouchActive)
803 buttons |= kTouch;
804
805 CPoint where (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam));
806 if (pFrame->platformOnMouseDown (where, buttons) == kMouseEventHandled && getPlatformWindow ())
807 SetCapture (getPlatformWindow ());
808 return 0;
809 }
810 case WM_MOUSELEAVE:
811 {
812 CPoint where;
813 getCurrentMousePosition (where);
814 CButtonState buttons;
815 getCurrentMouseButtons (buttons);
816 pFrame->platformOnMouseExited (where, buttons);
817 mouseInside = false;
818 return 0;
819 }
820 case WM_MOUSEMOVE:
821 {
822 CButtonState buttons = 0;
823 if (wParam & MK_LBUTTON)
824 buttons |= kLButton;
825 if (wParam & MK_RBUTTON)
826 buttons |= kRButton;
827 if (wParam & MK_MBUTTON)
828 buttons |= kMButton;
829 if (wParam & MK_XBUTTON1)
830 buttons |= kButton4;
831 if (wParam & MK_XBUTTON2)
832 buttons |= kButton5;
833 if (wParam & MK_CONTROL)
834 buttons |= kControl;
835 if (wParam & MK_SHIFT)
836 buttons |= kShift;
837 if (GetAsyncKeyState (VK_MENU) < 0)
838 buttons |= kAlt;
839 if (isTouchActive)
840 buttons |= kTouch;
841 if (!mouseInside)
842 {
843 // this makes sure that WM_MOUSELEAVE will be generated by the system
844 mouseInside = true;
845 TRACKMOUSEEVENT tme = {0};
846 tme.cbSize = sizeof (tme);
847 tme.dwFlags = TME_LEAVE;
848 tme.hwndTrack = windowHandle;
849 TrackMouseEvent (&tme);
850 }
851 CPoint where (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam));
852 pFrame->platformOnMouseMoved (where, buttons);
853 return 0;
854 }
855 case WM_LBUTTONUP:
856 case WM_RBUTTONUP:
857 case WM_MBUTTONUP:
858 case WM_XBUTTONUP:
859 {
860 CButtonState buttons = 0;
861 if (message & MK_LBUTTON || message == WM_LBUTTONUP)
862 buttons |= kLButton;
863 if (wParam & MK_RBUTTON || message == WM_RBUTTONUP)
864 buttons |= kRButton;
865 if (wParam & MK_MBUTTON || message == WM_MBUTTONUP)
866 buttons |= kMButton;
867 if (wParam & MK_XBUTTON1)
868 buttons |= kButton4;
869 if (wParam & MK_XBUTTON2)
870 buttons |= kButton5;
871 if (wParam & MK_CONTROL)
872 buttons |= kControl;
873 if (wParam & MK_SHIFT)
874 buttons |= kShift;
875 if (GetAsyncKeyState (VK_MENU) < 0)
876 buttons |= kAlt;
877 if (isTouchActive)
878 buttons |= kTouch;
879
880 POINT p{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
881 if (inPopup)
882 {
883 // Win32OptionMenu::popup does ClientToScreen for TrackPopupMenu, must do the opposite for MouseUp.
884 ScreenToClient(windowHandle, &p);
885 inPopup = false;
886 }
887
888 CPoint where(p.x, p.y);
889 pFrame->platformOnMouseUp (where, buttons);
890 ReleaseCapture ();
891 return 0;
892 }
893 case WM_KEYDOWN:
894 {
895 VstKeyCode key {};
896 if (GetAsyncKeyState (VK_SHIFT) < 0)
897 key.modifier |= MODIFIER_SHIFT;
898 if (GetAsyncKeyState (VK_CONTROL) < 0)
899 key.modifier |= MODIFIER_CONTROL;
900 if (GetAsyncKeyState (VK_MENU) < 0)
901 key.modifier |= MODIFIER_ALTERNATE;
902 key.virt = translateWinVirtualKey (wParam);
903 key.character = MapVirtualKey (static_cast<UINT> (wParam), MAPVK_VK_TO_CHAR);
904 if (key.virt || key.character)
905 {
906 key.character = std::tolower (key.character);
907 if (pFrame->platformOnKeyDown (key))
908 return 0;
909 }
910
911 if (IsWindow (oldFocusWindow))
912 {
913 auto oldProc = reinterpret_cast<WNDPROC> (GetWindowLongPtr (oldFocusWindow, GWLP_WNDPROC));
914 if (oldProc && oldProc != WindowProc)
915 return CallWindowProc (oldProc, oldFocusWindow, message, wParam, lParam);
916 }
917 break;
918 }
919 case WM_KEYUP:
920 {
921 VstKeyCode key {};
922 if (GetAsyncKeyState (VK_SHIFT) < 0)
923 key.modifier |= MODIFIER_SHIFT;
924 if (GetAsyncKeyState (VK_CONTROL) < 0)
925 key.modifier |= MODIFIER_CONTROL;
926 if (GetAsyncKeyState (VK_MENU) < 0)
927 key.modifier |= MODIFIER_ALTERNATE;
928 key.virt = translateWinVirtualKey (wParam);
929 key.character = MapVirtualKey (static_cast<UINT> (wParam), MAPVK_VK_TO_CHAR);
930 if (key.virt || key.character)
931 {
932 if (pFrame->platformOnKeyUp (key))
933 return 0;
934 }
935
936 if (IsWindow (oldFocusWindow))
937 {
938 auto oldProc = reinterpret_cast<WNDPROC> (GetWindowLongPtr (oldFocusWindow, GWLP_WNDPROC));
939 if (oldProc && oldProc != WindowProc)
940 return CallWindowProc (oldProc, oldFocusWindow, message, wParam, lParam);
941 }
942 break;
943 }
944 case WM_SETFOCUS:
945 {
946 pFrame->platformOnActivate (true);
947 break;
948 }
949 case WM_KILLFOCUS:
950 {
951 oldFocusWindow = 0;
952
953 HWND focusWindow = GetFocus ();
954 if (GetParent (focusWindow) != windowHandle)
955 pFrame->platformOnActivate (false);
956 break;
957 }
958 case WM_DESTROY:
959 {
960 #if DEBUG
961 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");
962 #endif
963 if (parentWindow)
964 windowHandle = 0;
965 break;
966 }
967 case WM_ERASEBKGND:
968 {
969 return 1; // don't draw background
970 }
971 case WM_COMMAND:
972 {
973 if (HIWORD (wParam) == EN_CHANGE)
974 {
975 // text control changes will be forwarded to the text control window proc
976 HWND controlWindow = (HWND)lParam;
977 WINDOWSPROC textEditWindowProc = (WINDOWSPROC)(LONG_PTR)GetWindowLongPtr (controlWindow, GWLP_WNDPROC);
978 if (textEditWindowProc)
979 {
980 textEditWindowProc (controlWindow, WM_COMMAND, wParam, lParam);
981 }
982 }
983 break;
984 }
985 }
986 return DefWindowProc (hwnd, message, wParam, lParam);
987 }
988
989 //-----------------------------------------------------------------------------
WindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)990 LONG_PTR WINAPI Win32Frame::WindowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
991 {
992 Win32Frame* win32Frame = (Win32Frame*)(LONG_PTR)GetWindowLongPtr (hwnd, GWLP_USERDATA);
993 if (win32Frame)
994 {
995 return win32Frame->proc (hwnd, message, wParam, lParam);
996 }
997 return DefWindowProc (hwnd, message, wParam, lParam);
998 }
999
1000 //-----------------------------------------------------------------------------
create(const ColorStopMap & colorStopMap)1001 CGradient* CGradient::create (const ColorStopMap& colorStopMap)
1002 {
1003 return new CGradient (colorStopMap);
1004 }
1005
1006 } // namespace
1007
1008 #endif // WINDOWS
1009