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