Torque3D Documentation / _generateds / win32WindowMgr.cpp

win32WindowMgr.cpp

Engine/source/windowManager/win32/win32WindowMgr.cpp

More...

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> &regions)
196{
197   EnumDisplayMonitors(NULL, NULL, MonitorRegionEnumProc, (U32)(void*)&regions);
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