BsWin32Window.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. #include "Win32/BsWin32Window.h"
  2. #include "Win32/BsWin32Platform.h"
  3. namespace BansheeEngine
  4. {
  5. struct Win32Window::Pimpl
  6. {
  7. HWND hWnd = nullptr;
  8. INT32 left = 0;
  9. INT32 top = 0;
  10. UINT32 width = 0;
  11. UINT32 height = 0;
  12. bool isExternal = false;
  13. DWORD style = 0;
  14. DWORD styleEx = 0;
  15. };
  16. Win32Window::Win32Window(const WINDOW_DESC& desc)
  17. {
  18. m = bs_new<Pimpl>();
  19. HMONITOR hMonitor = desc.monitor;
  20. if (!desc.external)
  21. {
  22. m->style = WS_CLIPCHILDREN;
  23. INT32 left = desc.left;
  24. INT32 top = desc.top;
  25. // If we didn't specified the adapter index, or if we didn't find it
  26. if (hMonitor == nullptr)
  27. {
  28. POINT windowAnchorPoint;
  29. // Fill in anchor point.
  30. windowAnchorPoint.x = left;
  31. windowAnchorPoint.y = top;
  32. // Get the nearest monitor to this window.
  33. hMonitor = MonitorFromPoint(windowAnchorPoint, MONITOR_DEFAULTTOPRIMARY);
  34. }
  35. // Get the target monitor info
  36. MONITORINFO monitorInfo;
  37. memset(&monitorInfo, 0, sizeof(MONITORINFO));
  38. monitorInfo.cbSize = sizeof(MONITORINFO);
  39. GetMonitorInfo(hMonitor, &monitorInfo);
  40. UINT32 width = desc.width;
  41. UINT32 height = desc.height;
  42. // No specified top left -> Center the window in the middle of the monitor
  43. if (left == -1 || top == -1)
  44. {
  45. int screenw = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
  46. int screenh = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
  47. // clamp window dimensions to screen size
  48. int outerw = (int(width) < screenw) ? int(width) : screenw;
  49. int outerh = (int(height) < screenh) ? int(height) : screenh;
  50. if (left == -1)
  51. left = monitorInfo.rcWork.left + (screenw - outerw) / 2;
  52. else if (hMonitor != nullptr)
  53. left += monitorInfo.rcWork.left;
  54. if (top == -1)
  55. top = monitorInfo.rcWork.top + (screenh - outerh) / 2;
  56. else if (hMonitor != nullptr)
  57. top += monitorInfo.rcWork.top;
  58. }
  59. else if (hMonitor != nullptr)
  60. {
  61. left += monitorInfo.rcWork.left;
  62. top += monitorInfo.rcWork.top;
  63. }
  64. if (!desc.fullscreen)
  65. {
  66. if (desc.parent)
  67. {
  68. if (desc.toolWindow)
  69. m->styleEx = WS_EX_TOOLWINDOW;
  70. else
  71. m->style |= WS_CHILD;
  72. }
  73. else
  74. {
  75. if (desc.toolWindow)
  76. m->styleEx = WS_EX_TOOLWINDOW;
  77. }
  78. if (!desc.parent || desc.toolWindow)
  79. {
  80. if (desc.border == WindowBorder::None)
  81. m->style |= WS_POPUP;
  82. else if (desc.border == WindowBorder::Fixed)
  83. m->style |= WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
  84. else
  85. m->style |= WS_OVERLAPPEDWINDOW;
  86. }
  87. if (!desc.outerDimensions)
  88. {
  89. // Calculate window dimensions required to get the requested client area
  90. RECT rect;
  91. SetRect(&rect, 0, 0, width, height);
  92. AdjustWindowRect(&rect, m->style, false);
  93. width = rect.right - rect.left;
  94. height = rect.bottom - rect.top;
  95. // Clamp width and height to the desktop dimensions
  96. int screenw = GetSystemMetrics(SM_CXSCREEN);
  97. int screenh = GetSystemMetrics(SM_CYSCREEN);
  98. if ((int)width > screenw)
  99. width = screenw;
  100. if ((int)height > screenh)
  101. height = screenh;
  102. if (left < 0)
  103. left = (screenw - width) / 2;
  104. if (top < 0)
  105. top = (screenh - height) / 2;
  106. }
  107. if (desc.background != nullptr)
  108. m->styleEx |= WS_EX_LAYERED;
  109. }
  110. else
  111. {
  112. m->style |= WS_POPUP;
  113. top = 0;
  114. left = 0;
  115. }
  116. UINT classStyle = 0;
  117. if (desc.enableDoubleClick)
  118. classStyle |= CS_DBLCLKS;
  119. // Register the window class
  120. WNDCLASS wc = { classStyle, Win32Platform::_win32WndProc, 0, 0, desc.module,
  121. LoadIcon(nullptr, IDI_APPLICATION), LoadCursor(nullptr, IDC_ARROW),
  122. (HBRUSH)GetStockObject(BLACK_BRUSH), 0, "Win32Wnd" };
  123. RegisterClass(&wc);
  124. // Create main window
  125. m->hWnd = CreateWindowEx(m->styleEx, "Win32Wnd", desc.title.c_str(), m->style,
  126. left, top, width, height, desc.parent, nullptr, desc.module, desc.creationParams);
  127. m->isExternal = false;
  128. }
  129. else
  130. {
  131. m->hWnd = desc.external;
  132. m->isExternal = true;
  133. }
  134. RECT rect;
  135. GetWindowRect(m->hWnd, &rect);
  136. m->top = rect.top;
  137. m->left = rect.left;
  138. GetClientRect(m->hWnd, &rect);
  139. m->width = rect.right;
  140. m->height = rect.bottom;
  141. // Set background, if any
  142. if (desc.background != nullptr)
  143. {
  144. HBITMAP backgroundBitmap = Win32Platform::createBitmap(*desc.background, true);
  145. HDC hdcScreen = GetDC(nullptr);
  146. HDC hdcMem = CreateCompatibleDC(hdcScreen);
  147. HBITMAP hOldBitmap = (HBITMAP)SelectObject(hdcMem, backgroundBitmap);
  148. BLENDFUNCTION blend = { 0 };
  149. blend.BlendOp = AC_SRC_OVER;
  150. blend.SourceConstantAlpha = 255;
  151. blend.AlphaFormat = AC_SRC_ALPHA;
  152. POINT origin;
  153. origin.x = m->left;
  154. origin.y = m->top;
  155. SIZE size;
  156. size.cx = m->width;
  157. size.cy = m->height;
  158. POINT zero = { 0 };
  159. UpdateLayeredWindow(m->hWnd, hdcScreen, &origin, &size,
  160. hdcMem, &zero, RGB(0, 0, 0), &blend, desc.alphaBlending ? ULW_ALPHA : ULW_OPAQUE);
  161. SelectObject(hdcMem, hOldBitmap);
  162. DeleteDC(hdcMem);
  163. ReleaseDC(nullptr, hdcScreen);
  164. }
  165. }
  166. Win32Window::~Win32Window()
  167. {
  168. if (m->hWnd && !m->isExternal)
  169. DestroyWindow(m->hWnd);
  170. bs_delete(m);
  171. }
  172. void Win32Window::move(INT32 left, INT32 top)
  173. {
  174. if (m->hWnd)
  175. {
  176. m->top = top;
  177. m->left = left;
  178. SetWindowPos(m->hWnd, nullptr, left, top, m->width, m->height, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  179. }
  180. }
  181. void Win32Window::resize(UINT32 width, UINT32 height)
  182. {
  183. if (m->hWnd)
  184. {
  185. RECT rc = { 0, 0, (LONG)width, (LONG)height };
  186. AdjustWindowRect(&rc, GetWindowLong(m->hWnd, GWL_STYLE), false);
  187. width = rc.right - rc.left;
  188. height = rc.bottom - rc.top;
  189. m->width = width;
  190. m->height = height;
  191. SetWindowPos(m->hWnd, nullptr, m->left, m->top, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  192. }
  193. }
  194. void Win32Window::setActive(bool state)
  195. {
  196. if (m->hWnd)
  197. {
  198. if (state)
  199. ShowWindow(m->hWnd, SW_RESTORE);
  200. else
  201. ShowWindow(m->hWnd, SW_SHOWMINNOACTIVE);
  202. }
  203. }
  204. void Win32Window::setHidden(bool hidden)
  205. {
  206. if (hidden)
  207. ShowWindow(m->hWnd, SW_HIDE);
  208. else
  209. ShowWindow(m->hWnd, SW_SHOWNORMAL);
  210. }
  211. void Win32Window::minimize()
  212. {
  213. if (m->hWnd)
  214. SendMessage(m->hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
  215. }
  216. void Win32Window::maximize()
  217. {
  218. if (m->hWnd)
  219. SendMessage(m->hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
  220. }
  221. void Win32Window::restore()
  222. {
  223. if (m->hWnd)
  224. SendMessage(m->hWnd, WM_SYSCOMMAND, SC_RESTORE, 0);
  225. }
  226. void Win32Window::_windowMovedOrResized()
  227. {
  228. if (!m->hWnd || IsIconic(m->hWnd))
  229. return;
  230. RECT rc;
  231. GetWindowRect(m->hWnd, &rc);
  232. m->top = rc.top;
  233. m->left = rc.left;
  234. GetClientRect(m->hWnd, &rc);
  235. m->width = rc.right - rc.left;
  236. m->height = rc.bottom - rc.top;
  237. }
  238. Vector2I Win32Window::screenToWindowPos(const Vector2I& screenPos) const
  239. {
  240. POINT pos;
  241. pos.x = screenPos.x;
  242. pos.y = screenPos.y;
  243. ScreenToClient(m->hWnd, &pos);
  244. return Vector2I(pos.x, pos.y);
  245. }
  246. Vector2I Win32Window::windowToScreenPos(const Vector2I& windowPos) const
  247. {
  248. POINT pos;
  249. pos.x = windowPos.x;
  250. pos.y = windowPos.y;
  251. ClientToScreen(m->hWnd, &pos);
  252. return Vector2I(pos.x, pos.y);
  253. }
  254. INT32 Win32Window::getLeft() const
  255. {
  256. return m->left;
  257. }
  258. INT32 Win32Window::getTop() const
  259. {
  260. return m->top;
  261. }
  262. UINT32 Win32Window::getWidth() const
  263. {
  264. return m->width;
  265. }
  266. UINT32 Win32Window::getHeight() const
  267. {
  268. return m->height;
  269. }
  270. HWND Win32Window::getHWnd() const
  271. {
  272. return m->hWnd;
  273. }
  274. DWORD Win32Window::getStyle() const
  275. {
  276. return m->style;
  277. }
  278. DWORD Win32Window::getStyleEx() const
  279. {
  280. return m->styleEx;
  281. }
  282. }