llwindowwin32.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 
00034 #if LL_WINDOWS && !LL_MESA_HEADLESS
00035 
00036 #include "llwindowwin32.h"
00037 
00038 #include <commdlg.h>
00039 #include <WinUser.h>
00040 #include <mapi.h>
00041 #include <process.h>    // for _spawn
00042 #include <shellapi.h>
00043 #include <Imm.h>
00044 
00045 // Require DirectInput version 8
00046 #define DIRECTINPUT_VERSION 0x0800
00047 #include <dinput.h>
00048 
00049 
00050 #include "llkeyboardwin32.h"
00051 #include "llerror.h"
00052 #include "llgl.h"
00053 #include "llstring.h"
00054 #include "lldir.h"
00055 
00056 #include "llglheaders.h"
00057 
00058 #include "indra_constants.h"
00059 
00060 // culled from winuser.h
00061 #ifndef WM_MOUSEWHEEL /* Added to be compatible with later SDK's */
00062 const S32       WM_MOUSEWHEEL = 0x020A;
00063 #endif
00064 #ifndef WHEEL_DELTA /* Added to be compatible with later SDK's */
00065 const S32       WHEEL_DELTA = 120;     /* Value for rolling one detent */
00066 #endif
00067 const S32       MAX_MESSAGE_PER_UPDATE = 20;
00068 const S32       BITS_PER_PIXEL = 32;
00069 const S32       MAX_NUM_RESOLUTIONS = 32;
00070 const F32       ICON_FLASH_TIME = 0.5f;
00071 
00072 extern BOOL gDebugWindowProc;
00073 
00074 LPWSTR gIconResource = IDI_APPLICATION;
00075 
00076 LLW32MsgCallback gAsyncMsgCallback = NULL;
00077 
00078 //
00079 // LLWindowWin32
00080 //
00081 
00082 void show_window_creation_error(const char* title)
00083 {
00084         llwarns << title << llendl;
00085         shell_open( "help/window_creation_error.html");
00086 }
00087 
00088 //static
00089 BOOL LLWindowWin32::sIsClassRegistered = FALSE;
00090 
00091 BOOL    LLWindowWin32::sLanguageTextInputAllowed = TRUE;
00092 BOOL    LLWindowWin32::sWinIMEOpened = FALSE;
00093 HKL             LLWindowWin32::sWinInputLocale = 0;
00094 DWORD   LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE;
00095 DWORD   LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC;
00096 
00097 // The following class LLWinImm delegates Windows IMM APIs.
00098 // We need this because some language versions of Windows,
00099 // e.g., US version of Windows XP, doesn't install IMM32.DLL
00100 // as a default, and we can't link against imm32.lib statically.
00101 // I believe DLL loading of this type is best suited to do
00102 // in a static initialization of a class.  What I'm not sure is
00103 // whether it follows the Linden Conding Standard... 
00104 // See http://wiki.secondlife.com/wiki/Coding_standards#Static_Members
00105 
00106 class LLWinImm
00107 {
00108 public:
00109         static bool             isAvailable() { return sTheInstance.mHImmDll != NULL; }
00110 
00111 public:
00112         // Wrappers for IMM API.
00113         static BOOL             isIME(HKL hkl);                                                                                                                 
00114         static HIMC             getContext(HWND hwnd);                                                                                                  
00115         static BOOL             releaseContext(HWND hwnd, HIMC himc);
00116         static BOOL             getOpenStatus(HIMC himc);                                                                                               
00117         static BOOL             setOpenStatus(HIMC himc, BOOL status);                                                                  
00118         static BOOL             getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence);   
00119         static BOOL             setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence);               
00120         static BOOL             getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form);                                        
00121         static BOOL             setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form);                                        
00122 
00123 private:
00124         LLWinImm();
00125         ~LLWinImm();
00126 
00127 private:
00128         // Pointers to IMM API.
00129         BOOL            (WINAPI *mImmIsIME)(HKL);
00130         HIMC            (WINAPI *mImmGetContext)(HWND);
00131         BOOL            (WINAPI *mImmReleaseContext)(HWND, HIMC);
00132         BOOL            (WINAPI *mImmGetOpenStatus)(HIMC);
00133         BOOL            (WINAPI *mImmSetOpenStatus)(HIMC, BOOL);
00134         BOOL            (WINAPI *mImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD);
00135         BOOL            (WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD);
00136         BOOL            (WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
00137         BOOL            (WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
00138 
00139 private:
00140         HMODULE         mHImmDll;
00141         static LLWinImm sTheInstance;
00142 };
00143 
00144 LLWinImm LLWinImm::sTheInstance;
00145 
00146 LLWinImm::LLWinImm() : mHImmDll(NULL)
00147 {
00148         // Check system metrics 
00149         if ( !GetSystemMetrics( SM_DBCSENABLED ) )
00150                 return;
00151         
00152 
00153         mHImmDll = LoadLibraryA("Imm32");
00154         if (mHImmDll != NULL)
00155         {
00156                 mImmIsIME               = (BOOL (WINAPI *)(HKL))                    GetProcAddress(mHImmDll, "ImmIsIME");
00157                 mImmGetContext          = (HIMC (WINAPI *)(HWND))                   GetProcAddress(mHImmDll, "ImmGetContext");
00158                 mImmReleaseContext      = (BOOL (WINAPI *)(HWND, HIMC))             GetProcAddress(mHImmDll, "ImmReleaseContext");
00159                 mImmGetOpenStatus       = (BOOL (WINAPI *)(HIMC))                   GetProcAddress(mHImmDll, "ImmGetOpenStatus");
00160                 mImmSetOpenStatus       = (BOOL (WINAPI *)(HIMC, BOOL))             GetProcAddress(mHImmDll, "ImmSetOpenStatus");
00161                 mImmGetConversionStatus = (BOOL (WINAPI *)(HIMC, LPDWORD, LPDWORD)) GetProcAddress(mHImmDll, "ImmGetConversionStatus");
00162                 mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD))     GetProcAddress(mHImmDll, "ImmSetConversionStatus");
00163                 mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmGetCompositionWindow");
00164                 mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmSetCompositionWindow");
00165 
00166                 if (mImmIsIME == NULL ||
00167                         mImmGetContext == NULL ||
00168                         mImmReleaseContext == NULL ||
00169                         mImmGetOpenStatus == NULL ||
00170                         mImmSetOpenStatus == NULL ||
00171                         mImmGetConversionStatus == NULL ||
00172                         mImmSetConversionStatus == NULL ||
00173                         mImmGetCompostitionWindow == NULL ||
00174                         mImmSetCompostitionWindow == NULL)
00175                 {
00176                         // If any of the above API entires are not found, we can't use IMM API.  
00177                         // So, turn off the IMM support.  We should log some warning message in 
00178                         // the case, since it is very unusual; these APIs are available from 
00179                         // the beginning, and all versions of IMM32.DLL should have them all.  
00180                         // Unfortunately, this code may be executed before initialization of 
00181                         // the logging channel (llwarns), and we can't do it here...  Yes, this 
00182                         // is one of disadvantages to use static constraction to DLL loading. 
00183                         FreeLibrary(mHImmDll);
00184                         mHImmDll = NULL;
00185 
00186                         // If we unload the library, make sure all the function pointers are cleared
00187                         mImmIsIME = NULL;
00188                         mImmGetContext = NULL;
00189                         mImmReleaseContext = NULL;
00190                         mImmGetOpenStatus = NULL;
00191                         mImmSetOpenStatus = NULL;
00192                         mImmGetConversionStatus = NULL;
00193                         mImmSetConversionStatus = NULL;
00194                         mImmGetCompostitionWindow = NULL;
00195                         mImmSetCompostitionWindow = NULL;
00196                 }
00197         }
00198 }
00199 
00200 
00201 // static 
00202 BOOL    LLWinImm::isIME(HKL hkl)                                                                                                                        
00203 { 
00204         if ( sTheInstance.mImmIsIME )
00205                 return sTheInstance.mImmIsIME(hkl); 
00206         return FALSE;
00207 }
00208 
00209 // static 
00210 HIMC            LLWinImm::getContext(HWND hwnd)
00211 {
00212         if ( sTheInstance.mImmGetContext )
00213                 return sTheInstance.mImmGetContext(hwnd); 
00214         return 0;
00215 }
00216 
00217 //static 
00218 BOOL            LLWinImm::releaseContext(HWND hwnd, HIMC himc)
00219 { 
00220         if ( sTheInstance.mImmIsIME )
00221                 return sTheInstance.mImmReleaseContext(hwnd, himc); 
00222         return FALSE;
00223 }
00224 
00225 // static 
00226 BOOL            LLWinImm::getOpenStatus(HIMC himc)
00227 { 
00228         if ( sTheInstance.mImmGetOpenStatus )
00229                 return sTheInstance.mImmGetOpenStatus(himc); 
00230         return FALSE;
00231 }
00232 
00233 // static 
00234 BOOL            LLWinImm::setOpenStatus(HIMC himc, BOOL status)                                                                 
00235 { 
00236         if ( sTheInstance.mImmSetOpenStatus )
00237                 return sTheInstance.mImmSetOpenStatus(himc, status); 
00238         return FALSE;
00239 }
00240 
00241 // static 
00242 BOOL            LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence)  
00243 { 
00244         if ( sTheInstance.mImmGetConversionStatus )
00245                 return sTheInstance.mImmGetConversionStatus(himc, conversion, sentence); 
00246         return FALSE;
00247 }
00248 
00249 // static 
00250 BOOL            LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence)              
00251 { 
00252         if ( sTheInstance.mImmSetConversionStatus )
00253                 return sTheInstance.mImmSetConversionStatus(himc, conversion, sentence); 
00254         return FALSE;
00255 }
00256 
00257 // static 
00258 BOOL            LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)                                       
00259 { 
00260         if ( sTheInstance.mImmGetCompostitionWindow )
00261                 return sTheInstance.mImmGetCompostitionWindow(himc, form);      
00262         return FALSE;
00263 }
00264 
00265 // static 
00266 BOOL            LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)                                       
00267 { 
00268         if ( sTheInstance.mImmSetCompostitionWindow )
00269                 return sTheInstance.mImmSetCompostitionWindow(himc, form);      
00270         return FALSE;
00271 }
00272 
00273 
00274 // ----------------------------------------------------------------------------------------
00275 LLWinImm::~LLWinImm()
00276 {
00277         if (mHImmDll != NULL)
00278         {
00279                 FreeLibrary(mHImmDll);
00280                 mHImmDll = NULL;
00281         }
00282 }
00283 
00284 
00285 LPDIRECTINPUT8       g_pDI              = NULL;         
00286 LPDIRECTINPUTDEVICE8 g_pJoystick        = NULL;     
00287 BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance,
00288                                                                         VOID* pContext );
00289 BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi,
00290                                                                   VOID* pContext );
00291 
00292 
00293 LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width,
00294                                                          S32 height, U32 flags, 
00295                                                          BOOL fullscreen, BOOL clearBg,
00296                                                          BOOL disable_vsync, BOOL use_gl,
00297                                                          BOOL ignore_pixel_depth, S32 stereo_mode)
00298         : LLWindow(fullscreen, flags)
00299 {
00300         S32 i = 0;
00301         mIconResource = gIconResource;
00302         mOverrideAspectRatio = 0.f;
00303         mNativeAspectRatio = 0.f;
00304         mMousePositionModified = FALSE;
00305         mInputProcessingPaused = FALSE;
00306         mStereoMode = stereo_mode;
00307 
00308         // Initialize the keyboard
00309         gKeyboard = new LLKeyboardWin32();
00310 
00311         // Initialize (boot strap) the Language text input management,
00312         // based on the system's (user's) default settings.
00313         allowLanguageTextInput(FALSE);
00314 
00315         GLuint                  pixel_format;
00316         WNDCLASS                wc;
00317         DWORD                   dw_ex_style;
00318         DWORD                   dw_style;
00319         RECT                    window_rect;
00320 
00321         // Set the window title
00322         if (!title)
00323         {
00324                 mWindowTitle = new WCHAR[50];
00325                 wsprintf(mWindowTitle, L"OpenGL Window");
00326         }
00327         else
00328         {
00329                 mWindowTitle = new WCHAR[256]; // Assume title length < 255 chars.
00330                 mbstowcs(mWindowTitle, title, 255);
00331                 mWindowTitle[255] = 0;
00332         }
00333 
00334         // Set the window class name
00335         if (!name)
00336         {
00337                 mWindowClassName = new WCHAR[50];
00338                 wsprintf(mWindowClassName, L"OpenGL Window");
00339         }
00340         else
00341         {
00342                 mWindowClassName = new WCHAR[256]; // Assume title length < 255 chars.
00343                 mbstowcs(mWindowClassName, name, 255);
00344                 mWindowClassName[255] = 0;
00345         }
00346 
00347 
00348         // We're not clipping yet
00349         SetRect( &mOldMouseClip, 0, 0, 0, 0 );
00350 
00351         // Make an instance of our window then define the window class
00352         mhInstance = GetModuleHandle(NULL);
00353         mWndProc = NULL;
00354 
00355         mSwapMethod = SWAP_METHOD_UNDEFINED;
00356 
00357         // No WPARAM yet.
00358         mLastSizeWParam = 0;
00359 
00360         // Windows GDI rects don't include rightmost pixel
00361         window_rect.left = (long) 0;
00362         window_rect.right = (long) width;
00363         window_rect.top = (long) 0;
00364         window_rect.bottom = (long) height;
00365 
00366         // Grab screen size to sanitize the window
00367         S32 window_border_y = GetSystemMetrics(SM_CYBORDER);
00368         S32 virtual_screen_x = GetSystemMetrics(SM_XVIRTUALSCREEN); 
00369         S32 virtual_screen_y = GetSystemMetrics(SM_YVIRTUALSCREEN); 
00370         S32 virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
00371         S32 virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
00372 
00373         if (x < virtual_screen_x) x = virtual_screen_x;
00374         if (y < virtual_screen_y - window_border_y) y = virtual_screen_y - window_border_y;
00375 
00376         if (x + width > virtual_screen_x + virtual_screen_width) x = virtual_screen_x + virtual_screen_width - width;
00377         if (y + height > virtual_screen_y + virtual_screen_height) y = virtual_screen_y + virtual_screen_height - height;
00378 
00379         if (!sIsClassRegistered)
00380         {
00381                 // Force redraw when resized and create a private device context
00382 
00383                 // Makes double click messages.
00384                 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
00385 
00386                 // Set message handler function
00387                 wc.lpfnWndProc = (WNDPROC) mainWindowProc;
00388 
00389                 // unused
00390                 wc.cbClsExtra = 0;
00391                 wc.cbWndExtra = 0;
00392 
00393                 wc.hInstance = mhInstance;
00394                 wc.hIcon = LoadIcon(mhInstance, mIconResource);
00395 
00396                 // We will set the cursor ourselves
00397                 wc.hCursor = NULL;
00398 
00399                 // background color is not used
00400                 if (clearBg)
00401                 {
00402                         wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
00403                 }
00404                 else
00405                 {
00406                         wc.hbrBackground = (HBRUSH) NULL;
00407                 }
00408 
00409                 // we don't use windows menus
00410                 wc.lpszMenuName = NULL;
00411 
00412                 wc.lpszClassName = mWindowClassName;
00413 
00414                 if (!RegisterClass(&wc))
00415                 {
00416                         OSMessageBox("RegisterClass failed", "Error", OSMB_OK);
00417                         return;
00418                 }
00419                 sIsClassRegistered = TRUE;
00420         }
00421 
00422         //-----------------------------------------------------------------------
00423         // Get the current refresh rate
00424         //-----------------------------------------------------------------------
00425 
00426         DEVMODE dev_mode;
00427         DWORD current_refresh;
00428         if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
00429         {
00430                 current_refresh = dev_mode.dmDisplayFrequency;
00431                 mNativeAspectRatio = ((F32)dev_mode.dmPelsWidth) / ((F32)dev_mode.dmPelsHeight);
00432         }
00433         else
00434         {
00435                 current_refresh = 60;
00436         }
00437 
00438         //-----------------------------------------------------------------------
00439         // Drop resolution and go fullscreen
00440         // use a display mode with our desired size and depth, with a refresh
00441         // rate as close at possible to the users' default
00442         //-----------------------------------------------------------------------
00443         if (mFullscreen)
00444         {
00445                 BOOL success = FALSE;
00446                 DWORD closest_refresh = 0;
00447 
00448                 for (S32 mode_num = 0;; mode_num++)
00449                 {
00450                         if (!EnumDisplaySettings(NULL, mode_num, &dev_mode))
00451                         {
00452                                 break;
00453                         }
00454 
00455                         if (dev_mode.dmPelsWidth == width &&
00456                                 dev_mode.dmPelsHeight == height &&
00457                                 dev_mode.dmBitsPerPel == BITS_PER_PIXEL)
00458                         {
00459                                 success = TRUE;
00460                                 if ((dev_mode.dmDisplayFrequency - current_refresh)
00461                                         < (closest_refresh - current_refresh))
00462                                 {
00463                                         closest_refresh = dev_mode.dmDisplayFrequency;
00464                                 }
00465                         }
00466                 }
00467 
00468                 if (closest_refresh == 0)
00469                 {
00470                         llwarns << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << llendl;
00471                         success = FALSE;
00472                 }
00473 
00474                 // If we found a good resolution, use it.
00475                 if (success)
00476                 {
00477                         success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh);
00478                 }
00479 
00480                 // Keep a copy of the actual current device mode in case we minimize 
00481                 // and change the screen resolution.   JC
00482                 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode);
00483 
00484                 // If it failed, we don't want to run fullscreen
00485                 if (success)
00486                 {
00487                         mFullscreen = TRUE;
00488                         mFullscreenWidth   = dev_mode.dmPelsWidth;
00489                         mFullscreenHeight  = dev_mode.dmPelsHeight;
00490                         mFullscreenBits    = dev_mode.dmBitsPerPel;
00491                         mFullscreenRefresh = dev_mode.dmDisplayFrequency;
00492 
00493                         llinfos << "Running at " << dev_mode.dmPelsWidth
00494                                 << "x"   << dev_mode.dmPelsHeight
00495                                 << "x"   << dev_mode.dmBitsPerPel
00496                                 << " @ " << dev_mode.dmDisplayFrequency
00497                                 << llendl;
00498                 }
00499                 else
00500                 {
00501                         mFullscreen = FALSE;
00502                         mFullscreenWidth   = -1;
00503                         mFullscreenHeight  = -1;
00504                         mFullscreenBits    = -1;
00505                         mFullscreenRefresh = -1;
00506 
00507                         char error[256];        /* Flawfinder: ignore */
00508                         snprintf(error, sizeof(error), "Unable to run fullscreen at %d x %d.\nRunning in window.", width, height);      /* Flawfinder: ignore */
00509                         OSMessageBox(error, "Error", OSMB_OK);
00510                 }
00511         }
00512 
00513         //-----------------------------------------------------------------------
00514         // Resize window to account for borders
00515         //-----------------------------------------------------------------------
00516         if (mFullscreen)
00517         {
00518                 dw_ex_style = WS_EX_APPWINDOW;
00519                 dw_style = WS_POPUP;
00520 
00521                 // Move window borders out not to cover window contents
00522                 AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style);
00523         }
00524         else
00525         {
00526                 // Window with an edge
00527                 dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
00528                 dw_style = WS_OVERLAPPEDWINDOW;
00529         }
00530 
00531         //-----------------------------------------------------------------------
00532         // Create the window
00533         // Microsoft help indicates that GL windows must be created with
00534         // WS_CLIPSIBLINGS and WS_CLIPCHILDREN, but not CS_PARENTDC
00535         //-----------------------------------------------------------------------
00536         mWindowHandle = CreateWindowEx(dw_ex_style,
00537                 mWindowClassName,
00538                 mWindowTitle,
00539                 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style,
00540                 x,                                                                                              // x pos
00541                 y,                                                                                              // y pos
00542                 window_rect.right - window_rect.left,                   // width
00543                 window_rect.bottom - window_rect.top,                   // height
00544                 NULL,
00545                 NULL,
00546                 mhInstance,
00547                 NULL);
00548 
00549         if (!mWindowHandle)
00550         {
00551                 OSMessageBox("Window creation error", "Error", OSMB_OK);
00552                 return;
00553         }
00554 
00555         // TODO: add this after resolving _WIN32_WINNT issue
00556         //      if (!fullscreen)
00557         //      {
00558         //              TRACKMOUSEEVENT track_mouse_event;
00559         //              track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT );
00560         //              track_mouse_event.dwFlags = TME_LEAVE;
00561         //              track_mouse_event.hwndTrack = mWindowHandle;
00562         //              track_mouse_event.dwHoverTime = HOVER_DEFAULT;
00563         //              TrackMouseEvent( &track_mouse_event ); 
00564         //      }
00565 
00566         S32 pfdflags = PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
00567         if (use_gl)
00568         {
00569                 pfdflags |= PFD_SUPPORT_OPENGL;
00570 
00571                 //************ UMICH 3D LAB *************
00572                 // if our stereo mode is for active/clone mode, then
00573                 // we need to add a special flag to the pixel format
00574                 if (mStereoMode == STEREO_MODE_ACTIVE) { pfdflags |= PFD_STEREO; }
00575                 //************ UMICH 3D LAB *************
00576         }
00577 
00578         //-----------------------------------------------------------------------
00579         // Create GL drawing context
00580         //-----------------------------------------------------------------------
00581         PIXELFORMATDESCRIPTOR pfd =
00582         {
00583                 sizeof(PIXELFORMATDESCRIPTOR), 
00584                         1,
00585                         pfdflags, 
00586                         PFD_TYPE_RGBA,
00587                         BITS_PER_PIXEL,
00588                         0, 0, 0, 0, 0, 0,       // RGB bits and shift, unused
00589                         8,                                      // alpha bits
00590                         0,                                      // alpha shift
00591                         0,                                      // accum bits
00592                         0, 0, 0, 0,                     // accum RGBA
00593                         24,                                     // depth bits
00594                         8,                                      // stencil bits, avi added for stencil test
00595                         0,
00596                         PFD_MAIN_PLANE,
00597                         0,
00598                         0, 0, 0
00599         };
00600 
00601         if (!(mhDC = GetDC(mWindowHandle)))
00602         {
00603                 close();
00604                 OSMessageBox("Can't make GL device context", "Error", OSMB_OK);
00605                 return;
00606         }
00607 
00608         if (!(pixel_format = ChoosePixelFormat(mhDC, &pfd)))
00609         {
00610                 close();
00611                 OSMessageBox("Can't find suitable pixel format", "Error", OSMB_OK);
00612                 return;
00613         }
00614 
00615         // Verify what pixel format we actually received.
00616         if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR),
00617                 &pfd))
00618         {
00619                 close();
00620                 OSMessageBox("Can't get pixel format description", "Error", OSMB_OK);
00621                 return;
00622         }
00623 
00624         // sanity check pfd returned by Windows
00625         if (!ignore_pixel_depth && (pfd.cColorBits < 32))
00626         {
00627                 close();
00628                 OSMessageBox(
00629                         "Second Life requires True Color (32-bit) to run in a window.\n"
00630                         "Please go to Control Panels -> Display -> Settings and\n"
00631                         "set the screen to 32-bit color.\n"
00632                         "Alternately, if you choose to run fullscreen, Second Life\n"
00633                         "will automatically adjust the screen each time it runs.",
00634                         "Error",
00635                         OSMB_OK);
00636                 return;
00637         }
00638 
00639         if (!ignore_pixel_depth && (pfd.cAlphaBits < 8))
00640         {
00641                 close();
00642                 OSMessageBox(
00643                         "Second Life is unable to run because it can't get an 8 bit alpha\n"
00644                         "channel.  Usually this is due to video card driver issues.\n"
00645                         "Please make sure you have the latest video card drivers installed.\n"
00646                         "Also be sure your monitor is set to True Color (32-bit) in\n"
00647                         "Control Panels -> Display -> Settings.\n"
00648                         "If you continue to receive this message, contact customer service.",
00649                         "Error",
00650                         OSMB_OK);
00651                 return;
00652         }
00653 
00654         if (!SetPixelFormat(mhDC, pixel_format, &pfd))
00655         {
00656                 close();
00657                 OSMessageBox("Can't set pixel format", "Error", OSMB_OK);
00658                 return;
00659         }
00660 
00661         if (use_gl)
00662         {
00663                 if (!(mhRC = wglCreateContext(mhDC)))
00664                 {
00665                         close();
00666                         OSMessageBox("Can't create GL rendering context", "Error", OSMB_OK);
00667                         return;
00668                 }
00669 
00670                 if (!wglMakeCurrent(mhDC, mhRC))
00671                 {
00672                         close();
00673                         OSMessageBox("Can't activate GL rendering context", "Error", OSMB_OK);
00674                         return;
00675                 }
00676 
00677                 gGLManager.initWGL();
00678 
00679                 if (gGLManager.mHasWGLARBPixelFormat && (wglChoosePixelFormatARB != NULL))
00680                 {
00681                         // OK, at this point, use the ARB wglChoosePixelFormatsARB function to see if we
00682                         // can get exactly what we want.
00683                         GLint attrib_list[256];
00684                         S32 cur_attrib = 0;
00685 
00686                         attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB;
00687                         attrib_list[cur_attrib++] = 24;
00688 
00689                         attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB;
00690                         attrib_list[cur_attrib++] = 8;
00691 
00692                         attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB;
00693                         attrib_list[cur_attrib++] = GL_TRUE;
00694 
00695                         attrib_list[cur_attrib++] = WGL_ACCELERATION_ARB;
00696                         attrib_list[cur_attrib++] = WGL_FULL_ACCELERATION_ARB;
00697 
00698                         attrib_list[cur_attrib++] = WGL_SUPPORT_OPENGL_ARB;
00699                         attrib_list[cur_attrib++] = GL_TRUE;
00700 
00701                         attrib_list[cur_attrib++] = WGL_DOUBLE_BUFFER_ARB;
00702                         attrib_list[cur_attrib++] = GL_TRUE;
00703 
00704                         attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB;
00705                         attrib_list[cur_attrib++] = 24;
00706 
00707                         attrib_list[cur_attrib++] = WGL_RED_BITS_ARB;
00708                         attrib_list[cur_attrib++] = 8;
00709 
00710                         attrib_list[cur_attrib++] = WGL_GREEN_BITS_ARB;
00711                         attrib_list[cur_attrib++] = 8;
00712 
00713                         attrib_list[cur_attrib++] = WGL_BLUE_BITS_ARB;
00714                         attrib_list[cur_attrib++] = 8;
00715 
00716                         attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB;
00717                         attrib_list[cur_attrib++] = 8;
00718 
00719                         // End the list
00720                         attrib_list[cur_attrib++] = 0;
00721 
00722                         GLint pixel_formats[256];
00723                         U32 num_formats = 0;
00724 
00725                         // First we try and get a 32 bit depth pixel format
00726                         BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
00727                         if (!result)
00728                         {
00729                                 close();
00730                                 show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit");
00731                                 return;
00732                         }
00733 
00734                         if (!num_formats)
00735                         {
00736                                 llinfos << "No 32 bit z-buffer, trying 24 bits instead" << llendl;
00737                                 // Try 24-bit format
00738                                 attrib_list[1] = 24;
00739                                 BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
00740                                 if (!result)
00741                                 {
00742                                         close();
00743                                         show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit");
00744                                         return;
00745                                 }
00746 
00747                                 if (!num_formats)
00748                                 {
00749                                         llwarns << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << llendl;
00750                                         attrib_list[1] = 16;
00751                                         BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
00752                                         if (!result || !num_formats)
00753                                         {
00754                                                 close();
00755                                                 show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit");
00756                                                 return;
00757                                         }
00758                                 }
00759 
00760                                 llinfos << "Choosing pixel formats: " << num_formats << " pixel formats returned" << llendl;
00761 
00762                                 pixel_format = pixel_formats[0];
00763                         }
00764 
00765                         DestroyWindow(mWindowHandle);
00766 
00767                         mWindowHandle = CreateWindowEx(dw_ex_style,
00768                                 mWindowClassName,
00769                                 mWindowTitle,
00770                                 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style,
00771                                 x,                                                              // x pos
00772                                 y,                                                              // y pos
00773                                 window_rect.right - window_rect.left,                   // width
00774                                 window_rect.bottom - window_rect.top,                   // height
00775                                 NULL,
00776                                 NULL,
00777                                 mhInstance,
00778                                 NULL);
00779 
00780                         if (!(mhDC = GetDC(mWindowHandle)))
00781                         {
00782                                 close();
00783                                 OSMessageBox("Can't make GL device context", "Error", OSMB_OK);
00784                                 return;
00785                         }
00786 
00787                         if (!SetPixelFormat(mhDC, pixel_format, &pfd))
00788                         {
00789                                 close();
00790                                 OSMessageBox("Can't set pixel format", "Error", OSMB_OK);
00791                                 return;
00792                         }
00793 
00794                         int swap_method = 0;
00795                         GLint swap_query = WGL_SWAP_METHOD_ARB;
00796 
00797                         if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method))
00798                         {
00799                                 switch (swap_method)
00800                                 {
00801                                 case WGL_SWAP_EXCHANGE_ARB:
00802                                         mSwapMethod = SWAP_METHOD_EXCHANGE;
00803                                         llinfos << "Swap Method: Exchange" << llendl;
00804                                         break;
00805                                 case WGL_SWAP_COPY_ARB:
00806                                         mSwapMethod = SWAP_METHOD_COPY;
00807                                         llinfos << "Swap Method: Copy" << llendl;
00808                                         break;
00809                                 case WGL_SWAP_UNDEFINED_ARB:
00810                                         mSwapMethod = SWAP_METHOD_UNDEFINED;
00811                                         llinfos << "Swap Method: Undefined" << llendl;
00812                                         break;
00813                                 default:
00814                                         mSwapMethod = SWAP_METHOD_UNDEFINED;
00815                                         llinfos << "Swap Method: Unknown" << llendl;
00816                                         break;
00817                                 }
00818                         }               
00819                 }
00820                 else
00821                 {
00822                         llwarns << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << llendl;
00823                 }
00824 
00825                 // Verify what pixel format we actually received.
00826                 if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR),
00827                         &pfd))
00828                 {
00829                         close();
00830                         OSMessageBox("Can't get pixel format description", "Error", OSMB_OK);
00831                         return;
00832                 }
00833                 llinfos << "GL buffer: Color Bits " << S32(pfd.cColorBits) 
00834                         << " Alpha Bits " << S32(pfd.cAlphaBits)
00835                         << " Depth Bits " << S32(pfd.cDepthBits) 
00836                         << llendl;
00837 
00838                 if (pfd.cColorBits < 32)
00839                 {
00840                         close();
00841                         OSMessageBox(
00842                                 "Second Life requires True Color (32-bit) to run in a window.\n"
00843                                 "Please go to Control Panels -> Display -> Settings and\n"
00844                                 "set the screen to 32-bit color.\n"
00845                                 "Alternately, if you choose to run fullscreen, Second Life\n"
00846                                 "will automatically adjust the screen each time it runs.",
00847                                 "Error",
00848                                 OSMB_OK);
00849                         return;
00850                 }
00851 
00852                 if (pfd.cAlphaBits < 8)
00853                 {
00854                         close();
00855                         OSMessageBox(
00856                                 "Second Life is unable to run because it can't get an 8 bit alpha\n"
00857                                 "channel.  Usually this is due to video card driver issues.\n"
00858                                 "Please make sure you have the latest video card drivers installed.\n"
00859                                 "Also be sure your monitor is set to True Color (32-bit) in\n"
00860                                 "Control Panels -> Display -> Settings.\n"
00861                                 "If you continue to receive this message, contact customer service.",
00862                                 "Error",
00863                                 OSMB_OK);
00864                         return;
00865                 }
00866 
00867                 if (!(mhRC = wglCreateContext(mhDC)))
00868                 {
00869                         close();
00870                         OSMessageBox("Can't create GL rendering context", "Error", OSMB_OK);
00871                         return;
00872                 }
00873 
00874                 if (!wglMakeCurrent(mhDC, mhRC))
00875                 {
00876                         close();
00877                         OSMessageBox("Can't activate GL rendering context", "Error", OSMB_OK);
00878                         return;
00879                 }
00880 
00881                 if (!gGLManager.initGL())
00882                 {
00883                         close();
00884                         OSMessageBox(
00885                                 "Second Life is unable to run because your video card drivers\n"
00886                                 "are out of date or unsupported. Please make sure you have\n"
00887                                 "the latest video card drivers installed.\n\n"
00888                                 "If you continue to receive this message, contact customer service.",
00889                                 "Error",
00890                                 OSMB_OK);
00891                         return;
00892                 }
00893 
00894                 // Disable vertical sync for swap
00895                 if (disable_vsync && wglSwapIntervalEXT)
00896                 {
00897                         llinfos << "Disabling vertical sync" << llendl;
00898                         wglSwapIntervalEXT(0);
00899                 }
00900                 else
00901                 {
00902                         llinfos << "Keeping vertical sync" << llendl;
00903                 }
00904 
00905 
00906                 // OK, let's get the current gamma information and store it off.
00907                 mCurrentGamma = 0.f; // Not set, default;
00908                 if (!GetDeviceGammaRamp(mhDC, mPrevGammaRamp))
00909                 {
00910                         llwarns << "Unable to get device gamma ramp" << llendl;
00911                 }
00912 
00913                 // Calculate what the current gamma is.  From a posting by Garrett T. Bass, Get/SetDeviceGammaRamp Demystified
00914                 // http://apollo.iwt.uni-bielefeld.de/~ml_robot/OpenGL-04-2000/0058.html
00915 
00916                 // We're going to assume that gamma's the same for all 3 channels, because I don't feel like doing it otherwise.
00917                 // Using the red channel.
00918 
00919                 F32 Csum = 0.0; 
00920                 S32 Ccount = 0; 
00921                 for (i = 0; i < 256; i++) 
00922                 { 
00923                         if (i != 0 && mPrevGammaRamp[i] != 0 && mPrevGammaRamp[i] != 65536) 
00924                         { 
00925                                 F64 B = (i % 256) / 256.0; 
00926                                 F64 A = mPrevGammaRamp[i] / 65536.0; 
00927                                 F32 C = (F32) ( log(A) / log(B) ); 
00928                                 Csum += C; 
00929                                 Ccount++; 
00930                         } 
00931                 } 
00932                 mCurrentGamma = Csum / Ccount; 
00933 
00934                 llinfos << "Previous gamma: " << mCurrentGamma << llendl;
00935         }
00936 
00937         //********** UMICH 3D LAB ***************
00938         // if we wanted active stereo, but couldn't get it then
00939         // we turn off stereo rendering.
00940         if((mStereoMode==STEREO_MODE_ACTIVE) && ((pfd.dwFlags & PFD_STEREO)==0))
00941         {       mStereoMode = STEREO_MODE_NONE; }
00942         //********** UMICH 3D LAB ****************
00943 
00944         //store this pointer for wndProc callback
00945         SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this);
00946 
00947         //start with arrow cursor
00948         initCursors();
00949         setCursor( UI_CURSOR_ARROW );
00950 
00951         // Direct Input
00952         HRESULT hr;
00953 
00954         if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, 
00955                 IID_IDirectInput8, (VOID**)&g_pDI, NULL ) ) )
00956         {
00957                 llwarns << "Direct8InputCreate failed!" << llendl;
00958         }
00959         else
00960         {
00961                 while(1)
00962                 {
00963                         // Look for a simple joystick we can use for this sample program.
00964                         if (FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, 
00965                                 EnumJoysticksCallback,
00966                                 NULL, DIEDFL_ATTACHEDONLY ) ) )
00967                                 break;
00968                         if (!g_pJoystick)
00969                                 break;
00970                         if( FAILED( hr = g_pJoystick->SetDataFormat( &c_dfDIJoystick ) ) )
00971                                 break;
00972                         if( FAILED( hr = g_pJoystick->EnumObjects( EnumObjectsCallback, 
00973                                 (VOID*)mWindowHandle, DIDFT_ALL ) ) )
00974                                 break;
00975                         g_pJoystick->Acquire();
00976                         break;
00977                 }
00978         }
00979 
00980         SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer
00981 }
00982 
00983 
00984 LLWindowWin32::~LLWindowWin32()
00985 {
00986         delete [] mWindowTitle;
00987         mWindowTitle = NULL;
00988 
00989         delete [] mSupportedResolutions;
00990         mSupportedResolutions = NULL;
00991 
00992         delete mWindowClassName;
00993         mWindowClassName = NULL;
00994 }
00995 
00996 void LLWindowWin32::show()
00997 {
00998         ShowWindow(mWindowHandle, SW_SHOW);
00999         SetForegroundWindow(mWindowHandle);
01000         SetFocus(mWindowHandle);
01001 }
01002 
01003 void LLWindowWin32::hide()
01004 {
01005         setMouseClipping(FALSE);
01006         ShowWindow(mWindowHandle, SW_HIDE);
01007 }
01008 
01009 void LLWindowWin32::minimize()
01010 {
01011         setMouseClipping(FALSE);
01012         showCursor();
01013         ShowWindow(mWindowHandle, SW_MINIMIZE);
01014 }
01015 
01016 
01017 void LLWindowWin32::restore()
01018 {
01019         ShowWindow(mWindowHandle, SW_RESTORE);
01020         SetForegroundWindow(mWindowHandle);
01021         SetFocus(mWindowHandle);
01022 }
01023 
01024 
01025 // close() destroys all OS-specific code associated with a window.
01026 // Usually called from LLWindowManager::destroyWindow()
01027 void LLWindowWin32::close()
01028 {
01029         llinfos << "Closing LLWindowWin32" << llendl;
01030         // Is window is already closed?
01031         if (!mWindowHandle)
01032         {
01033                 return;
01034         }
01035 
01036         // Make sure cursor is visible and we haven't mangled the clipping state.
01037         setMouseClipping(FALSE);
01038         showCursor();
01039 
01040         // Go back to screen mode written in the registry.
01041         if (mFullscreen)
01042         {
01043                 resetDisplayResolution();
01044         }
01045 
01046         // Clean up remaining GL state
01047         llinfos << "Shutting down GL" << llendl;
01048         gGLManager.shutdownGL();
01049 
01050         llinfos << "Releasing Context" << llendl;
01051         if (mhRC)
01052         {
01053                 if (!wglMakeCurrent(NULL, NULL))
01054                 {
01055                         llwarns << "Release of DC and RC failed" << llendl;
01056                 }
01057 
01058                 if (!wglDeleteContext(mhRC))
01059                 {
01060                         llwarns << "Release of rendering context failed" << llendl;
01061                 }
01062 
01063                 mhRC = NULL;
01064         }
01065 
01066         // Restore gamma to the system values.
01067         restoreGamma();
01068 
01069         if (mhDC && !ReleaseDC(mWindowHandle, mhDC))
01070         {
01071                 llwarns << "Release of ghDC failed" << llendl;
01072                 mhDC = NULL;
01073         }
01074 
01075         llinfos << "Destroying Window" << llendl;
01076         
01077         // Don't process events in our mainWindowProc any longer.
01078         SetWindowLong(mWindowHandle, GWL_USERDATA, NULL);
01079 
01080         // Make sure we don't leave a blank toolbar button.
01081         ShowWindow(mWindowHandle, SW_HIDE);
01082 
01083         // This causes WM_DESTROY to be sent *immediately*
01084         if (!DestroyWindow(mWindowHandle))
01085         {
01086                 OSMessageBox("DestroyWindow(mWindowHandle) failed", "Shutdown Error", OSMB_OK);
01087         }
01088 
01089         mWindowHandle = NULL;
01090 }
01091 
01092 BOOL LLWindowWin32::isValid()
01093 {
01094         return (mWindowHandle != NULL);
01095 }
01096 
01097 BOOL LLWindowWin32::getVisible()
01098 {
01099         return (mWindowHandle && IsWindowVisible(mWindowHandle));
01100 }
01101 
01102 BOOL LLWindowWin32::getMinimized()
01103 {
01104         return (mWindowHandle && IsIconic(mWindowHandle));
01105 }
01106 
01107 BOOL LLWindowWin32::getMaximized()
01108 {
01109         return (mWindowHandle && IsZoomed(mWindowHandle));
01110 }
01111 
01112 BOOL LLWindowWin32::maximize()
01113 {
01114         BOOL success = FALSE;
01115         if (!mWindowHandle) return success;
01116 
01117         WINDOWPLACEMENT placement;
01118         placement.length = sizeof(WINDOWPLACEMENT);
01119 
01120         success = GetWindowPlacement(mWindowHandle, &placement);
01121         if (!success) return success;
01122 
01123         placement.showCmd = SW_MAXIMIZE;
01124 
01125         success = SetWindowPlacement(mWindowHandle, &placement);
01126         return success;
01127 }
01128 
01129 BOOL LLWindowWin32::getFullscreen()
01130 {
01131         return mFullscreen;
01132 }
01133 
01134 BOOL LLWindowWin32::getPosition(LLCoordScreen *position)
01135 {
01136         RECT window_rect;
01137 
01138         if (!mWindowHandle ||
01139                 !GetWindowRect(mWindowHandle, &window_rect) ||
01140                 NULL == position)
01141         {
01142                 return FALSE;
01143         }
01144 
01145         position->mX = window_rect.left;
01146         position->mY = window_rect.top;
01147         return TRUE;
01148 }
01149 
01150 BOOL LLWindowWin32::getSize(LLCoordScreen *size)
01151 {
01152         RECT window_rect;
01153 
01154         if (!mWindowHandle ||
01155                 !GetWindowRect(mWindowHandle, &window_rect) ||
01156                 NULL == size)
01157         {
01158                 return FALSE;
01159         }
01160 
01161         size->mX = window_rect.right - window_rect.left;
01162         size->mY = window_rect.bottom - window_rect.top;
01163         return TRUE;
01164 }
01165 
01166 BOOL LLWindowWin32::getSize(LLCoordWindow *size)
01167 {
01168         RECT client_rect;
01169 
01170         if (!mWindowHandle ||
01171                 !GetClientRect(mWindowHandle, &client_rect) ||
01172                 NULL == size)
01173         {
01174                 return FALSE;
01175         }
01176 
01177         size->mX = client_rect.right - client_rect.left;
01178         size->mY = client_rect.bottom - client_rect.top;
01179         return TRUE;
01180 }
01181 
01182 BOOL LLWindowWin32::setPosition(const LLCoordScreen position)
01183 {
01184         LLCoordScreen size;
01185 
01186         if (!mWindowHandle)
01187         {
01188                 return FALSE;
01189         }
01190         getSize(&size);
01191         moveWindow(position, size);
01192         return TRUE;
01193 }
01194 
01195 BOOL LLWindowWin32::setSize(const LLCoordScreen size)
01196 {
01197         LLCoordScreen position;
01198 
01199         getPosition(&position);
01200         if (!mWindowHandle)
01201         {
01202                 return FALSE;
01203         }
01204 
01205         moveWindow(position, size);
01206         return TRUE;
01207 }
01208 
01209 // changing fullscreen resolution
01210 BOOL LLWindowWin32::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync)
01211 {
01212         GLuint  pixel_format;
01213         DEVMODE dev_mode;
01214         DWORD   current_refresh;
01215         DWORD   dw_ex_style;
01216         DWORD   dw_style;
01217         RECT    window_rect;
01218         S32 width = size.mX;
01219         S32 height = size.mY;
01220 
01221         resetDisplayResolution();
01222 
01223         if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
01224         {
01225                 current_refresh = dev_mode.dmDisplayFrequency;
01226         }
01227         else
01228         {
01229                 current_refresh = 60;
01230         }
01231 
01232         gGLManager.shutdownGL();
01233         //destroy gl context
01234         if (mhRC)
01235         {
01236                 if (!wglMakeCurrent(NULL, NULL))
01237                 {
01238                         llwarns << "Release of DC and RC failed" << llendl;
01239                 }
01240 
01241                 if (!wglDeleteContext(mhRC))
01242                 {
01243                         llwarns << "Release of rendering context failed" << llendl;
01244                 }
01245 
01246                 mhRC = NULL;
01247         }
01248 
01249         if (fullscreen)
01250         {
01251                 mFullscreen = TRUE;
01252                 BOOL success = FALSE;
01253                 DWORD closest_refresh = 0;
01254 
01255                 for (S32 mode_num = 0;; mode_num++)
01256                 {
01257                         if (!EnumDisplaySettings(NULL, mode_num, &dev_mode))
01258                         {
01259                                 break;
01260                         }
01261 
01262                         if (dev_mode.dmPelsWidth == width &&
01263                                 dev_mode.dmPelsHeight == height &&
01264                                 dev_mode.dmBitsPerPel == BITS_PER_PIXEL)
01265                         {
01266                                 success = TRUE;
01267                                 if ((dev_mode.dmDisplayFrequency - current_refresh)
01268                                         < (closest_refresh - current_refresh))
01269                                 {
01270                                         closest_refresh = dev_mode.dmDisplayFrequency;
01271                                 }
01272                         }
01273                 }
01274 
01275                 if (closest_refresh == 0)
01276                 {
01277                         llwarns << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << llendl;
01278                         return FALSE;
01279                 }
01280 
01281                 // If we found a good resolution, use it.
01282                 if (success)
01283                 {
01284                         success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh);
01285                 }
01286 
01287                 // Keep a copy of the actual current device mode in case we minimize 
01288                 // and change the screen resolution.   JC
01289                 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode);
01290 
01291                 if (success)
01292                 {
01293                         mFullscreen = TRUE;
01294                         mFullscreenWidth   = dev_mode.dmPelsWidth;
01295                         mFullscreenHeight  = dev_mode.dmPelsHeight;
01296                         mFullscreenBits    = dev_mode.dmBitsPerPel;
01297                         mFullscreenRefresh = dev_mode.dmDisplayFrequency;
01298 
01299                         llinfos << "Running at " << dev_mode.dmPelsWidth
01300                                 << "x"   << dev_mode.dmPelsHeight
01301                                 << "x"   << dev_mode.dmBitsPerPel
01302                                 << " @ " << dev_mode.dmDisplayFrequency
01303                                 << llendl;
01304 
01305                         window_rect.left = (long) 0;
01306                         window_rect.right = (long) width;                       // Windows GDI rects don't include rightmost pixel
01307                         window_rect.top = (long) 0;
01308                         window_rect.bottom = (long) height;
01309                         dw_ex_style = WS_EX_APPWINDOW;
01310                         dw_style = WS_POPUP;
01311 
01312                         // Move window borders out not to cover window contents
01313                         AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style);
01314                 }
01315                 // If it failed, we don't want to run fullscreen
01316                 else
01317                 {
01318                         mFullscreen = FALSE;
01319                         mFullscreenWidth   = -1;
01320                         mFullscreenHeight  = -1;
01321                         mFullscreenBits    = -1;
01322                         mFullscreenRefresh = -1;
01323 
01324                         llinfos << "Unable to run fullscreen at " << width << "x" << height << llendl;
01325                         llinfos << "Running in window." << llendl;
01326                         return FALSE;
01327                 }
01328         }
01329         else
01330         {
01331                 mFullscreen = FALSE;
01332                 window_rect.left = (long) 0;
01333                 window_rect.right = (long) width;                       // Windows GDI rects don't include rightmost pixel
01334                 window_rect.top = (long) 0;
01335                 window_rect.bottom = (long) height;
01336                 // Window with an edge
01337                 dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
01338                 dw_style = WS_OVERLAPPEDWINDOW;
01339         }
01340 
01341         // don't post quit messages when destroying old windows
01342         mPostQuit = FALSE;
01343 
01344         // create window
01345         DestroyWindow(mWindowHandle);
01346         mWindowHandle = CreateWindowEx(dw_ex_style,
01347                 mWindowClassName,
01348                 mWindowTitle,
01349                 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style,
01350                 window_rect.left,                                                               // x pos
01351                 window_rect.top,                                                                // y pos
01352                 window_rect.right - window_rect.left,                   // width
01353                 window_rect.bottom - window_rect.top,                   // height
01354                 NULL,
01355                 NULL,
01356                 mhInstance,
01357                 NULL);
01358 
01359         //-----------------------------------------------------------------------
01360         // Create GL drawing context
01361         //-----------------------------------------------------------------------
01362         static PIXELFORMATDESCRIPTOR pfd =
01363         {
01364                 sizeof(PIXELFORMATDESCRIPTOR), 
01365                         1,
01366                         PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, 
01367                         PFD_TYPE_RGBA,
01368                         BITS_PER_PIXEL,
01369                         0, 0, 0, 0, 0, 0,       // RGB bits and shift, unused
01370                         8,                                      // alpha bits
01371                         0,                                      // alpha shift
01372                         0,                                      // accum bits
01373                         0, 0, 0, 0,                     // accum RGBA
01374                         24,                                     // depth bits
01375                         8,                                      // stencil bits, avi added for stencil test
01376                         0,
01377                         PFD_MAIN_PLANE,
01378                         0,
01379                         0, 0, 0
01380         };
01381 
01382         if (!(mhDC = GetDC(mWindowHandle)))
01383         {
01384                 close();
01385                 OSMessageBox("Can't make GL device context", "Error", OSMB_OK);
01386                 return FALSE;
01387         }
01388 
01389         if (!(pixel_format = ChoosePixelFormat(mhDC, &pfd)))
01390         {
01391                 close();
01392                 OSMessageBox("Can't find suitable pixel format", "Error", OSMB_OK);
01393                 return FALSE;
01394         }
01395 
01396         // Verify what pixel format we actually received.
01397         if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR),
01398                 &pfd))
01399         {
01400                 close();
01401                 OSMessageBox("Can't get pixel format description", "Error", OSMB_OK);
01402                 return FALSE;
01403         }
01404 
01405         if (pfd.cColorBits < 32)
01406         {
01407                 close();
01408                 OSMessageBox(
01409                         "Second Life requires True Color (32-bit) to run in a window.\n"
01410                         "Please go to Control Panels -> Display -> Settings and\n"
01411                         "set the screen to 32-bit color.\n"
01412                         "Alternately, if you choose to run fullscreen, Second Life\n"
01413                         "will automatically adjust the screen each time it runs.",
01414                         "Error",
01415                         OSMB_OK);
01416                 return FALSE;
01417         }
01418 
01419         if (pfd.cAlphaBits < 8)
01420         {
01421                 close();
01422                 OSMessageBox(
01423                         "Second Life is unable to run because it can't get an 8 bit alpha\n"
01424                         "channel.  Usually this is due to video card driver issues.\n"
01425                         "Please make sure you have the latest video card drivers installed.\n"
01426                         "Also be sure your monitor is set to True Color (32-bit) in\n"
01427                         "Control Panels -> Display -> Settings.\n"
01428                         "If you continue to receive this message, contact customer service.",
01429                         "Error",
01430                         OSMB_OK);
01431                 return FALSE;
01432         }
01433 
01434         if (!SetPixelFormat(mhDC, pixel_format, &pfd))
01435         {
01436                 close();
01437                 OSMessageBox("Can't set pixel format", "Error", OSMB_OK);
01438                 return FALSE;
01439         }
01440 
01441         if (!(mhRC = wglCreateContext(mhDC)))
01442         {
01443                 close();
01444                 OSMessageBox("Can't create GL rendering context", "Error", OSMB_OK);
01445                 return FALSE;
01446         }
01447 
01448         if (!wglMakeCurrent(mhDC, mhRC))
01449         {
01450                 close();
01451                 OSMessageBox("Can't activate GL rendering context", "Error", OSMB_OK);
01452                 return FALSE;
01453         }
01454 
01455         gGLManager.initWGL();
01456 
01457         if (wglChoosePixelFormatARB)
01458         {
01459                 // OK, at this point, use the ARB wglChoosePixelFormatsARB function to see if we
01460                 // can get exactly what we want.
01461                 GLint attrib_list[256];
01462                 S32 cur_attrib = 0;
01463 
01464                 attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB;
01465                 attrib_list[cur_attrib++] = 24;
01466 
01467                 attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB;
01468                 attrib_list[cur_attrib++] = 8;
01469 
01470                 attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB;
01471                 attrib_list[cur_attrib++] = GL_TRUE;
01472 
01473                 attrib_list[cur_attrib++] = WGL_ACCELERATION_ARB;
01474                 attrib_list[cur_attrib++] = WGL_FULL_ACCELERATION_ARB;
01475 
01476                 attrib_list[cur_attrib++] = WGL_SUPPORT_OPENGL_ARB;
01477                 attrib_list[cur_attrib++] = GL_TRUE;
01478 
01479                 attrib_list[cur_attrib++] = WGL_DOUBLE_BUFFER_ARB;
01480                 attrib_list[cur_attrib++] = GL_TRUE;
01481 
01482                 attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB;
01483                 attrib_list[cur_attrib++] = 24;
01484 
01485                 attrib_list[cur_attrib++] = WGL_RED_BITS_ARB;
01486                 attrib_list[cur_attrib++] = 8;
01487 
01488                 attrib_list[cur_attrib++] = WGL_GREEN_BITS_ARB;
01489                 attrib_list[cur_attrib++] = 8;
01490 
01491                 attrib_list[cur_attrib++] = WGL_BLUE_BITS_ARB;
01492                 attrib_list[cur_attrib++] = 8;
01493 
01494                 attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB;
01495                 attrib_list[cur_attrib++] = 8;
01496 
01497                 // End the list
01498                 attrib_list[cur_attrib++] = 0;
01499 
01500                 GLint pixel_formats[256];
01501                 U32 num_formats = 0;
01502 
01503                 // First we try and get a 32 bit depth pixel format
01504                 BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
01505                 if (!result)
01506                 {
01507                         close();
01508                         show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit");
01509                         return FALSE;
01510                 }
01511 
01512                 if (!num_formats)
01513                 {
01514                         llinfos << "No 32 bit z-buffer, trying 24 bits instead" << llendl;
01515                         // Try 24-bit format
01516                         attrib_list[1] = 24;
01517                         BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
01518                         if (!result)
01519                         {
01520                                 close();
01521                                 show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit");
01522                                 return FALSE;
01523                         }
01524 
01525                         if (!num_formats)
01526                         {
01527                                 llwarns << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << llendl;
01528                                 attrib_list[1] = 16;
01529                                 BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
01530                                 if (!result || !num_formats)
01531                                 {
01532                                         close();
01533                                         show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit");
01534                                         return FALSE;
01535                                 }
01536                         }
01537 
01538                         llinfos << "Choosing pixel formats: " << num_formats << " pixel formats returned" << llendl;
01539 
01540                         pixel_format = pixel_formats[0];
01541                 }
01542 
01543                 DestroyWindow(mWindowHandle);
01544                 mWindowHandle = CreateWindowEx(dw_ex_style,
01545                         mWindowClassName,
01546                         mWindowTitle,
01547                         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style,
01548                         window_rect.left,                                                               // x pos
01549                         window_rect.top,                                                                // y pos
01550                         window_rect.right - window_rect.left,                   // width
01551                         window_rect.bottom - window_rect.top,                   // height
01552                         NULL,
01553                         NULL,
01554                         mhInstance,
01555                         NULL);
01556 
01557                 if (!(mhDC = GetDC(mWindowHandle)))
01558                 {
01559                         close();
01560                         OSMessageBox("Can't make GL device context", "Error", OSMB_OK);
01561                         return FALSE;
01562                 }
01563 
01564                 if (!SetPixelFormat(mhDC, pixel_format, &pfd))
01565                 {
01566                         close();
01567                         OSMessageBox("Can't set pixel format", "Error", OSMB_OK);
01568                         return FALSE;
01569                 }
01570 
01571                 int swap_method = 0;
01572                 GLint swap_query = WGL_SWAP_METHOD_ARB;
01573 
01574                 if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method))
01575                 {
01576                         switch (swap_method)
01577                         {
01578                         case WGL_SWAP_EXCHANGE_ARB:
01579                                 mSwapMethod = SWAP_METHOD_EXCHANGE;
01580                                 llinfos << "Swap Method: Exchange" << llendl;
01581                                 break;
01582                         case WGL_SWAP_COPY_ARB:
01583                                 mSwapMethod = SWAP_METHOD_COPY;
01584                                 llinfos << "Swap Method: Copy" << llendl;
01585                                 break;
01586                         case WGL_SWAP_UNDEFINED_ARB:
01587                                 mSwapMethod = SWAP_METHOD_UNDEFINED;
01588                                 llinfos << "Swap Method: Undefined" << llendl;
01589                                 break;
01590                         default:
01591                                 mSwapMethod = SWAP_METHOD_UNDEFINED;
01592                                 llinfos << "Swap Method: Unknown" << llendl;
01593                                 break;
01594                         }
01595                 }               
01596         }
01597         else
01598         {
01599                 llwarns << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << llendl;
01600         }
01601 
01602         // Verify what pixel format we actually received.
01603         if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR),
01604                 &pfd))
01605         {
01606                 close();
01607                 OSMessageBox("Can't get pixel format description", "Error", OSMB_OK);
01608                 return FALSE;
01609         }
01610 
01611         llinfos << "GL buffer: Color Bits " << S32(pfd.cColorBits) 
01612                 << " Alpha Bits " << S32(pfd.cAlphaBits)
01613                 << " Depth Bits " << S32(pfd.cDepthBits) 
01614                 << llendl;
01615 
01616         if (pfd.cColorBits < 32)
01617         {
01618                 close();
01619                 OSMessageBox(
01620                         "Second Life requires True Color (32-bit) to run in a window.\n"
01621                         "Please go to Control Panels -> Display -> Settings and\n"
01622                         "set the screen to 32-bit color.\n"
01623                         "Alternately, if you choose to run fullscreen, Second Life\n"
01624                         "will automatically adjust the screen each time it runs.",
01625                         "Error",
01626                         OSMB_OK);
01627                 return FALSE;
01628         }
01629 
01630         if (pfd.cAlphaBits < 8)
01631         {
01632                 close();
01633                 OSMessageBox(
01634                         "Second Life is unable to run because it can't get an 8 bit alpha\n"
01635                         "channel.  Usually this is due to video card driver issues.\n"
01636                         "Please make sure you have the latest video card drivers installed.\n"
01637                         "Also be sure your monitor is set to True Color (32-bit) in\n"
01638                         "Control Panels -> Display -> Settings.\n"
01639                         "If you continue to receive this message, contact customer service.",
01640                         "Error",
01641                         OSMB_OK);
01642                 return FALSE;
01643         }
01644 
01645         if (!(mhRC = wglCreateContext(mhDC)))
01646         {
01647                 close();
01648                 OSMessageBox("Can't create GL rendering context", "Error", OSMB_OK);
01649                 return FALSE;
01650         }
01651 
01652         if (!wglMakeCurrent(mhDC, mhRC))
01653         {
01654                 close();
01655                 OSMessageBox("Can't activate GL rendering context", "Error", OSMB_OK);
01656                 return FALSE;
01657         }
01658 
01659         if (!gGLManager.initGL())
01660         {
01661                 close();
01662                 OSMessageBox(
01663                                          "Second Life is unable to run because your video card drivers\n"
01664                                          "are out of date or unsupported. Please make sure you have\n"
01665                                          "the latest video card drivers installed.\n\n"
01666                                          "If you continue to receive this message, contact customer service.",
01667                                          "Error",
01668                                          OSMB_OK);
01669                 return FALSE;
01670         }
01671 
01672         // Disable vertical sync for swap
01673         if (disable_vsync && wglSwapIntervalEXT)
01674         {
01675                 llinfos << "Disabling vertical sync" << llendl;
01676                 wglSwapIntervalEXT(0);
01677         }
01678         else
01679         {
01680                 llinfos << "Keeping vertical sync" << llendl;
01681         }
01682 
01683         SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this);
01684         show();
01685 
01686         // ok to post quit messages now
01687         mPostQuit = TRUE;
01688         return TRUE;
01689 }
01690 
01691 void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size )
01692 {
01693         if( mIsMouseClipping )
01694         {
01695                 RECT client_rect_in_screen_space;
01696                 if( getClientRectInScreenSpace( &client_rect_in_screen_space ) )
01697                 {
01698                         ClipCursor( &client_rect_in_screen_space );
01699                 }
01700         }
01701 
01702         // if the window was already maximized, MoveWindow seems to still set the maximized flag even if
01703         // the window is smaller than maximized.
01704         // So we're going to do a restore first (which is a ShowWindow call) (SL-44655).
01705         ShowWindow(mWindowHandle, SW_RESTORE);
01706         // NOW we can call MoveWindow
01707         MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE);
01708 }
01709 
01710 BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position)
01711 {
01712         LLCoordScreen screen_pos;
01713 
01714         mMousePositionModified = TRUE;
01715         if (!mWindowHandle)
01716         {
01717                 return FALSE;
01718         }
01719 
01720         if (!convertCoords(position, &screen_pos))
01721         {
01722                 return FALSE;
01723         }
01724 
01725         return SetCursorPos(screen_pos.mX, screen_pos.mY);
01726 }
01727 
01728 BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position)
01729 {
01730         POINT cursor_point;
01731         LLCoordScreen screen_pos;
01732 
01733         if (!mWindowHandle ||
01734                 !GetCursorPos(&cursor_point))
01735         {
01736                 return FALSE;
01737         }
01738 
01739         screen_pos.mX = cursor_point.x;
01740         screen_pos.mY = cursor_point.y;
01741 
01742         return convertCoords(screen_pos, position);
01743 }
01744 
01745 void LLWindowWin32::hideCursor()
01746 {
01747         while (ShowCursor(FALSE) >= 0)
01748         {
01749                 // nothing, wait for cursor to push down
01750         }
01751         mCursorHidden = TRUE;
01752         mHideCursorPermanent = TRUE;
01753 }
01754 
01755 void LLWindowWin32::showCursor()
01756 {
01757         // makes sure the cursor shows up
01758         while (ShowCursor(TRUE) < 0)
01759         {
01760                 // do nothing, wait for cursor to pop out
01761         }
01762         mCursorHidden = FALSE;
01763         mHideCursorPermanent = FALSE;
01764 }
01765 
01766 void LLWindowWin32::showCursorFromMouseMove()
01767 {
01768         if (!mHideCursorPermanent)
01769         {
01770                 showCursor();
01771         }
01772 }
01773 
01774 void LLWindowWin32::hideCursorUntilMouseMove()
01775 {
01776         if (!mHideCursorPermanent)
01777         {
01778                 hideCursor();
01779                 mHideCursorPermanent = FALSE;
01780         }
01781 }
01782 
01783 BOOL LLWindowWin32::isCursorHidden()
01784 {
01785         return mCursorHidden;
01786 }
01787 
01788 
01789 HCURSOR LLWindowWin32::loadColorCursor(LPCTSTR name)
01790 {
01791         return (HCURSOR)LoadImage(mhInstance,
01792                                                           name,
01793                                                           IMAGE_CURSOR,
01794                                                           0,    // default width
01795                                                           0,    // default height
01796                                                           LR_DEFAULTCOLOR);
01797 }
01798 
01799 
01800 void LLWindowWin32::initCursors()
01801 {
01802         mCursor[ UI_CURSOR_ARROW ]              = LoadCursor(NULL, IDC_ARROW);
01803         mCursor[ UI_CURSOR_WAIT ]               = LoadCursor(NULL, IDC_WAIT);
01804         mCursor[ UI_CURSOR_HAND ]               = LoadCursor(NULL, IDC_HAND);
01805         mCursor[ UI_CURSOR_IBEAM ]              = LoadCursor(NULL, IDC_IBEAM);
01806         mCursor[ UI_CURSOR_CROSS ]              = LoadCursor(NULL, IDC_CROSS);
01807         mCursor[ UI_CURSOR_SIZENWSE ]   = LoadCursor(NULL, IDC_SIZENWSE);
01808         mCursor[ UI_CURSOR_SIZENESW ]   = LoadCursor(NULL, IDC_SIZENESW);
01809         mCursor[ UI_CURSOR_SIZEWE ]             = LoadCursor(NULL, IDC_SIZEWE);  
01810         mCursor[ UI_CURSOR_SIZENS ]             = LoadCursor(NULL, IDC_SIZENS);  
01811         mCursor[ UI_CURSOR_NO ]                 = LoadCursor(NULL, IDC_NO);
01812         mCursor[ UI_CURSOR_WORKING ]    = LoadCursor(NULL, IDC_APPSTARTING); 
01813 
01814         HMODULE module = GetModuleHandle(NULL);
01815         mCursor[ UI_CURSOR_TOOLGRAB ]   = LoadCursor(module, TEXT("TOOLGRAB"));
01816         mCursor[ UI_CURSOR_TOOLLAND ]   = LoadCursor(module, TEXT("TOOLLAND"));
01817         mCursor[ UI_CURSOR_TOOLFOCUS ]  = LoadCursor(module, TEXT("TOOLFOCUS"));
01818         mCursor[ UI_CURSOR_TOOLCREATE ] = LoadCursor(module, TEXT("TOOLCREATE"));
01819         mCursor[ UI_CURSOR_ARROWDRAG ]  = LoadCursor(module, TEXT("ARROWDRAG"));
01820         mCursor[ UI_CURSOR_ARROWCOPY ]  = LoadCursor(module, TEXT("ARROWCOPY"));
01821         mCursor[ UI_CURSOR_ARROWDRAGMULTI ]     = LoadCursor(module, TEXT("ARROWDRAGMULTI"));
01822         mCursor[ UI_CURSOR_ARROWCOPYMULTI ]     = LoadCursor(module, TEXT("ARROWCOPYMULTI"));
01823         mCursor[ UI_CURSOR_NOLOCKED ]   = LoadCursor(module, TEXT("NOLOCKED"));
01824         mCursor[ UI_CURSOR_ARROWLOCKED ]= LoadCursor(module, TEXT("ARROWLOCKED"));
01825         mCursor[ UI_CURSOR_GRABLOCKED ] = LoadCursor(module, TEXT("GRABLOCKED"));
01826         mCursor[ UI_CURSOR_TOOLTRANSLATE ]      = LoadCursor(module, TEXT("TOOLTRANSLATE"));
01827         mCursor[ UI_CURSOR_TOOLROTATE ] = LoadCursor(module, TEXT("TOOLROTATE")); 
01828         mCursor[ UI_CURSOR_TOOLSCALE ]  = LoadCursor(module, TEXT("TOOLSCALE"));
01829         mCursor[ UI_CURSOR_TOOLCAMERA ] = LoadCursor(module, TEXT("TOOLCAMERA"));
01830         mCursor[ UI_CURSOR_TOOLPAN ]    = LoadCursor(module, TEXT("TOOLPAN"));
01831         mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN"));
01832         mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3"));
01833         mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE"));
01834 
01835         // Color cursors
01836         mCursor[UI_CURSOR_TOOLSIT] = loadColorCursor(TEXT("TOOLSIT"));
01837         mCursor[UI_CURSOR_TOOLBUY] = loadColorCursor(TEXT("TOOLBUY"));
01838         mCursor[UI_CURSOR_TOOLPAY] = loadColorCursor(TEXT("TOOLPAY"));
01839         mCursor[UI_CURSOR_TOOLOPEN] = loadColorCursor(TEXT("TOOLOPEN"));
01840 
01841         // Note: custom cursors that are not found make LoadCursor() return NULL.
01842         for( S32 i = 0; i < UI_CURSOR_COUNT; i++ )
01843         {
01844                 if( !mCursor[i] )
01845                 {
01846                         mCursor[i] = LoadCursor(NULL, IDC_ARROW);
01847                 }
01848         }
01849 }
01850 
01851 
01852 
01853 void LLWindowWin32::setCursor(ECursorType cursor)
01854 {
01855         if (cursor == UI_CURSOR_ARROW
01856                 && mBusyCount > 0)
01857         {
01858                 cursor = UI_CURSOR_WORKING;
01859         }
01860 
01861         if( mCurrentCursor != cursor )
01862         {
01863                 mCurrentCursor = cursor;
01864                 SetCursor( mCursor[cursor] );
01865         }
01866 }
01867 
01868 ECursorType LLWindowWin32::getCursor() const
01869 {
01870         return mCurrentCursor;
01871 }
01872 
01873 void LLWindowWin32::captureMouse()
01874 {
01875         SetCapture(mWindowHandle);
01876 }
01877 
01878 void LLWindowWin32::releaseMouse()
01879 {
01880         ReleaseCapture();
01881 }
01882 
01883 
01884 void LLWindowWin32::delayInputProcessing()
01885 {
01886         mInputProcessingPaused = TRUE;
01887 }
01888 
01889 void LLWindowWin32::gatherInput()
01890 {
01891         MSG             msg;
01892         int             msg_count = 0;
01893 
01894         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) && msg_count < MAX_MESSAGE_PER_UPDATE)
01895         {
01896                 TranslateMessage(&msg);
01897                 DispatchMessage(&msg);
01898                 msg_count++;
01899 
01900                 if ( mInputProcessingPaused )
01901                 {
01902                         break;
01903                 }
01904                 /* Attempted workaround for problem where typing fast and hitting
01905                    return would result in only part of the text being sent. JC
01906 
01907                 BOOL key_posted = TranslateMessage(&msg);
01908                 DispatchMessage(&msg);
01909                 msg_count++;
01910 
01911                 // If a key was translated, a WM_CHAR might have been posted to the end
01912                 // of the event queue.  We need it immediately.
01913                 if (key_posted && msg.message == WM_KEYDOWN)
01914                 {
01915                         if (PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_REMOVE))
01916                         {
01917                                 TranslateMessage(&msg);
01918                                 DispatchMessage(&msg);
01919                                 msg_count++;
01920                         }
01921                 }
01922                 */
01923 
01924                 // For async host by name support.  Really hacky.
01925                 if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message))
01926                 {
01927                         gAsyncMsgCallback(msg);
01928                 }
01929         }
01930 
01931         mInputProcessingPaused = FALSE;
01932 
01933         // clear this once we've processed all mouse messages that might have occurred after
01934         // we slammed the mouse position
01935         mMousePositionModified = FALSE;
01936 }
01937 
01938 LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param)
01939 {
01940         LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(h_wnd, GWL_USERDATA);
01941 
01942         if (NULL != window_imp)
01943         {
01944                 // Has user provided their own window callback?
01945                 if (NULL != window_imp->mWndProc)
01946                 {
01947                         if (!window_imp->mWndProc(h_wnd, u_msg, w_param, l_param))
01948                         {
01949                                 // user has handled window message
01950                                 return 0;
01951                         }
01952                 }
01953 
01954                 // Juggle to make sure we can get negative positions for when
01955                 // mouse is outside window.
01956                 LLCoordWindow window_coord((S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param));
01957 
01958                 // This doesn't work, as LOWORD returns unsigned short.
01959                 //LLCoordWindow window_coord(LOWORD(l_param), HIWORD(l_param));
01960                 LLCoordGL gl_coord;
01961 
01962                 // pass along extended flag in mask
01963                 MASK mask = (l_param>>16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0;
01964                 BOOL eat_keystroke = TRUE;
01965 
01966                 switch(u_msg)
01967                 {
01968                         RECT    update_rect;
01969                         S32             update_width;
01970                         S32             update_height;
01971 
01972                 case WM_TIMER:
01973                         window_imp->updateJoystick( );
01974                         break;
01975 
01976                 case WM_PAINT:
01977                         GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE);
01978                         update_width = update_rect.right - update_rect.left + 1;
01979                         update_height = update_rect.bottom - update_rect.top + 1;
01980                         window_imp->mCallbacks->handlePaint(window_imp, update_rect.left, update_rect.top,
01981                                 update_width, update_height);
01982                         break;
01983                 case WM_PARENTNOTIFY:
01984                         u_msg = u_msg;
01985                         break;
01986 
01987                 case WM_SETCURSOR:
01988                         // This message is sent whenever the cursor is moved in a window.
01989                         // You need to set the appropriate cursor appearance.
01990 
01991                         // Only take control of cursor over client region of window
01992                         // This allows Windows(tm) to handle resize cursors, etc.
01993                         if (LOWORD(l_param) == HTCLIENT)
01994                         {
01995                                 SetCursor(window_imp->mCursor[ window_imp->mCurrentCursor] );
01996                                 return 0;
01997                         }
01998                         break;
01999 
02000                 case WM_ENTERMENULOOP:
02001                         window_imp->mCallbacks->handleWindowBlock(window_imp);
02002                         break;
02003 
02004                 case WM_EXITMENULOOP:
02005                         window_imp->mCallbacks->handleWindowUnblock(window_imp);
02006                         break;
02007 
02008                 case WM_ACTIVATEAPP:
02009                         {
02010                                 // This message should be sent whenever the app gains or loses focus.
02011                                 BOOL activating = (BOOL) w_param;
02012                                 BOOL minimized = window_imp->getMinimized();
02013 
02014                                 if (gDebugWindowProc)
02015                                 {
02016                                         llinfos << "WINDOWPROC ActivateApp "
02017                                                 << " activating " << S32(activating)
02018                                                 << " minimized " << S32(minimized)
02019                                                 << " fullscreen " << S32(window_imp->mFullscreen)
02020                                                 << llendl;
02021                                 }
02022 
02023                                 if (window_imp->mFullscreen)
02024                                 {
02025                                         // When we run fullscreen, restoring or minimizing the app needs 
02026                                         // to switch the screen resolution
02027                                         if (activating)
02028                                         {
02029                                                 window_imp->setFullscreenResolution();
02030                                                 window_imp->restore();
02031                                         }
02032                                         else
02033                                         {
02034                                                 window_imp->minimize();
02035                                                 window_imp->resetDisplayResolution();
02036                                         }
02037                                 }
02038                                 break;
02039                         }
02040 
02041                 case WM_ACTIVATE:
02042                         {
02043                                 // Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE
02044                                 BOOL activating = (LOWORD(w_param) != WA_INACTIVE);
02045 
02046                                 BOOL minimized = BOOL(HIWORD(w_param));
02047 
02048                                 // JC - I'm not sure why, but if we don't report that we handled the 
02049                                 // WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work 
02050                                 // properly when we run fullscreen.
02051                                 if (gDebugWindowProc)
02052                                 {
02053                                         llinfos << "WINDOWPROC Activate "
02054                                                 << " activating " << S32(activating) 
02055                                                 << " minimized " << S32(minimized)
02056                                                 << llendl;
02057                                 }
02058 
02059                                 // Don't handle this.
02060                                 break;
02061                         }
02062 
02063                 case WM_QUERYOPEN:
02064                         // TODO: use this to return a nice icon
02065                         break;
02066 
02067                 case WM_SYSCOMMAND:
02068                         switch(w_param)
02069                         {
02070                         case SC_KEYMENU: 
02071                                 // Disallow the ALT key from triggering the default system menu.
02072                                 return 0;               
02073 
02074                         case SC_SCREENSAVE:
02075                         case SC_MONITORPOWER:
02076                                 // eat screen save messages and prevent them!
02077                                 return 0;
02078                         }
02079                         break;
02080 
02081                 case WM_CLOSE:
02082                         // Will the app allow the window to close?
02083                         if (window_imp->mCallbacks->handleCloseRequest(window_imp))
02084                         {
02085                                 // Get the app to initiate cleanup.
02086                                 window_imp->mCallbacks->handleQuit(window_imp);
02087                                 // The app is responsible for calling destroyWindow when done with GL
02088                         }
02089                         return 0;
02090 
02091                 case WM_DESTROY:
02092                         if (window_imp->shouldPostQuit())
02093                         {
02094                                 PostQuitMessage(0);  // Posts WM_QUIT with an exit code of 0
02095                         }
02096                         return 0;
02097 
02098                 case WM_COMMAND:
02099                         if (!HIWORD(w_param)) // this message is from a menu
02100                         {
02101                                 window_imp->mCallbacks->handleMenuSelect(window_imp, LOWORD(w_param));
02102                         }
02103                         break;
02104 
02105                 case WM_SYSKEYDOWN:
02106                         // allow system keys, such as ALT-F4 to be processed by Windows
02107                         eat_keystroke = FALSE;
02108                 case WM_KEYDOWN:
02109                         {
02110                                 if (gDebugWindowProc)
02111                                 {
02112                                         llinfos << "Debug WindowProc WM_KEYDOWN "
02113                                                 << " key " << S32(w_param) 
02114                                                 << llendl;
02115                                 }
02116                                 if(gKeyboard->handleKeyDown(w_param, mask) && eat_keystroke)
02117                                 {
02118                                         return 0;
02119                                 }
02120                                 // pass on to windows if we didn't handle it
02121                                 break;
02122                         }
02123                 case WM_SYSKEYUP:
02124                         eat_keystroke = FALSE;
02125                 case WM_KEYUP:
02126                         if (gDebugWindowProc)
02127                         {
02128                                 llinfos << "Debug WindowProc WM_KEYUP "
02129                                         << " key " << S32(w_param) 
02130                                         << llendl;
02131                         }
02132                         if (gKeyboard->handleKeyUp(w_param, mask) && eat_keystroke)
02133                         {
02134                                 return 0;
02135                         }
02136 
02137                         // pass on to windows
02138                         break;
02139 
02140 
02141                 case WM_CHAR:
02142                         // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need
02143                         // to figure out how that works. - Doug
02144                         //
02145                         // ... Well, I don't think so.
02146                         // How it works is explained in Win32 API document, but WM_UNICHAR didn't work
02147                         // as specified at least on Windows XP SP1 Japanese version.  I have never used
02148                         // it since then, and I'm not sure whether it has been fixed now, but I don't think
02149                         // it is worth trying.  The good old WM_CHAR works just fine even for supplementary
02150                         // characters.  We just need to take care of surrogate pairs sent as two WM_CHAR's
02151                         // by ourselves.  It is not that tough.  -- Alissa Sabre @ SL
02152                         //
02153                         // llinfos << "WM_CHAR: " << w_param << llendl;
02154                         if (gDebugWindowProc)
02155                         {
02156                                 llinfos << "Debug WindowProc WM_CHAR "
02157                                         << " key " << S32(w_param) 
02158                                         << llendl;
02159                         }
02160                         // Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE,
02161                         // we *did* processed the event, so I believe we should not pass it to DefWindowProc...
02162                         window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE));
02163                         return 0;
02164 
02165                 case WM_LBUTTONDOWN:
02166                         {
02167                                 // Because we move the cursor position in the app, we need to query
02168                                 // to find out where the cursor at the time the event is handled.
02169                                 // If we don't do this, many clicks could get buffered up, and if the
02170                                 // first click changes the cursor position, all subsequent clicks
02171                                 // will occur at the wrong location.  JC
02172                                 LLCoordWindow cursor_coord_window;
02173                                 if (window_imp->mMousePositionModified)
02174                                 {
02175                                         window_imp->getCursorPosition(&cursor_coord_window);
02176                                         window_imp->convertCoords(cursor_coord_window, &gl_coord);
02177                                 }
02178                                 else
02179                                 {
02180                                         window_imp->convertCoords(window_coord, &gl_coord);
02181                                 }
02182                                 MASK mask = gKeyboard->currentMask(TRUE);
02183                                 if (window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask))
02184                                 {
02185                                         return 0;
02186                                 }
02187                         }
02188                         break;
02189 
02190                 case WM_LBUTTONDBLCLK:
02191                 //RN: ignore right button double clicks for now
02192                 //case WM_RBUTTONDBLCLK:
02193                         {
02194                                 // Because we move the cursor position in the app, we need to query
02195                                 // to find out where the cursor at the time the event is handled.
02196                                 // If we don't do this, many clicks could get buffered up, and if the
02197                                 // first click changes the cursor position, all subsequent clicks
02198                                 // will occur at the wrong location.  JC
02199                                 LLCoordWindow cursor_coord_window;
02200                                 if (window_imp->mMousePositionModified)
02201                                 {
02202                                         window_imp->getCursorPosition(&cursor_coord_window);
02203                                         window_imp->convertCoords(cursor_coord_window, &gl_coord);
02204                                 }
02205                                 else
02206                                 {
02207                                         window_imp->convertCoords(window_coord, &gl_coord);
02208                                 }
02209                                 MASK mask = gKeyboard->currentMask(TRUE);
02210                                 if (window_imp->mCallbacks->handleDoubleClick(window_imp, gl_coord, mask) )
02211                                 {
02212                                         return 0;
02213                                 }
02214                         }
02215                         break;
02216 
02217                 case WM_LBUTTONUP:
02218                         {
02219                                 //if (gDebugClicks)
02220                                 //{
02221                                 //      llinfos << "WndProc left button up" << llendl;
02222                                 //}
02223                                 // Because we move the cursor position in the app, we need to query
02224                                 // to find out where the cursor at the time the event is handled.
02225                                 // If we don't do this, many clicks could get buffered up, and if the
02226                                 // first click changes the cursor position, all subsequent clicks
02227                                 // will occur at the wrong location.  JC
02228                                 LLCoordWindow cursor_coord_window;
02229                                 if (window_imp->mMousePositionModified)
02230                                 {
02231                                         window_imp->getCursorPosition(&cursor_coord_window);
02232                                         window_imp->convertCoords(cursor_coord_window, &gl_coord);
02233                                 }
02234                                 else
02235                                 {
02236                                         window_imp->convertCoords(window_coord, &gl_coord);
02237                                 }
02238                                 MASK mask = gKeyboard->currentMask(TRUE);
02239                                 if (window_imp->mCallbacks->handleMouseUp(window_imp, gl_coord, mask))
02240                                 {
02241                                         return 0;
02242                                 }
02243                         }
02244                         break;
02245 
02246                 case WM_RBUTTONDBLCLK:
02247                 case WM_RBUTTONDOWN:
02248                         {
02249                                 // Because we move the cursor position in tllviewerhe app, we need to query
02250                                 // to find out where the cursor at the time the event is handled.
02251                                 // If we don't do this, many clicks could get buffered up, and if the
02252                                 // first click changes the cursor position, all subsequent clicks
02253                                 // will occur at the wrong location.  JC
02254                                 LLCoordWindow cursor_coord_window;
02255                                 if (window_imp->mMousePositionModified)
02256                                 {
02257                                         window_imp->getCursorPosition(&cursor_coord_window);
02258                                         window_imp->convertCoords(cursor_coord_window, &gl_coord);
02259                                 }
02260                                 else
02261                                 {
02262                                         window_imp->convertCoords(window_coord, &gl_coord);
02263                                 }
02264                                 MASK mask = gKeyboard->currentMask(TRUE);
02265                                 if (window_imp->mCallbacks->handleRightMouseDown(window_imp, gl_coord, mask))
02266                                 {
02267                                         return 0;
02268                                 }
02269                         }
02270                         break;
02271 
02272                 case WM_RBUTTONUP:
02273                         {
02274                                 // Because we move the cursor position in the app, we need to query
02275                                 // to find out where the cursor at the time the event is handled.
02276                                 // If we don't do this, many clicks could get buffered up, and if the
02277                                 // first click changes the cursor position, all subsequent clicks
02278                                 // will occur at the wrong location.  JC
02279                                 LLCoordWindow cursor_coord_window;
02280                                 if (window_imp->mMousePositionModified)
02281                                 {
02282                                         window_imp->getCursorPosition(&cursor_coord_window);
02283                                         window_imp->convertCoords(cursor_coord_window, &gl_coord);
02284                                 }
02285                                 else
02286                                 {
02287                                         window_imp->convertCoords(window_coord, &gl_coord);
02288                                 }
02289                                 MASK mask = gKeyboard->currentMask(TRUE);
02290                                 if (window_imp->mCallbacks->handleRightMouseUp(window_imp, gl_coord, mask))
02291                                 {
02292                                         return 0;
02293                                 }
02294                         }
02295                         break;
02296 
02297                 case WM_MBUTTONDOWN:
02298 //              case WM_MBUTTONDBLCLK:
02299                         {
02300                                 // Because we move the cursor position in tllviewerhe app, we need to query
02301                                 // to find out where the cursor at the time the event is handled.
02302                                 // If we don't do this, many clicks could get buffered up, and if the
02303                                 // first click changes the cursor position, all subsequent clicks
02304                                 // will occur at the wrong location.  JC
02305                                 LLCoordWindow cursor_coord_window;
02306                                 if (window_imp->mMousePositionModified)
02307                                 {
02308                                         window_imp->getCursorPosition(&cursor_coord_window);
02309                                         window_imp->convertCoords(cursor_coord_window, &gl_coord);
02310                                 }
02311                                 else
02312                                 {
02313                                         window_imp->convertCoords(window_coord, &gl_coord);
02314                                 }
02315                                 MASK mask = gKeyboard->currentMask(TRUE);
02316                                 if (window_imp->mCallbacks->handleMiddleMouseDown(window_imp, gl_coord, mask))
02317                                 {
02318                                         return 0;
02319                                 }
02320                         }
02321                         break;
02322 
02323                 case WM_MBUTTONUP:
02324                         {
02325                                 // Because we move the cursor position in tllviewerhe app, we need to query
02326                                 // to find out where the cursor at the time the event is handled.
02327                                 // If we don't do this, many clicks could get buffered up, and if the
02328                                 // first click changes the cursor position, all subsequent clicks
02329                                 // will occur at the wrong location.  JC
02330                                 LLCoordWindow cursor_coord_window;
02331                                 if (window_imp->mMousePositionModified)
02332                                 {
02333                                         window_imp->getCursorPosition(&cursor_coord_window);
02334                                         window_imp->convertCoords(cursor_coord_window, &gl_coord);
02335                                 }
02336                                 else
02337                                 {
02338                                         window_imp->convertCoords(window_coord, &gl_coord);
02339                                 }
02340                                 MASK mask = gKeyboard->currentMask(TRUE);
02341                                 if (window_imp->mCallbacks->handleMiddleMouseUp(window_imp, gl_coord, mask))
02342                                 {
02343                                         return 0;
02344                                 }
02345                         }
02346                         break;
02347 
02348                 case WM_MOUSEWHEEL:
02349                         {
02350                                 static short z_delta = 0;
02351 
02352                                 z_delta += HIWORD(w_param);
02353                                 // cout << "z_delta " << z_delta << endl;
02354 
02355                                 // current mouse wheels report changes in increments of zDelta (+120, -120)
02356                                 // Future, higher resolution mouse wheels may report smaller deltas.
02357                                 // So we sum the deltas and only act when we've exceeded WHEEL_DELTA
02358                                 //
02359                                 // If the user rapidly spins the wheel, we can get messages with
02360                                 // large deltas, like 480 or so.  Thus we need to scroll more quickly.
02361                                 if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta)
02362                                 {
02363                                         window_imp->mCallbacks->handleScrollWheel(window_imp, -z_delta / WHEEL_DELTA);
02364                                         z_delta = 0;
02365                                 }
02366                                 return 0;
02367                         }
02368                         /*
02369                         // TODO: add this after resolving _WIN32_WINNT issue
02370                         case WM_MOUSELEAVE:
02371                         {
02372                         window_imp->mCallbacks->handleMouseLeave(window_imp);
02373 
02374                         //                              TRACKMOUSEEVENT track_mouse_event;
02375                         //                              track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT );
02376                         //                              track_mouse_event.dwFlags = TME_LEAVE;
02377                         //                              track_mouse_event.hwndTrack = h_wnd;
02378                         //                              track_mouse_event.dwHoverTime = HOVER_DEFAULT;
02379                         //                              TrackMouseEvent( &track_mouse_event ); 
02380                         return 0;
02381                         }
02382                         */
02383                         // Handle mouse movement within the window
02384                 case WM_MOUSEMOVE:
02385                         {
02386                                 window_imp->convertCoords(window_coord, &gl_coord);
02387                                 MASK mask = gKeyboard->currentMask(TRUE);
02388                                 window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
02389                                 return 0;
02390                         }
02391 
02392                 case WM_SIZE:
02393                         {
02394                                 S32 width = S32( LOWORD(l_param) );
02395                                 S32 height = S32( HIWORD(l_param) );
02396 
02397                                 if (gDebugWindowProc)
02398                                 {
02399                                         BOOL maximized = ( w_param == SIZE_MAXIMIZED );
02400                                         BOOL restored  = ( w_param == SIZE_RESTORED );
02401                                         BOOL minimized = ( w_param == SIZE_MINIMIZED );
02402 
02403                                         llinfos << "WINDOWPROC Size "
02404                                                 << width << "x" << height
02405                                                 << " max " << S32(maximized)
02406                                                 << " min " << S32(minimized)
02407                                                 << " rest " << S32(restored)
02408                                                 << llendl;
02409                                 }
02410 
02411                                 // There's an odd behavior with WM_SIZE that I would call a bug. If 
02412                                 // the window is maximized, and you call MoveWindow() with a size smaller
02413                                 // than a maximized window, it ends up sending WM_SIZE with w_param set 
02414                                 // to SIZE_MAXIMIZED -- which isn't true. So the logic below doesn't work.
02415                                 // (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see 
02416                                 // LLWindowWin32::moveWindow in this file). 
02417 
02418                                 // If we are now restored, but we weren't before, this
02419                                 // means that the window was un-minimized.
02420                                 if (w_param == SIZE_RESTORED && window_imp->mLastSizeWParam != SIZE_RESTORED)
02421                                 {
02422                                         window_imp->mCallbacks->handleActivate(window_imp, TRUE);
02423                                 }
02424 
02425                                 // handle case of window being maximized from fully minimized state
02426                                 if (w_param == SIZE_MAXIMIZED && window_imp->mLastSizeWParam != SIZE_MAXIMIZED)
02427                                 {
02428                                         window_imp->mCallbacks->handleActivate(window_imp, TRUE);
02429                                 }
02430 
02431                                 // Also handle the minimization case
02432                                 if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED)
02433                                 {
02434                                         window_imp->mCallbacks->handleActivate(window_imp, FALSE);
02435                                 }
02436 
02437                                 // Actually resize all of our views
02438                                 if (w_param != SIZE_MINIMIZED)
02439                                 {
02440                                         // Ignore updates for minimizing and minimized "windows"
02441                                         window_imp->mCallbacks->handleResize(   window_imp, 
02442                                                 LOWORD(l_param), 
02443                                                 HIWORD(l_param) );
02444                                 }
02445 
02446                                 window_imp->mLastSizeWParam = w_param;
02447 
02448                                 return 0;
02449                         }
02450 
02451                 case WM_SETFOCUS:
02452                         if (gDebugWindowProc)
02453                         {
02454                                 llinfos << "WINDOWPROC SetFocus" << llendl;
02455                         }
02456                         window_imp->mCallbacks->handleFocus(window_imp);
02457                         return 0;
02458 
02459                 case WM_KILLFOCUS:
02460                         if (gDebugWindowProc)
02461                         {
02462                                 llinfos << "WINDOWPROC KillFocus" << llendl;
02463                         }
02464                         window_imp->mCallbacks->handleFocusLost(window_imp);
02465                         return 0;
02466 
02467                 case WM_COPYDATA:
02468                         // received a URL
02469                         PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT) l_param;
02470                         window_imp->mCallbacks->handleDataCopy(window_imp, myCDS->dwData, myCDS->lpData);
02471                         return 0;                       
02472                 }
02473         }
02474 
02475         // pass unhandled messages down to Windows
02476         return DefWindowProc(h_wnd, u_msg, w_param, l_param);
02477 }
02478 
02479 BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to)
02480 {
02481         S32             client_height;
02482         RECT    client_rect;
02483         LLCoordWindow window_position;
02484 
02485         if (!mWindowHandle ||
02486                 !GetClientRect(mWindowHandle, &client_rect) ||
02487                 NULL == to)
02488         {
02489                 return FALSE;
02490         }
02491 
02492         to->mX = from.mX;
02493         client_height = client_rect.bottom - client_rect.top;
02494         to->mY = client_height - from.mY - 1;
02495 
02496         return TRUE;
02497 }
02498 
02499 BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordGL* to)
02500 {
02501         S32             client_height;
02502         RECT    client_rect;
02503 
02504         if (!mWindowHandle ||
02505                 !GetClientRect(mWindowHandle, &client_rect) ||
02506                 NULL == to)
02507         {
02508                 return FALSE;
02509         }
02510 
02511         to->mX = from.mX;
02512         client_height = client_rect.bottom - client_rect.top;
02513         to->mY = client_height - from.mY - 1;
02514 
02515         return TRUE;
02516 }
02517 
02518 BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordWindow* to)
02519 {       
02520         POINT mouse_point;
02521 
02522         mouse_point.x = from.mX;
02523         mouse_point.y = from.mY;
02524         BOOL result = ScreenToClient(mWindowHandle, &mouse_point);
02525 
02526         if (result)
02527         {
02528                 to->mX = mouse_point.x;
02529                 to->mY = mouse_point.y;
02530         }
02531 
02532         return result;
02533 }
02534 
02535 BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordScreen *to)
02536 {
02537         POINT mouse_point;
02538 
02539         mouse_point.x = from.mX;
02540         mouse_point.y = from.mY;
02541         BOOL result = ClientToScreen(mWindowHandle, &mouse_point);
02542 
02543         if (result)
02544         {
02545                 to->mX = mouse_point.x;
02546                 to->mY = mouse_point.y;
02547         }
02548 
02549         return result;
02550 }
02551 
02552 BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordGL *to)
02553 {
02554         LLCoordWindow window_coord;
02555 
02556         if (!mWindowHandle || (NULL == to))
02557         {
02558                 return FALSE;
02559         }
02560 
02561         convertCoords(from, &window_coord);
02562         convertCoords(window_coord, to);
02563         return TRUE;
02564 }
02565 
02566 BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordScreen *to)
02567 {
02568         LLCoordWindow window_coord;
02569 
02570         if (!mWindowHandle || (NULL == to))
02571         {
02572                 return FALSE;
02573         }
02574 
02575         convertCoords(from, &window_coord);
02576         convertCoords(window_coord, to);
02577         return TRUE;
02578 }
02579 
02580 
02581 BOOL LLWindowWin32::isClipboardTextAvailable()
02582 {
02583         return IsClipboardFormatAvailable(CF_UNICODETEXT);
02584 }
02585 
02586 
02587 BOOL LLWindowWin32::pasteTextFromClipboard(LLWString &dst)
02588 {
02589         BOOL success = FALSE;
02590 
02591         if (IsClipboardFormatAvailable(CF_UNICODETEXT))
02592         {
02593                 if (OpenClipboard(mWindowHandle))
02594                 {
02595                         HGLOBAL h_data = GetClipboardData(CF_UNICODETEXT);
02596                         if (h_data)
02597                         {
02598                                 WCHAR *utf16str = (WCHAR*) GlobalLock(h_data);
02599                                 if (utf16str)
02600                                 {
02601                                         dst = utf16str_to_wstring(utf16str);
02602                                         LLWString::removeCRLF(dst);
02603                                         GlobalUnlock(h_data);
02604                                         success = TRUE;
02605                                 }
02606                         }
02607                         CloseClipboard();
02608                 }
02609         }
02610 
02611         return success;
02612 }
02613 
02614 
02615 BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr)
02616 {
02617         BOOL success = FALSE;
02618 
02619         if (OpenClipboard(mWindowHandle))
02620         {
02621                 EmptyClipboard();
02622 
02623                 // Provide a copy of the data in Unicode format.
02624                 LLWString sanitized_string(wstr);
02625                 LLWString::addCRLF(sanitized_string);
02626                 llutf16string out_utf16 = wstring_to_utf16str(sanitized_string);
02627                 const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(WCHAR);
02628 
02629                 // Memory is allocated and then ownership of it is transfered to the system.
02630                 HGLOBAL hglobal_copy_utf16 = GlobalAlloc(GMEM_MOVEABLE, size_utf16); 
02631                 if (hglobal_copy_utf16)
02632                 {
02633                         WCHAR* copy_utf16 = (WCHAR*) GlobalLock(hglobal_copy_utf16);
02634                         if (copy_utf16)
02635                         {
02636                                 memcpy(copy_utf16, out_utf16.c_str(), size_utf16);      /* Flawfinder: ignore */
02637                                 GlobalUnlock(hglobal_copy_utf16);
02638 
02639                                 if (SetClipboardData(CF_UNICODETEXT, hglobal_copy_utf16))
02640                                 {
02641                                         success = TRUE;
02642                                 }
02643                         }
02644                 }
02645 
02646                 CloseClipboard();
02647         }
02648 
02649         return success;
02650 }
02651 
02652 // Constrains the mouse to the window.
02653 void LLWindowWin32::setMouseClipping( BOOL b )
02654 {
02655         if( b != mIsMouseClipping )
02656         {
02657                 BOOL success = FALSE;
02658 
02659                 if( b )
02660                 {
02661                         GetClipCursor( &mOldMouseClip );
02662 
02663                         RECT client_rect_in_screen_space;
02664                         if( getClientRectInScreenSpace( &client_rect_in_screen_space ) )
02665                         {
02666                                 success = ClipCursor( &client_rect_in_screen_space );
02667                         }
02668                 }
02669                 else
02670                 {
02671                         // Must restore the old mouse clip, which may be set by another window.
02672                         success = ClipCursor( &mOldMouseClip );
02673                         SetRect( &mOldMouseClip, 0, 0, 0, 0 );
02674                 }
02675 
02676                 if( success )
02677                 {
02678                         mIsMouseClipping = b;
02679                 }
02680         }
02681 }
02682 
02683 BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp )
02684 {
02685         BOOL success = FALSE;
02686 
02687         RECT client_rect;
02688         if( mWindowHandle && GetClientRect(mWindowHandle, &client_rect) )
02689         {
02690                 POINT top_left;
02691                 top_left.x = client_rect.left;
02692                 top_left.y = client_rect.top;
02693                 ClientToScreen(mWindowHandle, &top_left); 
02694 
02695                 POINT bottom_right;
02696                 bottom_right.x = client_rect.right;
02697                 bottom_right.y = client_rect.bottom;
02698                 ClientToScreen(mWindowHandle, &bottom_right); 
02699 
02700                 SetRect( rectp,
02701                         top_left.x,
02702                         top_left.y,
02703                         bottom_right.x,
02704                         bottom_right.y );
02705 
02706                 success = TRUE;
02707         }
02708 
02709         return success;
02710 }
02711 
02712 
02713 BOOL LLWindowWin32::sendEmail(const char* address, const char* subject, const char* body_text,
02714                                                                            const char* attachment, const char* attachment_displayed_name )
02715 {
02716         // Based on "A SendMail() DLL" by Greg Turner, Windows Developer Magazine, Nov. 1997.
02717         // See article for use of GetProcAddress
02718         // No restrictions on use.
02719 
02720         enum SendResult
02721         {
02722                 LL_EMAIL_SUCCESS,
02723                 LL_EMAIL_MAPI_NOT_INSTALLED,    // No MAPI Server (eg Microsoft Exchange) installed
02724                 LL_EMAIL_MAPILOAD_FAILED,               // Load of MAPI32.DLL failed
02725                 LL_EMAIL_SEND_FAILED                    // The message send itself failed
02726         };
02727 
02728         SendResult  result = LL_EMAIL_SUCCESS;
02729 
02730         U32 mapi_installed = GetProfileInt(L"Mail", L"MAPI", 0);
02731         if( !mapi_installed)
02732         {
02733                 result = LL_EMAIL_MAPI_NOT_INSTALLED;
02734         }
02735         else
02736         {
02737                 HINSTANCE hMAPIInst = LoadLibrary(L"MAPI32.DLL");       /* Flawfinder: ignore */
02738                 if(!hMAPIInst)
02739                 {
02740                         result =  LL_EMAIL_MAPILOAD_FAILED;
02741                 }
02742                 else
02743                 {
02744                         LPMAPISENDMAIL  pMAPISendMail   = (LPMAPISENDMAIL)      GetProcAddress(hMAPIInst, "MAPISendMail");
02745 
02746                         // Send the message
02747                         MapiRecipDesc recipients[1];
02748                         recipients[0].ulReserved = 0;
02749                         recipients[0].ulRecipClass = MAPI_TO;
02750                         recipients[0].lpszName = (char*)address;
02751                         recipients[0].lpszAddress = (char*)address;
02752                         recipients[0].ulEIDSize = 0;
02753                         recipients[0].lpEntryID = 0;
02754 
02755                         MapiFileDesc files[1];
02756                         files[0].ulReserved = 0;
02757                         files[0].flFlags = 0;                           // non-OLE file
02758                         files[0].nPosition = -1;                        // Leave file location in email unspecified.
02759                         files[0].lpszPathName = (char*)attachment; // Must be fully qualified name, including drive letter.
02760                         files[0].lpszFileName = (char*)attachment_displayed_name;               // If NULL, uses attachment as displayed name.
02761                         files[0].lpFileType = NULL;                     // Recipient will have to figure out what kind of file this is.
02762 
02763                         MapiMessage msg;
02764                         memset(&msg, 0, sizeof(msg));
02765                         msg.lpszSubject         = (char*)subject;               // may be NULL
02766                         msg.lpszNoteText        = (char*)body_text;
02767                         msg.nRecipCount         = address ? 1 : 0;
02768                         msg.lpRecips            = address ? recipients : NULL;
02769                         msg.nFileCount                  = attachment ? 1 : 0;
02770                         msg.lpFiles                             = attachment ? files : NULL;
02771 
02772                         U32 success = pMAPISendMail(0, (U32) mWindowHandle, &msg, MAPI_DIALOG|MAPI_LOGON_UI|MAPI_NEW_SESSION, 0);
02773                         if(success != SUCCESS_SUCCESS)
02774                         {
02775                                 result = LL_EMAIL_SEND_FAILED;
02776                         }
02777 
02778                         FreeLibrary(hMAPIInst);
02779                 }
02780         }
02781 
02782         return result == LL_EMAIL_SUCCESS;
02783 }
02784 
02785 
02786 S32 LLWindowWin32::stat(const char* file_name, struct stat* stat_info)
02787 {
02788         llassert( sizeof(struct stat) == sizeof(struct _stat) );  // They are defined identically in sys/stat.h, but I'm paranoid.
02789         return LLFile::stat( file_name, (struct _stat*) stat_info );
02790 }
02791 
02792 void LLWindowWin32::flashIcon(F32 seconds)
02793 {
02794         FLASHWINFO flash_info;
02795 
02796         flash_info.cbSize = sizeof(FLASHWINFO);
02797         flash_info.hwnd = mWindowHandle;
02798         flash_info.dwFlags = FLASHW_TRAY;
02799         flash_info.uCount = UINT(seconds / ICON_FLASH_TIME);
02800         flash_info.dwTimeout = DWORD(1000.f * ICON_FLASH_TIME); // milliseconds
02801         FlashWindowEx(&flash_info);
02802 }
02803 
02804 F32 LLWindowWin32::getGamma()
02805 {
02806         return mCurrentGamma;
02807 }
02808 
02809 BOOL LLWindowWin32::restoreGamma()
02810 {
02811         return SetDeviceGammaRamp(mhDC, mPrevGammaRamp);
02812 }
02813 
02814 BOOL LLWindowWin32::setGamma(const F32 gamma)
02815 {
02816         mCurrentGamma = gamma;
02817 
02818         llinfos << "Setting gamma to " << gamma << llendl;
02819 
02820         for ( int i = 0; i < 256; ++i )
02821         {
02822                 int mult = 256 - ( int ) ( ( gamma - 1.0f ) * 128.0f );
02823 
02824                 int value = mult * i;
02825 
02826                 if ( value > 0xffff )
02827                         value = 0xffff;
02828 
02829                 mCurrentGammaRamp [ 0 * 256 + i ] = 
02830                         mCurrentGammaRamp [ 1 * 256 + i ] = 
02831                                 mCurrentGammaRamp [ 2 * 256 + i ] = ( WORD )value;
02832         };
02833 
02834         return SetDeviceGammaRamp ( mhDC, mCurrentGammaRamp );
02835 }
02836 
02837 LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions)
02838 {
02839         if (!mSupportedResolutions)
02840         {
02841                 mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS];
02842                 DEVMODE dev_mode;
02843 
02844                 mNumSupportedResolutions = 0;
02845                 for (S32 mode_num = 0; mNumSupportedResolutions < MAX_NUM_RESOLUTIONS; mode_num++)
02846                 {
02847                         if (!EnumDisplaySettings(NULL, mode_num, &dev_mode))
02848                         {
02849                                 break;
02850                         }
02851 
02852                         if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL &&
02853                                 dev_mode.dmPelsWidth >= 800 &&
02854                                 dev_mode.dmPelsHeight >= 600)
02855                         {
02856                                 BOOL resolution_exists = FALSE;
02857                                 for(S32 i = 0; i < mNumSupportedResolutions; i++)
02858                                 {
02859                                         if (mSupportedResolutions[i].mWidth == dev_mode.dmPelsWidth &&
02860                                                 mSupportedResolutions[i].mHeight == dev_mode.dmPelsHeight)
02861                                         {
02862                                                 resolution_exists = TRUE;
02863                                         }
02864                                 }
02865                                 if (!resolution_exists)
02866                                 {
02867                                         mSupportedResolutions[mNumSupportedResolutions].mWidth = dev_mode.dmPelsWidth;
02868                                         mSupportedResolutions[mNumSupportedResolutions].mHeight = dev_mode.dmPelsHeight;
02869                                         mNumSupportedResolutions++;
02870                                 }
02871                         }
02872                 }
02873         }
02874 
02875         num_resolutions = mNumSupportedResolutions;
02876         return mSupportedResolutions;
02877 }
02878 
02879 
02880 F32 LLWindowWin32::getNativeAspectRatio()
02881 {
02882         if (mOverrideAspectRatio > 0.f)
02883         {
02884                 return mOverrideAspectRatio;
02885         }
02886         else if (mNativeAspectRatio > 0.f)
02887         {
02888                 // we grabbed this value at startup, based on the user's desktop settings
02889                 return mNativeAspectRatio;
02890         }
02891         // RN: this hack presumes that the largest supported resolution is monitor-limited
02892         // and that pixels in that mode are square, therefore defining the native aspect ratio
02893         // of the monitor...this seems to work to a close approximation for most CRTs/LCDs
02894         S32 num_resolutions;
02895         LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions);
02896 
02897         return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight);
02898 }
02899 
02900 F32 LLWindowWin32::getPixelAspectRatio()
02901 {
02902         F32 pixel_aspect = 1.f;
02903         if (getFullscreen())
02904         {
02905                 LLCoordScreen screen_size;
02906                 getSize(&screen_size);
02907                 pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX;
02908         }
02909 
02910         return pixel_aspect;
02911 }
02912 
02913 // Change display resolution.  Returns true if successful.
02914 // protected
02915 BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh)
02916 {
02917         DEVMODE dev_mode;
02918         dev_mode.dmSize = sizeof(dev_mode);
02919         BOOL success = FALSE;
02920 
02921         // Don't change anything if we don't have to
02922         if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
02923         {
02924                 if (dev_mode.dmPelsWidth        == width &&
02925                         dev_mode.dmPelsHeight       == height &&
02926                         dev_mode.dmBitsPerPel       == bits &&
02927                         dev_mode.dmDisplayFrequency == refresh )
02928                 {
02929                         // ...display mode identical, do nothing
02930                         return TRUE;
02931                 }
02932         }
02933 
02934         memset(&dev_mode, 0, sizeof(dev_mode));
02935         dev_mode.dmSize = sizeof(dev_mode);
02936         dev_mode.dmPelsWidth        = width;
02937         dev_mode.dmPelsHeight       = height;
02938         dev_mode.dmBitsPerPel       = bits;
02939         dev_mode.dmDisplayFrequency = refresh;
02940         dev_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
02941 
02942         // CDS_FULLSCREEN indicates that this is a temporary change to the device mode.
02943         LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN);
02944 
02945         success = (DISP_CHANGE_SUCCESSFUL == cds_result);
02946 
02947         if (!success)
02948         {
02949                 llwarns << "setDisplayResolution failed, "
02950                         << width << "x" << height << "x" << bits << " @ " << refresh << llendl;
02951         }
02952 
02953         return success;
02954 }
02955 
02956 // protected
02957 BOOL LLWindowWin32::setFullscreenResolution()
02958 {
02959         if (mFullscreen)
02960         {
02961                 return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh);
02962         }
02963         else
02964         {
02965                 return FALSE;
02966         }
02967 }
02968 
02969 // protected
02970 BOOL LLWindowWin32::resetDisplayResolution()
02971 {
02972         llinfos << "resetDisplayResolution START" << llendl;
02973 
02974         LONG cds_result = ChangeDisplaySettings(NULL, 0);
02975 
02976         BOOL success = (DISP_CHANGE_SUCCESSFUL == cds_result);
02977 
02978         if (!success)
02979         {
02980                 llwarns << "resetDisplayResolution failed" << llendl;
02981         }
02982 
02983         llinfos << "resetDisplayResolution END" << llendl;
02984 
02985         return success;
02986 }
02987 
02988 void LLWindowWin32::swapBuffers()
02989 {
02990         SwapBuffers(mhDC);
02991 }
02992 
02993 
02994 BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance,
02995                                                                         VOID* pContext )
02996 {
02997         HRESULT hr;
02998 
02999         // Obtain an interface to the enumerated joystick.
03000         hr = g_pDI->CreateDevice( pdidInstance->guidInstance, &g_pJoystick, NULL );
03001 
03002         // If it failed, then we can't use this joystick. (Maybe the user unplugged
03003         // it while we were in the middle of enumerating it.)
03004         if( FAILED(hr) ) 
03005                 return DIENUM_CONTINUE;
03006 
03007         // Stop enumeration. Note: we're just taking the first joystick we get. You
03008         // could store all the enumerated joysticks and let the user pick.
03009         return DIENUM_STOP;
03010 }
03011 
03012 BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi,
03013                                                                   VOID* pContext )
03014 {
03015         if( pdidoi->dwType & DIDFT_AXIS )
03016         {
03017                 DIPROPRANGE diprg; 
03018                 diprg.diph.dwSize       = sizeof(DIPROPRANGE); 
03019                 diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
03020                 diprg.diph.dwHow        = DIPH_BYID; 
03021                 diprg.diph.dwObj        = pdidoi->dwType; // Specify the enumerated axis
03022                 diprg.lMin              = -1000; 
03023                 diprg.lMax              = +1000; 
03024 
03025                 // Set the range for the axis
03026                 if( FAILED( g_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) ) 
03027                         return DIENUM_STOP;
03028 
03029         }
03030         return DIENUM_CONTINUE;
03031 }
03032 
03033 void LLWindowWin32::updateJoystick( )
03034 {
03035         HRESULT hr;
03036         DIJOYSTATE js;           // DInput joystick state
03037 
03038         if (!g_pJoystick)
03039                 return;
03040         hr = g_pJoystick->Poll();
03041         if ( hr == DIERR_INPUTLOST )
03042         {
03043                 hr = g_pJoystick->Acquire();
03044                 return;
03045         }
03046         else if ( FAILED(hr) )
03047                 return;
03048 
03049         // Get the input's device state
03050         if( FAILED( hr = g_pJoystick->GetDeviceState( sizeof(DIJOYSTATE), &js ) ) )
03051                 return; // The device should have been acquired during the Poll()
03052 
03053         mJoyAxis[0] = js.lX/1000.f;
03054         mJoyAxis[1] = js.lY/1000.f;
03055         mJoyAxis[2] = js.lZ/1000.f;
03056         mJoyAxis[3] = js.lRx/1000.f;
03057         mJoyAxis[4] = js.lRy/1000.f;
03058         mJoyAxis[5] = js.lRz/1000.f;
03059 
03060         for (U32 i = 0; i < 16; i++)
03061         {
03062                 mJoyButtonState[i] = js.rgbButtons[i];
03063         }
03064 }
03065 
03066 
03067 //
03068 // LLSplashScreenImp
03069 //
03070 LLSplashScreenWin32::LLSplashScreenWin32()
03071 :       mWindow(NULL)
03072 {
03073 }
03074 
03075 LLSplashScreenWin32::~LLSplashScreenWin32()
03076 {
03077 }
03078 
03079 void LLSplashScreenWin32::showImpl()
03080 {
03081         // This appears to work.  ???
03082         HINSTANCE hinst = GetModuleHandle(NULL);
03083 
03084         mWindow = CreateDialog(hinst, 
03085                 TEXT("SPLASHSCREEN"), 
03086                 NULL,   // no parent
03087                 (DLGPROC) LLSplashScreenWin32::windowProc); 
03088         ShowWindow(mWindow, SW_SHOW);
03089 }
03090 
03091 
03092 void LLSplashScreenWin32::updateImpl(const char *mesg)
03093 {
03094         if (!mWindow) return;
03095 
03096         WCHAR w_mesg[1024];
03097         mbstowcs(w_mesg, mesg, 1024);
03098 
03099         SendDlgItemMessage(mWindow,
03100                 666,            // HACK: text id
03101                 WM_SETTEXT,
03102                 FALSE,
03103                 (LPARAM)w_mesg);
03104 }
03105 
03106 
03107 void LLSplashScreenWin32::hideImpl()
03108 {
03109         if (mWindow)
03110         {
03111                 DestroyWindow(mWindow);
03112                 mWindow = NULL; 
03113         }
03114 }
03115 
03116 
03117 // static
03118 LRESULT CALLBACK LLSplashScreenWin32::windowProc(HWND h_wnd, UINT u_msg,
03119                                                                                         WPARAM w_param, LPARAM l_param)
03120 {
03121         // Just give it to windows
03122         return DefWindowProc(h_wnd, u_msg, w_param, l_param);
03123 }
03124 
03125 //
03126 // Helper Funcs
03127 //
03128 
03129 S32 OSMessageBoxWin32(const char* text, const char* caption, U32 type)
03130 {
03131         UINT uType;
03132 
03133         switch(type)
03134         {
03135         case OSMB_OK:
03136                 uType = MB_OK;
03137                 break;
03138         case OSMB_OKCANCEL:
03139                 uType = MB_OKCANCEL;
03140                 break;
03141         case OSMB_YESNO:
03142                 uType = MB_YESNO;
03143                 break;
03144         default:
03145                 uType = MB_OK;
03146                 break;
03147         }
03148 
03149         // HACK! Doesn't properly handle wide strings!
03150         int retval_win = MessageBoxA(NULL, text, caption, uType);
03151         S32 retval;
03152 
03153         switch(retval_win)
03154         {
03155         case IDYES:
03156                 retval = OSBTN_YES;
03157                 break;
03158         case IDNO:
03159                 retval = OSBTN_NO;
03160                 break;
03161         case IDOK:
03162                 retval = OSBTN_OK;
03163                 break;
03164         case IDCANCEL:
03165                 retval = OSBTN_CANCEL;
03166                 break;
03167         default:
03168                 retval = OSBTN_CANCEL;
03169                 break;
03170         }
03171 
03172         return retval;
03173 }
03174 
03175 
03176 void spawn_web_browser(const char* escaped_url )
03177 {
03178         bool found = false;
03179         S32 i;
03180         for (i = 0; i < gURLProtocolWhitelistCount; i++)
03181         {
03182                 S32 len = strlen(gURLProtocolWhitelist[i]);     /* Flawfinder: ignore */
03183                 if (!strncmp(escaped_url, gURLProtocolWhitelist[i], len)
03184                         && escaped_url[len] == ':')
03185                 {
03186                         found = true;
03187                         break;
03188                 }
03189         }
03190 
03191         if (!found)
03192         {
03193                 llwarns << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << llendl;
03194                 return;
03195         }
03196 
03197         llinfos << "Opening URL " << escaped_url << llendl;
03198 
03199         // Figure out the user's default web browser
03200         // HKEY_CLASSES_ROOT\http\shell\open\command
03201         char reg_path_str[256]; /* Flawfinder: ignore */
03202         snprintf(reg_path_str, sizeof(reg_path_str), "%s\\shell\\open\\command", gURLProtocolWhitelistHandler[i]);      /* Flawfinder: ignore */
03203         WCHAR reg_path_wstr[256];
03204         mbstowcs(reg_path_wstr, reg_path_str, sizeof(reg_path_wstr)/sizeof(reg_path_wstr[0]));
03205 
03206         HKEY key;
03207         WCHAR browser_open_wstr[1024];
03208         DWORD buffer_length = 1024;
03209         RegOpenKeyEx(HKEY_CLASSES_ROOT, reg_path_wstr, 0, KEY_QUERY_VALUE, &key);
03210         RegQueryValueEx(key, NULL, NULL, NULL, (LPBYTE)browser_open_wstr, &buffer_length);
03211         RegCloseKey(key);
03212 
03213         // Convert to STL string
03214         LLWString browser_open_wstring = utf16str_to_wstring(browser_open_wstr);
03215 
03216         if (browser_open_wstring.length() < 2)
03217         {
03218                 llwarns << "Invalid browser executable in registry " << browser_open_wstring << llendl;
03219                 return;
03220         }
03221 
03222         // Extract the process that's supposed to be launched
03223         LLWString browser_executable;
03224         if (browser_open_wstring[0] == '"')
03225         {
03226                 // executable is quoted, find the matching quote
03227                 size_t quote_pos = browser_open_wstring.find('"', 1);
03228                 // copy out the string including both quotes
03229                 browser_executable = browser_open_wstring.substr(0, quote_pos+1);
03230         }
03231         else
03232         {
03233                 // executable not quoted, find a space
03234                 size_t space_pos = browser_open_wstring.find(' ', 1);
03235                 browser_executable = browser_open_wstring.substr(0, space_pos);
03236         }
03237 
03238         llinfos << "Browser reg key: " << wstring_to_utf8str(browser_open_wstring) << llendl;
03239         llinfos << "Browser executable: " << wstring_to_utf8str(browser_executable) << llendl;
03240 
03241         // Convert URL to wide string for Windows API
03242         // Assume URL is UTF8, as can come from scripts
03243         LLWString url_wstring = utf8str_to_wstring(escaped_url);
03244         llutf16string url_utf16 = wstring_to_utf16str(url_wstring);
03245 
03246         // Convert executable and path to wide string for Windows API
03247         llutf16string browser_exec_utf16 = wstring_to_utf16str(browser_executable);
03248 
03249         // ShellExecute returns HINSTANCE for backwards compatiblity.
03250         // MS docs say to cast to int and compare to 32.
03251         HWND our_window = NULL;
03252         LPCWSTR directory_wstr = NULL;
03253         int retval = (int) ShellExecute(our_window,     /* Flawfinder: ignore */
03254                                                                         L"open", 
03255                                                                         browser_exec_utf16.c_str(), 
03256                                                                         url_utf16.c_str(), 
03257                                                                         directory_wstr,
03258                                                                         SW_SHOWNORMAL);
03259         if (retval > 32)
03260         {
03261                 llinfos << "load_url success with " << retval << llendl;
03262         }
03263         else
03264         {
03265                 llinfos << "load_url failure with " << retval << llendl;
03266         }
03267 }
03268 
03269 void shell_open( const char* file_path )
03270 {
03271         llinfos << "Opening " << file_path << llendl;
03272 
03273         WCHAR wstr[1024];
03274         mbstowcs(wstr, file_path, 1024);
03275 
03276         HWND our_window = NULL;
03277         int retval = (int) ShellExecute(our_window, L"open", wstr, NULL, NULL, SW_SHOWNORMAL);  /* Flawfinder: ignore */
03278         if (retval > 32)
03279         {
03280                 llinfos << "ShellExecute success with " << retval << llendl;
03281         }
03282         else
03283         {
03284                 llinfos << "ShellExecute failure with " << retval << llendl;
03285         }
03286 }
03287 
03288 BOOL LLWindowWin32::dialog_color_picker ( F32 *r, F32 *g, F32 *b )
03289 {
03290         BOOL retval = FALSE;
03291 
03292         static CHOOSECOLOR cc;
03293         static COLORREF crCustColors[16];
03294         cc.lStructSize = sizeof(CHOOSECOLOR);
03295         cc.hwndOwner = mWindowHandle;
03296         cc.hInstance = NULL;
03297         cc.rgbResult = RGB ((*r * 255.f),(*g *255.f),(*b * 255.f));
03298         //cc.rgbResult = RGB (0x80,0x80,0x80); 
03299         cc.lpCustColors = crCustColors;
03300         cc.Flags = CC_RGBINIT | CC_FULLOPEN;
03301         cc.lCustData = 0;
03302         cc.lpfnHook = NULL;
03303         cc.lpTemplateName = NULL;
03304  
03305         // This call is modal, so pause agent
03306         //send_agent_pause();   // this is in newview and we don't want to set up a dependency
03307         {
03308                 retval = ChooseColor(&cc);
03309         }
03310         //send_agent_resume();  // this is in newview and we don't want to set up a dependency
03311 
03312         *b = ((F32)((cc.rgbResult >> 16) & 0xff)) / 255.f;
03313 
03314         *g = ((F32)((cc.rgbResult >> 8) & 0xff)) / 255.f;
03315         
03316         *r = ((F32)(cc.rgbResult & 0xff)) / 255.f;
03317 
03318         return (retval);
03319 }
03320 
03321 void *LLWindowWin32::getPlatformWindow()
03322 {
03323         return (void*)mWindowHandle;
03324 }
03325 
03326 void LLWindowWin32::bringToFront()
03327 {
03328         BringWindowToTop(mWindowHandle);
03329 }
03330 
03331 // set (OS) window focus back to the client
03332 void LLWindowWin32::focusClient()
03333 {
03334         SetFocus ( mWindowHandle );
03335 }
03336 
03337 void LLWindowWin32::allowLanguageTextInput(BOOL b)
03338 {
03339         if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable())
03340         {
03341                 return;
03342         }
03343         sLanguageTextInputAllowed = b;
03344 
03345         if (b)
03346         {
03347                 // Allowing: Restore the previous IME status, so that the user has a feeling that the previous 
03348                 // text input continues naturally.  Be careful, however, the IME status is meaningful only during the user keeps 
03349                 // using same Input Locale (aka Keyboard Layout).
03350                 if (sWinIMEOpened && GetKeyboardLayout(0) == sWinInputLocale)
03351                 {
03352                         HIMC himc = LLWinImm::getContext(mWindowHandle);
03353                         LLWinImm::setOpenStatus(himc, TRUE);
03354                         LLWinImm::setConversionStatus(himc, sWinIMEConversionMode, sWinIMESentenceMode);
03355                         LLWinImm::releaseContext(mWindowHandle, himc);
03356                 }
03357         }
03358         else
03359         {
03360                 // Disallowing: Turn off the IME so that succeeding key events bypass IME and come to us directly.
03361                 // However, do it after saving the current IME  status.  We need to restore the status when
03362                 //   allowing language text input again.
03363                 sWinInputLocale = GetKeyboardLayout(0);
03364                 sWinIMEOpened = LLWinImm::isIME(sWinInputLocale);
03365                 if (sWinIMEOpened)
03366                 {
03367                         HIMC himc = LLWinImm::getContext(mWindowHandle);
03368                         sWinIMEOpened = LLWinImm::getOpenStatus(himc);
03369                         if (sWinIMEOpened)
03370                         {
03371                                 LLWinImm::getConversionStatus(himc, &sWinIMEConversionMode, &sWinIMESentenceMode);
03372 
03373                                 // We need both ImmSetConversionStatus and ImmSetOpenStatus here to surely disable IME's 
03374                                 // keyboard hooking, because Some IME reacts only on the former and some other on the latter...
03375                                 LLWinImm::setConversionStatus(himc, IME_CMODE_NOCONVERSION, sWinIMESentenceMode);
03376                                 LLWinImm::setOpenStatus(himc, FALSE);
03377                         }
03378                         LLWinImm::releaseContext(mWindowHandle, himc);
03379                 }
03380         }
03381 
03382 }
03383 
03384 
03385 // Put the IME window at the right place (near current text input).   Point coordinates should be the top of the current text line.
03386 void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position )
03387 {
03388         if (sLanguageTextInputAllowed && LLWinImm::isAvailable())
03389         {
03390                 HIMC himc = LLWinImm::getContext(mWindowHandle);
03391 
03392                 LLCoordWindow win_pos;
03393                 convertCoords( position, &win_pos );
03394 
03395                 if ( win_pos.mX >= 0 && win_pos.mY >= 0 )
03396                 {
03397                         COMPOSITIONFORM ime_form;
03398                         memset( &ime_form, 0, sizeof(ime_form) );
03399                         ime_form.dwStyle = CFS_POINT;
03400                         ime_form.ptCurrentPos.x = win_pos.mX;
03401                         ime_form.ptCurrentPos.y = win_pos.mY;
03402 
03403                         LLWinImm::setCompositionWindow( himc, &ime_form );
03404                 }
03405 
03406                 LLWinImm::releaseContext(mWindowHandle, himc);
03407 
03408         }
03409 }
03410 
03411 #endif // LL_WINDOWS

Generated on Thu Jul 1 06:09:47 2010 for Second Life Viewer by  doxygen 1.4.7