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