CmWin32Window.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. #ifndef _WIN32_WINNT
  2. #define _WIN32_WINNT 0x0500
  3. #endif
  4. #include "CmWin32Window.h"
  5. #include "CmInput.h"
  6. #include "CmRenderSystem.h"
  7. #include "CmCoreThread.h"
  8. #include "CmException.h"
  9. #include "CmWin32GLSupport.h"
  10. #include "CmWin32Context.h"
  11. #include "Win32/CmPlatformWndProc.h"
  12. #include "CmWin32VideoModeInfo.h"
  13. #include "CmGLPixelFormat.h"
  14. GLenum GLEWAPIENTRY wglewContextInit(BansheeEngine::GLSupport *glSupport);
  15. namespace BansheeEngine
  16. {
  17. #define _MAX_CLASS_NAME_ 128
  18. Win32Window::Win32Window(const RENDER_WINDOW_DESC& desc, Win32GLSupport &glsupport):
  19. RenderWindow(desc),
  20. mGLSupport(glsupport),
  21. mContext(0)
  22. {
  23. mIsFullScreen = false;
  24. mHWnd = 0;
  25. mIsExternal = false;
  26. mIsExternalGLControl = false;
  27. mSizing = false;
  28. mClosed = false;
  29. mDisplayFrequency = 0;
  30. mActive = false;
  31. mDeviceName = NULL;
  32. }
  33. Win32Window::~Win32Window()
  34. {
  35. }
  36. void Win32Window::initialize_internal()
  37. {
  38. #ifdef CM_STATIC_LIB
  39. HINSTANCE hInst = GetModuleHandle(NULL);
  40. #else
  41. HINSTANCE hInst = GetModuleHandle(MODULE_NAME.c_str());
  42. #endif
  43. mHWnd = 0;
  44. mName = mDesc.title;
  45. mIsFullScreen = mDesc.fullscreen;
  46. mClosed = false;
  47. mDisplayFrequency = mDesc.displayFrequency;
  48. mColorDepth = mDesc.colorDepth;
  49. HWND parent = 0;
  50. HMONITOR hMonitor = NULL;
  51. int monitorIndex = mDesc.monitorIndex;
  52. // Get variable-length params
  53. NameValuePairList::const_iterator opt;
  54. NameValuePairList::const_iterator end = mDesc.platformSpecific.end();
  55. if ((opt = mDesc.platformSpecific.find("externalWindowHandle")) != end)
  56. {
  57. mHWnd = (HWND)parseUnsignedInt(opt->second);
  58. if (mHWnd)
  59. {
  60. mIsExternal = true;
  61. mIsChild = true;
  62. mIsFullScreen = false;
  63. }
  64. if ((opt = mDesc.platformSpecific.find("externalGLControl")) != end) {
  65. mIsExternalGLControl = parseBool(opt->second);
  66. }
  67. }
  68. HGLRC glrc = 0;
  69. if ((opt = mDesc.platformSpecific.find("externalGLContext")) != end)
  70. {
  71. glrc = (HGLRC)parseUnsignedLong(opt->second);
  72. }
  73. // incompatible with fullscreen
  74. if ((opt = mDesc.platformSpecific.find("parentWindowHandle")) != end)
  75. parent = (HWND)parseUnsignedInt(opt->second);
  76. // monitor handle
  77. if ((opt = mDesc.platformSpecific.find("monitorHandle")) != end)
  78. hMonitor = (HMONITOR)parseInt(opt->second);
  79. if (!mIsFullScreen)
  80. {
  81. // make sure we don't exceed desktop colour depth
  82. if ((int)mColorDepth > GetDeviceCaps(GetDC(0), BITSPIXEL))
  83. mColorDepth = GetDeviceCaps(GetDC(0), BITSPIXEL);
  84. }
  85. if (!mIsExternal)
  86. {
  87. DWORD dwStyle = WS_VISIBLE | WS_CLIPCHILDREN;
  88. DWORD dwStyleEx = 0;
  89. MONITORINFOEX monitorInfoEx;
  90. RECT rc;
  91. // If we didn't specified the adapter index, or if it didn't find it
  92. if (hMonitor == NULL)
  93. {
  94. POINT windowAnchorPoint;
  95. // Fill in anchor point.
  96. windowAnchorPoint.x = mDesc.left;
  97. windowAnchorPoint.y = mDesc.top;
  98. // Get the nearest monitor to this window.
  99. hMonitor = MonitorFromPoint(windowAnchorPoint, MONITOR_DEFAULTTONEAREST);
  100. }
  101. // Get the target monitor info
  102. memset(&monitorInfoEx, 0, sizeof(MONITORINFOEX));
  103. monitorInfoEx.cbSize = sizeof(MONITORINFOEX);
  104. GetMonitorInfo(hMonitor, &monitorInfoEx);
  105. size_t devNameLen = strlen(monitorInfoEx.szDevice);
  106. mDeviceName = (char*)cm_alloc<ScratchAlloc>((UINT32)(devNameLen + 1));
  107. strcpy_s(mDeviceName, devNameLen + 1, monitorInfoEx.szDevice);
  108. UINT32 left = mDesc.left;
  109. UINT32 top = mDesc.top;
  110. // No specified top left -> Center the window in the middle of the monitor
  111. if (left == -1 || top == -1)
  112. {
  113. int screenw = monitorInfoEx.rcWork.right - monitorInfoEx.rcWork.left;
  114. int screenh = monitorInfoEx.rcWork.bottom - monitorInfoEx.rcWork.top;
  115. unsigned int winWidth, winHeight;
  116. _adjustWindow(mDesc.width, mDesc.height, &winWidth, &winHeight);
  117. // clamp window dimensions to screen size
  118. int outerw = (int(winWidth) < screenw)? int(winWidth) : screenw;
  119. int outerh = (int(winHeight) < screenh)? int(winHeight) : screenh;
  120. if (left == -1)
  121. left = monitorInfoEx.rcWork.left + (screenw - outerw) / 2;
  122. else if (mDesc.monitorIndex != -1)
  123. left += monitorInfoEx.rcWork.left;
  124. if (top == -1)
  125. top = monitorInfoEx.rcWork.top + (screenh - outerh) / 2;
  126. else if (mDesc.monitorIndex != -1)
  127. top += monitorInfoEx.rcWork.top;
  128. }
  129. else if (mDesc.monitorIndex != -1)
  130. {
  131. left += monitorInfoEx.rcWork.left;
  132. top += monitorInfoEx.rcWork.top;
  133. }
  134. mWidth = mDesc.width;
  135. mHeight = mDesc.height;
  136. mTop = top;
  137. mLeft = left;
  138. if (mIsFullScreen)
  139. {
  140. dwStyle |= WS_POPUP;
  141. dwStyleEx |= WS_EX_TOPMOST;
  142. mTop = monitorInfoEx.rcMonitor.top;
  143. mLeft = monitorInfoEx.rcMonitor.left;
  144. }
  145. else
  146. {
  147. if (parent)
  148. {
  149. if(mDesc.toolWindow)
  150. dwStyleEx = WS_EX_TOOLWINDOW;
  151. else
  152. dwStyle |= WS_CHILD;
  153. }
  154. if (!parent || mDesc.toolWindow)
  155. {
  156. if (mDesc.border == WindowBorder::None)
  157. dwStyle |= WS_POPUP;
  158. else if (mDesc.border == WindowBorder::Fixed)
  159. dwStyle |= WS_OVERLAPPED | WS_BORDER | WS_CAPTION |
  160. WS_SYSMENU | WS_MINIMIZEBOX;
  161. else
  162. dwStyle |= WS_OVERLAPPEDWINDOW;
  163. }
  164. int screenw = GetSystemMetrics(SM_CXSCREEN);
  165. int screenh = GetSystemMetrics(SM_CYSCREEN);
  166. if (!mDesc.outerDimensions)
  167. {
  168. // Calculate window dimensions required
  169. // to get the requested client area
  170. SetRect(&rc, 0, 0, mWidth, mHeight);
  171. AdjustWindowRect(&rc, dwStyle, false);
  172. mWidth = rc.right - rc.left;
  173. mHeight = rc.bottom - rc.top;
  174. // Clamp window rect to the nearest display monitor.
  175. if (mLeft < monitorInfoEx.rcWork.left)
  176. mLeft = monitorInfoEx.rcWork.left;
  177. if (mTop < monitorInfoEx.rcWork.top)
  178. mTop = monitorInfoEx.rcWork.top;
  179. if ((int)mWidth > monitorInfoEx.rcWork.right - mLeft)
  180. mWidth = monitorInfoEx.rcWork.right - mLeft;
  181. if ((int)mHeight > monitorInfoEx.rcWork.bottom - mTop)
  182. mHeight = monitorInfoEx.rcWork.bottom - mTop;
  183. }
  184. }
  185. // register class and create window
  186. WNDCLASS wc = { CS_OWNDC, PlatformWndProc::_win32WndProc, 0, 0, hInst,
  187. LoadIcon(NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
  188. (HBRUSH)GetStockObject(BLACK_BRUSH), NULL, "GLWindow" };
  189. RegisterClass(&wc);
  190. if (mIsFullScreen)
  191. {
  192. DEVMODE displayDeviceMode;
  193. memset(&displayDeviceMode, 0, sizeof(displayDeviceMode));
  194. displayDeviceMode.dmSize = sizeof(DEVMODE);
  195. displayDeviceMode.dmBitsPerPel = mColorDepth;
  196. displayDeviceMode.dmPelsWidth = mWidth;
  197. displayDeviceMode.dmPelsHeight = mHeight;
  198. displayDeviceMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
  199. if (mDisplayFrequency)
  200. {
  201. displayDeviceMode.dmDisplayFrequency = mDisplayFrequency;
  202. displayDeviceMode.dmFields |= DM_DISPLAYFREQUENCY;
  203. if (ChangeDisplaySettingsEx(mDeviceName, &displayDeviceMode, NULL, CDS_FULLSCREEN | CDS_TEST, NULL) != DISP_CHANGE_SUCCESSFUL)
  204. {
  205. // TODO LOG PORT - Log this somewhere
  206. //LogManager::getSingleton().logMessage(LML_NORMAL, "ChangeDisplaySettings with user display frequency failed");
  207. //displayDeviceMode.dmFields ^= DM_DISPLAYFREQUENCY;
  208. }
  209. }
  210. if (ChangeDisplaySettingsEx(mDeviceName, &displayDeviceMode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL)
  211. {
  212. // TODO LOG PORT - Log this somewhere
  213. //LogManager::getSingleton().logMessage(LML_CRITICAL, "ChangeDisplaySettings failed");
  214. }
  215. }
  216. // Pass pointer to self as WM_CREATE parameter
  217. mHWnd = CreateWindowEx(dwStyleEx, "GLWindow", mDesc.title.c_str(),
  218. dwStyle, mLeft, mTop, mWidth, mHeight, parent, 0, hInst, this);
  219. }
  220. RECT rc;
  221. // top and left represent outer window position
  222. GetWindowRect(mHWnd, &rc);
  223. mTop = rc.top;
  224. mLeft = rc.left;
  225. // width and height represent drawable area only
  226. GetClientRect(mHWnd, &rc);
  227. mWidth = rc.right;
  228. mHeight = rc.bottom;
  229. mHDC = GetDC(mHWnd);
  230. if (!mIsExternalGLControl)
  231. {
  232. int testFsaa = mFSAA;
  233. bool testHwGamma = mDesc.gamma;
  234. bool formatOk = mGLSupport.selectPixelFormat(mHDC, mColorDepth, testFsaa, testHwGamma);
  235. if (!formatOk)
  236. {
  237. if (mFSAA > 0)
  238. {
  239. // try without FSAA
  240. testFsaa = 0;
  241. formatOk = mGLSupport.selectPixelFormat(mHDC, mColorDepth, testFsaa, testHwGamma);
  242. }
  243. if (!formatOk && mDesc.gamma)
  244. {
  245. // try without sRGB
  246. testHwGamma = false;
  247. testFsaa = mFSAA;
  248. formatOk = mGLSupport.selectPixelFormat(mHDC, mColorDepth, testFsaa, testHwGamma);
  249. }
  250. if (!formatOk && mDesc.gamma && (mFSAA > 0))
  251. {
  252. // try without both
  253. testHwGamma = false;
  254. testFsaa = 0;
  255. formatOk = mGLSupport.selectPixelFormat(mHDC, mColorDepth, testFsaa, testHwGamma);
  256. }
  257. if (!formatOk)
  258. CM_EXCEPT(RenderingAPIException, "selectPixelFormat failed");
  259. }
  260. // record what gamma option we used in the end
  261. // this will control enabling of sRGB state flags when used
  262. mHwGamma = testHwGamma;
  263. mFSAA = testFsaa;
  264. }
  265. mActive = true;
  266. mContext = mGLSupport.createContext(mHDC, glrc);
  267. RenderWindow::initialize_internal();
  268. }
  269. void Win32Window::destroy_internal()
  270. {
  271. if (!mHWnd)
  272. return;
  273. // Unregister and destroy GLContext
  274. cm_delete(mContext);
  275. if (!mIsExternal)
  276. {
  277. if (mIsFullScreen)
  278. ChangeDisplaySettingsEx(mDeviceName, NULL, NULL, 0, NULL);
  279. DestroyWindow(mHWnd);
  280. }
  281. else
  282. {
  283. // just release the DC
  284. ReleaseDC(mHWnd, mHDC);
  285. }
  286. mActive = false;
  287. mClosed = true;
  288. mHDC = 0; // no release thanks to CS_OWNDC wndclass style
  289. mHWnd = 0;
  290. if (mDeviceName != NULL)
  291. {
  292. cm_free<ScratchAlloc>(mDeviceName);
  293. mDeviceName = NULL;
  294. }
  295. RenderWindow::destroy_internal();
  296. }
  297. void Win32Window::setFullscreen(UINT32 width, UINT32 height, float refreshRate, UINT32 monitorIdx)
  298. {
  299. THROW_IF_NOT_CORE_THREAD;
  300. if (mIsChild)
  301. return;
  302. const Win32VideoModeInfo& videoModeInfo = static_cast<const Win32VideoModeInfo&>(RenderSystem::instance().getVideoModeInfo());
  303. UINT32 numOutputs = videoModeInfo.getNumOutputs();
  304. if (numOutputs == 0)
  305. return;
  306. UINT32 actualMonitorIdx = std::min(monitorIdx, numOutputs - 1);
  307. const Win32VideoOutputInfo& outputInfo = static_cast<const Win32VideoOutputInfo&>(videoModeInfo.getOutputInfo(actualMonitorIdx));
  308. bool oldFullscreen = mIsFullScreen;
  309. DWORD style = WS_VISIBLE | WS_CLIPCHILDREN | WS_POPUP;
  310. mDisplayFrequency = Math::roundToInt(refreshRate);
  311. mIsFullScreen = true;
  312. DEVMODE displayDeviceMode;
  313. memset(&displayDeviceMode, 0, sizeof(displayDeviceMode));
  314. displayDeviceMode.dmSize = sizeof(DEVMODE);
  315. displayDeviceMode.dmBitsPerPel = mColorDepth;
  316. displayDeviceMode.dmPelsWidth = width;
  317. displayDeviceMode.dmPelsHeight = height;
  318. displayDeviceMode.dmDisplayFrequency = mDisplayFrequency;
  319. displayDeviceMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
  320. // Move window to 0,0 before display switch
  321. SetWindowPos(mHWnd, HWND_TOPMOST, 0, 0, mWidth, mHeight, SWP_NOACTIVATE);
  322. if (ChangeDisplaySettingsEx(mDeviceName, &displayDeviceMode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL)
  323. {
  324. CM_EXCEPT(RenderingAPIException, "ChangeDisplaySettings failed");
  325. }
  326. HMONITOR hMonitor = outputInfo.getMonitorHandle();
  327. MONITORINFO monitorInfo;
  328. memset(&monitorInfo, 0, sizeof(MONITORINFO));
  329. monitorInfo.cbSize = sizeof(MONITORINFO);
  330. GetMonitorInfo(hMonitor, &monitorInfo);
  331. mTop = monitorInfo.rcMonitor.top;
  332. mLeft = monitorInfo.rcMonitor.left;
  333. mWidth = width;
  334. mHeight = height;
  335. SetWindowLong(mHWnd, GWL_STYLE, style);
  336. SetWindowPos(mHWnd, HWND_TOPMOST, mLeft, mTop, width, height, SWP_NOACTIVATE);
  337. }
  338. void Win32Window::setFullscreen(const VideoMode& mode, UINT32 refreshRateIdx)
  339. {
  340. THROW_IF_NOT_CORE_THREAD;
  341. const VideoOutputInfo& outputInfo = mode.getParentOutput();
  342. UINT32 monitorIdx = 0;
  343. for (UINT32 i = 0; i < outputInfo.getNumVideoModes(); i++)
  344. {
  345. if (&outputInfo.getVideoMode(i) == &mode)
  346. {
  347. monitorIdx = i;
  348. break;
  349. }
  350. }
  351. setFullscreen(mode.getWidth(), mode.getHeight(), mode.getRefreshRate(refreshRateIdx), monitorIdx);
  352. }
  353. void Win32Window::setWindowed()
  354. {
  355. THROW_IF_NOT_CORE_THREAD;
  356. if (!mIsFullScreen)
  357. return;
  358. mIsFullScreen = false;
  359. DWORD style = WS_VISIBLE | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW;
  360. // Drop out of fullscreen
  361. ChangeDisplaySettingsEx(mDeviceName, NULL, NULL, 0, NULL);
  362. // Calculate overall dimensions for requested client area
  363. unsigned int winWidth, winHeight;
  364. _adjustWindow(mWidth, mHeight, &winWidth, &winHeight);
  365. // Deal with centering when switching down to smaller resolution
  366. HMONITOR hMonitor = MonitorFromWindow(mHWnd, MONITOR_DEFAULTTONEAREST);
  367. MONITORINFO monitorInfo;
  368. memset(&monitorInfo, 0, sizeof(MONITORINFO));
  369. monitorInfo.cbSize = sizeof(MONITORINFO);
  370. GetMonitorInfo(hMonitor, &monitorInfo);
  371. LONG screenw = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
  372. LONG screenh = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
  373. int left = screenw > int(winWidth) ? ((screenw - int(winWidth)) / 2) : 0;
  374. int top = screenh > int(winHeight) ? ((screenh - int(winHeight)) / 2) : 0;
  375. SetWindowLong(mHWnd, GWL_STYLE, style);
  376. SetWindowPos(mHWnd, HWND_NOTOPMOST, left, top, winWidth, winHeight,
  377. SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOACTIVATE);
  378. _windowMovedOrResized();
  379. }
  380. bool Win32Window::isActive(void) const
  381. {
  382. if (isFullScreen())
  383. return isVisible();
  384. return mActive && isVisible();
  385. }
  386. bool Win32Window::isVisible() const
  387. {
  388. return (mHWnd && !IsIconic(mHWnd));
  389. }
  390. bool Win32Window::isClosed() const
  391. {
  392. return mClosed;
  393. }
  394. void Win32Window::move(INT32 left, INT32 top)
  395. {
  396. THROW_IF_NOT_CORE_THREAD;
  397. if (mHWnd && !mIsFullScreen)
  398. {
  399. mLeft = left;
  400. mTop = top;
  401. SetWindowPos(mHWnd, 0, left, top, 0, 0,
  402. SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  403. }
  404. }
  405. void Win32Window::resize(UINT32 width, UINT32 height)
  406. {
  407. THROW_IF_NOT_CORE_THREAD;
  408. if (mHWnd && !mIsFullScreen)
  409. {
  410. mWidth = width;
  411. mHeight = height;
  412. RECT rc = { 0, 0, width, height };
  413. AdjustWindowRect(&rc, GetWindowLong(mHWnd, GWL_STYLE), false);
  414. width = rc.right - rc.left;
  415. height = rc.bottom - rc.top;
  416. SetWindowPos(mHWnd, 0, 0, 0, width, height,
  417. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  418. }
  419. }
  420. void Win32Window::swapBuffers()
  421. {
  422. THROW_IF_NOT_CORE_THREAD;
  423. if (!mIsExternalGLControl) {
  424. SwapBuffers(mHDC);
  425. }
  426. }
  427. void Win32Window::copyToMemory(const PixelData &dst, FrameBuffer buffer)
  428. {
  429. THROW_IF_NOT_CORE_THREAD;
  430. if ((dst.getLeft() < 0) || (dst.getRight() > mWidth) ||
  431. (dst.getTop() < 0) || (dst.getBottom() > mHeight) ||
  432. (dst.getFront() != 0) || (dst.getBack() != 1))
  433. {
  434. CM_EXCEPT(InvalidParametersException, "Invalid box.");
  435. }
  436. if (buffer == FB_AUTO)
  437. {
  438. buffer = mIsFullScreen? FB_FRONT : FB_BACK;
  439. }
  440. GLenum format = BansheeEngine::GLPixelUtil::getGLOriginFormat(dst.getFormat());
  441. GLenum type = BansheeEngine::GLPixelUtil::getGLOriginDataType(dst.getFormat());
  442. if ((format == GL_NONE) || (type == 0))
  443. {
  444. CM_EXCEPT(InvalidParametersException, "Unsupported format.");
  445. }
  446. // Must change the packing to ensure no overruns!
  447. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  448. glReadBuffer((buffer == FB_FRONT)? GL_FRONT : GL_BACK);
  449. glReadPixels((GLint)dst.getLeft(), (GLint)dst.getTop(),
  450. (GLsizei)dst.getWidth(), (GLsizei)dst.getHeight(),
  451. format, type, dst.getData());
  452. // restore default alignment
  453. glPixelStorei(GL_PACK_ALIGNMENT, 4);
  454. //vertical flip
  455. {
  456. size_t rowSpan = dst.getWidth() * PixelUtil::getNumElemBytes(dst.getFormat());
  457. size_t height = dst.getHeight();
  458. UINT8 *tmpData = (UINT8*)cm_alloc<ScratchAlloc>((UINT32)(rowSpan * height));
  459. UINT8 *srcRow = (UINT8 *)dst.getData(), *tmpRow = tmpData + (height - 1) * rowSpan;
  460. while (tmpRow >= tmpData)
  461. {
  462. memcpy(tmpRow, srcRow, rowSpan);
  463. srcRow += rowSpan;
  464. tmpRow -= rowSpan;
  465. }
  466. memcpy(dst.getData(), tmpData, rowSpan * height);
  467. cm_free<ScratchAlloc>(tmpData);
  468. }
  469. }
  470. Vector2I Win32Window::screenToWindowPos(const Vector2I& screenPos) const
  471. {
  472. POINT pos;
  473. pos.x = screenPos.x;
  474. pos.y = screenPos.y;
  475. ScreenToClient(mHWnd, &pos);
  476. return Vector2I(pos.x, pos.y);
  477. }
  478. Vector2I Win32Window::windowToScreenPos(const Vector2I& windowPos) const
  479. {
  480. POINT pos;
  481. pos.x = windowPos.x;
  482. pos.y = windowPos.y;
  483. ClientToScreen(mHWnd, &pos);
  484. return Vector2I(pos.x, pos.y);
  485. }
  486. void Win32Window::getCustomAttribute( const String& name, void* pData ) const
  487. {
  488. if( name == "GLCONTEXT" ) {
  489. *static_cast<GLContext**>(pData) = mContext;
  490. return;
  491. } else if( name == "WINDOW" )
  492. {
  493. HWND *pHwnd = (HWND*)pData;
  494. *pHwnd = _getWindowHandle();
  495. return;
  496. }
  497. }
  498. void Win32Window::setActive( bool state )
  499. {
  500. THROW_IF_NOT_CORE_THREAD;
  501. if (mDeviceName != NULL && state == false)
  502. {
  503. HWND hActiveWindow = GetActiveWindow();
  504. char classNameSrc[_MAX_CLASS_NAME_ + 1];
  505. char classNameDst[_MAX_CLASS_NAME_ + 1];
  506. GetClassName(mHWnd, classNameSrc, _MAX_CLASS_NAME_);
  507. GetClassName(hActiveWindow, classNameDst, _MAX_CLASS_NAME_);
  508. if (strcmp(classNameDst, classNameSrc) == 0)
  509. {
  510. state = true;
  511. }
  512. }
  513. mActive = state;
  514. if( mIsFullScreen )
  515. {
  516. if( state == false )
  517. { //Restore Desktop
  518. ChangeDisplaySettingsEx(mDeviceName, NULL, NULL, 0, NULL);
  519. ShowWindow(mHWnd, SW_SHOWMINNOACTIVE);
  520. }
  521. else
  522. { //Restore App
  523. ShowWindow(mHWnd, SW_SHOWNORMAL);
  524. DEVMODE displayDeviceMode;
  525. memset(&displayDeviceMode, 0, sizeof(displayDeviceMode));
  526. displayDeviceMode.dmSize = sizeof(DEVMODE);
  527. displayDeviceMode.dmBitsPerPel = mColorDepth;
  528. displayDeviceMode.dmPelsWidth = mWidth;
  529. displayDeviceMode.dmPelsHeight = mHeight;
  530. displayDeviceMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
  531. if (mDisplayFrequency)
  532. {
  533. displayDeviceMode.dmDisplayFrequency = mDisplayFrequency;
  534. displayDeviceMode.dmFields |= DM_DISPLAYFREQUENCY;
  535. }
  536. ChangeDisplaySettingsEx(mDeviceName, &displayDeviceMode, NULL, CDS_FULLSCREEN, NULL);
  537. }
  538. }
  539. }
  540. void Win32Window::setHidden(bool hidden)
  541. {
  542. THROW_IF_NOT_CORE_THREAD;
  543. mHidden = hidden;
  544. if (!mIsExternal)
  545. {
  546. if (hidden)
  547. ShowWindow(mHWnd, SW_HIDE);
  548. else
  549. ShowWindow(mHWnd, SW_SHOWNORMAL);
  550. }
  551. }
  552. void Win32Window::_windowMovedOrResized()
  553. {
  554. if (!mHWnd || IsIconic(mHWnd))
  555. return;
  556. RECT rc;
  557. // top and left represent outer window position
  558. GetWindowRect(mHWnd, &rc);
  559. mTop = rc.top;
  560. mLeft = rc.left;
  561. // width and height represent drawable area only
  562. GetClientRect(mHWnd, &rc);
  563. mWidth = rc.right - rc.left;
  564. mHeight = rc.bottom - rc.top;
  565. RenderWindow::_windowMovedOrResized();
  566. }
  567. void Win32Window::_adjustWindow(unsigned int clientWidth, unsigned int clientHeight,
  568. unsigned int* winWidth, unsigned int* winHeight)
  569. {
  570. // NB only call this for non full screen
  571. RECT rc;
  572. SetRect(&rc, 0, 0, clientWidth, clientHeight);
  573. AdjustWindowRect(&rc, WS_VISIBLE | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, false);
  574. *winWidth = rc.right - rc.left;
  575. *winHeight = rc.bottom - rc.top;
  576. // adjust to monitor
  577. HMONITOR hMonitor = MonitorFromWindow(mHWnd, MONITOR_DEFAULTTONEAREST);
  578. // Get monitor info
  579. MONITORINFO monitorInfo;
  580. memset(&monitorInfo, 0, sizeof(MONITORINFO));
  581. monitorInfo.cbSize = sizeof(MONITORINFO);
  582. GetMonitorInfo(hMonitor, &monitorInfo);
  583. LONG maxW = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
  584. LONG maxH = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
  585. if (*winWidth > (unsigned int)maxW)
  586. *winWidth = maxW;
  587. if (*winHeight > (unsigned int)maxH)
  588. *winHeight = maxH;
  589. }
  590. }