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

Generated on Fri May 16 08:33:05 2008 for SecondLife by  doxygen 1.5.5