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