• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // Win32Window.cpp: Implementation of OSWindow for Win32 (Windows)
8 
9 #include "windows/win32/Win32Window.h"
10 
11 #include <sstream>
12 
VirtualKeyCodeToKey(WPARAM key,LPARAM flags)13 Key VirtualKeyCodeToKey(WPARAM key, LPARAM flags)
14 {
15     switch (key)
16     {
17         // Check the scancode to distinguish between left and right shift
18         case VK_SHIFT:
19         {
20             static unsigned int lShift = MapVirtualKey(VK_LSHIFT, MAPVK_VK_TO_VSC);
21             unsigned int scancode      = static_cast<unsigned int>((flags & (0xFF << 16)) >> 16);
22             return scancode == lShift ? KEY_LSHIFT : KEY_RSHIFT;
23         }
24 
25         // Check the "extended" flag to distinguish between left and right alt
26         case VK_MENU:
27             return (HIWORD(flags) & KF_EXTENDED) ? KEY_RALT : KEY_LALT;
28 
29         // Check the "extended" flag to distinguish between left and right control
30         case VK_CONTROL:
31             return (HIWORD(flags) & KF_EXTENDED) ? KEY_RCONTROL : KEY_LCONTROL;
32 
33         // Other keys are reported properly
34         case VK_LWIN:
35             return KEY_LSYSTEM;
36         case VK_RWIN:
37             return KEY_RSYSTEM;
38         case VK_APPS:
39             return KEY_MENU;
40         case VK_OEM_1:
41             return KEY_SEMICOLON;
42         case VK_OEM_2:
43             return KEY_SLASH;
44         case VK_OEM_PLUS:
45             return KEY_EQUAL;
46         case VK_OEM_MINUS:
47             return KEY_DASH;
48         case VK_OEM_4:
49             return KEY_LBRACKET;
50         case VK_OEM_6:
51             return KEY_RBRACKET;
52         case VK_OEM_COMMA:
53             return KEY_COMMA;
54         case VK_OEM_PERIOD:
55             return KEY_PERIOD;
56         case VK_OEM_7:
57             return KEY_QUOTE;
58         case VK_OEM_5:
59             return KEY_BACKSLASH;
60         case VK_OEM_3:
61             return KEY_TILDE;
62         case VK_ESCAPE:
63             return KEY_ESCAPE;
64         case VK_SPACE:
65             return KEY_SPACE;
66         case VK_RETURN:
67             return KEY_RETURN;
68         case VK_BACK:
69             return KEY_BACK;
70         case VK_TAB:
71             return KEY_TAB;
72         case VK_PRIOR:
73             return KEY_PAGEUP;
74         case VK_NEXT:
75             return KEY_PAGEDOWN;
76         case VK_END:
77             return KEY_END;
78         case VK_HOME:
79             return KEY_HOME;
80         case VK_INSERT:
81             return KEY_INSERT;
82         case VK_DELETE:
83             return KEY_DELETE;
84         case VK_ADD:
85             return KEY_ADD;
86         case VK_SUBTRACT:
87             return KEY_SUBTRACT;
88         case VK_MULTIPLY:
89             return KEY_MULTIPLY;
90         case VK_DIVIDE:
91             return KEY_DIVIDE;
92         case VK_PAUSE:
93             return KEY_PAUSE;
94         case VK_F1:
95             return KEY_F1;
96         case VK_F2:
97             return KEY_F2;
98         case VK_F3:
99             return KEY_F3;
100         case VK_F4:
101             return KEY_F4;
102         case VK_F5:
103             return KEY_F5;
104         case VK_F6:
105             return KEY_F6;
106         case VK_F7:
107             return KEY_F7;
108         case VK_F8:
109             return KEY_F8;
110         case VK_F9:
111             return KEY_F9;
112         case VK_F10:
113             return KEY_F10;
114         case VK_F11:
115             return KEY_F11;
116         case VK_F12:
117             return KEY_F12;
118         case VK_F13:
119             return KEY_F13;
120         case VK_F14:
121             return KEY_F14;
122         case VK_F15:
123             return KEY_F15;
124         case VK_LEFT:
125             return KEY_LEFT;
126         case VK_RIGHT:
127             return KEY_RIGHT;
128         case VK_UP:
129             return KEY_UP;
130         case VK_DOWN:
131             return KEY_DOWN;
132         case VK_NUMPAD0:
133             return KEY_NUMPAD0;
134         case VK_NUMPAD1:
135             return KEY_NUMPAD1;
136         case VK_NUMPAD2:
137             return KEY_NUMPAD2;
138         case VK_NUMPAD3:
139             return KEY_NUMPAD3;
140         case VK_NUMPAD4:
141             return KEY_NUMPAD4;
142         case VK_NUMPAD5:
143             return KEY_NUMPAD5;
144         case VK_NUMPAD6:
145             return KEY_NUMPAD6;
146         case VK_NUMPAD7:
147             return KEY_NUMPAD7;
148         case VK_NUMPAD8:
149             return KEY_NUMPAD8;
150         case VK_NUMPAD9:
151             return KEY_NUMPAD9;
152         case 'A':
153             return KEY_A;
154         case 'Z':
155             return KEY_Z;
156         case 'E':
157             return KEY_E;
158         case 'R':
159             return KEY_R;
160         case 'T':
161             return KEY_T;
162         case 'Y':
163             return KEY_Y;
164         case 'U':
165             return KEY_U;
166         case 'I':
167             return KEY_I;
168         case 'O':
169             return KEY_O;
170         case 'P':
171             return KEY_P;
172         case 'Q':
173             return KEY_Q;
174         case 'S':
175             return KEY_S;
176         case 'D':
177             return KEY_D;
178         case 'F':
179             return KEY_F;
180         case 'G':
181             return KEY_G;
182         case 'H':
183             return KEY_H;
184         case 'J':
185             return KEY_J;
186         case 'K':
187             return KEY_K;
188         case 'L':
189             return KEY_L;
190         case 'M':
191             return KEY_M;
192         case 'W':
193             return KEY_W;
194         case 'X':
195             return KEY_X;
196         case 'C':
197             return KEY_C;
198         case 'V':
199             return KEY_V;
200         case 'B':
201             return KEY_B;
202         case 'N':
203             return KEY_N;
204         case '0':
205             return KEY_NUM0;
206         case '1':
207             return KEY_NUM1;
208         case '2':
209             return KEY_NUM2;
210         case '3':
211             return KEY_NUM3;
212         case '4':
213             return KEY_NUM4;
214         case '5':
215             return KEY_NUM5;
216         case '6':
217             return KEY_NUM6;
218         case '7':
219             return KEY_NUM7;
220         case '8':
221             return KEY_NUM8;
222         case '9':
223             return KEY_NUM9;
224     }
225 
226     return Key(0);
227 }
228 
WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)229 LRESULT CALLBACK Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
230 {
231     switch (message)
232     {
233         case WM_NCCREATE:
234         {
235             LPCREATESTRUCT pCreateStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
236             SetWindowLongPtr(hWnd, GWLP_USERDATA,
237                              reinterpret_cast<LONG_PTR>(pCreateStruct->lpCreateParams));
238             return DefWindowProcA(hWnd, message, wParam, lParam);
239         }
240     }
241 
242     Win32Window *window = reinterpret_cast<Win32Window *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
243     if (window)
244     {
245         switch (message)
246         {
247             case WM_DESTROY:
248             case WM_CLOSE:
249             {
250                 Event event;
251                 event.type = Event::EVENT_CLOSED;
252                 window->pushEvent(event);
253                 break;
254             }
255 
256             case WM_MOVE:
257             {
258                 RECT winRect;
259                 GetClientRect(hWnd, &winRect);
260 
261                 POINT topLeft;
262                 topLeft.x = winRect.left;
263                 topLeft.y = winRect.top;
264                 ClientToScreen(hWnd, &topLeft);
265 
266                 Event event;
267                 event.type   = Event::EVENT_MOVED;
268                 event.move.x = topLeft.x;
269                 event.move.y = topLeft.y;
270                 window->pushEvent(event);
271 
272                 break;
273             }
274 
275             case WM_SIZE:
276             {
277                 RECT winRect;
278                 GetClientRect(hWnd, &winRect);
279 
280                 POINT topLeft;
281                 topLeft.x = winRect.left;
282                 topLeft.y = winRect.top;
283                 ClientToScreen(hWnd, &topLeft);
284 
285                 POINT botRight;
286                 botRight.x = winRect.right;
287                 botRight.y = winRect.bottom;
288                 ClientToScreen(hWnd, &botRight);
289 
290                 Event event;
291                 event.type        = Event::EVENT_RESIZED;
292                 event.size.width  = botRight.x - topLeft.x;
293                 event.size.height = botRight.y - topLeft.y;
294                 window->pushEvent(event);
295 
296                 break;
297             }
298 
299             case WM_SETFOCUS:
300             {
301                 Event event;
302                 event.type = Event::EVENT_GAINED_FOCUS;
303                 window->pushEvent(event);
304                 break;
305             }
306 
307             case WM_KILLFOCUS:
308             {
309                 Event event;
310                 event.type = Event::EVENT_LOST_FOCUS;
311                 window->pushEvent(event);
312                 break;
313             }
314 
315             case WM_KEYDOWN:
316             case WM_SYSKEYDOWN:
317             case WM_KEYUP:
318             case WM_SYSKEYUP:
319             {
320                 bool down = (message == WM_KEYDOWN || message == WM_SYSKEYDOWN);
321 
322                 Event event;
323                 event.type        = down ? Event::EVENT_KEY_PRESSED : Event::EVENT_KEY_RELEASED;
324                 event.key.alt     = HIWORD(GetAsyncKeyState(VK_MENU)) != 0;
325                 event.key.control = HIWORD(GetAsyncKeyState(VK_CONTROL)) != 0;
326                 event.key.shift = HIWORD(GetAsyncKeyState(VK_SHIFT)) != 0;
327                 event.key.system =
328                     HIWORD(GetAsyncKeyState(VK_LWIN)) || HIWORD(GetAsyncKeyState(VK_RWIN));
329                 event.key.code = VirtualKeyCodeToKey(wParam, lParam);
330                 window->pushEvent(event);
331 
332                 break;
333             }
334 
335             case WM_MOUSEWHEEL:
336             {
337                 Event event;
338                 event.type             = Event::EVENT_MOUSE_WHEEL_MOVED;
339                 event.mouseWheel.delta = static_cast<short>(HIWORD(wParam)) / 120;
340                 window->pushEvent(event);
341                 break;
342             }
343 
344             case WM_LBUTTONDOWN:
345             case WM_LBUTTONDBLCLK:
346             {
347                 Event event;
348                 event.type               = Event::EVENT_MOUSE_BUTTON_PRESSED;
349                 event.mouseButton.button = MOUSEBUTTON_LEFT;
350                 event.mouseButton.x      = static_cast<short>(LOWORD(lParam));
351                 event.mouseButton.y = static_cast<short>(HIWORD(lParam));
352                 window->pushEvent(event);
353                 break;
354             }
355 
356             case WM_LBUTTONUP:
357             {
358                 Event event;
359                 event.type               = Event::EVENT_MOUSE_BUTTON_RELEASED;
360                 event.mouseButton.button = MOUSEBUTTON_LEFT;
361                 event.mouseButton.x      = static_cast<short>(LOWORD(lParam));
362                 event.mouseButton.y = static_cast<short>(HIWORD(lParam));
363                 window->pushEvent(event);
364                 break;
365             }
366 
367             case WM_RBUTTONDOWN:
368             case WM_RBUTTONDBLCLK:
369             {
370                 Event event;
371                 event.type               = Event::EVENT_MOUSE_BUTTON_PRESSED;
372                 event.mouseButton.button = MOUSEBUTTON_RIGHT;
373                 event.mouseButton.x      = static_cast<short>(LOWORD(lParam));
374                 event.mouseButton.y = static_cast<short>(HIWORD(lParam));
375                 window->pushEvent(event);
376                 break;
377             }
378 
379             // Mouse right button up event
380             case WM_RBUTTONUP:
381             {
382                 Event event;
383                 event.type               = Event::EVENT_MOUSE_BUTTON_RELEASED;
384                 event.mouseButton.button = MOUSEBUTTON_RIGHT;
385                 event.mouseButton.x      = static_cast<short>(LOWORD(lParam));
386                 event.mouseButton.y = static_cast<short>(HIWORD(lParam));
387                 window->pushEvent(event);
388                 break;
389             }
390 
391             // Mouse wheel button down event
392             case WM_MBUTTONDOWN:
393             case WM_MBUTTONDBLCLK:
394             {
395                 Event event;
396                 event.type               = Event::EVENT_MOUSE_BUTTON_PRESSED;
397                 event.mouseButton.button = MOUSEBUTTON_MIDDLE;
398                 event.mouseButton.x      = static_cast<short>(LOWORD(lParam));
399                 event.mouseButton.y = static_cast<short>(HIWORD(lParam));
400                 window->pushEvent(event);
401                 break;
402             }
403 
404             // Mouse wheel button up event
405             case WM_MBUTTONUP:
406             {
407                 Event event;
408                 event.type               = Event::EVENT_MOUSE_BUTTON_RELEASED;
409                 event.mouseButton.button = MOUSEBUTTON_MIDDLE;
410                 event.mouseButton.x      = static_cast<short>(LOWORD(lParam));
411                 event.mouseButton.y = static_cast<short>(HIWORD(lParam));
412                 window->pushEvent(event);
413                 break;
414             }
415 
416             // Mouse X button down event
417             case WM_XBUTTONDOWN:
418             case WM_XBUTTONDBLCLK:
419             {
420                 Event event;
421                 event.type = Event::EVENT_MOUSE_BUTTON_PRESSED;
422                 event.mouseButton.button =
423                     (HIWORD(wParam) == XBUTTON1) ? MOUSEBUTTON_BUTTON4 : MOUSEBUTTON_BUTTON5;
424                 event.mouseButton.x = static_cast<short>(LOWORD(lParam));
425                 event.mouseButton.y = static_cast<short>(HIWORD(lParam));
426                 window->pushEvent(event);
427                 break;
428             }
429 
430             // Mouse X button up event
431             case WM_XBUTTONUP:
432             {
433                 Event event;
434                 event.type = Event::EVENT_MOUSE_BUTTON_RELEASED;
435                 event.mouseButton.button =
436                     (HIWORD(wParam) == XBUTTON1) ? MOUSEBUTTON_BUTTON4 : MOUSEBUTTON_BUTTON5;
437                 event.mouseButton.x = static_cast<short>(LOWORD(lParam));
438                 event.mouseButton.y = static_cast<short>(HIWORD(lParam));
439                 window->pushEvent(event);
440                 break;
441             }
442 
443             case WM_MOUSEMOVE:
444             {
445                 if (!window->mIsMouseInWindow)
446                 {
447                     window->mIsMouseInWindow = true;
448                     Event event;
449                     event.type = Event::EVENT_MOUSE_ENTERED;
450                     window->pushEvent(event);
451                 }
452 
453                 int mouseX = static_cast<short>(LOWORD(lParam));
454                 int mouseY = static_cast<short>(HIWORD(lParam));
455 
456                 Event event;
457                 event.type        = Event::EVENT_MOUSE_MOVED;
458                 event.mouseMove.x = mouseX;
459                 event.mouseMove.y = mouseY;
460                 window->pushEvent(event);
461                 break;
462             }
463 
464             case WM_MOUSELEAVE:
465             {
466                 Event event;
467                 event.type = Event::EVENT_MOUSE_LEFT;
468                 window->pushEvent(event);
469                 window->mIsMouseInWindow = false;
470                 break;
471             }
472 
473             case WM_USER:
474             {
475                 Event testEvent;
476                 testEvent.type = Event::EVENT_TEST;
477                 window->pushEvent(testEvent);
478                 break;
479             }
480         }
481     }
482     return DefWindowProcA(hWnd, message, wParam, lParam);
483 }
484 
Win32Window()485 Win32Window::Win32Window()
486     : mIsVisible(false),
487       mSetVisibleTimer(CreateTimer()),
488       mIsMouseInWindow(false),
489       mNativeWindow(0),
490       mParentWindow(0),
491       mNativeDisplay(0)
492 {
493 }
494 
~Win32Window()495 Win32Window::~Win32Window()
496 {
497     destroy();
498     delete mSetVisibleTimer;
499 }
500 
initialize(const std::string & name,size_t width,size_t height)501 bool Win32Window::initialize(const std::string &name, size_t width, size_t height)
502 {
503     destroy();
504 
505     // Use a new window class name for ever window to ensure that a new window can be created
506     // even if the last one was not properly destroyed
507     static size_t windowIdx = 0;
508     std::ostringstream nameStream;
509     nameStream << name << "_" << windowIdx++;
510 
511     mParentClassName = nameStream.str();
512     mChildClassName  = mParentClassName + "_Child";
513 
514     // Work around compile error from not defining "UNICODE" while Chromium does
515     const LPSTR idcArrow = MAKEINTRESOURCEA(32512);
516 
517     WNDCLASSEXA parentWindowClass   = {0};
518     parentWindowClass.cbSize        = sizeof(WNDCLASSEXA);
519     parentWindowClass.style         = 0;
520     parentWindowClass.lpfnWndProc   = WndProc;
521     parentWindowClass.cbClsExtra    = 0;
522     parentWindowClass.cbWndExtra    = 0;
523     parentWindowClass.hInstance     = GetModuleHandle(nullptr);
524     parentWindowClass.hIcon         = nullptr;
525     parentWindowClass.hCursor       = LoadCursorA(nullptr, idcArrow);
526     parentWindowClass.hbrBackground = 0;
527     parentWindowClass.lpszMenuName  = nullptr;
528     parentWindowClass.lpszClassName = mParentClassName.c_str();
529     if (!RegisterClassExA(&parentWindowClass))
530     {
531         return false;
532     }
533 
534     WNDCLASSEXA childWindowClass   = {0};
535     childWindowClass.cbSize        = sizeof(WNDCLASSEXA);
536     childWindowClass.style         = CS_OWNDC;
537     childWindowClass.lpfnWndProc   = WndProc;
538     childWindowClass.cbClsExtra    = 0;
539     childWindowClass.cbWndExtra    = 0;
540     childWindowClass.hInstance     = GetModuleHandle(nullptr);
541     childWindowClass.hIcon         = nullptr;
542     childWindowClass.hCursor       = LoadCursorA(nullptr, idcArrow);
543     childWindowClass.hbrBackground = 0;
544     childWindowClass.lpszMenuName  = nullptr;
545     childWindowClass.lpszClassName = mChildClassName.c_str();
546     if (!RegisterClassExA(&childWindowClass))
547     {
548         return false;
549     }
550 
551     DWORD parentStyle         = WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU;
552     DWORD parentExtendedStyle = WS_EX_APPWINDOW;
553 
554     RECT sizeRect = {0, 0, static_cast<LONG>(width), static_cast<LONG>(height)};
555     AdjustWindowRectEx(&sizeRect, parentStyle, FALSE, parentExtendedStyle);
556 
557     mParentWindow = CreateWindowExA(parentExtendedStyle, mParentClassName.c_str(), name.c_str(),
558                                     parentStyle, CW_USEDEFAULT, CW_USEDEFAULT,
559                                     sizeRect.right - sizeRect.left, sizeRect.bottom - sizeRect.top,
560                                     nullptr, nullptr, GetModuleHandle(nullptr), this);
561 
562     mNativeWindow = CreateWindowExA(0, mChildClassName.c_str(), name.c_str(), WS_CHILD, 0, 0,
563                                     static_cast<int>(width), static_cast<int>(height),
564                                     mParentWindow, nullptr, GetModuleHandle(nullptr), this);
565 
566     mNativeDisplay = GetDC(mNativeWindow);
567     if (!mNativeDisplay)
568     {
569         destroy();
570         return false;
571     }
572 
573     return true;
574 }
575 
destroy()576 void Win32Window::destroy()
577 {
578     if (mNativeDisplay)
579     {
580         ReleaseDC(mNativeWindow, mNativeDisplay);
581         mNativeDisplay = 0;
582     }
583 
584     if (mNativeWindow)
585     {
586         DestroyWindow(mNativeWindow);
587         mNativeWindow = 0;
588     }
589 
590     if (mParentWindow)
591     {
592         DestroyWindow(mParentWindow);
593         mParentWindow = 0;
594     }
595 
596     UnregisterClassA(mParentClassName.c_str(), nullptr);
597     UnregisterClassA(mChildClassName.c_str(), nullptr);
598 }
599 
takeScreenshot(uint8_t * pixelData)600 bool Win32Window::takeScreenshot(uint8_t *pixelData)
601 {
602     if (mIsVisible)
603     {
604         return false;
605     }
606 
607     bool error = false;
608 
609     // Hack for DWM: There is no way to wait for DWM animations to finish, so we just have to wait
610     // for a while before issuing screenshot if window was just made visible.
611     {
612         static const double WAIT_WINDOW_VISIBLE_MS = 0.5;  // Half a second for the animation
613         double timeSinceVisible                    = mSetVisibleTimer->getElapsedTime();
614 
615         if (timeSinceVisible < WAIT_WINDOW_VISIBLE_MS)
616         {
617             Sleep(static_cast<DWORD>((WAIT_WINDOW_VISIBLE_MS - timeSinceVisible) * 1000));
618         }
619     }
620 
621     HDC screenDC      = nullptr;
622     HDC windowDC      = nullptr;
623     HDC tmpDC         = nullptr;
624     HBITMAP tmpBitmap = nullptr;
625 
626     if (!error)
627     {
628         screenDC = GetDC(HWND_DESKTOP);
629         error    = screenDC == nullptr;
630     }
631 
632     if (!error)
633     {
634         windowDC = GetDC(mNativeWindow);
635         error    = windowDC == nullptr;
636     }
637 
638     if (!error)
639     {
640         tmpDC = CreateCompatibleDC(screenDC);
641         error = tmpDC == nullptr;
642     }
643 
644     if (!error)
645     {
646         tmpBitmap = CreateCompatibleBitmap(screenDC, mWidth, mHeight);
647         error     = tmpBitmap == nullptr;
648     }
649 
650     POINT topLeft = {0, 0};
651     if (!error)
652     {
653         error = (MapWindowPoints(mNativeWindow, HWND_DESKTOP, &topLeft, 1) == 0);
654     }
655 
656     if (!error)
657     {
658         error = SelectObject(tmpDC, tmpBitmap) == nullptr;
659     }
660 
661     if (!error)
662     {
663         error = BitBlt(tmpDC, 0, 0, mWidth, mHeight, screenDC, topLeft.x, topLeft.y, SRCCOPY) == 0;
664     }
665 
666     if (!error)
667     {
668         BITMAPINFOHEADER bitmapInfo;
669         bitmapInfo.biSize          = sizeof(BITMAPINFOHEADER);
670         bitmapInfo.biWidth         = mWidth;
671         bitmapInfo.biHeight        = -mHeight;
672         bitmapInfo.biPlanes        = 1;
673         bitmapInfo.biBitCount      = 32;
674         bitmapInfo.biCompression   = BI_RGB;
675         bitmapInfo.biSizeImage     = 0;
676         bitmapInfo.biXPelsPerMeter = 0;
677         bitmapInfo.biYPelsPerMeter = 0;
678         bitmapInfo.biClrUsed       = 0;
679         bitmapInfo.biClrImportant  = 0;
680         int getBitsResult = GetDIBits(screenDC, tmpBitmap, 0, mHeight, pixelData,
681                                       reinterpret_cast<BITMAPINFO *>(&bitmapInfo), DIB_RGB_COLORS);
682         error = (getBitsResult == 0);
683     }
684 
685     if (tmpBitmap != nullptr)
686     {
687         DeleteObject(tmpBitmap);
688     }
689     if (tmpDC != nullptr)
690     {
691         DeleteDC(tmpDC);
692     }
693     if (screenDC != nullptr)
694     {
695         ReleaseDC(nullptr, screenDC);
696     }
697     if (windowDC != nullptr)
698     {
699         ReleaseDC(mNativeWindow, windowDC);
700     }
701 
702     return !error;
703 }
704 
getNativeWindow() const705 EGLNativeWindowType Win32Window::getNativeWindow() const
706 {
707     return mNativeWindow;
708 }
709 
getNativeDisplay() const710 EGLNativeDisplayType Win32Window::getNativeDisplay() const
711 {
712     return mNativeDisplay;
713 }
714 
getFramebufferNativeWindow() const715 void* Win32Window::getFramebufferNativeWindow() const
716 {
717     return mNativeWindow;
718 }
719 
messageLoop()720 void Win32Window::messageLoop()
721 {
722     MSG msg;
723     while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
724     {
725         TranslateMessage(&msg);
726         DispatchMessage(&msg);
727     }
728 }
729 
setMousePosition(int x,int y)730 void Win32Window::setMousePosition(int x, int y)
731 {
732     RECT winRect;
733     GetClientRect(mNativeWindow, &winRect);
734 
735     POINT topLeft;
736     topLeft.x = winRect.left;
737     topLeft.y = winRect.top;
738     ClientToScreen(mNativeWindow, &topLeft);
739 
740     SetCursorPos(topLeft.x + x, topLeft.y + y);
741 }
742 
CreateOSWindow()743 OSWindow *CreateOSWindow()
744 {
745     return new Win32Window();
746 }
747 
setPosition(int x,int y)748 bool Win32Window::setPosition(int x, int y)
749 {
750     if (mX == x && mY == y)
751     {
752         return true;
753     }
754 
755     RECT windowRect;
756     if (!GetWindowRect(mParentWindow, &windowRect))
757     {
758         return false;
759     }
760 
761     if (!MoveWindow(mParentWindow, x, y, windowRect.right - windowRect.left,
762                     windowRect.bottom - windowRect.top, TRUE))
763     {
764         return false;
765     }
766 
767     return true;
768 }
769 
resize(int width,int height)770 bool Win32Window::resize(int width, int height)
771 {
772     if (width == mWidth && height == mHeight)
773     {
774         return true;
775     }
776 
777     RECT windowRect;
778     if (!GetWindowRect(mParentWindow, &windowRect))
779     {
780         return false;
781     }
782 
783     RECT clientRect;
784     if (!GetClientRect(mParentWindow, &clientRect))
785     {
786         return false;
787     }
788 
789     LONG diffX = (windowRect.right - windowRect.left) - clientRect.right;
790     LONG diffY = (windowRect.bottom - windowRect.top) - clientRect.bottom;
791     if (!MoveWindow(mParentWindow, windowRect.left, windowRect.top, width + diffX, height + diffY,
792                     TRUE))
793     {
794         return false;
795     }
796 
797     if (!MoveWindow(mNativeWindow, 0, 0, width, height, FALSE))
798     {
799         return false;
800     }
801 
802     return true;
803 }
804 
setVisible(bool isVisible)805 void Win32Window::setVisible(bool isVisible)
806 {
807     int flag = (isVisible ? SW_SHOW : SW_HIDE);
808 
809     ShowWindow(mParentWindow, flag);
810     ShowWindow(mNativeWindow, flag);
811 
812     if (isVisible)
813     {
814         mSetVisibleTimer->stop();
815         mSetVisibleTimer->start();
816     }
817 }
818 
pushEvent(Event event)819 void Win32Window::pushEvent(Event event)
820 {
821     OSWindow::pushEvent(event);
822 
823     switch (event.type)
824     {
825         case Event::EVENT_RESIZED:
826             MoveWindow(mNativeWindow, 0, 0, mWidth, mHeight, FALSE);
827             break;
828         default:
829             break;
830     }
831 }
832 
signalTestEvent()833 void Win32Window::signalTestEvent()
834 {
835     PostMessage(mNativeWindow, WM_USER, 0, 0);
836 }
837