Torque3D Documentation / _generateds / win32Window.cpp

win32Window.cpp

Engine/source/windowManager/win32/win32Window.cpp

More...

Public Defines

Public Functions

DISPLAY_DEVICE
bool
isMenuItemIDEnabled(HMENU menu, U32 id)

Detailed Description

Public Defines

IDI_ICON1() 107
SCREENSAVER_QUERY_DENY() 0
SPI_GETSCREENSAVERRUNNING() 114

Public Variables

const UTF16 * _CurtainWindowClassName 
const UTF16 * _MainWindowClassName 

Public Functions

GetPrimaryDevice()

isMenuItemIDEnabled(HMENU menu, U32 id)

isScreenSaverRunning()

   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#if !defined(TORQUE_SDL)
  25
  26#include <windows.h>
  27#include <tchar.h>
  28#include <winuser.h>
  29#include "math/mMath.h"
  30#include "gfx/gfxDevice.h"
  31#include "gfx/gfxStructs.h"
  32
  33#include "windowManager/platformWindowMgr.h"
  34#include "windowManager/win32/win32Window.h"
  35#include "windowManager/win32/win32WindowMgr.h"
  36#include "windowManager/win32/win32CursorController.h"
  37#include "windowManager/win32/winDispatch.h"
  38
  39#include "platform/menus/popupMenu.h"
  40#include "platform/platformInput.h"
  41
  42// for winState structure
  43#include "platformWin32/platformWin32.h"
  44
  45const UTF16* _MainWindowClassName = L"TorqueJuggernaughtWindow";
  46const UTF16* _CurtainWindowClassName = L"TorqueJuggernaughtCurtainWindow";
  47
  48#define SCREENSAVER_QUERY_DENY 0 // Disable screensaver
  49
  50#ifndef IDI_ICON1 
  51#define IDI_ICON1 107
  52#endif
  53
  54static bool isScreenSaverRunning()
  55{
  56#ifndef SPI_GETSCREENSAVERRUNNING
  57#define SPI_GETSCREENSAVERRUNNING 114
  58#endif
  59   // Windows 2K, and higher. It might be better to hook into
  60   // the broadcast WM_SETTINGCHANGE message instead of polling for
  61   // the screen saver status.
  62   BOOL sreensaver = false;
  63   SystemParametersInfo(SPI_GETSCREENSAVERRUNNING,0,&sreensaver,0);
  64   return sreensaver;
  65}
  66
  67DISPLAY_DEVICE GetPrimaryDevice()
  68{
  69   int index = 0;
  70   DISPLAY_DEVICE dd;
  71   dd.cb = sizeof(DISPLAY_DEVICE);
  72
  73   while (EnumDisplayDevices(NULL, index++, &dd, 0))
  74   {
  75      if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) return dd;
  76   }
  77   return dd;
  78}
  79
  80Win32Window::Win32Window(): mMouseLockPosition(0,0),
  81mShouldLockMouse(false),
  82mMouseLocked(false),
  83mOwningManager(NULL),
  84mNextWindow(NULL),
  85mWindowHandle(NULL),
  86mOldParent(NULL),
  87mTarget(NULL),
  88mDevice(NULL),
  89mAccelHandle(NULL),
  90mSuppressReset(false),
  91mMenuHandle(NULL),
  92mWindowedWindowStyle(0),
  93mPosition(0,0),
  94mFullscreen(false)
  95{
  96   mCursorController = new Win32CursorController( this );
  97
  98   mVideoMode.bitDepth = 32;
  99   mVideoMode.fullScreen = false;
 100   mVideoMode.refreshRate = 60;
 101   mVideoMode.resolution.set(800,600);
 102
 103   _registerWindowClass();
 104}
 105
 106Win32Window::~Win32Window()
 107{
 108   if(mAccelHandle)
 109   {
 110      DestroyAcceleratorTable(mAccelHandle);
 111      mAccelHandle = NULL;
 112   }
 113
 114   // delete our win handle..
 115   DestroyWindow(mWindowHandle);
 116
 117   // unlink ourselves from the window list...
 118   AssertFatal(mOwningManager, "Win32Window::~Win32Window - orphan window, cannot unlink!");
 119   mOwningManager->unlinkWindow(this);
 120
 121   _unregisterWindowClass();
 122}
 123
 124void* Win32Window::getSystemWindow(const WindowSystem system)
 125{
 126   if( system == WindowSystem_Windows)
 127      return getHWND();
 128
 129     return NULL;
 130}
 131
 132GFXDevice * Win32Window::getGFXDevice()
 133{
 134   return mDevice;
 135}
 136
 137GFXWindowTarget * Win32Window::getGFXTarget()
 138{
 139   return mTarget;
 140}
 141
 142const GFXVideoMode & Win32Window::getVideoMode()
 143{
 144   return mVideoMode;
 145}
 146
 147void Win32Window::_setVideoMode( const GFXVideoMode &mode )
 148{
 149   bool needCurtain = ( mVideoMode.fullScreen != mode.fullScreen );
 150
 151   if( needCurtain )
 152   {
 153      Con::printf( "Win32Window::setVideoMode - invoking curtain" );
 154      mOwningManager->lowerCurtain();
 155   }
 156
 157   mVideoMode = mode;
 158   mSuppressReset = true;
 159
 160   // Can't switch to fullscreen while a child of another window
 161   if( mode.fullScreen && !Platform::getWebDeployment() && mOwningManager->getParentWindow() )
 162   {
 163      mOldParent = reinterpret_cast<HWND>( mOwningManager->getParentWindow() );
 164      mOwningManager->setParentWindow( NULL );
 165   }
 166   else if( !mode.fullScreen && mOldParent )
 167   {
 168      mOwningManager->setParentWindow( mOldParent );
 169      mOldParent = NULL;
 170   }
 171
 172   // Set our window to have the right style based on the mode
 173   if( mode.fullScreen && !Platform::getWebDeployment() && !mOffscreenRender )
 174   {
 175      WINDOWPLACEMENT wplacement = { sizeof( wplacement ) };
 176      DWORD dwStyle = GetWindowLong( getHWND(), GWL_STYLE );
 177      MONITORINFO mi = { sizeof(mi) };
 178
 179      if ( GetWindowPlacement( getHWND(), &wplacement ) && GetMonitorInfo( MonitorFromWindow( getHWND(), MONITOR_DEFAULTTOPRIMARY ), &mi ) )
 180      {
 181         DISPLAY_DEVICE dd = GetPrimaryDevice();
 182         DEVMODE dv;
 183         ZeroMemory( &dv, sizeof( dv ) );
 184         dv.dmSize = sizeof( DEVMODE );
 185         EnumDisplaySettings( dd.DeviceName, ENUM_CURRENT_SETTINGS, &dv );
 186         dv.dmPelsWidth = mode.resolution.x;
 187         dv.dmPelsHeight = mode.resolution.y;
 188         dv.dmBitsPerPel = mode.bitDepth;
 189         dv.dmDisplayFrequency = mode.refreshRate;
 190         dv.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
 191         ChangeDisplaySettings( &dv, CDS_FULLSCREEN );
 192         SetWindowLong( getHWND(), GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW );
 193         SetWindowPos( getHWND(), HWND_TOP,  mi.rcMonitor.left,
 194                                             mi.rcMonitor.top,
 195                                             mi.rcMonitor.right - mi.rcMonitor.left,
 196                                             mi.rcMonitor.bottom - mi.rcMonitor.top,
 197                                             SWP_NOOWNERZORDER | SWP_FRAMECHANGED );
 198      }
 199
 200      if( mDisplayWindow )
 201         ShowWindow( getHWND(), SW_SHOWNORMAL );
 202
 203      // Clear the menu bar from the window for full screen
 204      if( GetMenu( getHWND() ) )
 205         SetMenu( getHWND(), NULL );
 206
 207      // When switching to Fullscreen, reset device after setting style
 208      if( mTarget.isValid() )
 209         mTarget->resetMode();
 210
 211      mFullscreen = true;
 212   }
 213   else
 214   {
 215      DISPLAY_DEVICE dd = GetPrimaryDevice();
 216      DEVMODE dv;
 217      ZeroMemory( &dv, sizeof( dv ) );
 218      dv.dmSize = sizeof( DEVMODE );
 219      EnumDisplaySettings( dd.DeviceName, ENUM_CURRENT_SETTINGS, &dv );
 220
 221      if (  ( WindowManager->getDesktopResolution() != mode.resolution || 
 222            ( mode.resolution.x != dv.dmPelsWidth ) || ( mode.resolution.y != dv.dmPelsHeight ) ) )
 223         ChangeDisplaySettings( NULL, 0 );
 224
 225      // Reset device *first*, so that when we call setSize() and let it
 226      // access the monitor settings, it won't end up with our fullscreen
 227      // geometry that is just about to change.
 228
 229      if( mTarget.isValid() )
 230         mTarget->resetMode();
 231
 232      if ( !mOffscreenRender )
 233      {
 234         SetWindowLong( getHWND(), GWL_STYLE, mWindowedWindowStyle);
 235         SetWindowPos( getHWND(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
 236
 237         // Put back the menu bar, if any
 238         if(mMenuHandle)
 239         {
 240            SetMenu(getHWND(), mMenuHandle);
 241         }
 242      }
 243
 244      // Make sure we're the correct resolution for web deployment
 245      if (!Platform::getWebDeployment() || !mOwningManager->getParentWindow() || mOffscreenRender)
 246      {
 247         setSize(mode.resolution);
 248      }
 249      else
 250      {
 251         HWND parentWin = reinterpret_cast<HWND>( mOwningManager->getParentWindow() );
 252         RECT windowRect;
 253         GetClientRect( parentWin, &windowRect );
 254         Point2I res( windowRect.right - windowRect.left, windowRect.bottom - windowRect.top );
 255
 256         if ( res.x == 0 || res.y == 0 )
 257            setSize( mode.resolution ); // Must be too early in the window set up to obtain the parent's size.
 258         else
 259            setSize( res );
 260      }
 261
 262      if ( !mOffscreenRender )
 263      {
 264         // We have to force Win32 to update the window frame and make the window
 265         // visible and no longer topmost - this code might be possible to simplify.
 266         SetWindowPos( getHWND(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED );
 267
 268         if(mDisplayWindow)
 269            ShowWindow( getHWND(), SW_SHOWNORMAL );
 270      }
 271
 272      mFullscreen = false;
 273   }
 274
 275   mSuppressReset = false;
 276
 277   if( needCurtain )
 278      mOwningManager->raiseCurtain();
 279
 280   SetForegroundWindow( getHWND() );
 281}
 282
 283bool Win32Window::clearFullscreen()
 284{
 285   return true;
 286}
 287
 288bool Win32Window::isFullscreen()
 289{   
 290   return mFullscreen;
 291}
 292
 293void Win32Window::_setFullscreen(const bool fullscreen)
 294{
 295   if (fullscreen == mFullscreen)
 296      return;
 297
 298   mFullscreen = fullscreen;
 299   if(fullscreen && !mOffscreenRender)
 300   {
 301      Con::printf("Win32Window::setFullscreen (full) enter");
 302      SetWindowLong( getHWND(), GWL_STYLE, WS_POPUP|WS_SYSMENU );
 303      SetWindowPos( getHWND(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
 304   }
 305   else
 306   {
 307      Con::printf("Win32Window::setFullscreen (windowed) enter");
 308      if (!mOffscreenRender)
 309      {
 310         SetWindowLong( getHWND(), GWL_STYLE, mWindowedWindowStyle);
 311         SetWindowPos( getHWND(), HWND_NOTOPMOST, 0, 0, mVideoMode.resolution.x, mVideoMode.resolution.y, SWP_FRAMECHANGED | SWP_SHOWWINDOW);         
 312      }
 313
 314      setSize(mVideoMode.resolution);
 315
 316   }
 317   Con::printf("Win32Window::setFullscreen exit");   
 318}
 319
 320bool Win32Window::setCaption( const char *cap )
 321{
 322   return SetWindowTextA(mWindowHandle, cap);
 323}
 324
 325const char * Win32Window::getCaption()
 326{
 327   char buff[512];
 328   S32 strLen = GetWindowTextA(mWindowHandle, buff, 512);
 329
 330   if(strLen==0)
 331      return NULL;
 332
 333   return StringTable->insert(buff);
 334}
 335
 336void Win32Window::setFocus()
 337{
 338   ::SetFocus( mWindowHandle );
 339}
 340
 341void Win32Window::setClientExtent( const Point2I newExtent )
 342{
 343   Point2I oldExtent = getClientExtent();
 344   if (oldExtent == newExtent)
 345      return;   
 346
 347   RECT rtClient;
 348   DWORD Style, ExStyle;
 349   SetRect( &rtClient, 0, 0, newExtent.x, newExtent.y );
 350   Style = GetWindowLong( mWindowHandle, GWL_STYLE);
 351   ExStyle = GetWindowLong( mWindowHandle, GWL_EXSTYLE );
 352
 353   AdjustWindowRectEx( &rtClient, Style, getMenuHandle() != NULL, ExStyle );
 354   if( Style & WS_VSCROLL ) 
 355      rtClient.right += GetSystemMetrics( SM_CXVSCROLL );
 356   if( Style & WS_HSCROLL ) 
 357      rtClient.bottom += GetSystemMetrics( SM_CYVSCROLL );
 358
 359   SetWindowPos( mWindowHandle, NULL, 0, 0, rtClient.right - rtClient.left, rtClient.bottom - rtClient.top, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
 360}
 361
 362const Point2I Win32Window::getClientExtent()
 363{
 364   // Fetch Client Rect from Windows
 365   RECT clientRect;
 366   ::GetClientRect(mWindowHandle, &clientRect);
 367
 368   // Return as a Torque Point2I - We don't care about origin as it's always 0,0
 369   return Point2I(clientRect.right - clientRect.left, clientRect.bottom - clientRect.top);
 370}
 371
 372void Win32Window::setBounds( const RectI &newBounds )
 373{
 374   RECT newRect;
 375   newRect.left = newBounds.point.x;
 376   newRect.top  = newBounds.point.y;
 377   newRect.bottom = newRect.top + newBounds.extent.y;
 378   newRect.right  = newRect.left + newBounds.extent.x;
 379
 380   MoveWindow(mWindowHandle, newRect.left, newRect.top, newRect.right - newRect.left, newRect.bottom - newRect.top, true);
 381}
 382
 383const RectI Win32Window::getBounds() const
 384{
 385   // Fetch Window Rect from OS
 386   RECT windowRect;
 387   ::GetWindowRect(mWindowHandle, &windowRect);
 388
 389   // Return as a Torque RectI
 390   return RectI(windowRect.left,windowRect.top,windowRect.right - windowRect.left, windowRect.bottom - windowRect.top);   
 391}
 392
 393void Win32Window::setPosition( const Point2I newPosition )
 394{
 395   SetWindowPos( mWindowHandle, HWND_NOTOPMOST, newPosition.x, newPosition.y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE );
 396}
 397
 398const Point2I Win32Window::getPosition()
 399{
 400   RECT windowRect;
 401   GetWindowRect( mWindowHandle, &windowRect );
 402
 403   // Return position
 404   return Point2I(windowRect.left,windowRect.top);
 405}
 406
 407Point2I Win32Window::clientToScreen( const Point2I& pos )
 408{
 409   POINT p = { pos.x, pos.y };
 410   
 411   ClientToScreen( mWindowHandle, &p );
 412   return Point2I( p.x, p.y );
 413}
 414
 415Point2I Win32Window::screenToClient( const Point2I& pos )
 416{
 417   POINT p = { pos.x, pos.y };
 418   
 419   ScreenToClient( mWindowHandle, &p );
 420   return Point2I( p.x, p.y );
 421}
 422
 423void Win32Window::centerWindow()
 424{
 425   RECT newRect;
 426   GetWindowRect(mWindowHandle,&newRect);
 427   newRect.bottom -= newRect.top;
 428   newRect.right -= newRect.left;
 429   newRect.top    = 0;
 430   newRect.left   = 0;
 431
 432   HMONITOR hMon = MonitorFromWindow(mWindowHandle, MONITOR_DEFAULTTONEAREST);
 433
 434   // Get the monitor's extents.
 435   MONITORINFO monInfo;
 436   dMemset(&monInfo, 0, sizeof(MONITORINFO));
 437   monInfo.cbSize = sizeof(MONITORINFO);
 438   GetMonitorInfo(hMon, &monInfo);
 439
 440   // Calculate the offset to center the window in the working area
 441   S32 deltaX = ((monInfo.rcWork.right - monInfo.rcWork.left) / 2) - ((newRect.right - newRect.left) / 2);
 442   S32 deltaY = ((monInfo.rcWork.bottom - monInfo.rcWork.top) / 2) - ((newRect.bottom - newRect.top) / 2);
 443
 444   // Calculate the new left and top position for the window
 445   S32 newLeft = newRect.left + deltaX;
 446   S32 newTop  = newRect.top  + deltaY;
 447
 448   // Clamp these to be greater than 0 so that the top left corner is never offscreen
 449   newLeft = mClamp(newLeft, 0, newLeft);
 450   newTop  = mClamp(newLeft, 0, newTop);
 451
 452   // Calculate the new width and height
 453   S32 newWidth  = newRect.right - newRect.left;
 454   S32 newHeight = newRect.bottom - newRect.top;
 455
 456   // If the new width and height of the window is larger
 457   // than the working area of the monitor but is smaller
 458   // than the monitor size then have it max out at the
 459   // working area so that it will remain uncovered. We
 460   // leave it alone if it is bigger than the monitor size
 461   // (with a small fudge) to support multiple monitors.
 462   if (newLeft + newWidth > (monInfo.rcWork.right - monInfo.rcWork.left) &&
 463       newLeft + newWidth <= (monInfo.rcMonitor.right - monInfo.rcMonitor.left) + 4)
 464       newWidth = (monInfo.rcWork.right - monInfo.rcWork.left) - newLeft;
 465   if (newTop + newHeight > (monInfo.rcWork.bottom - monInfo.rcWork.top) &&
 466       newTop + newHeight <= (monInfo.rcMonitor.bottom - monInfo.rcMonitor.top) + 4)
 467       newHeight = (monInfo.rcWork.bottom - monInfo.rcWork.top) - newTop;
 468
 469   MoveWindow( mWindowHandle, newLeft, newTop, newWidth, newHeight, true );
 470
 471   // Make sure the resolution matches the client extent
 472   Point2I clientExt = getClientExtent();
 473   mVideoMode.resolution.set( clientExt.x, clientExt.y );
 474
 475   // Let GFX get an update about the new resolution
 476   if (mTarget.isValid())
 477      mTarget->resetMode();
 478}
 479
 480bool Win32Window::setSize( const Point2I &newSize )
 481{
 482   // Create the window rect (screen centered if not owned by a parent)
 483   RECT newRect;
 484   newRect.left = 0;
 485   newRect.top  = 0;
 486   newRect.bottom = newRect.top + newSize.y;
 487   newRect.right  = newRect.left + newSize.x;
 488
 489   // Adjust the window rect to ensure the client rectangle is the desired resolution
 490   AdjustWindowRect( &newRect, mWindowedWindowStyle, false);//(bool)(getMenuHandle() != NULL) );
 491
 492   // Center the window on the screen if we're not a child
 493   if( !mOwningManager->mParentWindow )
 494   {
 495      HMONITOR hMon = MonitorFromWindow(mWindowHandle, MONITOR_DEFAULTTONEAREST);
 496
 497      // Get the monitor's extents.
 498      MONITORINFO monInfo;
 499      dMemset(&monInfo, 0, sizeof(MONITORINFO));
 500      monInfo.cbSize = sizeof(MONITORINFO);
 501      GetMonitorInfo(hMon, &monInfo);
 502
 503      // Calculate the offset to center the window in the working area
 504      S32 deltaX = ((monInfo.rcWork.right - monInfo.rcWork.left) / 2) - ((newRect.right - newRect.left) / 2);
 505      S32 deltaY = ((monInfo.rcWork.bottom - monInfo.rcWork.top) / 2) - ((newRect.bottom - newRect.top) / 2);
 506
 507      // Calculate the new left and top position for the window
 508      S32 newLeft = newRect.left + deltaX;
 509      S32 newTop  = newRect.top  + deltaY;
 510
 511      // Clamp these to be greater than 0 so that the top left corner is never offscreen
 512      newLeft = mClamp(newLeft, 0, newLeft);
 513      newTop  = mClamp(newLeft, 0, newTop);
 514
 515      // Calculate the new width and height
 516      S32 newWidth  = newRect.right - newRect.left;
 517      S32 newHeight = newRect.bottom - newRect.top;
 518
 519      // If the new width and height of the window is larger
 520      // than the working area of the monitor but is smaller
 521      // than the monitor size then have it max out at the
 522      // working area so that it will remain uncovered. We
 523      // leave it alone if it is bigger than the monitor size
 524      // (with a small fudge) to support multiple monitors.
 525      if (newLeft + newWidth > (monInfo.rcWork.right - monInfo.rcWork.left) &&
 526          newLeft + newWidth <= (monInfo.rcMonitor.right - monInfo.rcMonitor.left) + 4)
 527          newWidth = (monInfo.rcWork.right - monInfo.rcWork.left) - newLeft;
 528      if (newTop + newHeight > (monInfo.rcWork.bottom - monInfo.rcWork.top) &&
 529          newTop + newHeight <= (monInfo.rcMonitor.bottom - monInfo.rcMonitor.top) + 4)
 530          newHeight = (monInfo.rcWork.bottom - monInfo.rcWork.top) - newTop;
 531
 532      MoveWindow( mWindowHandle, newLeft, newTop, newWidth, newHeight, true );
 533   }
 534   else // Just position it according to the mPosition plus new extent
 535      MoveWindow(mWindowHandle, newRect.left, newRect.top, newRect.right - newRect.left, newRect.bottom - newRect.top, true);
 536
 537   // Make sure the resolution matches the client extent
 538   Point2I clientExt = getClientExtent();
 539   mVideoMode.resolution.set( clientExt.x, clientExt.y );
 540
 541   // Let GFX get an update about the new resolution
 542   if (mTarget.isValid())
 543      mTarget->resetMode();
 544
 545   InvalidateRect( NULL, NULL, true );
 546
 547   return true;
 548}
 549
 550bool Win32Window::isOpen()
 551{
 552   return true;
 553}
 554
 555bool Win32Window::isVisible()
 556{
 557   // Is the window open and visible, ie. not minimized?
 558
 559   if(!mWindowHandle)
 560      return false;
 561
 562   if (mOffscreenRender)
 563      return true;
 564
 565   return IsWindowVisible(mWindowHandle) 
 566      && !IsIconic(mWindowHandle)
 567      && !isScreenSaverRunning();
 568}
 569
 570bool Win32Window::isFocused()
 571{
 572
 573   if (mOffscreenRender)
 574      return true;
 575
 576   // CodeReview This is enough to make the plugin and normal/editor scenarios
 577   // coexist but it seems brittle. I think we need a better way to detect
 578   // if we're the foreground window, maybe taking into account if any of our
 579   // window's parents are foreground? [bjg 4/30/07]
 580   if(mOwningManager->mParentWindow)
 581      return (GetFocus() == mWindowHandle || IsChild(mWindowHandle, GetFocus()));
 582   else
 583      return ((GetFocus() == mWindowHandle ||  IsChild(mWindowHandle, GetFocus())) && GetForegroundWindow() == mWindowHandle);
 584}
 585
 586bool Win32Window::isMinimized()
 587{
 588   if (mOffscreenRender)
 589      return false;
 590
 591    WINDOWPLACEMENT wd;
 592    if ( GetWindowPlacement( mWindowHandle, &wd ) )
 593    {
 594        return ( wd.showCmd == SW_SHOWMINIMIZED );
 595    }
 596
 597    return false;
 598}
 599
 600bool Win32Window::isMaximized()
 601{
 602   if (mOffscreenRender)
 603      return true;
 604
 605    WINDOWPLACEMENT wd;
 606    if ( GetWindowPlacement( mWindowHandle, &wd ) )
 607    {
 608        return ( wd.showCmd == SW_SHOWMAXIMIZED );
 609    }
 610
 611    return false;
 612}
 613
 614WindowId Win32Window::getWindowId()
 615{
 616   return mWindowId;
 617}
 618
 619void Win32Window::minimize()
 620{
 621   if (mOffscreenRender)
 622      return;
 623
 624   ShowWindow( mWindowHandle, SW_MINIMIZE );
 625}
 626
 627void Win32Window::maximize()
 628{
 629   if (mOffscreenRender)
 630      return;
 631
 632   ShowWindow( mWindowHandle, SW_MAXIMIZE );
 633}
 634
 635void Win32Window::restore()
 636{
 637   if (mOffscreenRender)
 638      return;
 639
 640   ShowWindow( mWindowHandle, SW_RESTORE );
 641}
 642
 643void Win32Window::hide()
 644{
 645   if (mOffscreenRender)
 646      return;
 647
 648   ShowWindow( mWindowHandle, SW_HIDE );
 649}
 650
 651void Win32Window::show()
 652{
 653   if (mOffscreenRender)
 654      return;
 655
 656   ShowWindow( mWindowHandle, SW_SHOWNORMAL );
 657}
 658
 659void Win32Window::close()
 660{
 661   delete this;
 662}
 663
 664void Win32Window::_registerWindowClass()
 665{
 666   // Check to see if it exists already.
 667   WNDCLASSEX classInfo;
 668   if (GetClassInfoEx(GetModuleHandle(NULL),_MainWindowClassName,&classInfo))
 669      return;
 670
 671   HMODULE appInstance = GetModuleHandle(NULL);
 672   HICON   appIcon = LoadIcon(appInstance, MAKEINTRESOURCE(IDI_ICON1));
 673
 674   // Window class shared by all MainWindow objects
 675   classInfo.lpszClassName = _MainWindowClassName;
 676   classInfo.cbSize        = sizeof(WNDCLASSEX);
 677   classInfo.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
 678   classInfo.lpfnWndProc   = (WNDPROC)WindowProc;
 679   classInfo.hInstance     = appInstance;       // Owner of this class
 680   classInfo.hIcon         = appIcon;           // Icon name
 681   classInfo.hIconSm       = appIcon;           // Icon name
 682   classInfo.hCursor       = LoadCursor(NULL, IDC_ARROW); // Cursor
 683   classInfo.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);    // Default color
 684   classInfo.lpszMenuName  = NULL;
 685   classInfo.cbClsExtra    = 0;
 686   classInfo.cbWndExtra    = 0;
 687   if (!RegisterClassEx(&classInfo))
 688      AssertISV(false,"Window class initialization failed");
 689
 690   classInfo.lpfnWndProc = DefWindowProc;
 691   classInfo.hCursor = NULL;
 692   classInfo.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
 693   classInfo.lpszClassName = _CurtainWindowClassName;
 694   if (!RegisterClassEx(&classInfo))
 695      AssertISV(false,"Curtain window class initialization failed");
 696}
 697
 698void Win32Window::_unregisterWindowClass()
 699{
 700   WNDCLASSEX classInfo;
 701   if (GetClassInfoEx(GetModuleHandle(NULL),_MainWindowClassName,&classInfo))
 702      UnregisterClass(_MainWindowClassName,GetModuleHandle(NULL));
 703   if (GetClassInfoEx(GetModuleHandle(NULL),_CurtainWindowClassName,&classInfo))
 704      UnregisterClass(_CurtainWindowClassName,GetModuleHandle(NULL));
 705}
 706
 707LRESULT PASCAL Win32Window::WindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
 708{
 709   // CodeReview [tom, 4/30/2007] The two casts here seem somewhat silly and redundant ?
 710   Win32Window* window = (Win32Window*)((PlatformWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA));
 711   const WindowId devId = window ? window->getWindowId() : 0;
 712
 713   if (window && window->getOffscreenRender())
 714      return DefWindowProc(hWnd, message, wParam, lParam);
 715
 716   switch (message)
 717   {
 718
 719   case WM_DISPLAYCHANGE:
 720      // Update the monitor list
 721      PlatformWindowManager::get()->buildMonitorsList();
 722
 723      if(window && window->isVisible() && !window->mSuppressReset && window->getVideoMode().bitDepth != wParam)
 724      {
 725         Con::warnf("Win32Window::WindowProc - resetting device due to display mode BPP change.");
 726         window->getGFXTarget()->resetMode();
 727      }
 728      break;
 729
 730   case WM_MOUSEACTIVATE:
 731      SetFocus(hWnd);
 732      return MA_ACTIVATE;
 733
 734   case WM_MOUSEMOVE:
 735      if (window && GetFocus() != hWnd && IsChild(hWnd, GetFocus()))
 736      {
 737         SetFocus(hWnd);
 738         break;
 739      }
 740
 741      // If our foreground window is the browser and we don't have focus grab it
 742      if (Platform::getWebDeployment() && GetFocus() != hWnd)
 743      {
 744         HWND phwnd = GetParent(hWnd);
 745         while (phwnd)
 746         {
 747            if (GetForegroundWindow() == phwnd)
 748            {
 749               SetFocus(hWnd);
 750               break;
 751            }
 752            phwnd = GetParent(phwnd);
 753         }
 754      }
 755      break;
 756
 757      // Associate the window pointer with this window
 758   case WM_CREATE:
 759      // CodeReview [tom, 4/30/2007] Why don't we just cast this to a LONG 
 760      //            instead of having a ton of essentially pointless casts ?
 761      SetWindowLongPtr(hWnd, GWLP_USERDATA,
 762         (LONG_PTR)((PlatformWindow*)((CREATESTRUCT*)lParam)->lpCreateParams));
 763      break;
 764
 765   case WM_SETFOCUS:
 766      // NOTE: if wParam is NOT equal to our window handle then we are GAINING focus
 767      Dispatch(DelayedDispatch, hWnd, message, wParam, lParam);
 768      return 0;
 769
 770   case WM_KILLFOCUS:
 771      // NOTE: if wParam is NOT equal to our window handle then we are LOSING focus
 772      Dispatch(DelayedDispatch, hWnd, message, wParam, lParam);
 773      return 0;
 774
 775      // The window is being dragged
 776   case WM_MOVE:
 777      if(!window)
 778         break;
 779
 780      window->mPosition.x = (int)LOWORD(lParam);
 781      window->mPosition.y = (int)HIWORD(lParam);
 782      return 0;
 783
 784      // Update viewport when the window moves
 785   case WM_SIZE:
 786      if(window && window->mSuppressReset)
 787         break;
 788
 789      // This is dispatched immediately to prevent a race condition with journaling and window minimizing
 790      if (wParam != SIZE_MINIMIZED && !Journal::IsPlaying()) 
 791         Dispatch( ImmediateDispatch, hWnd,message,wParam,lParam );
 792
 793      if(wParam != SIZE_MINIMIZED && window != NULL )
 794      {
 795         if(!window->mVideoMode.fullScreen)
 796         {
 797            U32 width = LOWORD( lParam );
 798            U32 height = HIWORD( lParam );
 799
 800            window->mVideoMode.resolution.set( width, height );
 801         }
 802
 803         if(window->getGFXTarget())
 804         {
 805            Con::warnf("Win32Window::WindowProc - resetting device due to window size change.");
 806            window->getGFXTarget()->resetMode();
 807         }
 808
 809         window->resizeEvent.trigger(window, true);
 810      }
 811      return 0;
 812
 813      // Limit resize to a safe minimum
 814   case WM_GETMINMAXINFO:
 815      MINMAXINFO *winfo;
 816      winfo = (MINMAXINFO*)(lParam);
 817      
 818      if(window && window->mMinimumSize.lenSquared() > 0)
 819      {
 820         winfo->ptMinTrackSize.x = window->mMinimumSize.x;
 821         winfo->ptMinTrackSize.y = window->mMinimumSize.y;
 822      }     
 823
 824      //Is the window size locked?
 825      if (window && window->isSizeLocked())
 826      {
 827         Point2I lockedSize = window->getLockedSize();
 828
 829         winfo->ptMinTrackSize.x = lockedSize.x;
 830         winfo->ptMinTrackSize.y = lockedSize.y;
 831         winfo->ptMaxTrackSize.x = lockedSize.x;
 832         winfo->ptMaxTrackSize.y = lockedSize.y;
 833      }
 834
 835      break;
 836
 837      // Override background erase so window doesn't get cleared
 838   case WM_ERASEBKGND:
 839      return 1;
 840
 841   case WM_MENUSELECT:
 842      winState.renderThreadBlocked = true;
 843      break;
 844
 845      // Refresh the window
 846   case WM_PAINT:
 847      // Use validate instead of begin/end paint, which seem to installs
 848      // some Dx clipping state that isn't getting restored properly
 849      ValidateRect(hWnd,0);
 850
 851      // Skip it if we're dispatching.
 852      if(Journal::IsDispatching())
 853         break;
 854
 855      if( window == NULL )
 856         break;
 857
 858      //// Default render if..
 859      //// 1. We have no device
 860      //// 2. We have a device but it's not allowing rendering
 861      if( !window->getGFXDevice() || !window->getGFXDevice()->allowRender() )
 862         window->defaultRender();
 863      if( winState.renderThreadBlocked )
 864         window->displayEvent.trigger(devId);
 865      break;
 866
 867      // Power shutdown query
 868   case WM_POWERBROADCAST: {
 869      if (wParam == PBT_APMQUERYSUSPEND)
 870         if (GetForegroundWindow() == hWnd)
 871            return BROADCAST_QUERY_DENY;
 872      break;
 873                     }
 874
 875                     // Screensaver activation and monitor power requests
 876   case WM_SYSCOMMAND:
 877      switch (wParam) {
 878   case SC_SCREENSAVE:
 879   case SC_MONITORPOWER:
 880      if (GetForegroundWindow() == hWnd)
 881         return SCREENSAVER_QUERY_DENY;
 882      break;
 883      }
 884      break;
 885
 886      // Menus
 887   case WM_COMMAND:
 888      {
 889         winState.renderThreadBlocked = false;
 890
 891         if( window == NULL )
 892            break;
 893
 894         // [tom, 8/21/2006] Pass off to the relevant PopupMenu if it's a menu
 895         // or accelerator command. PopupMenu will in turn hand off to script.
 896         //
 897         // Note: PopupMenu::handleSelect() will not do anything if the menu
 898         // item is disabled, so we don't need to deal with that here.
 899
 900         S32 numItems = GetMenuItemCount(window->getMenuHandle());
 901         for(S32 i = 0;i < numItems;i++)
 902         {
 903            MENUITEMINFOA mi;
 904            mi.cbSize = sizeof(mi);
 905            mi.fMask = MIIM_DATA;
 906            if(GetMenuItemInfoA(window->getMenuHandle(), i, TRUE, &mi))
 907            {
 908               if(mi.fMask & MIIM_DATA && mi.dwItemData != 0)
 909               {
 910                  PopupMenu *mnu = (PopupMenu *)mi.dwItemData;
 911
 912                  PopupMenu::smSelectionEventHandled = false;
 913                  PopupMenu::smPopupMenuEvent.trigger(mnu->getPopupGUID(), LOWORD(wParam));
 914                  if (PopupMenu::smSelectionEventHandled)
 915                     return 0;
 916               }
 917            }
 918         }
 919      }
 920      break;
 921
 922   case WM_INITMENUPOPUP:
 923      {
 924         HMENU menu = (HMENU)wParam;
 925         MENUINFO mi;
 926         mi.cbSize = sizeof(mi);
 927         mi.fMask = MIM_MENUDATA;
 928         if(GetMenuInfo(menu, &mi) && mi.dwMenuData != 0)
 929         {
 930            PopupMenu *pm = (PopupMenu *)mi.dwMenuData;
 931            if(pm != NULL)
 932               pm->onMenuSelect();
 933         }
 934      }
 935      break;
 936      // Some events need to be consumed as well as queued up
 937      // for later dispatch.
 938   case WM_CLOSE:
 939   case WM_MOUSEWHEEL:
 940#ifdef WM_MOUSEHWHEEL // Vista
 941   case WM_MOUSEHWHEEL:
 942#endif
 943
 944      // CodeReview This fixes some issues with inappropriate event handling
 945      //            around device resets and in full-screen mode but feels 
 946      //            heavy-handed. Is it clobbering something important?
 947      //            [bjg 6/13/07]
 948   case WM_KEYUP:
 949   case WM_KEYDOWN:
 950   case WM_SYSKEYUP:
 951   case WM_SYSKEYDOWN:
 952      Dispatch(DelayedDispatch,hWnd,message,wParam,lParam);
 953      return 0;
 954   }
 955
 956   // Queue up for later and invoke the Windows default handler.
 957   Dispatch(DelayedDispatch,hWnd,message,wParam,lParam);
 958   return DefWindowProc(hWnd, message, wParam, lParam);
 959}
 960
 961
 962void Win32Window::defaultRender()
 963{
 964   // Get Window Device Context
 965   HDC logoDC = GetDC(mWindowHandle);
 966
 967   // Get Window Rectangle
 968   RECT lRect;
 969   GetClientRect(mWindowHandle,&lRect);
 970
 971   // Fill with AppWorkspace color
 972   FillRect( logoDC, &lRect, (HBRUSH)GetSysColorBrush(COLOR_APPWORKSPACE) );
 973
 974   // Release Device Context
 975   ReleaseDC(mWindowHandle,logoDC);
 976}
 977
 978//-----------------------------------------------------------------------------
 979// Accelerators
 980//-----------------------------------------------------------------------------
 981
 982void Win32Window::addAccelerator(Accelerator &accel)
 983{
 984   ACCEL winAccel;
 985   winAccel.fVirt = FVIRTKEY;
 986   winAccel.cmd = accel.mID;
 987
 988   if(accel.mDescriptor.flags & SI_SHIFT)
 989      winAccel.fVirt |= FSHIFT;
 990   if(accel.mDescriptor.flags & SI_CTRL)
 991      winAccel.fVirt |= FCONTROL;
 992   if(accel.mDescriptor.flags & SI_ALT)
 993      winAccel.fVirt |= FALT;
 994
 995   winAccel.key = TranslateKeyCodeToOS(accel.mDescriptor.eventCode);
 996
 997   for(WinAccelList::iterator i = mWinAccelList.begin();i != mWinAccelList.end();++i)
 998   {
 999      if(i->cmd == winAccel.cmd)
1000      {
1001         // Already in list, just update it
1002         i->fVirt = winAccel.fVirt;
1003         i->key = winAccel.key;
1004         return;
1005      }
1006
1007      if(i->fVirt == winAccel.fVirt && i->key == winAccel.key)
1008      {
1009         // Existing accelerator in list, don't add this one
1010         return;
1011      }
1012   }
1013
1014   mWinAccelList.push_back(winAccel);
1015}
1016
1017void Win32Window::removeAccelerator(Accelerator &accel)
1018{
1019   for(WinAccelList::iterator i = mWinAccelList.begin();i != mWinAccelList.end();++i)
1020   {
1021      if(i->cmd == accel.mID)
1022      {
1023         mWinAccelList.erase(i);
1024         return;
1025      }
1026   }
1027}
1028
1029//-----------------------------------------------------------------------------
1030
1031static bool isMenuItemIDEnabled(HMENU menu, U32 id)
1032{
1033   S32 numItems = GetMenuItemCount(menu);
1034   for(S32 i = 0;i < numItems;i++)
1035   {
1036      MENUITEMINFOA mi;
1037      mi.cbSize = sizeof(mi);
1038      mi.fMask = MIIM_ID|MIIM_STATE|MIIM_SUBMENU|MIIM_DATA;
1039      if(GetMenuItemInfoA(menu, i, TRUE, &mi))
1040      {
1041         if(mi.fMask & MIIM_ID && mi.wID == id)
1042         {
1043            // This is an item on this menu
1044            return (mi.fMask & MIIM_STATE) && ! (mi.fState & MFS_DISABLED);
1045         }
1046
1047         if((mi.fMask & MIIM_SUBMENU) && mi.hSubMenu != 0 && (mi.fMask & MIIM_DATA) && mi.dwItemData != 0)
1048         {
1049            // This is a submenu, if it can handle this ID then recurse to find correct state
1050            PopupMenu *mnu = (PopupMenu *)mi.dwItemData;
1051            if(mnu->canHandleID(id))
1052               return isMenuItemIDEnabled(mi.hSubMenu, id);
1053         }
1054      }
1055   }
1056
1057   return false;
1058}
1059
1060bool Win32Window::isAccelerator(const InputEventInfo &info)
1061{
1062   U32 virt;
1063   virt = FVIRTKEY;
1064   if(info.modifier & SI_SHIFT)
1065      virt |= FSHIFT;
1066   if(info.modifier & SI_CTRL)
1067      virt |= FCONTROL;
1068   if(info.modifier & SI_ALT)
1069      virt |= FALT;
1070
1071   U8 keyCode = TranslateKeyCodeToOS(info.objInst);
1072
1073   for(S32 i = 0;i < mWinAccelList.size();++i)
1074   {
1075      const ACCEL &accel = mWinAccelList[i];
1076      if(accel.key == keyCode && accel.fVirt == virt && isMenuItemIDEnabled(getMenuHandle(), accel.cmd))
1077         return true;
1078   }
1079   return false;
1080}
1081
1082//-----------------------------------------------------------------------------
1083
1084void Win32Window::addAccelerators(AcceleratorList &list)
1085{
1086   if(mAccelHandle)
1087   {
1088      DestroyAcceleratorTable(mAccelHandle);
1089      mAccelHandle = NULL;
1090   }
1091
1092   for(AcceleratorList::iterator i = list.begin();i != list.end();++i)
1093   {
1094      addAccelerator(*i);
1095   }
1096
1097   if(mWinAccelList.size() > 0)
1098      mAccelHandle = CreateAcceleratorTable(&mWinAccelList[0], mWinAccelList.size());
1099}
1100
1101void Win32Window::removeAccelerators(AcceleratorList &list)
1102{
1103   if(mAccelHandle)
1104   {
1105      DestroyAcceleratorTable(mAccelHandle);
1106      mAccelHandle = NULL;
1107   }
1108
1109   for(AcceleratorList::iterator i = list.begin();i != list.end();++i)
1110   {
1111      removeAccelerator(*i);
1112   }
1113
1114   if(mWinAccelList.size() > 0)
1115      mAccelHandle = CreateAcceleratorTable(mWinAccelList.address(), mWinAccelList.size());
1116}
1117
1118bool Win32Window::translateMessage(MSG &msg)
1119{
1120   if(mAccelHandle == NULL || mWindowHandle == NULL || !mEnableAccelerators)
1121      return false;
1122
1123   S32 ret = TranslateAccelerator(mWindowHandle, mAccelHandle, &msg);
1124   return ret != 0;
1125}
1126
1127//-----------------------------------------------------------------------------
1128// Mouse Locking
1129//-----------------------------------------------------------------------------
1130
1131void Win32Window::setMouseLocked( bool enable )
1132{
1133
1134   if (mOffscreenRender)
1135      return;
1136
1137   // Maintain a good state without unnecessary 
1138   //  cursor hides/modifications
1139   if( enable && mMouseLocked && mShouldLockMouse )
1140      return;
1141   else if(!enable && !mMouseLocked && !mShouldLockMouse )
1142      return;
1143
1144   // Need to be focused to enable mouse lock
1145   // but we can disable it no problem if we're 
1146   // not focused
1147   if( !isFocused() && enable )
1148   {
1149      mShouldLockMouse = enable;
1150      return;
1151   }
1152
1153   // Set Flag
1154   mMouseLocked = enable;
1155
1156   if( enable )
1157   {
1158      getCursorPosition( mMouseLockPosition );
1159
1160      RECT r;
1161      GetWindowRect(getHWND(), &r);
1162
1163      // Hide the cursor before it's moved
1164      setCursorVisible( false );
1165
1166      // We have to nudge the cursor clip rect in a bit so we don't go out
1167      // side the bounds of the window... We'll just do it by 32 in all
1168      // directions, which will break for very small windows (< 200x200 or so)
1169      // but otherwise won't matter.
1170      RECT rCopy = r;
1171      rCopy.top  += 32; rCopy.bottom -= 64;
1172      rCopy.left += 32; rCopy.right  -= 64;
1173      ClipCursor(&rCopy);
1174
1175      S32 centerX = (r.right + r.left) >> 1;
1176      S32 centerY = ((r.bottom + r.top) >> 1);
1177
1178
1179      // Consume all existing mouse events and those posted to our own dispatch queue
1180      MSG msg;
1181      PeekMessage( &msg, 0,WM_MOUSEFIRST,WM_MOUSELAST , PM_QS_POSTMESSAGE | PM_NOYIELD | PM_REMOVE );
1182      RemoveMessages( NULL, WM_MOUSEMOVE, WM_MOUSEMOVE );
1183
1184      // Set the CursorPos
1185      SetCursorPos(centerX, centerY);
1186
1187      // reset should lock flag
1188      mShouldLockMouse = true;
1189   }
1190   else
1191   {
1192      // This belongs before the unlock code
1193      mShouldLockMouse = false;
1194
1195      ClipCursor(NULL);
1196      setCursorPosition( mMouseLockPosition.x,mMouseLockPosition.y );
1197
1198      // Consume all existing mouse events and those posted to our own dispatch queue
1199      MSG msg;
1200      PeekMessage( &msg, NULL,WM_MOUSEFIRST,WM_MOUSELAST , PM_QS_POSTMESSAGE | PM_NOYIELD | PM_REMOVE );
1201      RemoveMessages( NULL, WM_MOUSEMOVE, WM_MOUSEMOVE );
1202
1203      // Show the Cursor
1204      setCursorVisible( true );
1205
1206   }
1207}
1208
1209const UTF16 *Win32Window::getWindowClassName()
1210{
1211   return _MainWindowClassName;
1212}
1213
1214const UTF16 *Win32Window::getCurtainWindowClassName()
1215{
1216   return _CurtainWindowClassName;
1217}
1218
1219#endif
1220