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