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