win32WindowMgr.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  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. // ------------------------------------------------------------------------
  29. void CloseSplashWindow(HINSTANCE hinst);
  30. PlatformWindowManager * CreatePlatformWindowManager()
  31. {
  32. return new Win32WindowManager();
  33. }
  34. // ------------------------------------------------------------------------
  35. Win32WindowManager::Win32WindowManager()
  36. {
  37. // Register in the process list.
  38. Process::notify(this, &Win32WindowManager::_process, PROCESS_INPUT_ORDER);
  39. // Init our list of allocated windows.
  40. mWindowListHead = NULL;
  41. // By default, we have no parent window.
  42. mParentWindow = NULL;
  43. mCurtainWindow = NULL;
  44. mOffscreenRender = false;
  45. }
  46. Win32WindowManager::~Win32WindowManager()
  47. {
  48. // Get ourselves off the process list.
  49. Process::remove(this, &Win32WindowManager::_process);
  50. // Kill all our windows first.
  51. while(mWindowListHead)
  52. // The destructors update the list, so this works just fine.
  53. delete mWindowListHead;
  54. }
  55. RectI Win32WindowManager::getPrimaryDesktopArea()
  56. {
  57. RECT primaryWorkRect;
  58. SystemParametersInfo(SPI_GETWORKAREA, 0, &primaryWorkRect, 0);
  59. RectI res;
  60. res.point.x = primaryWorkRect.left;
  61. res.point.y = primaryWorkRect.top;
  62. res.extent.x = primaryWorkRect.right - primaryWorkRect.left;
  63. res.extent.y = primaryWorkRect.bottom - primaryWorkRect.top;
  64. return res;
  65. }
  66. Point2I Win32WindowManager::getDesktopResolution()
  67. {
  68. DEVMODE devMode;
  69. dMemset( &devMode, 0, sizeof( devMode ) );
  70. devMode.dmSize = sizeof( devMode );
  71. if (!::EnumDisplaySettings(NULL, ENUM_REGISTRY_SETTINGS, &devMode))
  72. return Point2I(-1,-1);
  73. // Return Resolution
  74. return Point2I(devMode.dmPelsWidth, devMode.dmPelsHeight);
  75. }
  76. S32 Win32WindowManager::getDesktopBitDepth()
  77. {
  78. DEVMODE devMode;
  79. dMemset( &devMode, 0, sizeof( devMode ) );
  80. devMode.dmSize = sizeof( devMode );
  81. if (!::EnumDisplaySettings(NULL, ENUM_REGISTRY_SETTINGS, &devMode))
  82. return -1;
  83. // Return Bits per Pixel
  84. return (S32)devMode.dmBitsPerPel;
  85. }
  86. BOOL Win32WindowManager::MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData )
  87. {
  88. Vector<RectI> * regions = (Vector<RectI>*)dwData;
  89. regions->increment();
  90. regions->last().point.x = lprcMonitor->left;
  91. regions->last().point.y = lprcMonitor->top;
  92. regions->last().extent.x = lprcMonitor->right - lprcMonitor->left;
  93. regions->last().extent.y = lprcMonitor->bottom - lprcMonitor->top;
  94. return true;
  95. }
  96. void Win32WindowManager::getMonitorRegions(Vector<RectI> &regions)
  97. {
  98. EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (U32)(void*)&regions);
  99. }
  100. void Win32WindowManager::getWindows(VectorPtr<PlatformWindow*> &windows)
  101. {
  102. Win32Window *win = mWindowListHead;
  103. while(win)
  104. {
  105. windows.push_back(win);
  106. win = win->mNextWindow;
  107. }
  108. }
  109. PlatformWindow *Win32WindowManager::createWindow(GFXDevice *device, const GFXVideoMode &mode)
  110. {
  111. // Do the allocation.
  112. Win32Window *w32w = new Win32Window();
  113. w32w->setOffscreenRender(mOffscreenRender);
  114. w32w->mWindowId = getNextId();
  115. w32w->mOwningManager = this;
  116. // Link into our list of windows.
  117. linkWindow(w32w);
  118. DWORD dwExStyle;
  119. DWORD dwStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
  120. dwStyle |= WS_OVERLAPPEDWINDOW | WS_THICKFRAME | WS_CAPTION;
  121. dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
  122. // If we're parented, we want a different set of window styles.
  123. if(mParentWindow)
  124. dwStyle = WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CHILDWINDOW;
  125. if (mOffscreenRender)
  126. {
  127. dwStyle = WS_OVERLAPPEDWINDOW;
  128. dwExStyle = 0;
  129. }
  130. // Create the window handle
  131. w32w->mWindowHandle = CreateWindowEx(
  132. dwExStyle,
  133. Win32Window::getWindowClassName(), //class name
  134. String( getEngineProductString() ).utf16(), //window title
  135. dwStyle, //style - need clip siblings/children for opengl
  136. 0,
  137. 0,
  138. 0,
  139. 0,
  140. mParentWindow, //parent window
  141. NULL, //menu? No.
  142. NULL, //the hInstance
  143. NULL ); //no funky params
  144. // Note the style we created with so we can switch back to it when we're
  145. // done with full-screen mode.
  146. w32w->mWindowedWindowStyle = dwStyle;
  147. // Set the video mode on the window
  148. w32w->setVideoMode(mode);
  149. // Associate our window struct with the HWND.
  150. SetWindowLongPtrW(w32w->mWindowHandle, GWLP_USERDATA, (LONG)w32w);
  151. // Do some error checking.
  152. AssertFatal(w32w->mWindowHandle != NULL, "Win32WindowManager::createWindow - Could not create window!");
  153. if(w32w->mWindowHandle == NULL)
  154. {
  155. Con::errorf("Win32WindowManager::createWindow - Could not create window!");
  156. delete w32w;
  157. return NULL;
  158. }
  159. // If we're not rendering offscreen, make sure our window is shown and drawn to.
  160. if (!mOffscreenRender)
  161. ShowWindow( w32w->mWindowHandle, SW_SHOWDEFAULT );
  162. // Close any splash screen we created
  163. CloseSplashWindow(winState.appInstance);
  164. // Bind the window to the specified device.
  165. if(device)
  166. {
  167. w32w->mDevice = device;
  168. w32w->mTarget = device->allocWindowTarget(w32w);
  169. AssertISV(w32w->mTarget,
  170. "Win32WindowManager::createWindow - failed to get a window target back from the device.");
  171. }
  172. else
  173. {
  174. Con::warnf("Win32WindowManager::createWindow - created a window with no device!");
  175. }
  176. // Update it if needed.
  177. UpdateWindow( w32w->mWindowHandle );
  178. return w32w;
  179. }
  180. void Win32WindowManager::setParentWindow(void* newParent)
  181. {
  182. Con::printf( "Setting parent HWND: %d", newParent );
  183. mParentWindow = (HWND)newParent;
  184. if( mWindowListHead && mWindowListHead->mWindowHandle )
  185. ::SetParent( mWindowListHead->mWindowHandle, mParentWindow);
  186. }
  187. void* Win32WindowManager::getParentWindow()
  188. {
  189. return (void*)mParentWindow;
  190. }
  191. void Win32WindowManager::_process()
  192. {
  193. MSG msg;
  194. bool _blocking = false;
  195. // CodeReview [tom, 4/30/2007] Maintaining two completely separate message
  196. // handlers that are essentially the same is silly. The first one never
  197. // seems to run as _blocking is hard coded to false above, so is this even
  198. // needed ? If it is, this should be rewritten to use the one loop that
  199. // adjusts as needed based on _blocking and Journal::IsPlaying()
  200. if (_blocking && !Journal::IsPlaying())
  201. {
  202. // In blocking mode, we process one message at a time.
  203. if (GetMessage(&msg, NULL, 0, 0))
  204. {
  205. bool noTranslate = false;
  206. Win32Window *w32w = mWindowListHead;
  207. while(w32w)
  208. {
  209. noTranslate = w32w->translateMessage(msg);
  210. if(noTranslate) break;
  211. w32w = w32w->mNextWindow;
  212. }
  213. if(! noTranslate)
  214. {
  215. TranslateMessage(&msg);
  216. DispatchMessage(&msg);
  217. }
  218. }
  219. else
  220. // This should be WM_QUIT
  221. Dispatch(ImmediateDispatch,0,msg.message,msg.wParam,msg.lParam);
  222. }
  223. else
  224. {
  225. // Process all queued up messages
  226. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  227. {
  228. bool translated = false;
  229. // Win32Window *w32w = mWindowListHead;
  230. // while(w32w)
  231. // {
  232. // noTranslate = w32w->translateMessage(msg);
  233. // if(noTranslate) break;
  234. // w32w = w32w->mNextWindow;
  235. // }
  236. // [tom, 4/30/2007] I think this should work, but leaving the above commented
  237. // out just in case this is actually fubared with multiple windows.
  238. Win32Window* window = (Win32Window*)(GetWindowLong(msg.hwnd, GWL_USERDATA));
  239. if(window)
  240. translated = window->translateMessage(msg);
  241. if(! translated)
  242. {
  243. // Win32Window::translateMessage() will post a WM_COMMAND event for
  244. // translated accelerator events, so dispatching again will cause a
  245. // the input event to be dispatched, which is usually not what we want.
  246. TranslateMessage(&msg);
  247. DispatchMessage(&msg);
  248. }
  249. if (msg.message == WM_QUIT)
  250. {
  251. Dispatch(ImmediateDispatch,0,msg.message,msg.wParam,msg.lParam);
  252. break;
  253. }
  254. }
  255. }
  256. // Dispatch any delayed events
  257. while (DispatchNext());
  258. // Fire off idle events for every window.
  259. Win32Window *w32w = mWindowListHead;
  260. while(w32w)
  261. {
  262. w32w->idleEvent.trigger();
  263. w32w = w32w->mNextWindow;
  264. }
  265. }
  266. PlatformWindow * Win32WindowManager::getWindowById( WindowId id )
  267. {
  268. // Walk the list and find the matching id, if any.
  269. Win32Window *win = mWindowListHead;
  270. while(win)
  271. {
  272. if(win->getWindowId() == id)
  273. return win;
  274. win = win->mNextWindow;
  275. }
  276. return NULL;
  277. }
  278. PlatformWindow * Win32WindowManager::getFirstWindow()
  279. {
  280. return mWindowListHead != NULL ? mWindowListHead : NULL;
  281. }
  282. PlatformWindow* Win32WindowManager::getFocusedWindow()
  283. {
  284. Win32Window* window = mWindowListHead;
  285. while( window )
  286. {
  287. if( window->isFocused() )
  288. return window;
  289. window = window->mNextWindow;
  290. }
  291. return NULL;
  292. }
  293. void Win32WindowManager::linkWindow( Win32Window *w )
  294. {
  295. w->mNextWindow = mWindowListHead;
  296. mWindowListHead = w;
  297. }
  298. void Win32WindowManager::unlinkWindow( Win32Window *w )
  299. {
  300. Win32Window **walk = &mWindowListHead;
  301. while(*walk)
  302. {
  303. if(*walk != w)
  304. {
  305. // Advance to next item in list.
  306. walk = &(*walk)->mNextWindow;
  307. continue;
  308. }
  309. // Got a match - unlink and return.
  310. *walk = (*walk)->mNextWindow;
  311. return;
  312. }
  313. }
  314. void Win32WindowManager::_processCmdLineArgs( const S32 argc, const char **argv )
  315. {
  316. if (argc > 1)
  317. {
  318. for (int i = 1; i < argc; i++)
  319. {
  320. if ( dStrnicmp( argv[i], "-window", 7 ) == 0 )
  321. {
  322. i++;
  323. if ( i >= argc )
  324. {
  325. Con::errorf( "Command line error: -window requires an argument" );
  326. break;
  327. }
  328. S32 hwnd = dAtoi( argv[i] );
  329. if ( hwnd == 0 || hwnd == S32_MAX )
  330. {
  331. Con::errorf( "Command line error: -window requires a number, found [%s]", argv[i] );
  332. break;
  333. }
  334. mParentWindow = (HWND)hwnd;
  335. Con::printf( "HWND from command line: %d", hwnd );
  336. }
  337. if ( dStrnicmp( argv[i], "-offscreen", 10 ) == 0 )
  338. {
  339. mOffscreenRender = true;
  340. }
  341. }
  342. }
  343. }
  344. void Win32WindowManager::lowerCurtain()
  345. {
  346. if(mCurtainWindow)
  347. return;
  348. // For now just grab monitor of the first window... we may need to
  349. // beef this up later on, maybe by passing in the window that's entering
  350. // leaving full-screen to lowerCurtain.
  351. HMONITOR hMon = MonitorFromWindow(mWindowListHead->getHWND(), MONITOR_DEFAULTTOPRIMARY);
  352. // Get the monitor's extents.
  353. MONITORINFO monInfo;
  354. dMemset(&monInfo, 0, sizeof MONITORINFO);
  355. monInfo.cbSize = sizeof MONITORINFO;
  356. GetMonitorInfo(hMon, &monInfo);
  357. mCurtainWindow = CreateWindow(Win32Window::getCurtainWindowClassName(),
  358. dT(""), (WS_POPUP | WS_MAXIMIZE | WS_VISIBLE),
  359. monInfo.rcWork.left, monInfo.rcWork.top,
  360. monInfo.rcWork.right - monInfo.rcWork.left,
  361. monInfo.rcWork.bottom - monInfo.rcWork.top,
  362. NULL, NULL, NULL, NULL);
  363. if (!mOffscreenRender)
  364. SetWindowPos(mCurtainWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  365. }
  366. void Win32WindowManager::raiseCurtain()
  367. {
  368. if(!mCurtainWindow)
  369. return;
  370. DestroyWindow(mCurtainWindow);
  371. mCurtainWindow = NULL;
  372. }