win32WindowMgr.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platformWin32/platformWin32.h"
  23. #include "windowManager/win32/win32WindowMgr.h"
  24. #include "gfx/gfxDevice.h"
  25. #include "windowManager/win32/winDispatch.h"
  26. #include "core/util/journal/process.h"
  27. #include "core/strings/unicode.h"
  28. #if !defined( TORQUE_SDL )
  29. // ------------------------------------------------------------------------
  30. void CloseSplashWindow(HINSTANCE hinst);
  31. PlatformWindowManager * CreatePlatformWindowManager()
  32. {
  33. return new Win32WindowManager();
  34. }
  35. // ------------------------------------------------------------------------
  36. Win32WindowManager::Win32WindowManager()
  37. {
  38. // Register in the process list.
  39. mOnProcessSignalSlot.setDelegate( this, &Win32WindowManager::_process );
  40. Process::notify( mOnProcessSignalSlot, PROCESS_INPUT_ORDER );
  41. // Init our list of allocated windows.
  42. mWindowListHead = NULL;
  43. // By default, we have no parent window.
  44. mParentWindow = NULL;
  45. mCurtainWindow = NULL;
  46. mOffscreenRender = false;
  47. mDisplayWindow = false;
  48. buildMonitorsList();
  49. }
  50. Win32WindowManager::~Win32WindowManager()
  51. {
  52. // Kill all our windows first.
  53. while(mWindowListHead)
  54. // The destructors update the list, so this works just fine.
  55. delete mWindowListHead;
  56. }
  57. RectI Win32WindowManager::getPrimaryDesktopArea()
  58. {
  59. RECT primaryWorkRect;
  60. SystemParametersInfo(SPI_GETWORKAREA, 0, &primaryWorkRect, 0);
  61. RectI res;
  62. res.point.x = primaryWorkRect.left;
  63. res.point.y = primaryWorkRect.top;
  64. res.extent.x = primaryWorkRect.right - primaryWorkRect.left;
  65. res.extent.y = primaryWorkRect.bottom - primaryWorkRect.top;
  66. return res;
  67. }
  68. Point2I Win32WindowManager::getDesktopResolution()
  69. {
  70. DEVMODE devMode;
  71. dMemset( &devMode, 0, sizeof( devMode ) );
  72. devMode.dmSize = sizeof( devMode );
  73. if (!::EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devMode))
  74. return Point2I(-1,-1);
  75. // Return Resolution
  76. return Point2I(devMode.dmPelsWidth, devMode.dmPelsHeight);
  77. }
  78. S32 Win32WindowManager::getDesktopBitDepth()
  79. {
  80. DEVMODE devMode;
  81. dMemset( &devMode, 0, sizeof( devMode ) );
  82. devMode.dmSize = sizeof( devMode );
  83. if (!::EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devMode))
  84. return -1;
  85. // Return Bits per Pixel
  86. return (S32)devMode.dmBitsPerPel;
  87. }
  88. BOOL Win32WindowManager::MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData )
  89. {
  90. Vector<MonitorInfo> * monitors = (Vector<MonitorInfo>*)dwData;
  91. // Fill out the new monitor structure
  92. monitors->increment();
  93. MonitorInfo& monitor = monitors->last();
  94. monitor.monitorHandle = hMonitor;
  95. monitor.region.point.x = lprcMonitor->left;
  96. monitor.region.point.y = lprcMonitor->top;
  97. monitor.region.extent.x = lprcMonitor->right - lprcMonitor->left;
  98. monitor.region.extent.y = lprcMonitor->bottom - lprcMonitor->top;
  99. MONITORINFOEX info;
  100. info.cbSize = sizeof(MONITORINFOEX);
  101. if(GetMonitorInfo(hMonitor, &info))
  102. {
  103. monitor.name = info.szDevice;
  104. }
  105. return true;
  106. }
  107. void Win32WindowManager::buildMonitorsList()
  108. {
  109. // Clear the list
  110. mMonitors.clear();
  111. // Enumerate all monitors
  112. EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (uintptr_t)&mMonitors);
  113. }
  114. S32 Win32WindowManager::findFirstMatchingMonitor(const char* name)
  115. {
  116. // Try and match the first part of the output device display name. For example,
  117. // a Monitor name of "\\.\DISPLAY1" might correspond to a display name
  118. // of "\\.\DISPLAY1\Monitor0". If two monitors are set up in duplicate mode then
  119. // they will have the same 'display' part in their display name.
  120. for(U32 i=0; i<mMonitors.size(); ++i)
  121. {
  122. if(dStrstr(name, mMonitors[i].name) == name)
  123. return i;
  124. }
  125. return -1;
  126. }
  127. U32 Win32WindowManager::getMonitorCount()
  128. {
  129. return mMonitors.size();
  130. }
  131. const char* Win32WindowManager::getMonitorName(U32 index)
  132. {
  133. if(index >= mMonitors.size())
  134. return "";
  135. return mMonitors[index].name.c_str();
  136. }
  137. RectI Win32WindowManager::getMonitorRect(U32 index)
  138. {
  139. if(index >= mMonitors.size())
  140. return RectI(0, 0, 0, 0);
  141. return mMonitors[index].region;
  142. }
  143. BOOL Win32WindowManager::MonitorRegionEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData )
  144. {
  145. Vector<RectI> * regions = (Vector<RectI>*)dwData;
  146. regions->increment();
  147. RectI& lastRegion = regions->last();
  148. lastRegion.point.x = lprcMonitor->left;
  149. lastRegion.point.y = lprcMonitor->top;
  150. lastRegion.extent.x = lprcMonitor->right - lprcMonitor->left;
  151. lastRegion.extent.y = lprcMonitor->bottom - lprcMonitor->top;
  152. return true;
  153. }
  154. void Win32WindowManager::getMonitorRegions(Vector<RectI> &regions)
  155. {
  156. EnumDisplayMonitors(NULL, NULL, MonitorRegionEnumProc, (U32)(void*)&regions);
  157. }
  158. void Win32WindowManager::getWindows(VectorPtr<PlatformWindow*> &windows)
  159. {
  160. Win32Window *win = mWindowListHead;
  161. while(win)
  162. {
  163. windows.push_back(win);
  164. win = win->mNextWindow;
  165. }
  166. }
  167. PlatformWindow *Win32WindowManager::createWindow(GFXDevice *device, const GFXVideoMode &mode)
  168. {
  169. // Do the allocation.
  170. Win32Window *w32w = new Win32Window();
  171. w32w->setOffscreenRender(mOffscreenRender);
  172. w32w->mWindowId = getNextId();
  173. w32w->mOwningManager = this;
  174. // Link into our list of windows.
  175. linkWindow(w32w);
  176. DWORD dwExStyle;
  177. DWORD dwStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
  178. dwStyle |= WS_OVERLAPPEDWINDOW | WS_THICKFRAME | WS_CAPTION;
  179. dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
  180. // If we're parented, we want a different set of window styles.
  181. if(mParentWindow)
  182. dwStyle = WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CHILDWINDOW;
  183. if (mOffscreenRender)
  184. {
  185. dwStyle = WS_OVERLAPPEDWINDOW;
  186. dwExStyle = 0;
  187. }
  188. // Create the window handle
  189. w32w->mWindowHandle = CreateWindowEx(
  190. dwExStyle,
  191. Win32Window::getWindowClassName(), //class name
  192. String( getEngineProductString() ).utf16(), //window title
  193. dwStyle, //style - need clip siblings/children for opengl
  194. 0,
  195. 0,
  196. 0,
  197. 0,
  198. mParentWindow, //parent window
  199. NULL, //menu? No.
  200. NULL, //the hInstance
  201. NULL ); //no funky params
  202. // Note the style we created with so we can switch back to it when we're
  203. // done with full-screen mode.
  204. w32w->mWindowedWindowStyle = dwStyle;
  205. // Set the video mode on the window
  206. w32w->setVideoMode(mode);
  207. // Associate our window struct with the HWND.
  208. SetWindowLongPtr(w32w->mWindowHandle, GWLP_USERDATA, (LONG_PTR)w32w);
  209. // Do some error checking.
  210. AssertFatal(w32w->mWindowHandle != NULL, "Win32WindowManager::createWindow - Could not create window!");
  211. if(w32w->mWindowHandle == NULL)
  212. {
  213. Con::errorf("Win32WindowManager::createWindow - Could not create window!");
  214. delete w32w;
  215. return NULL;
  216. }
  217. // If we're not rendering offscreen, make sure our window is shown and drawn to.
  218. w32w->setDisplayWindow(mDisplayWindow);
  219. if (!mOffscreenRender && mDisplayWindow)
  220. {
  221. ShowWindow( w32w->mWindowHandle, SW_SHOWDEFAULT );
  222. CloseSplashWindow(winState.appInstance);
  223. }
  224. // Bind the window to the specified device.
  225. if(device)
  226. {
  227. w32w->mDevice = device;
  228. w32w->mTarget = device->allocWindowTarget(w32w);
  229. AssertISV(w32w->mTarget,
  230. "Win32WindowManager::createWindow - failed to get a window target back from the device.");
  231. }
  232. else
  233. {
  234. Con::warnf("Win32WindowManager::createWindow - created a window with no device!");
  235. }
  236. // Update it if needed.
  237. UpdateWindow( w32w->mWindowHandle );
  238. return w32w;
  239. }
  240. void Win32WindowManager::setParentWindow(void* newParent)
  241. {
  242. Con::printf( "Setting parent HWND: %d", newParent );
  243. mParentWindow = (HWND)newParent;
  244. if( mWindowListHead && mWindowListHead->mWindowHandle )
  245. ::SetParent( mWindowListHead->mWindowHandle, mParentWindow);
  246. }
  247. void* Win32WindowManager::getParentWindow()
  248. {
  249. return (void*)mParentWindow;
  250. }
  251. void Win32WindowManager::_process()
  252. {
  253. MSG msg;
  254. bool _blocking = false;
  255. // CodeReview [tom, 4/30/2007] Maintaining two completely separate message
  256. // handlers that are essentially the same is silly. The first one never
  257. // seems to run as _blocking is hard coded to false above, so is this even
  258. // needed ? If it is, this should be rewritten to use the one loop that
  259. // adjusts as needed based on _blocking and Journal::IsPlaying()
  260. if (_blocking && !Journal::IsPlaying())
  261. {
  262. // In blocking mode, we process one message at a time.
  263. if (GetMessage(&msg, NULL, 0, 0))
  264. {
  265. bool noTranslate = false;
  266. Win32Window *w32w = mWindowListHead;
  267. while(w32w)
  268. {
  269. noTranslate = w32w->translateMessage(msg);
  270. if(noTranslate) break;
  271. w32w = w32w->mNextWindow;
  272. }
  273. if(! noTranslate)
  274. {
  275. TranslateMessage(&msg);
  276. DispatchMessage(&msg);
  277. }
  278. }
  279. else
  280. // This should be WM_QUIT
  281. Dispatch(ImmediateDispatch,0,msg.message,msg.wParam,msg.lParam);
  282. }
  283. else
  284. {
  285. // Process all queued up messages
  286. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  287. {
  288. bool translated = false;
  289. // Win32Window *w32w = mWindowListHead;
  290. // while(w32w)
  291. // {
  292. // noTranslate = w32w->translateMessage(msg);
  293. // if(noTranslate) break;
  294. // w32w = w32w->mNextWindow;
  295. // }
  296. // [tom, 4/30/2007] I think this should work, but leaving the above commented
  297. // out just in case this is actually fubared with multiple windows.
  298. Win32Window* window = (Win32Window*)(GetWindowLongPtr(msg.hwnd, GWLP_USERDATA));
  299. if(window)
  300. translated = window->translateMessage(msg);
  301. if(! translated)
  302. {
  303. // Win32Window::translateMessage() will post a WM_COMMAND event for
  304. // translated accelerator events, so dispatching again will cause a
  305. // the input event to be dispatched, which is usually not what we want.
  306. TranslateMessage(&msg);
  307. DispatchMessage(&msg);
  308. }
  309. if (msg.message == WM_QUIT)
  310. {
  311. Dispatch(ImmediateDispatch,0,msg.message,msg.wParam,msg.lParam);
  312. break;
  313. }
  314. }
  315. }
  316. // Dispatch any delayed events
  317. while (DispatchNext());
  318. // Fire off idle events for every window.
  319. Win32Window *w32w = mWindowListHead;
  320. while(w32w)
  321. {
  322. w32w->idleEvent.trigger();
  323. w32w = w32w->mNextWindow;
  324. }
  325. }
  326. PlatformWindow * Win32WindowManager::getWindowById( WindowId id )
  327. {
  328. // Walk the list and find the matching id, if any.
  329. Win32Window *win = mWindowListHead;
  330. while(win)
  331. {
  332. if(win->getWindowId() == id)
  333. return win;
  334. win = win->mNextWindow;
  335. }
  336. return NULL;
  337. }
  338. PlatformWindow * Win32WindowManager::getFirstWindow()
  339. {
  340. return mWindowListHead != NULL ? mWindowListHead : NULL;
  341. }
  342. PlatformWindow* Win32WindowManager::getFocusedWindow()
  343. {
  344. Win32Window* window = mWindowListHead;
  345. while( window )
  346. {
  347. if( window->isFocused() )
  348. return window;
  349. window = window->mNextWindow;
  350. }
  351. return NULL;
  352. }
  353. void Win32WindowManager::linkWindow( Win32Window *w )
  354. {
  355. w->mNextWindow = mWindowListHead;
  356. mWindowListHead = w;
  357. }
  358. void Win32WindowManager::unlinkWindow( Win32Window *w )
  359. {
  360. Win32Window **walk = &mWindowListHead;
  361. while(*walk)
  362. {
  363. if(*walk != w)
  364. {
  365. // Advance to next item in list.
  366. walk = &(*walk)->mNextWindow;
  367. continue;
  368. }
  369. // Got a match - unlink and return.
  370. *walk = (*walk)->mNextWindow;
  371. return;
  372. }
  373. }
  374. void Win32WindowManager::_processCmdLineArgs( const S32 argc, const char **argv )
  375. {
  376. if (argc > 1)
  377. {
  378. for (S32 i = 1; i < argc; i++)
  379. {
  380. if ( dStrnicmp( argv[i], "-window", 7 ) == 0 )
  381. {
  382. i++;
  383. if ( i >= argc )
  384. {
  385. Con::errorf( "Command line error: -window requires an argument" );
  386. break;
  387. }
  388. S32 hwnd = dAtoi( argv[i] );
  389. if ( hwnd == 0 || hwnd == S32_MAX )
  390. {
  391. Con::errorf( "Command line error: -window requires a number, found [%s]", argv[i] );
  392. break;
  393. }
  394. mParentWindow = (HWND)hwnd;
  395. Con::printf( "HWND from command line: %d", hwnd );
  396. }
  397. if ( dStrnicmp( argv[i], "-offscreen", 10 ) == 0 )
  398. {
  399. mOffscreenRender = true;
  400. }
  401. }
  402. }
  403. }
  404. void Win32WindowManager::lowerCurtain()
  405. {
  406. if(mCurtainWindow)
  407. return;
  408. // For now just grab monitor of the first window... we may need to
  409. // beef this up later on, maybe by passing in the window that's entering
  410. // leaving full-screen to lowerCurtain.
  411. HMONITOR hMon = MonitorFromWindow(mWindowListHead->getHWND(), MONITOR_DEFAULTTOPRIMARY);
  412. // Get the monitor's extents.
  413. MONITORINFO monInfo;
  414. dMemset(&monInfo, 0, sizeof(MONITORINFO));
  415. monInfo.cbSize = sizeof(MONITORINFO);
  416. GetMonitorInfo(hMon, &monInfo);
  417. mCurtainWindow = CreateWindow(Win32Window::getCurtainWindowClassName(),
  418. dT(""), (WS_POPUP | WS_MAXIMIZE | WS_VISIBLE),
  419. monInfo.rcWork.left, monInfo.rcWork.top,
  420. monInfo.rcWork.right - monInfo.rcWork.left,
  421. monInfo.rcWork.bottom - monInfo.rcWork.top,
  422. NULL, NULL, NULL, NULL);
  423. if (!mOffscreenRender)
  424. SetWindowPos(mCurtainWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  425. }
  426. void Win32WindowManager::raiseCurtain()
  427. {
  428. if(!mCurtainWindow)
  429. return;
  430. DestroyWindow(mCurtainWindow);
  431. mCurtainWindow = NULL;
  432. }
  433. #endif