| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- #include "Win32/BsWin32Window.h"
- #include "Win32/BsWin32PlatformUtility.h"
- namespace BansheeEngine
- {
- Vector<Win32Window*> Win32Window::sAllWindows;
- Vector<Win32Window*> Win32Window::sModalWindowStack;
- Mutex Win32Window::sWindowsMutex;
- struct Win32Window::Pimpl
- {
- HWND hWnd = nullptr;
- INT32 left = 0;
- INT32 top = 0;
- UINT32 width = 0;
- UINT32 height = 0;
- bool isExternal = false;
- bool isModal = false;
- DWORD style = 0;
- DWORD styleEx = 0;
- };
- Win32Window::Win32Window(const WINDOW_DESC& desc)
- {
- m = bs_new<Pimpl>();
- m->isModal = desc.modal;
- HMONITOR hMonitor = desc.monitor;
- if (!desc.external)
- {
- m->style = WS_CLIPCHILDREN;
- INT32 left = desc.left;
- INT32 top = desc.top;
- // If we didn't specified the adapter index, or if we didn't find it
- if (hMonitor == nullptr)
- {
- POINT windowAnchorPoint;
- // Fill in anchor point.
- windowAnchorPoint.x = left;
- windowAnchorPoint.y = top;
- // Get the nearest monitor to this window.
- hMonitor = MonitorFromPoint(windowAnchorPoint, MONITOR_DEFAULTTOPRIMARY);
- }
- // Get the target monitor info
- MONITORINFO monitorInfo;
- memset(&monitorInfo, 0, sizeof(MONITORINFO));
- monitorInfo.cbSize = sizeof(MONITORINFO);
- GetMonitorInfo(hMonitor, &monitorInfo);
- UINT32 width = desc.width;
- UINT32 height = desc.height;
- // No specified top left -> Center the window in the middle of the monitor
- if (left == -1 || top == -1)
- {
- int screenw = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
- int screenh = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
- // clamp window dimensions to screen size
- int outerw = (int(width) < screenw) ? int(width) : screenw;
- int outerh = (int(height) < screenh) ? int(height) : screenh;
- if (left == -1)
- left = monitorInfo.rcWork.left + (screenw - outerw) / 2;
- else if (hMonitor != nullptr)
- left += monitorInfo.rcWork.left;
- if (top == -1)
- top = monitorInfo.rcWork.top + (screenh - outerh) / 2;
- else if (hMonitor != nullptr)
- top += monitorInfo.rcWork.top;
- }
- else if (hMonitor != nullptr)
- {
- left += monitorInfo.rcWork.left;
- top += monitorInfo.rcWork.top;
- }
- if (!desc.fullscreen)
- {
- if (desc.parent)
- {
- if (desc.toolWindow)
- m->styleEx = WS_EX_TOOLWINDOW;
- else
- m->style |= WS_CHILD;
- }
- else
- {
- if (desc.toolWindow)
- m->styleEx = WS_EX_TOOLWINDOW;
- }
- if (!desc.parent || desc.toolWindow)
- {
- if (desc.border == WindowBorder::None)
- m->style |= WS_POPUP;
- else if (desc.border == WindowBorder::Fixed)
- m->style |= WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
- else
- m->style |= WS_OVERLAPPEDWINDOW;
- }
- if (!desc.outerDimensions)
- {
- // Calculate window dimensions required to get the requested client area
- RECT rect;
- SetRect(&rect, 0, 0, width, height);
- AdjustWindowRect(&rect, m->style, false);
- width = rect.right - rect.left;
- height = rect.bottom - rect.top;
- // Clamp width and height to the desktop dimensions
- int screenw = GetSystemMetrics(SM_CXSCREEN);
- int screenh = GetSystemMetrics(SM_CYSCREEN);
- if ((int)width > screenw)
- width = screenw;
- if ((int)height > screenh)
- height = screenh;
- if (left < 0)
- left = (screenw - width) / 2;
- if (top < 0)
- top = (screenh - height) / 2;
- }
- if (desc.backgroundPixels != nullptr)
- m->styleEx |= WS_EX_LAYERED;
- }
- else
- {
- m->style |= WS_POPUP;
- top = 0;
- left = 0;
- }
- UINT classStyle = 0;
- if (desc.enableDoubleClick)
- classStyle |= CS_DBLCLKS;
- // Register the window class
- WNDCLASS wc = { classStyle, desc.wndProc, 0, 0, desc.module,
- LoadIcon(nullptr, IDI_APPLICATION), LoadCursor(nullptr, IDC_ARROW),
- (HBRUSH)GetStockObject(BLACK_BRUSH), 0, "Win32Wnd" };
- RegisterClass(&wc);
- // Create main window
- m->hWnd = CreateWindowEx(m->styleEx, "Win32Wnd", desc.title.c_str(), m->style,
- left, top, width, height, desc.parent, nullptr, desc.module, desc.creationParams);
- m->isExternal = false;
- }
- else
- {
- m->hWnd = desc.external;
- m->isExternal = true;
- }
- RECT rect;
- GetWindowRect(m->hWnd, &rect);
- m->top = rect.top;
- m->left = rect.left;
- GetClientRect(m->hWnd, &rect);
- m->width = rect.right;
- m->height = rect.bottom;
- // Set background, if any
- if (desc.backgroundPixels != nullptr)
- {
- HBITMAP backgroundBitmap = Win32PlatformUtility::createBitmap(
- desc.backgroundPixels, desc.backgroundWidth, desc.backgroundHeight, true);
- HDC hdcScreen = GetDC(nullptr);
- HDC hdcMem = CreateCompatibleDC(hdcScreen);
- HBITMAP hOldBitmap = (HBITMAP)SelectObject(hdcMem, backgroundBitmap);
- BLENDFUNCTION blend = { 0 };
- blend.BlendOp = AC_SRC_OVER;
- blend.SourceConstantAlpha = 255;
- blend.AlphaFormat = AC_SRC_ALPHA;
- POINT origin;
- origin.x = m->left;
- origin.y = m->top;
- SIZE size;
- size.cx = m->width;
- size.cy = m->height;
- POINT zero = { 0 };
- UpdateLayeredWindow(m->hWnd, hdcScreen, &origin, &size,
- hdcMem, &zero, RGB(0, 0, 0), &blend, desc.alphaBlending ? ULW_ALPHA : ULW_OPAQUE);
- SelectObject(hdcMem, hOldBitmap);
- DeleteDC(hdcMem);
- ReleaseDC(nullptr, hdcScreen);
- }
- // Handle modal windows
- bs_frame_mark();
- {
- FrameVector<HWND> windowsToDisable;
- FrameVector<HWND> windowsToBringToFront;
- {
- BS_LOCK_MUTEX(sWindowsMutex);
- if (m->isModal)
- {
- if (!sModalWindowStack.empty())
- {
- Win32Window* curModalWindow = sModalWindowStack.back();
- windowsToDisable.push_back(curModalWindow->m->hWnd);
- }
- else
- {
- for (auto& window : sAllWindows)
- windowsToDisable.push_back(window->m->hWnd);
- }
- sModalWindowStack.push_back(this);
- }
- else
- {
- // A non-modal window was opened while another modal one is open,
- // immediately deactivate it and make sure the modal windows stay on top.
- if (!sModalWindowStack.empty())
- {
- windowsToDisable.push_back(m->hWnd);
- for (auto window : sModalWindowStack)
- windowsToBringToFront.push_back(window->m->hWnd);
- }
- }
- sAllWindows.push_back(this);
- }
- for(auto& entry : windowsToDisable)
- EnableWindow(entry, FALSE);
- for (auto& entry : windowsToBringToFront)
- BringWindowToTop(entry);
- }
- bs_frame_clear();
- }
- Win32Window::~Win32Window()
- {
- if (m->hWnd && !m->isExternal)
- {
- // Handle modal windows
- bs_frame_mark();
-
- {
- FrameVector<HWND> windowsToEnable;
- {
- BS_LOCK_MUTEX(sWindowsMutex);
- // Hidden dependency: All windows must be re-enabled before a window is destroyed, otherwise the incorrect
- // window in the z order will be activated.
- bool reenableWindows = false;
- if (!sModalWindowStack.empty())
- {
- // Start from back because the most common case is closing the top-most modal window
- for (auto iter = sModalWindowStack.rbegin(); iter != sModalWindowStack.rend(); ++iter)
- {
- if (*iter == this)
- {
- auto iterFwd = std::next(iter).base(); // erase doesn't accept reverse iter, so convert
- sModalWindowStack.erase(iterFwd);
- break;
- }
- }
- if (!sModalWindowStack.empty()) // Enable next modal window
- {
- Win32Window* curModalWindow = sModalWindowStack.back();
- windowsToEnable.push_back(curModalWindow->m->hWnd);
- }
- else
- reenableWindows = true; // No more modal windows, re-enable any remaining window
- }
- if (reenableWindows)
- {
- for (auto& window : sAllWindows)
- windowsToEnable.push_back(window->m->hWnd);
- }
- }
- for(auto& entry : windowsToEnable)
- EnableWindow(entry, TRUE);
- }
- bs_frame_clear();
- DestroyWindow(m->hWnd);
- }
- {
- BS_LOCK_MUTEX(sWindowsMutex);
- auto iterFind = std::find(sAllWindows.begin(), sAllWindows.end(), this);
- sAllWindows.erase(iterFind);
- }
- bs_delete(m);
- }
- void Win32Window::move(INT32 left, INT32 top)
- {
- if (m->hWnd)
- {
- m->top = top;
- m->left = left;
- SetWindowPos(m->hWnd, HWND_TOP, left, top, m->width, m->height, SWP_NOSIZE);
- }
- }
- void Win32Window::resize(UINT32 width, UINT32 height)
- {
- if (m->hWnd)
- {
- RECT rc = { 0, 0, (LONG)width, (LONG)height };
- AdjustWindowRect(&rc, GetWindowLong(m->hWnd, GWL_STYLE), false);
- width = rc.right - rc.left;
- height = rc.bottom - rc.top;
- m->width = width;
- m->height = height;
- SetWindowPos(m->hWnd, HWND_TOP, m->left, m->top, width, height, SWP_NOMOVE);
- }
- }
- void Win32Window::setActive(bool state)
- {
- if (m->hWnd)
- {
- if (state)
- ShowWindow(m->hWnd, SW_RESTORE);
- else
- ShowWindow(m->hWnd, SW_SHOWMINNOACTIVE);
- }
- }
- void Win32Window::setHidden(bool hidden)
- {
- if (hidden)
- ShowWindow(m->hWnd, SW_HIDE);
- else
- ShowWindow(m->hWnd, SW_SHOW);
- }
- void Win32Window::minimize()
- {
- if (m->hWnd)
- ShowWindow(m->hWnd, SW_MINIMIZE);
- }
- void Win32Window::maximize()
- {
- if (m->hWnd)
- ShowWindow(m->hWnd, SW_MAXIMIZE);
- }
- void Win32Window::restore()
- {
- if (m->hWnd)
- ShowWindow(m->hWnd, SW_RESTORE);
- }
- void Win32Window::_windowMovedOrResized()
- {
- if (!m->hWnd || IsIconic(m->hWnd))
- return;
- RECT rc;
- GetWindowRect(m->hWnd, &rc);
- m->top = rc.top;
- m->left = rc.left;
- GetClientRect(m->hWnd, &rc);
- m->width = rc.right - rc.left;
- m->height = rc.bottom - rc.top;
- }
- Vector2I Win32Window::screenToWindowPos(const Vector2I& screenPos) const
- {
- POINT pos;
- pos.x = screenPos.x;
- pos.y = screenPos.y;
- ScreenToClient(m->hWnd, &pos);
- return Vector2I(pos.x, pos.y);
- }
- Vector2I Win32Window::windowToScreenPos(const Vector2I& windowPos) const
- {
- POINT pos;
- pos.x = windowPos.x;
- pos.y = windowPos.y;
- ClientToScreen(m->hWnd, &pos);
- return Vector2I(pos.x, pos.y);
- }
- INT32 Win32Window::getLeft() const
- {
- return m->left;
- }
- INT32 Win32Window::getTop() const
- {
- return m->top;
- }
- UINT32 Win32Window::getWidth() const
- {
- return m->width;
- }
- UINT32 Win32Window::getHeight() const
- {
- return m->height;
- }
- HWND Win32Window::getHWnd() const
- {
- return m->hWnd;
- }
- DWORD Win32Window::getStyle() const
- {
- return m->style;
- }
- DWORD Win32Window::getStyleEx() const
- {
- return m->styleEx;
- }
- void Win32Window::_enableAllWindows()
- {
- Vector<HWND> windowsToEnable;
- {
- BS_LOCK_MUTEX(sWindowsMutex);
- for (auto& window : sAllWindows)
- windowsToEnable.push_back(window->m->hWnd);
- }
- for (auto& entry : windowsToEnable)
- EnableWindow(entry, TRUE);
- }
- void Win32Window::_restoreModalWindows()
- {
- FrameVector<HWND> windowsToDisable;
- HWND bringToFrontHwnd = 0;
- {
- BS_LOCK_MUTEX(sWindowsMutex)
- if (!sModalWindowStack.empty())
- {
- Win32Window* curModalWindow = sModalWindowStack.back();
- bringToFrontHwnd = curModalWindow->m->hWnd;
- for (auto& window : sAllWindows)
- {
- if (window != curModalWindow)
- windowsToDisable.push_back(window->m->hWnd);
- }
- }
- }
- for (auto& entry : windowsToDisable)
- EnableWindow(entry, FALSE);
- if (bringToFrontHwnd != nullptr)
- BringWindowToTop(bringToFrontHwnd);
- }
- }
|