| // |
| // Copyright 2014 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| // Win32Window.cpp: Implementation of OSWindow for Win32 (Windows) |
| |
| #include "util/windows/win32/Win32Window.h" |
| |
| #include <sstream> |
| |
| #include "common/debug.h" |
| |
| Key VirtualKeyCodeToKey(WPARAM key, LPARAM flags) |
| { |
| switch (key) |
| { |
| // Check the scancode to distinguish between left and right shift |
| case VK_SHIFT: |
| { |
| static unsigned int lShift = MapVirtualKey(VK_LSHIFT, MAPVK_VK_TO_VSC); |
| unsigned int scancode = static_cast<unsigned int>((flags & (0xFF << 16)) >> 16); |
| return scancode == lShift ? KEY_LSHIFT : KEY_RSHIFT; |
| } |
| |
| // Check the "extended" flag to distinguish between left and right alt |
| case VK_MENU: |
| return (HIWORD(flags) & KF_EXTENDED) ? KEY_RALT : KEY_LALT; |
| |
| // Check the "extended" flag to distinguish between left and right control |
| case VK_CONTROL: |
| return (HIWORD(flags) & KF_EXTENDED) ? KEY_RCONTROL : KEY_LCONTROL; |
| |
| // Other keys are reported properly |
| case VK_LWIN: |
| return KEY_LSYSTEM; |
| case VK_RWIN: |
| return KEY_RSYSTEM; |
| case VK_APPS: |
| return KEY_MENU; |
| case VK_OEM_1: |
| return KEY_SEMICOLON; |
| case VK_OEM_2: |
| return KEY_SLASH; |
| case VK_OEM_PLUS: |
| return KEY_EQUAL; |
| case VK_OEM_MINUS: |
| return KEY_DASH; |
| case VK_OEM_4: |
| return KEY_LBRACKET; |
| case VK_OEM_6: |
| return KEY_RBRACKET; |
| case VK_OEM_COMMA: |
| return KEY_COMMA; |
| case VK_OEM_PERIOD: |
| return KEY_PERIOD; |
| case VK_OEM_7: |
| return KEY_QUOTE; |
| case VK_OEM_5: |
| return KEY_BACKSLASH; |
| case VK_OEM_3: |
| return KEY_TILDE; |
| case VK_ESCAPE: |
| return KEY_ESCAPE; |
| case VK_SPACE: |
| return KEY_SPACE; |
| case VK_RETURN: |
| return KEY_RETURN; |
| case VK_BACK: |
| return KEY_BACK; |
| case VK_TAB: |
| return KEY_TAB; |
| case VK_PRIOR: |
| return KEY_PAGEUP; |
| case VK_NEXT: |
| return KEY_PAGEDOWN; |
| case VK_END: |
| return KEY_END; |
| case VK_HOME: |
| return KEY_HOME; |
| case VK_INSERT: |
| return KEY_INSERT; |
| case VK_DELETE: |
| return KEY_DELETE; |
| case VK_ADD: |
| return KEY_ADD; |
| case VK_SUBTRACT: |
| return KEY_SUBTRACT; |
| case VK_MULTIPLY: |
| return KEY_MULTIPLY; |
| case VK_DIVIDE: |
| return KEY_DIVIDE; |
| case VK_PAUSE: |
| return KEY_PAUSE; |
| case VK_F1: |
| return KEY_F1; |
| case VK_F2: |
| return KEY_F2; |
| case VK_F3: |
| return KEY_F3; |
| case VK_F4: |
| return KEY_F4; |
| case VK_F5: |
| return KEY_F5; |
| case VK_F6: |
| return KEY_F6; |
| case VK_F7: |
| return KEY_F7; |
| case VK_F8: |
| return KEY_F8; |
| case VK_F9: |
| return KEY_F9; |
| case VK_F10: |
| return KEY_F10; |
| case VK_F11: |
| return KEY_F11; |
| case VK_F12: |
| return KEY_F12; |
| case VK_F13: |
| return KEY_F13; |
| case VK_F14: |
| return KEY_F14; |
| case VK_F15: |
| return KEY_F15; |
| case VK_LEFT: |
| return KEY_LEFT; |
| case VK_RIGHT: |
| return KEY_RIGHT; |
| case VK_UP: |
| return KEY_UP; |
| case VK_DOWN: |
| return KEY_DOWN; |
| case VK_NUMPAD0: |
| return KEY_NUMPAD0; |
| case VK_NUMPAD1: |
| return KEY_NUMPAD1; |
| case VK_NUMPAD2: |
| return KEY_NUMPAD2; |
| case VK_NUMPAD3: |
| return KEY_NUMPAD3; |
| case VK_NUMPAD4: |
| return KEY_NUMPAD4; |
| case VK_NUMPAD5: |
| return KEY_NUMPAD5; |
| case VK_NUMPAD6: |
| return KEY_NUMPAD6; |
| case VK_NUMPAD7: |
| return KEY_NUMPAD7; |
| case VK_NUMPAD8: |
| return KEY_NUMPAD8; |
| case VK_NUMPAD9: |
| return KEY_NUMPAD9; |
| case 'A': |
| return KEY_A; |
| case 'Z': |
| return KEY_Z; |
| case 'E': |
| return KEY_E; |
| case 'R': |
| return KEY_R; |
| case 'T': |
| return KEY_T; |
| case 'Y': |
| return KEY_Y; |
| case 'U': |
| return KEY_U; |
| case 'I': |
| return KEY_I; |
| case 'O': |
| return KEY_O; |
| case 'P': |
| return KEY_P; |
| case 'Q': |
| return KEY_Q; |
| case 'S': |
| return KEY_S; |
| case 'D': |
| return KEY_D; |
| case 'F': |
| return KEY_F; |
| case 'G': |
| return KEY_G; |
| case 'H': |
| return KEY_H; |
| case 'J': |
| return KEY_J; |
| case 'K': |
| return KEY_K; |
| case 'L': |
| return KEY_L; |
| case 'M': |
| return KEY_M; |
| case 'W': |
| return KEY_W; |
| case 'X': |
| return KEY_X; |
| case 'C': |
| return KEY_C; |
| case 'V': |
| return KEY_V; |
| case 'B': |
| return KEY_B; |
| case 'N': |
| return KEY_N; |
| case '0': |
| return KEY_NUM0; |
| case '1': |
| return KEY_NUM1; |
| case '2': |
| return KEY_NUM2; |
| case '3': |
| return KEY_NUM3; |
| case '4': |
| return KEY_NUM4; |
| case '5': |
| return KEY_NUM5; |
| case '6': |
| return KEY_NUM6; |
| case '7': |
| return KEY_NUM7; |
| case '8': |
| return KEY_NUM8; |
| case '9': |
| return KEY_NUM9; |
| } |
| |
| return Key(0); |
| } |
| |
| LRESULT CALLBACK Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
| { |
| switch (message) |
| { |
| case WM_NCCREATE: |
| { |
| LPCREATESTRUCT pCreateStruct = reinterpret_cast<LPCREATESTRUCT>(lParam); |
| SetWindowLongPtr(hWnd, GWLP_USERDATA, |
| reinterpret_cast<LONG_PTR>(pCreateStruct->lpCreateParams)); |
| return DefWindowProcA(hWnd, message, wParam, lParam); |
| } |
| } |
| |
| Win32Window *window = reinterpret_cast<Win32Window *>(GetWindowLongPtr(hWnd, GWLP_USERDATA)); |
| if (window) |
| { |
| switch (message) |
| { |
| case WM_DESTROY: |
| case WM_CLOSE: |
| { |
| Event event; |
| event.Type = Event::EVENT_CLOSED; |
| window->pushEvent(event); |
| break; |
| } |
| |
| case WM_MOVE: |
| { |
| RECT winRect; |
| GetClientRect(hWnd, &winRect); |
| |
| POINT topLeft; |
| topLeft.x = winRect.left; |
| topLeft.y = winRect.top; |
| ClientToScreen(hWnd, &topLeft); |
| |
| Event event; |
| event.Type = Event::EVENT_MOVED; |
| event.Move.X = topLeft.x; |
| event.Move.Y = topLeft.y; |
| window->pushEvent(event); |
| |
| break; |
| } |
| |
| case WM_SIZE: |
| { |
| RECT winRect; |
| GetClientRect(hWnd, &winRect); |
| |
| POINT topLeft; |
| topLeft.x = winRect.left; |
| topLeft.y = winRect.top; |
| ClientToScreen(hWnd, &topLeft); |
| |
| POINT botRight; |
| botRight.x = winRect.right; |
| botRight.y = winRect.bottom; |
| ClientToScreen(hWnd, &botRight); |
| |
| Event event; |
| event.Type = Event::EVENT_RESIZED; |
| event.Size.Width = botRight.x - topLeft.x; |
| event.Size.Height = botRight.y - topLeft.y; |
| window->pushEvent(event); |
| |
| break; |
| } |
| |
| case WM_SETFOCUS: |
| { |
| Event event; |
| event.Type = Event::EVENT_GAINED_FOCUS; |
| window->pushEvent(event); |
| break; |
| } |
| |
| case WM_KILLFOCUS: |
| { |
| Event event; |
| event.Type = Event::EVENT_LOST_FOCUS; |
| window->pushEvent(event); |
| break; |
| } |
| |
| case WM_KEYDOWN: |
| case WM_SYSKEYDOWN: |
| case WM_KEYUP: |
| case WM_SYSKEYUP: |
| { |
| bool down = (message == WM_KEYDOWN || message == WM_SYSKEYDOWN); |
| |
| Event event; |
| event.Type = down ? Event::EVENT_KEY_PRESSED : Event::EVENT_KEY_RELEASED; |
| event.Key.Alt = HIWORD(GetAsyncKeyState(VK_MENU)) != 0; |
| event.Key.Control = HIWORD(GetAsyncKeyState(VK_CONTROL)) != 0; |
| event.Key.Shift = HIWORD(GetAsyncKeyState(VK_SHIFT)) != 0; |
| event.Key.System = |
| HIWORD(GetAsyncKeyState(VK_LWIN)) || HIWORD(GetAsyncKeyState(VK_RWIN)); |
| event.Key.Code = VirtualKeyCodeToKey(wParam, lParam); |
| window->pushEvent(event); |
| |
| break; |
| } |
| |
| case WM_MOUSEWHEEL: |
| { |
| Event event; |
| event.Type = Event::EVENT_MOUSE_WHEEL_MOVED; |
| event.MouseWheel.Delta = static_cast<short>(HIWORD(wParam)) / 120; |
| window->pushEvent(event); |
| break; |
| } |
| |
| case WM_LBUTTONDOWN: |
| case WM_LBUTTONDBLCLK: |
| { |
| Event event; |
| event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED; |
| event.MouseButton.Button = MOUSEBUTTON_LEFT; |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); |
| window->pushEvent(event); |
| break; |
| } |
| |
| case WM_LBUTTONUP: |
| { |
| Event event; |
| event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED; |
| event.MouseButton.Button = MOUSEBUTTON_LEFT; |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); |
| window->pushEvent(event); |
| break; |
| } |
| |
| case WM_RBUTTONDOWN: |
| case WM_RBUTTONDBLCLK: |
| { |
| Event event; |
| event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED; |
| event.MouseButton.Button = MOUSEBUTTON_RIGHT; |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); |
| window->pushEvent(event); |
| break; |
| } |
| |
| // Mouse right button up event |
| case WM_RBUTTONUP: |
| { |
| Event event; |
| event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED; |
| event.MouseButton.Button = MOUSEBUTTON_RIGHT; |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); |
| window->pushEvent(event); |
| break; |
| } |
| |
| // Mouse wheel button down event |
| case WM_MBUTTONDOWN: |
| case WM_MBUTTONDBLCLK: |
| { |
| Event event; |
| event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED; |
| event.MouseButton.Button = MOUSEBUTTON_MIDDLE; |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); |
| window->pushEvent(event); |
| break; |
| } |
| |
| // Mouse wheel button up event |
| case WM_MBUTTONUP: |
| { |
| Event event; |
| event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED; |
| event.MouseButton.Button = MOUSEBUTTON_MIDDLE; |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); |
| window->pushEvent(event); |
| break; |
| } |
| |
| // Mouse X button down event |
| case WM_XBUTTONDOWN: |
| case WM_XBUTTONDBLCLK: |
| { |
| Event event; |
| event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED; |
| event.MouseButton.Button = |
| (HIWORD(wParam) == XBUTTON1) ? MOUSEBUTTON_BUTTON4 : MOUSEBUTTON_BUTTON5; |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); |
| window->pushEvent(event); |
| break; |
| } |
| |
| // Mouse X button up event |
| case WM_XBUTTONUP: |
| { |
| Event event; |
| event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED; |
| event.MouseButton.Button = |
| (HIWORD(wParam) == XBUTTON1) ? MOUSEBUTTON_BUTTON4 : MOUSEBUTTON_BUTTON5; |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); |
| window->pushEvent(event); |
| break; |
| } |
| |
| case WM_MOUSEMOVE: |
| { |
| if (!window->mIsMouseInWindow) |
| { |
| window->mIsMouseInWindow = true; |
| Event event; |
| event.Type = Event::EVENT_MOUSE_ENTERED; |
| window->pushEvent(event); |
| } |
| |
| int mouseX = static_cast<short>(LOWORD(lParam)); |
| int mouseY = static_cast<short>(HIWORD(lParam)); |
| |
| Event event; |
| event.Type = Event::EVENT_MOUSE_MOVED; |
| event.MouseMove.X = mouseX; |
| event.MouseMove.Y = mouseY; |
| window->pushEvent(event); |
| break; |
| } |
| |
| case WM_MOUSELEAVE: |
| { |
| Event event; |
| event.Type = Event::EVENT_MOUSE_LEFT; |
| window->pushEvent(event); |
| window->mIsMouseInWindow = false; |
| break; |
| } |
| |
| case WM_USER: |
| { |
| Event testEvent; |
| testEvent.Type = Event::EVENT_TEST; |
| window->pushEvent(testEvent); |
| break; |
| } |
| } |
| } |
| return DefWindowProcA(hWnd, message, wParam, lParam); |
| } |
| |
| Win32Window::Win32Window() |
| : mIsVisible(false), |
| mIsMouseInWindow(false), |
| mNativeWindow(0), |
| mParentWindow(0), |
| mNativeDisplay(0) |
| {} |
| |
| Win32Window::~Win32Window() |
| { |
| destroy(); |
| } |
| |
| bool Win32Window::initialize(const std::string &name, int width, int height) |
| { |
| destroy(); |
| |
| // Use a new window class name for ever window to ensure that a new window can be created |
| // even if the last one was not properly destroyed |
| static size_t windowIdx = 0; |
| std::ostringstream nameStream; |
| nameStream << name << "_" << windowIdx++; |
| |
| mParentClassName = nameStream.str(); |
| mChildClassName = mParentClassName + "_Child"; |
| |
| // Work around compile error from not defining "UNICODE" while Chromium does |
| const LPSTR idcArrow = MAKEINTRESOURCEA(32512); |
| |
| WNDCLASSEXA parentWindowClass = {0}; |
| parentWindowClass.cbSize = sizeof(WNDCLASSEXA); |
| parentWindowClass.style = 0; |
| parentWindowClass.lpfnWndProc = WndProc; |
| parentWindowClass.cbClsExtra = 0; |
| parentWindowClass.cbWndExtra = 0; |
| parentWindowClass.hInstance = GetModuleHandle(nullptr); |
| parentWindowClass.hIcon = nullptr; |
| parentWindowClass.hCursor = LoadCursorA(nullptr, idcArrow); |
| parentWindowClass.hbrBackground = 0; |
| parentWindowClass.lpszMenuName = nullptr; |
| parentWindowClass.lpszClassName = mParentClassName.c_str(); |
| if (!RegisterClassExA(&parentWindowClass)) |
| { |
| return false; |
| } |
| |
| WNDCLASSEXA childWindowClass = {0}; |
| childWindowClass.cbSize = sizeof(WNDCLASSEXA); |
| childWindowClass.style = CS_OWNDC; |
| childWindowClass.lpfnWndProc = WndProc; |
| childWindowClass.cbClsExtra = 0; |
| childWindowClass.cbWndExtra = 0; |
| childWindowClass.hInstance = GetModuleHandle(nullptr); |
| childWindowClass.hIcon = nullptr; |
| childWindowClass.hCursor = LoadCursorA(nullptr, idcArrow); |
| childWindowClass.hbrBackground = 0; |
| childWindowClass.lpszMenuName = nullptr; |
| childWindowClass.lpszClassName = mChildClassName.c_str(); |
| if (!RegisterClassExA(&childWindowClass)) |
| { |
| return false; |
| } |
| |
| DWORD parentStyle = WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU; |
| DWORD parentExtendedStyle = WS_EX_APPWINDOW | WS_EX_TOOLWINDOW; |
| |
| RECT sizeRect = {0, 0, static_cast<LONG>(width), static_cast<LONG>(height)}; |
| AdjustWindowRectEx(&sizeRect, parentStyle, FALSE, parentExtendedStyle); |
| |
| mParentWindow = CreateWindowExA(parentExtendedStyle, mParentClassName.c_str(), name.c_str(), |
| parentStyle, CW_USEDEFAULT, CW_USEDEFAULT, |
| sizeRect.right - sizeRect.left, sizeRect.bottom - sizeRect.top, |
| nullptr, nullptr, GetModuleHandle(nullptr), this); |
| |
| mNativeWindow = CreateWindowExA(0, mChildClassName.c_str(), name.c_str(), WS_CHILD, 0, 0, |
| static_cast<int>(width), static_cast<int>(height), |
| mParentWindow, nullptr, GetModuleHandle(nullptr), this); |
| |
| mNativeDisplay = GetDC(mNativeWindow); |
| if (!mNativeDisplay) |
| { |
| destroy(); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void Win32Window::destroy() |
| { |
| if (mNativeDisplay) |
| { |
| ReleaseDC(mNativeWindow, mNativeDisplay); |
| mNativeDisplay = 0; |
| } |
| |
| if (mNativeWindow) |
| { |
| DestroyWindow(mNativeWindow); |
| mNativeWindow = 0; |
| } |
| |
| if (mParentWindow) |
| { |
| DestroyWindow(mParentWindow); |
| mParentWindow = 0; |
| } |
| |
| UnregisterClassA(mParentClassName.c_str(), nullptr); |
| UnregisterClassA(mChildClassName.c_str(), nullptr); |
| } |
| |
| bool Win32Window::takeScreenshot(uint8_t *pixelData) |
| { |
| if (mIsVisible) |
| { |
| return false; |
| } |
| |
| bool error = false; |
| |
| // Hack for DWM: There is no way to wait for DWM animations to finish, so we just have to wait |
| // for a while before issuing screenshot if window was just made visible. |
| { |
| static const double WAIT_WINDOW_VISIBLE_MS = 0.5; // Half a second for the animation |
| double timeSinceVisible = mSetVisibleTimer.getElapsedTime(); |
| |
| if (timeSinceVisible < WAIT_WINDOW_VISIBLE_MS) |
| { |
| Sleep(static_cast<DWORD>((WAIT_WINDOW_VISIBLE_MS - timeSinceVisible) * 1000)); |
| } |
| } |
| |
| HDC screenDC = nullptr; |
| HDC windowDC = nullptr; |
| HDC tmpDC = nullptr; |
| HBITMAP tmpBitmap = nullptr; |
| |
| if (!error) |
| { |
| screenDC = GetDC(HWND_DESKTOP); |
| error = screenDC == nullptr; |
| } |
| |
| if (!error) |
| { |
| windowDC = GetDC(mNativeWindow); |
| error = windowDC == nullptr; |
| } |
| |
| if (!error) |
| { |
| tmpDC = CreateCompatibleDC(screenDC); |
| error = tmpDC == nullptr; |
| } |
| |
| if (!error) |
| { |
| tmpBitmap = CreateCompatibleBitmap(screenDC, mWidth, mHeight); |
| error = tmpBitmap == nullptr; |
| } |
| |
| POINT topLeft = {0, 0}; |
| if (!error) |
| { |
| error = (MapWindowPoints(mNativeWindow, HWND_DESKTOP, &topLeft, 1) == 0); |
| } |
| |
| if (!error) |
| { |
| error = SelectObject(tmpDC, tmpBitmap) == nullptr; |
| } |
| |
| if (!error) |
| { |
| error = BitBlt(tmpDC, 0, 0, mWidth, mHeight, screenDC, topLeft.x, topLeft.y, SRCCOPY) == 0; |
| } |
| |
| if (!error) |
| { |
| BITMAPINFOHEADER bitmapInfo; |
| bitmapInfo.biSize = sizeof(BITMAPINFOHEADER); |
| bitmapInfo.biWidth = mWidth; |
| bitmapInfo.biHeight = -mHeight; |
| bitmapInfo.biPlanes = 1; |
| bitmapInfo.biBitCount = 32; |
| bitmapInfo.biCompression = BI_RGB; |
| bitmapInfo.biSizeImage = 0; |
| bitmapInfo.biXPelsPerMeter = 0; |
| bitmapInfo.biYPelsPerMeter = 0; |
| bitmapInfo.biClrUsed = 0; |
| bitmapInfo.biClrImportant = 0; |
| int getBitsResult = GetDIBits(screenDC, tmpBitmap, 0, mHeight, pixelData, |
| reinterpret_cast<BITMAPINFO *>(&bitmapInfo), DIB_RGB_COLORS); |
| error = (getBitsResult == 0); |
| } |
| |
| if (tmpBitmap != nullptr) |
| { |
| DeleteObject(tmpBitmap); |
| } |
| if (tmpDC != nullptr) |
| { |
| DeleteDC(tmpDC); |
| } |
| if (screenDC != nullptr) |
| { |
| ReleaseDC(nullptr, screenDC); |
| } |
| if (windowDC != nullptr) |
| { |
| ReleaseDC(mNativeWindow, windowDC); |
| } |
| |
| return !error; |
| } |
| |
| void Win32Window::resetNativeWindow() {} |
| |
| EGLNativeWindowType Win32Window::getNativeWindow() const |
| { |
| return mNativeWindow; |
| } |
| |
| EGLNativeDisplayType Win32Window::getNativeDisplay() const |
| { |
| return mNativeDisplay; |
| } |
| |
| void Win32Window::messageLoop() |
| { |
| MSG msg; |
| while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) |
| { |
| TranslateMessage(&msg); |
| DispatchMessage(&msg); |
| } |
| } |
| |
| void Win32Window::setMousePosition(int x, int y) |
| { |
| RECT winRect; |
| GetClientRect(mNativeWindow, &winRect); |
| |
| POINT topLeft; |
| topLeft.x = winRect.left; |
| topLeft.y = winRect.top; |
| ClientToScreen(mNativeWindow, &topLeft); |
| |
| SetCursorPos(topLeft.x + x, topLeft.y + y); |
| } |
| |
| bool Win32Window::setPosition(int x, int y) |
| { |
| if (mX == x && mY == y) |
| { |
| return true; |
| } |
| |
| RECT windowRect; |
| if (!GetWindowRect(mParentWindow, &windowRect)) |
| { |
| return false; |
| } |
| |
| if (!MoveWindow(mParentWindow, x, y, windowRect.right - windowRect.left, |
| windowRect.bottom - windowRect.top, TRUE)) |
| { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool Win32Window::resize(int width, int height) |
| { |
| if (width == mWidth && height == mHeight) |
| { |
| return true; |
| } |
| |
| RECT windowRect; |
| if (!GetWindowRect(mParentWindow, &windowRect)) |
| { |
| return false; |
| } |
| |
| RECT clientRect; |
| if (!GetClientRect(mParentWindow, &clientRect)) |
| { |
| return false; |
| } |
| |
| LONG diffX = (windowRect.right - windowRect.left) - clientRect.right; |
| LONG diffY = (windowRect.bottom - windowRect.top) - clientRect.bottom; |
| if (!MoveWindow(mParentWindow, windowRect.left, windowRect.top, width + diffX, height + diffY, |
| TRUE)) |
| { |
| return false; |
| } |
| |
| if (!MoveWindow(mNativeWindow, 0, 0, width, height, FALSE)) |
| { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void Win32Window::setVisible(bool isVisible) |
| { |
| int flag = (isVisible ? SW_SHOW : SW_HIDE); |
| |
| ShowWindow(mParentWindow, flag); |
| ShowWindow(mNativeWindow, flag); |
| |
| if (isVisible) |
| { |
| mSetVisibleTimer.stop(); |
| mSetVisibleTimer.start(); |
| } |
| } |
| |
| void Win32Window::pushEvent(Event event) |
| { |
| OSWindow::pushEvent(event); |
| |
| switch (event.Type) |
| { |
| case Event::EVENT_RESIZED: |
| MoveWindow(mNativeWindow, 0, 0, mWidth, mHeight, FALSE); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| void Win32Window::signalTestEvent() |
| { |
| PostMessage(mNativeWindow, WM_USER, 0, 0); |
| } |
| |
| // static |
| OSWindow *OSWindow::New() |
| { |
| return new Win32Window(); |
| } |