diff options
Diffstat (limited to 'indra/llwindow/llwindowwin32.cpp')
-rw-r--r-- | indra/llwindow/llwindowwin32.cpp | 1407 |
1 files changed, 508 insertions, 899 deletions
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index a5367aac8a..87075c7318 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -2,30 +2,25 @@ * @file llwindowwin32.cpp * @brief Platform-dependent implementation of llwindow * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,31 +30,34 @@ #include "llwindowwin32.h" +// LLWindow library includes +#include "llkeyboardwin32.h" +#include "lldragdropwin32.h" +#include "llpreeditor.h" +#include "llwindowcallbacks.h" + +// Linden library includes +#include "llerror.h" +#include "llgl.h" +#include "llstring.h" +#include "lldir.h" + +// System includes #include <commdlg.h> #include <WinUser.h> #include <mapi.h> #include <process.h> // for _spawn #include <shellapi.h> +#include <fstream> #include <Imm.h> // Require DirectInput version 8 #define DIRECTINPUT_VERSION 0x0800 #include <dinput.h> +#include <Dbt.h.> - -#include "llkeyboardwin32.h" -#include "llerror.h" -#include "llgl.h" -#include "llstring.h" -#include "lldir.h" - -#include "llglheaders.h" - -#include "indra_constants.h" - -#include "llpreeditor.h" - +#include "llmemtype.h" // culled from winuser.h #ifndef WM_MOUSEWHEEL /* Added to be compatible with later SDK's */ const S32 WM_MOUSEWHEEL = 0x020A; @@ -82,9 +80,9 @@ LLW32MsgCallback gAsyncMsgCallback = NULL; // LLWindowWin32 // -void show_window_creation_error(const char* title) +void show_window_creation_error(const std::string& title) { - llwarns << title << llendl; + LL_WARNS("Window") << title << LL_ENDL; } //static @@ -359,44 +357,44 @@ LLWinImm::~LLWinImm() } -LPDIRECTINPUT8 g_pDI = NULL; -LPDIRECTINPUTDEVICE8 g_pJoystick = NULL; -BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, - VOID* pContext ); -BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, - VOID* pContext ); - - -LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, +LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl, - BOOL ignore_pixel_depth) - : LLWindow(fullscreen, flags) + BOOL ignore_pixel_depth, + U32 fsaa_samples) + : LLWindow(callbacks, fullscreen, flags) { - S32 i = 0; + mFSAASamples = fsaa_samples; mIconResource = gIconResource; mOverrideAspectRatio = 0.f; mNativeAspectRatio = 0.f; mMousePositionModified = FALSE; mInputProcessingPaused = FALSE; mPreeditor = NULL; + mKeyCharCode = 0; + mKeyScanCode = 0; + mKeyVirtualKey = 0; + mhDC = NULL; + mhRC = NULL; // Initialize the keyboard gKeyboard = new LLKeyboardWin32(); + gKeyboard->setCallbacks(callbacks); + + // Initialize the Drag and Drop functionality + mDragDrop = new LLDragDropWin32; // Initialize (boot strap) the Language text input management, // based on the system's (user's) default settings. allowLanguageTextInput(mPreeditor, FALSE); - GLuint pixel_format; WNDCLASS wc; - DWORD dw_ex_style; - DWORD dw_style; RECT window_rect; // Set the window title - if (!title) + if (title.empty()) { mWindowTitle = new WCHAR[50]; wsprintf(mWindowTitle, L"OpenGL Window"); @@ -404,12 +402,12 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, else { mWindowTitle = new WCHAR[256]; // Assume title length < 255 chars. - mbstowcs(mWindowTitle, title, 255); + mbstowcs(mWindowTitle, title.c_str(), 255); mWindowTitle[255] = 0; } // Set the window class name - if (!name) + if (name.empty()) { mWindowClassName = new WCHAR[50]; wsprintf(mWindowClassName, L"OpenGL Window"); @@ -417,7 +415,7 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, else { mWindowClassName = new WCHAR[256]; // Assume title length < 255 chars. - mbstowcs(mWindowClassName, name, 255); + mbstowcs(mWindowClassName, name.c_str(), 255); mWindowClassName[255] = 0; } @@ -429,7 +427,7 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, mhInstance = GetModuleHandle(NULL); mWndProc = NULL; - mSwapMethod = SWAP_METHOD_EXCHANGE; + mSwapMethod = SWAP_METHOD_UNDEFINED; // No WPARAM yet. mLastSizeWParam = 0; @@ -490,7 +488,8 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, if (!RegisterClass(&wc)) { - OSMessageBox("RegisterClass failed", "Error", OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBRegClassFailed"), + mCallbacks->translateString("MBError"), OSMB_OK); return; } sIsClassRegistered = TRUE; @@ -544,7 +543,7 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, if (closest_refresh == 0) { - llwarns << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << llendl; + LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; success = FALSE; } @@ -567,11 +566,11 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, mFullscreenBits = dev_mode.dmBitsPerPel; mFullscreenRefresh = dev_mode.dmDisplayFrequency; - llinfos << "Running at " << dev_mode.dmPelsWidth + LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth << "x" << dev_mode.dmPelsHeight << "x" << dev_mode.dmBitsPerPel << " @ " << dev_mode.dmDisplayFrequency - << llendl; + << LL_ENDL; } else { @@ -581,54 +580,14 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, mFullscreenBits = -1; mFullscreenRefresh = -1; - char error[256]; /* Flawfinder: ignore */ - snprintf(error, sizeof(error), "Unable to run fullscreen at %d x %d.\nRunning in window.", width, height); /* Flawfinder: ignore */ - OSMessageBox(error, "Error", OSMB_OK); + std::map<std::string,std::string> args; + args["[WIDTH]"] = llformat("%d", width); + args["[HEIGHT]"] = llformat ("%d", height); + OSMessageBox(mCallbacks->translateString("MBFullScreenErr", args), + mCallbacks->translateString("MBError"), OSMB_OK); } } - //----------------------------------------------------------------------- - // Resize window to account for borders - //----------------------------------------------------------------------- - if (mFullscreen) - { - dw_ex_style = WS_EX_APPWINDOW; - dw_style = WS_POPUP; - - // Move window borders out not to cover window contents - AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style); - } - else - { - // Window with an edge - dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - dw_style = WS_OVERLAPPEDWINDOW; - } - - //----------------------------------------------------------------------- - // Create the window - // Microsoft help indicates that GL windows must be created with - // WS_CLIPSIBLINGS and WS_CLIPCHILDREN, but not CS_PARENTDC - //----------------------------------------------------------------------- - mWindowHandle = CreateWindowEx(dw_ex_style, - mWindowClassName, - mWindowTitle, - WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, - x, // x pos - y, // y pos - window_rect.right - window_rect.left, // width - window_rect.bottom - window_rect.top, // height - NULL, - NULL, - mhInstance, - NULL); - - if (!mWindowHandle) - { - OSMessageBox("Window creation error", "Error", OSMB_OK); - return; - } - // TODO: add this after resolving _WIN32_WINNT issue // if (!fullscreen) // { @@ -641,376 +600,17 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, // } - - S32 pfdflags = PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER; - if (use_gl) - { - pfdflags |= PFD_SUPPORT_OPENGL; - } - //----------------------------------------------------------------------- // Create GL drawing context //----------------------------------------------------------------------- - PIXELFORMATDESCRIPTOR pfd = + LLCoordScreen windowPos(x,y); + LLCoordScreen windowSize(window_rect.right - window_rect.left, + window_rect.bottom - window_rect.top); + if (!switchContext(mFullscreen, windowSize, TRUE, &windowPos)) { - sizeof(PIXELFORMATDESCRIPTOR), - 1, - pfdflags, - PFD_TYPE_RGBA, - BITS_PER_PIXEL, - 0, 0, 0, 0, 0, 0, // RGB bits and shift, unused - 8, // alpha bits - 0, // alpha shift - 0, // accum bits - 0, 0, 0, 0, // accum RGBA - 24, // depth bits - 8, // stencil bits, avi added for stencil test - 0, - PFD_MAIN_PLANE, - 0, - 0, 0, 0 - }; - - if (!(mhDC = GetDC(mWindowHandle))) - { - close(); - OSMessageBox("Can't make GL device context", "Error", OSMB_OK); return; } - - if (!(pixel_format = ChoosePixelFormat(mhDC, &pfd))) - { - close(); - OSMessageBox("Can't find suitable pixel format", "Error", OSMB_OK); - return; - } - - // Verify what pixel format we actually received. - if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), - &pfd)) - { - close(); - OSMessageBox("Can't get pixel format description", "Error", OSMB_OK); - return; - } - - // sanity check pfd returned by Windows - if (!ignore_pixel_depth && (pfd.cColorBits < 32)) - { - close(); - OSMessageBox( - "Second Life requires True Color (32-bit) to run in a window.\n" - "Please go to Control Panels -> Display -> Settings and\n" - "set the screen to 32-bit color.\n" - "Alternately, if you choose to run fullscreen, Second Life\n" - "will automatically adjust the screen each time it runs.", - "Error", - OSMB_OK); - return; - } - - if (!ignore_pixel_depth && (pfd.cAlphaBits < 8)) - { - close(); - OSMessageBox( - "Second Life is unable to run because it can't get an 8 bit alpha\n" - "channel. Usually this is due to video card driver issues.\n" - "Please make sure you have the latest video card drivers installed.\n" - "Also be sure your monitor is set to True Color (32-bit) in\n" - "Control Panels -> Display -> Settings.\n" - "If you continue to receive this message, contact customer service.", - "Error", - OSMB_OK); - return; - } - - if (!SetPixelFormat(mhDC, pixel_format, &pfd)) - { - close(); - OSMessageBox("Can't set pixel format", "Error", OSMB_OK); - return; - } - - if (use_gl) - { - if (!(mhRC = wglCreateContext(mhDC))) - { - close(); - OSMessageBox("Can't create GL rendering context", "Error", OSMB_OK); - return; - } - - if (!wglMakeCurrent(mhDC, mhRC)) - { - close(); - OSMessageBox("Can't activate GL rendering context", "Error", OSMB_OK); - return; - } - - gGLManager.initWGL(); - - if (gGLManager.mHasWGLARBPixelFormat && (wglChoosePixelFormatARB != NULL)) - { - // OK, at this point, use the ARB wglChoosePixelFormatsARB function to see if we - // can get exactly what we want. - GLint attrib_list[256]; - S32 cur_attrib = 0; - - attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB; - attrib_list[cur_attrib++] = 24; - - attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB; - attrib_list[cur_attrib++] = 8; - - attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB; - attrib_list[cur_attrib++] = GL_TRUE; - - attrib_list[cur_attrib++] = WGL_ACCELERATION_ARB; - attrib_list[cur_attrib++] = WGL_FULL_ACCELERATION_ARB; - - attrib_list[cur_attrib++] = WGL_SUPPORT_OPENGL_ARB; - attrib_list[cur_attrib++] = GL_TRUE; - - attrib_list[cur_attrib++] = WGL_DOUBLE_BUFFER_ARB; - attrib_list[cur_attrib++] = GL_TRUE; - - attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB; - attrib_list[cur_attrib++] = 32; - - attrib_list[cur_attrib++] = WGL_RED_BITS_ARB; - attrib_list[cur_attrib++] = 8; - - attrib_list[cur_attrib++] = WGL_GREEN_BITS_ARB; - attrib_list[cur_attrib++] = 8; - - attrib_list[cur_attrib++] = WGL_BLUE_BITS_ARB; - attrib_list[cur_attrib++] = 8; - - attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB; - attrib_list[cur_attrib++] = 8; - - // End the list - attrib_list[cur_attrib++] = 0; - - GLint pixel_formats[256]; - U32 num_formats = 0; - - // First we try and get a 32 bit depth pixel format - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - if (!result) - { - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit"); - return; - } - - if (!num_formats) - { - llinfos << "No 32 bit z-buffer, trying 24 bits instead" << llendl; - // Try 24-bit format - attrib_list[1] = 24; - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - if (!result) - { - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit"); - return; - } - - if (!num_formats) - { - llwarns << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << llendl; - attrib_list[1] = 16; - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - if (!result || !num_formats) - { - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit"); - return; - } - } - - llinfos << "Choosing pixel formats: " << num_formats << " pixel formats returned" << llendl; - - pixel_format = pixel_formats[0]; - } - - DestroyWindow(mWindowHandle); - - mWindowHandle = CreateWindowEx(dw_ex_style, - mWindowClassName, - mWindowTitle, - WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, - x, // x pos - y, // y pos - window_rect.right - window_rect.left, // width - window_rect.bottom - window_rect.top, // height - NULL, - NULL, - mhInstance, - NULL); - - if (!(mhDC = GetDC(mWindowHandle))) - { - close(); - OSMessageBox("Can't make GL device context", "Error", OSMB_OK); - return; - } - - if (!SetPixelFormat(mhDC, pixel_format, &pfd)) - { - close(); - OSMessageBox("Can't set pixel format", "Error", OSMB_OK); - return; - } - - int swap_method = 0; - GLint swap_query = WGL_SWAP_METHOD_ARB; - - if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) - { - switch (swap_method) - { - case WGL_SWAP_EXCHANGE_ARB: - mSwapMethod = SWAP_METHOD_EXCHANGE; - llinfos << "Swap Method: Exchange" << llendl; - break; - case WGL_SWAP_COPY_ARB: - mSwapMethod = SWAP_METHOD_COPY; - llinfos << "Swap Method: Copy" << llendl; - break; - case WGL_SWAP_UNDEFINED_ARB: - mSwapMethod = SWAP_METHOD_UNDEFINED; - llinfos << "Swap Method: Undefined" << llendl; - break; - default: - mSwapMethod = SWAP_METHOD_UNDEFINED; - llinfos << "Swap Method: Unknown" << llendl; - break; - } - } - } - else - { - llwarns << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << llendl; - } - - // Verify what pixel format we actually received. - if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), - &pfd)) - { - close(); - OSMessageBox("Can't get pixel format description", "Error", OSMB_OK); - return; - } - llinfos << "GL buffer: Color Bits " << S32(pfd.cColorBits) - << " Alpha Bits " << S32(pfd.cAlphaBits) - << " Depth Bits " << S32(pfd.cDepthBits) - << llendl; - - if (pfd.cColorBits < 32) - { - close(); - OSMessageBox( - "Second Life requires True Color (32-bit) to run in a window.\n" - "Please go to Control Panels -> Display -> Settings and\n" - "set the screen to 32-bit color.\n" - "Alternately, if you choose to run fullscreen, Second Life\n" - "will automatically adjust the screen each time it runs.", - "Error", - OSMB_OK); - return; - } - - if (pfd.cAlphaBits < 8) - { - close(); - OSMessageBox( - "Second Life is unable to run because it can't get an 8 bit alpha\n" - "channel. Usually this is due to video card driver issues.\n" - "Please make sure you have the latest video card drivers installed.\n" - "Also be sure your monitor is set to True Color (32-bit) in\n" - "Control Panels -> Display -> Settings.\n" - "If you continue to receive this message, contact customer service.", - "Error", - OSMB_OK); - return; - } - - if (!(mhRC = wglCreateContext(mhDC))) - { - close(); - OSMessageBox("Can't create GL rendering context", "Error", OSMB_OK); - return; - } - - if (!wglMakeCurrent(mhDC, mhRC)) - { - close(); - OSMessageBox("Can't activate GL rendering context", "Error", OSMB_OK); - return; - } - - if (!gGLManager.initGL()) - { - close(); - OSMessageBox( - "Second Life is unable to run because your video card drivers\n" - "are out of date or unsupported. Please make sure you have\n" - "the latest video card drivers installed.\n\n" - "If you continue to receive this message, contact customer service.", - "Error", - OSMB_OK); - return; - } - - // Disable vertical sync for swap - if (disable_vsync && wglSwapIntervalEXT) - { - llinfos << "Disabling vertical sync" << llendl; - wglSwapIntervalEXT(0); - } - else - { - llinfos << "Keeping vertical sync" << llendl; - } - - - // OK, let's get the current gamma information and store it off. - mCurrentGamma = 0.f; // Not set, default; - if (!GetDeviceGammaRamp(mhDC, mPrevGammaRamp)) - { - llwarns << "Unable to get device gamma ramp" << llendl; - } - - // Calculate what the current gamma is. From a posting by Garrett T. Bass, Get/SetDeviceGammaRamp Demystified - // http://apollo.iwt.uni-bielefeld.de/~ml_robot/OpenGL-04-2000/0058.html - - // We're going to assume that gamma's the same for all 3 channels, because I don't feel like doing it otherwise. - // Using the red channel. - - F32 Csum = 0.0; - S32 Ccount = 0; - for (i = 0; i < 256; i++) - { - if (i != 0 && mPrevGammaRamp[i] != 0 && mPrevGammaRamp[i] != 65536) - { - F64 B = (i % 256) / 256.0; - F64 A = mPrevGammaRamp[i] / 65536.0; - F32 C = (F32) ( log(A) / log(B) ); - Csum += C; - Ccount++; - } - } - mCurrentGamma = Csum / Ccount; - - llinfos << "Previous gamma: " << mCurrentGamma << llendl; - } - - - //store this pointer for wndProc callback - SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this); - + //start with arrow cursor initCursors(); setCursor( UI_CURSOR_ARROW ); @@ -1018,47 +618,13 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, // Initialize (boot strap) the Language text input management, // based on the system's (or user's) default settings. allowLanguageTextInput(NULL, FALSE); - - initInputDevices(); -} - -void LLWindowWin32::initInputDevices() -{ - // Direct Input - HRESULT hr; - - if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, - IID_IDirectInput8, (VOID**)&g_pDI, NULL ) ) ) - { - llwarns << "Direct8InputCreate failed!" << llendl; - } - else - { - while(1) - { - // Look for a simple joystick we can use for this sample program. - if (FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, - EnumJoysticksCallback, - NULL, DIEDFL_ATTACHEDONLY ) ) ) - break; - if (!g_pJoystick) - break; - if( FAILED( hr = g_pJoystick->SetDataFormat( &c_dfDIJoystick ) ) ) - break; - if( FAILED( hr = g_pJoystick->EnumObjects( EnumObjectsCallback, - (VOID*)mWindowHandle, DIDFT_ALL ) ) ) - break; - g_pJoystick->Acquire(); - break; - } - } - - SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer } LLWindowWin32::~LLWindowWin32() { + delete mDragDrop; + delete [] mWindowTitle; mWindowTitle = NULL; @@ -1082,6 +648,7 @@ void LLWindowWin32::hide() ShowWindow(mWindowHandle, SW_HIDE); } +//virtual void LLWindowWin32::minimize() { setMouseClipping(FALSE); @@ -1089,7 +656,7 @@ void LLWindowWin32::minimize() ShowWindow(mWindowHandle, SW_MINIMIZE); } - +//virtual void LLWindowWin32::restore() { ShowWindow(mWindowHandle, SW_RESTORE); @@ -1102,13 +669,15 @@ void LLWindowWin32::restore() // Usually called from LLWindowManager::destroyWindow() void LLWindowWin32::close() { - llinfos << "Closing LLWindowWin32" << llendl; + LL_DEBUGS("Window") << "Closing LLWindowWin32" << LL_ENDL; // Is window is already closed? if (!mWindowHandle) { return; } + mDragDrop->reset(); + // Make sure cursor is visible and we haven't mangled the clipping state. setMouseClipping(FALSE); showCursor(); @@ -1120,20 +689,20 @@ void LLWindowWin32::close() } // Clean up remaining GL state - llinfos << "Shutting down GL" << llendl; + LL_DEBUGS("Window") << "Shutting down GL" << LL_ENDL; gGLManager.shutdownGL(); - llinfos << "Releasing Context" << llendl; + LL_DEBUGS("Window") << "Releasing Context" << LL_ENDL; if (mhRC) { if (!wglMakeCurrent(NULL, NULL)) { - llwarns << "Release of DC and RC failed" << llendl; + LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; } if (!wglDeleteContext(mhRC)) { - llwarns << "Release of rendering context failed" << llendl; + LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; } mhRC = NULL; @@ -1144,11 +713,11 @@ void LLWindowWin32::close() if (mhDC && !ReleaseDC(mWindowHandle, mhDC)) { - llwarns << "Release of ghDC failed" << llendl; + LL_WARNS("Window") << "Release of ghDC failed" << LL_ENDL; mhDC = NULL; } - llinfos << "Destroying Window" << llendl; + LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; // Don't process events in our mainWindowProc any longer. SetWindowLong(mWindowHandle, GWL_USERDATA, NULL); @@ -1159,7 +728,9 @@ void LLWindowWin32::close() // This causes WM_DESTROY to be sent *immediately* if (!DestroyWindow(mWindowHandle)) { - OSMessageBox("DestroyWindow(mWindowHandle) failed", "Shutdown Error", OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"), + mCallbacks->translateString("MBShutdownErr"), + OSMB_OK); } mWindowHandle = NULL; @@ -1283,7 +854,7 @@ BOOL LLWindowWin32::setSize(const LLCoordScreen size) } // changing fullscreen resolution -BOOL LLWindowWin32::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync) +BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp) { GLuint pixel_format; DEVMODE dev_mode; @@ -1293,8 +864,13 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disa RECT window_rect; S32 width = size.mX; S32 height = size.mY; + BOOL auto_show = FALSE; - resetDisplayResolution(); + if (mhRC) + { + auto_show = TRUE; + resetDisplayResolution(); + } if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) { @@ -1311,12 +887,12 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disa { if (!wglMakeCurrent(NULL, NULL)) { - llwarns << "Release of DC and RC failed" << llendl; + LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; } if (!wglDeleteContext(mhRC)) { - llwarns << "Release of rendering context failed" << llendl; + LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; } mhRC = NULL; @@ -1350,7 +926,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disa if (closest_refresh == 0) { - llwarns << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << llendl; + LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; return FALSE; } @@ -1372,11 +948,11 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disa mFullscreenBits = dev_mode.dmBitsPerPel; mFullscreenRefresh = dev_mode.dmDisplayFrequency; - llinfos << "Running at " << dev_mode.dmPelsWidth + LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth << "x" << dev_mode.dmPelsHeight << "x" << dev_mode.dmBitsPerPel << " @ " << dev_mode.dmDisplayFrequency - << llendl; + << LL_ENDL; window_rect.left = (long) 0; window_rect.right = (long) width; // Windows GDI rects don't include rightmost pixel @@ -1397,18 +973,17 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disa mFullscreenBits = -1; mFullscreenRefresh = -1; - llinfos << "Unable to run fullscreen at " << width << "x" << height << llendl; - llinfos << "Running in window." << llendl; + LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL; return FALSE; } } else { mFullscreen = FALSE; - window_rect.left = (long) 0; - window_rect.right = (long) width; // Windows GDI rects don't include rightmost pixel - window_rect.top = (long) 0; - window_rect.bottom = (long) height; + window_rect.left = (long) (posp ? posp->mX : 0); + window_rect.right = (long) width + window_rect.left; // Windows GDI rects don't include rightmost pixel + window_rect.top = (long) (posp ? posp->mY : 0); + window_rect.bottom = (long) height + window_rect.top; // Window with an edge dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; dw_style = WS_OVERLAPPEDWINDOW; @@ -1458,14 +1033,16 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disa if (!(mhDC = GetDC(mWindowHandle))) { close(); - OSMessageBox("Can't make GL device context", "Error", OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBDevContextErr"), + mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } if (!(pixel_format = ChoosePixelFormat(mhDC, &pfd))) { close(); - OSMessageBox("Can't find suitable pixel format", "Error", OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), + mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } @@ -1474,57 +1051,48 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disa &pfd)) { close(); - OSMessageBox("Can't get pixel format description", "Error", OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), + mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } if (pfd.cColorBits < 32) { close(); - OSMessageBox( - "Second Life requires True Color (32-bit) to run in a window.\n" - "Please go to Control Panels -> Display -> Settings and\n" - "set the screen to 32-bit color.\n" - "Alternately, if you choose to run fullscreen, Second Life\n" - "will automatically adjust the screen each time it runs.", - "Error", - OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"), + mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } if (pfd.cAlphaBits < 8) { close(); - OSMessageBox( - "Second Life is unable to run because it can't get an 8 bit alpha\n" - "channel. Usually this is due to video card driver issues.\n" - "Please make sure you have the latest video card drivers installed.\n" - "Also be sure your monitor is set to True Color (32-bit) in\n" - "Control Panels -> Display -> Settings.\n" - "If you continue to receive this message, contact customer service.", - "Error", - OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBAlpha"), + mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } if (!SetPixelFormat(mhDC, pixel_format, &pfd)) { close(); - OSMessageBox("Can't set pixel format", "Error", OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), + mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } if (!(mhRC = wglCreateContext(mhDC))) { close(); - OSMessageBox("Can't create GL rendering context", "Error", OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBGLContextErr"), + mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } if (!wglMakeCurrent(mhDC, mhRC)) { close(); - OSMessageBox("Can't activate GL rendering context", "Error", OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), + mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } @@ -1558,17 +1126,19 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disa attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB; attrib_list[cur_attrib++] = 24; - attrib_list[cur_attrib++] = WGL_RED_BITS_ARB; - attrib_list[cur_attrib++] = 8; - - attrib_list[cur_attrib++] = WGL_GREEN_BITS_ARB; + attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB; attrib_list[cur_attrib++] = 8; - attrib_list[cur_attrib++] = WGL_BLUE_BITS_ARB; - attrib_list[cur_attrib++] = 8; + U32 end_attrib = 0; + if (mFSAASamples > 0) + { + end_attrib = cur_attrib; + attrib_list[cur_attrib++] = WGL_SAMPLE_BUFFERS_ARB; + attrib_list[cur_attrib++] = GL_TRUE; - attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB; - attrib_list[cur_attrib++] = 8; + attrib_list[cur_attrib++] = WGL_SAMPLES_ARB; + attrib_list[cur_attrib++] = mFSAASamples; + } // End the list attrib_list[cur_attrib++] = 0; @@ -1587,36 +1157,87 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disa if (!num_formats) { - llinfos << "No 32 bit z-buffer, trying 24 bits instead" << llendl; - // Try 24-bit format - attrib_list[1] = 24; - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - if (!result) - { - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit"); - return FALSE; + if (end_attrib > 0) + { + LL_INFOS("Window") << "No valid pixel format for " << mFSAASamples << "x anti-aliasing." << LL_ENDL; + attrib_list[end_attrib] = 0; + + BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + if (!result) + { + close(); + show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit no AA"); + return FALSE; + } } if (!num_formats) { - llwarns << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << llendl; - attrib_list[1] = 16; + LL_INFOS("Window") << "No 32 bit z-buffer, trying 24 bits instead" << LL_ENDL; + // Try 24-bit format + attrib_list[1] = 24; BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - if (!result || !num_formats) + if (!result) { close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit"); + show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit"); return FALSE; } + + if (!num_formats) + { + LL_WARNS("Window") << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << LL_ENDL; + attrib_list[1] = 16; + BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + if (!result || !num_formats) + { + close(); + show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit"); + return FALSE; + } + } } - llinfos << "Choosing pixel formats: " << num_formats << " pixel formats returned" << llendl; + LL_INFOS("Window") << "Choosing pixel formats: " << num_formats << " pixel formats returned" << LL_ENDL; + } + + + + S32 swap_method = 0; + S32 cur_format = num_formats-1; + GLint swap_query = WGL_SWAP_METHOD_ARB; + + BOOL found_format = FALSE; + + while (!found_format && wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) + { + if (swap_method == WGL_SWAP_UNDEFINED_ARB || cur_format <= 0) + { + found_format = TRUE; + } + else + { + --cur_format; + } + } + + pixel_format = pixel_formats[cur_format]; + + if (mhDC != 0) // Does The Window Have A Device Context? + { + wglMakeCurrent(mhDC, 0); // Set The Current Active Rendering Context To Zero + if (mhRC != 0) // Does The Window Have A Rendering Context? + { + wglDeleteContext (mhRC); // Release The Rendering Context + mhRC = 0; // Zero The Rendering Context - pixel_format = pixel_formats[0]; + } + ReleaseDC (mWindowHandle, mhDC); // Release The Device Context + mhDC = 0; // Zero The Device Context } + DestroyWindow (mWindowHandle); // Destroy The Window + - DestroyWindow(mWindowHandle); mWindowHandle = CreateWindowEx(dw_ex_style, mWindowClassName, mWindowTitle, @@ -1633,46 +1254,44 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disa if (!(mhDC = GetDC(mWindowHandle))) { close(); - OSMessageBox("Can't make GL device context", "Error", OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } if (!SetPixelFormat(mhDC, pixel_format, &pfd)) { close(); - OSMessageBox("Can't set pixel format", "Error", OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), + mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } - int swap_method = 0; - GLint swap_query = WGL_SWAP_METHOD_ARB; - if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) { switch (swap_method) { case WGL_SWAP_EXCHANGE_ARB: mSwapMethod = SWAP_METHOD_EXCHANGE; - llinfos << "Swap Method: Exchange" << llendl; + LL_DEBUGS("Window") << "Swap Method: Exchange" << LL_ENDL; break; case WGL_SWAP_COPY_ARB: mSwapMethod = SWAP_METHOD_COPY; - llinfos << "Swap Method: Copy" << llendl; + LL_DEBUGS("Window") << "Swap Method: Copy" << LL_ENDL; break; case WGL_SWAP_UNDEFINED_ARB: mSwapMethod = SWAP_METHOD_UNDEFINED; - llinfos << "Swap Method: Undefined" << llendl; + LL_DEBUGS("Window") << "Swap Method: Undefined" << LL_ENDL; break; default: mSwapMethod = SWAP_METHOD_UNDEFINED; - llinfos << "Swap Method: Unknown" << llendl; + LL_DEBUGS("Window") << "Swap Method: Unknown" << LL_ENDL; break; } } } else { - llwarns << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << llendl; + LL_WARNS("Window") << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << LL_ENDL; } // Verify what pixel format we actually received. @@ -1680,89 +1299,83 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disa &pfd)) { close(); - OSMessageBox("Can't get pixel format description", "Error", OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } - llinfos << "GL buffer: Color Bits " << S32(pfd.cColorBits) + LL_INFOS("Window") << "GL buffer: Color Bits " << S32(pfd.cColorBits) << " Alpha Bits " << S32(pfd.cAlphaBits) << " Depth Bits " << S32(pfd.cDepthBits) - << llendl; + << LL_ENDL; - if (pfd.cColorBits < 32) + // make sure we have 32 bits per pixel + if (pfd.cColorBits < 32 || GetDeviceCaps(mhDC, BITSPIXEL) < 32) { close(); - OSMessageBox( - "Second Life requires True Color (32-bit) to run in a window.\n" - "Please go to Control Panels -> Display -> Settings and\n" - "set the screen to 32-bit color.\n" - "Alternately, if you choose to run fullscreen, Second Life\n" - "will automatically adjust the screen each time it runs.", - "Error", - OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"), mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } if (pfd.cAlphaBits < 8) { close(); - OSMessageBox( - "Second Life is unable to run because it can't get an 8 bit alpha\n" - "channel. Usually this is due to video card driver issues.\n" - "Please make sure you have the latest video card drivers installed.\n" - "Also be sure your monitor is set to True Color (32-bit) in\n" - "Control Panels -> Display -> Settings.\n" - "If you continue to receive this message, contact customer service.", - "Error", - OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBAlpha"), mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } if (!(mhRC = wglCreateContext(mhDC))) { close(); - OSMessageBox("Can't create GL rendering context", "Error", OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } if (!wglMakeCurrent(mhDC, mhRC)) { close(); - OSMessageBox("Can't activate GL rendering context", "Error", OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } if (!gGLManager.initGL()) { close(); - OSMessageBox( - "Second Life is unable to run because your video card drivers\n" - "are out of date or unsupported. Please make sure you have\n" - "the latest video card drivers installed.\n\n" - "If you continue to receive this message, contact customer service.", - "Error", - OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK); return FALSE; } // Disable vertical sync for swap if (disable_vsync && wglSwapIntervalEXT) { - llinfos << "Disabling vertical sync" << llendl; + LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL; wglSwapIntervalEXT(0); } else { - llinfos << "Keeping vertical sync" << llendl; + LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL; } SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this); - show(); - initInputDevices(); + // register this window as handling drag/drop events from the OS + DragAcceptFiles( mWindowHandle, TRUE ); + + mDragDrop->init( mWindowHandle ); + + //register joystick timer callback + SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer // ok to post quit messages now mPostQuit = TRUE; + + if (auto_show) + { + show(); + glClearColor(0.0f, 0.0f, 0.0f, 0.f); + glClear(GL_COLOR_BUFFER_BIT); + swapBuffers(); + } + return TRUE; } @@ -1780,7 +1393,9 @@ void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScre // if the window was already maximized, MoveWindow seems to still set the maximized flag even if // the window is smaller than maximized. // So we're going to do a restore first (which is a ShowWindow call) (SL-44655). - ShowWindow(mWindowHandle, SW_RESTORE); + + // THIS CAUSES DEV-15484 and DEV-15949 + //ShowWindow(mWindowHandle, SW_RESTORE); // NOW we can call MoveWindow MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE); } @@ -1800,6 +1415,20 @@ BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position) return FALSE; } + // Inform the application of the new mouse position (needed for per-frame + // hover/picking to function). + LLCoordGL gl_pos; + convertCoords(position, &gl_pos); + mCallbacks->handleMouseMove(this, gl_pos, (MASK)0); + + // DEV-18951 VWR-8524 Camera moves wildly when alt-clicking. + // Because we have preemptively notified the application of the new + // mouse position via handleMouseMove() above, we need to clear out + // any stale mouse move events. RN/JC + MSG msg; + while (PeekMessage(&msg, NULL, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE)) + { } + return SetCursorPos(screen_pos.mX, screen_pos.mY); } @@ -1909,15 +1538,14 @@ void LLWindowWin32::initCursors() mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN")); mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3")); mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE")); + mCursor[ UI_CURSOR_TOOLSIT ] = LoadCursor(module, TEXT("TOOLSIT")); + mCursor[ UI_CURSOR_TOOLBUY ] = LoadCursor(module, TEXT("TOOLBUY")); + mCursor[ UI_CURSOR_TOOLOPEN ] = LoadCursor(module, TEXT("TOOLOPEN")); // Color cursors - mCursor[UI_CURSOR_TOOLSIT] = loadColorCursor(TEXT("TOOLSIT")); - mCursor[UI_CURSOR_TOOLBUY] = loadColorCursor(TEXT("TOOLBUY")); - mCursor[UI_CURSOR_TOOLPAY] = loadColorCursor(TEXT("TOOLPAY")); - mCursor[UI_CURSOR_TOOLOPEN] = loadColorCursor(TEXT("TOOLOPEN")); - mCursor[UI_CURSOR_TOOLPLAY] = loadColorCursor(TEXT("TOOLPLAY")); - mCursor[UI_CURSOR_TOOLPAUSE] = loadColorCursor(TEXT("TOOLPAUSE")); - mCursor[UI_CURSOR_TOOLMEDIAOPEN] = loadColorCursor(TEXT("TOOLMEDIAOPEN")); + mCursor[ UI_CURSOR_TOOLPLAY ] = loadColorCursor(TEXT("TOOLPLAY")); + mCursor[ UI_CURSOR_TOOLPAUSE ] = loadColorCursor(TEXT("TOOLPAUSE")); + mCursor[ UI_CURSOR_TOOLMEDIAOPEN ] = loadColorCursor(TEXT("TOOLMEDIAOPEN")); // Note: custom cursors that are not found make LoadCursor() return NULL. for( S32 i = 0; i < UI_CURSOR_COUNT; i++ ) @@ -1958,7 +1586,13 @@ void LLWindowWin32::captureMouse() void LLWindowWin32::releaseMouse() { + // *NOTE:Mani ReleaseCapture will spawn new windows messages... + // which will in turn call our MainWindowProc. It therefore requires + // pausing *and more importantly resumption* of the mainlooptimeout... + // just like DispatchMessage below. + mCallbacks->handlePauseWatchdog(this); ReleaseCapture(); + mCallbacks->handleResumeWatchdog(this); } @@ -1972,10 +1606,17 @@ void LLWindowWin32::gatherInput() MSG msg; int msg_count = 0; + LLMemType m1(LLMemType::MTYPE_GATHER_INPUT); + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) && msg_count < MAX_MESSAGE_PER_UPDATE) { + mCallbacks->handlePingWatchdog(this, "Main:TranslateGatherInput"); TranslateMessage(&msg); + + // turn watchdog off in here to not fail if windows is doing something wacky + mCallbacks->handlePauseWatchdog(this); DispatchMessage(&msg); + mCallbacks->handleResumeWatchdog(this); msg_count++; if ( mInputProcessingPaused ) @@ -2001,7 +1642,7 @@ void LLWindowWin32::gatherInput() } } */ - + mCallbacks->handlePingWatchdog(this, "Main:AsyncCallbackGatherInput"); // For async host by name support. Really hacky. if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message)) { @@ -2016,12 +1657,18 @@ void LLWindowWin32::gatherInput() mMousePositionModified = FALSE; } +static LLFastTimer::DeclareTimer FTM_KEYHANDLER("Handle Keyboard"); +static LLFastTimer::DeclareTimer FTM_MOUSEHANDLER("Handle Mouse"); + LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param) { LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(h_wnd, GWL_USERDATA); + if (NULL != window_imp) { + window_imp->mCallbacks->handleResumeWatchdog(window_imp); + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:StartWndProc"); // Has user provided their own window callback? if (NULL != window_imp->mWndProc) { @@ -2032,6 +1679,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } } + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:PreSwitchWndProc"); + // Juggle to make sure we can get negative positions for when // mouse is outside window. LLCoordWindow window_coord((S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)); @@ -2051,10 +1700,28 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ S32 update_height; case WM_TIMER: - window_imp->updateJoystick( ); + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_TIMER"); + window_imp->mCallbacks->handleTimerEvent(window_imp); + break; + + case WM_DEVICECHANGE: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DEVICECHANGE"); + if (gDebugWindowProc) + { + llinfos << " WM_DEVICECHANGE: wParam=" << w_param + << "; lParam=" << l_param << llendl; + } + if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL) + { + if (window_imp->mCallbacks->handleDeviceChange(window_imp)) + { + return 0; + } + } break; case WM_PAINT: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PAINT"); GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE); update_width = update_rect.right - update_rect.left + 1; update_height = update_rect.bottom - update_rect.top + 1; @@ -2062,6 +1729,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ update_width, update_height); break; case WM_PARENTNOTIFY: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PARENTNOTIFY"); u_msg = u_msg; break; @@ -2071,6 +1739,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // Only take control of cursor over client region of window // This allows Windows(tm) to handle resize cursors, etc. + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETCURSOR"); if (LOWORD(l_param) == HTCLIENT) { SetCursor(window_imp->mCursor[ window_imp->mCurrentCursor] ); @@ -2079,14 +1748,17 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; case WM_ENTERMENULOOP: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ENTERMENULOOP"); window_imp->mCallbacks->handleWindowBlock(window_imp); break; case WM_EXITMENULOOP: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_EXITMENULOOP"); window_imp->mCallbacks->handleWindowUnblock(window_imp); break; case WM_ACTIVATEAPP: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ACTIVATEAPP"); { // This message should be sent whenever the app gains or loses focus. BOOL activating = (BOOL) w_param; @@ -2094,11 +1766,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ if (gDebugWindowProc) { - llinfos << "WINDOWPROC ActivateApp " + LL_INFOS("Window") << "WINDOWPROC ActivateApp " << " activating " << S32(activating) << " minimized " << S32(minimized) << " fullscreen " << S32(window_imp->mFullscreen) - << llendl; + << LL_ENDL; } if (window_imp->mFullscreen) @@ -2116,10 +1788,14 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->resetDisplayResolution(); } } + + window_imp->mCallbacks->handleActivateApp(window_imp, activating); + break; } case WM_ACTIVATE: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ACTIVATE"); { // Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE BOOL activating = (LOWORD(w_param) != WA_INACTIVE); @@ -2136,10 +1812,10 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // properly when we run fullscreen. if (gDebugWindowProc) { - llinfos << "WINDOWPROC Activate " + LL_INFOS("Window") << "WINDOWPROC Activate " << " activating " << S32(activating) << " minimized " << S32(minimized) - << llendl; + << LL_ENDL; } // Don't handle this. @@ -2151,6 +1827,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; case WM_SYSCOMMAND: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSCOMMAND"); switch(w_param) { case SC_KEYMENU: @@ -2165,6 +1842,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; case WM_CLOSE: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CLOSE"); // Will the app allow the window to close? if (window_imp->mCallbacks->handleCloseRequest(window_imp)) { @@ -2175,6 +1853,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ return 0; case WM_DESTROY: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DESTROY"); if (window_imp->shouldPostQuit()) { PostQuitMessage(0); // Posts WM_QUIT with an exit code of 0 @@ -2182,6 +1861,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ return 0; case WM_COMMAND: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_COMMAND"); if (!HIWORD(w_param)) // this message is from a menu { window_imp->mCallbacks->handleMenuSelect(window_imp, LOWORD(w_param)); @@ -2189,15 +1869,21 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; case WM_SYSKEYDOWN: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSKEYDOWN"); // allow system keys, such as ALT-F4 to be processed by Windows eat_keystroke = FALSE; case WM_KEYDOWN: + window_imp->mKeyCharCode = 0; // don't know until wm_char comes in next + window_imp->mKeyScanCode = ( l_param >> 16 ) & 0xff; + window_imp->mKeyVirtualKey = w_param; + + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYDOWN"); { if (gDebugWindowProc) { - llinfos << "Debug WindowProc WM_KEYDOWN " + LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN " << " key " << S32(w_param) - << llendl; + << LL_ENDL; } if(gKeyboard->handleKeyDown(w_param, mask) && eat_keystroke) { @@ -2210,13 +1896,17 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ eat_keystroke = FALSE; case WM_KEYUP: { - LLFastTimer t2(LLFastTimer::FTM_KEYHANDLER); + window_imp->mKeyScanCode = ( l_param >> 16 ) & 0xff; + window_imp->mKeyVirtualKey = w_param; + + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP"); + LLFastTimer t2(FTM_KEYHANDLER); if (gDebugWindowProc) { - llinfos << "Debug WindowProc WM_KEYUP " + LL_INFOS("Window") << "Debug WindowProc WM_KEYUP " << " key " << S32(w_param) - << llendl; + << LL_ENDL; } if (gKeyboard->handleKeyUp(w_param, mask) && eat_keystroke) { @@ -2227,6 +1917,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; } case WM_IME_SETCONTEXT: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_SETCONTEXT"); + if (gDebugWindowProc) + { + llinfos << "WM_IME_SETCONTEXT" << llendl; + } if (LLWinImm::isAvailable() && window_imp->mPreeditor) { l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW; @@ -2235,6 +1930,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; case WM_IME_STARTCOMPOSITION: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_STARTCOMPOSITION"); + if (gDebugWindowProc) + { + llinfos << "WM_IME_STARTCOMPOSITION" << llendl; + } if (LLWinImm::isAvailable() && window_imp->mPreeditor) { window_imp->handleStartCompositionMessage(); @@ -2243,6 +1943,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; case WM_IME_ENDCOMPOSITION: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_ENDCOMPOSITION"); + if (gDebugWindowProc) + { + llinfos << "WM_IME_ENDCOMPOSITION" << llendl; + } if (LLWinImm::isAvailable() && window_imp->mPreeditor) { return 0; @@ -2250,6 +1955,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; case WM_IME_COMPOSITION: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_COMPOSITION"); + if (gDebugWindowProc) + { + llinfos << "WM_IME_COMPOSITION" << llendl; + } if (LLWinImm::isAvailable() && window_imp->mPreeditor) { window_imp->handleCompositionMessage(l_param); @@ -2258,6 +1968,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; case WM_IME_REQUEST: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_REQUEST"); + if (gDebugWindowProc) + { + llinfos << "WM_IME_REQUEST" << llendl; + } if (LLWinImm::isAvailable() && window_imp->mPreeditor) { LRESULT result = 0; @@ -2269,6 +1984,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; case WM_CHAR: + window_imp->mKeyCharCode = w_param; + // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need // to figure out how that works. - Doug // @@ -2279,13 +1996,12 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // it is worth trying. The good old WM_CHAR works just fine even for supplementary // characters. We just need to take care of surrogate pairs sent as two WM_CHAR's // by ourselves. It is not that tough. -- Alissa Sabre @ SL - // - // llinfos << "WM_CHAR: " << w_param << llendl; + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CHAR"); if (gDebugWindowProc) { - llinfos << "Debug WindowProc WM_CHAR " + LL_INFOS("Window") << "Debug WindowProc WM_CHAR " << " key " << S32(w_param) - << llendl; + << LL_ENDL; } // Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE, // we *did* processed the event, so I believe we should not pass it to DefWindowProc... @@ -2294,7 +2010,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_LBUTTONDOWN: { - LLFastTimer t2(LLFastTimer::FTM_MOUSEHANDLER); + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDOWN"); + LLFastTimer t2(FTM_MOUSEHANDLER); if (LLWinImm::isAvailable() && window_imp->mPreeditor) { window_imp->interruptLanguageTextInput(); @@ -2316,6 +2033,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->convertCoords(window_coord, &gl_coord); } MASK mask = gKeyboard->currentMask(TRUE); + // generate move event to update mouse coordinates + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); if (window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask)) { return 0; @@ -2327,6 +2046,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ //RN: ignore right button double clicks for now //case WM_RBUTTONDBLCLK: { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDBLCLK"); // Because we move the cursor position in the app, we need to query // to find out where the cursor at the time the event is handled. // If we don't do this, many clicks could get buffered up, and if the @@ -2343,6 +2063,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->convertCoords(window_coord, &gl_coord); } MASK mask = gKeyboard->currentMask(TRUE); + // generate move event to update mouse coordinates + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); if (window_imp->mCallbacks->handleDoubleClick(window_imp, gl_coord, mask) ) { return 0; @@ -2352,10 +2074,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_LBUTTONUP: { - LLFastTimer t2(LLFastTimer::FTM_MOUSEHANDLER); + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONUP"); + LLFastTimer t2(FTM_MOUSEHANDLER); //if (gDebugClicks) //{ - // llinfos << "WndProc left button up" << llendl; + // LL_INFOS("Window") << "WndProc left button up" << LL_ENDL; //} // Because we move the cursor position in the app, we need to query // to find out where the cursor at the time the event is handled. @@ -2373,6 +2096,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->convertCoords(window_coord, &gl_coord); } MASK mask = gKeyboard->currentMask(TRUE); + // generate move event to update mouse coordinates + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); if (window_imp->mCallbacks->handleMouseUp(window_imp, gl_coord, mask)) { return 0; @@ -2383,13 +2108,14 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_RBUTTONDBLCLK: case WM_RBUTTONDOWN: { - LLFastTimer t2(LLFastTimer::FTM_MOUSEHANDLER); + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONDOWN"); + LLFastTimer t2(FTM_MOUSEHANDLER); if (LLWinImm::isAvailable() && window_imp->mPreeditor) { window_imp->interruptLanguageTextInput(); } - // Because we move the cursor position in tllviewerhe app, we need to query + // Because we move the cursor position in the llviewerapp, we need to query // to find out where the cursor at the time the event is handled. // If we don't do this, many clicks could get buffered up, and if the // first click changes the cursor position, all subsequent clicks @@ -2405,6 +2131,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->convertCoords(window_coord, &gl_coord); } MASK mask = gKeyboard->currentMask(TRUE); + // generate move event to update mouse coordinates + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); if (window_imp->mCallbacks->handleRightMouseDown(window_imp, gl_coord, mask)) { return 0; @@ -2414,7 +2142,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_RBUTTONUP: { - LLFastTimer t2(LLFastTimer::FTM_MOUSEHANDLER); + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONUP"); + LLFastTimer t2(FTM_MOUSEHANDLER); // Because we move the cursor position in the app, we need to query // to find out where the cursor at the time the event is handled. // If we don't do this, many clicks could get buffered up, and if the @@ -2431,6 +2160,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->convertCoords(window_coord, &gl_coord); } MASK mask = gKeyboard->currentMask(TRUE); + // generate move event to update mouse coordinates + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); if (window_imp->mCallbacks->handleRightMouseUp(window_imp, gl_coord, mask)) { return 0; @@ -2441,7 +2172,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_MBUTTONDOWN: // case WM_MBUTTONDBLCLK: { - LLFastTimer t2(LLFastTimer::FTM_MOUSEHANDLER); + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONDOWN"); + LLFastTimer t2(FTM_MOUSEHANDLER); if (LLWinImm::isAvailable() && window_imp->mPreeditor) { window_imp->interruptLanguageTextInput(); @@ -2463,6 +2195,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->convertCoords(window_coord, &gl_coord); } MASK mask = gKeyboard->currentMask(TRUE); + // generate move event to update mouse coordinates + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); if (window_imp->mCallbacks->handleMiddleMouseDown(window_imp, gl_coord, mask)) { return 0; @@ -2472,8 +2206,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_MBUTTONUP: { - LLFastTimer t2(LLFastTimer::FTM_MOUSEHANDLER); - // Because we move the cursor position in tllviewerhe app, we need to query + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONUP"); + LLFastTimer t2(FTM_MOUSEHANDLER); + // Because we move the cursor position in the llviewer app, we need to query // to find out where the cursor at the time the event is handled. // If we don't do this, many clicks could get buffered up, and if the // first click changes the cursor position, all subsequent clicks @@ -2489,6 +2224,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->convertCoords(window_coord, &gl_coord); } MASK mask = gKeyboard->currentMask(TRUE); + // generate move event to update mouse coordinates + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); if (window_imp->mCallbacks->handleMiddleMouseUp(window_imp, gl_coord, mask)) { return 0; @@ -2498,9 +2235,30 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_MOUSEWHEEL: { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEWHEEL"); static short z_delta = 0; - z_delta += HIWORD(w_param); + RECT client_rect; + + // eat scroll events that occur outside our window, since we use mouse position to direct scroll + // instead of keyboard focus + // NOTE: mouse_coord is in *window* coordinates for scroll events + POINT mouse_coord = {(S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)}; + + if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord) + && GetClientRect(window_imp->mWindowHandle, &client_rect)) + { + // we have a valid mouse point and client rect + if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x + || mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y) + { + // mouse is outside of client rect, so don't do anything + return 0; + } + } + + S16 incoming_z_delta = HIWORD(w_param); + z_delta += incoming_z_delta; // cout << "z_delta " << z_delta << endl; // current mouse wheels report changes in increments of zDelta (+120, -120) @@ -2534,6 +2292,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // Handle mouse movement within the window case WM_MOUSEMOVE: { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEMOVE"); window_imp->convertCoords(window_coord, &gl_coord); MASK mask = gKeyboard->currentMask(TRUE); window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); @@ -2542,6 +2301,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_SIZE: { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SIZE"); S32 width = S32( LOWORD(l_param) ); S32 height = S32( HIWORD(l_param) ); @@ -2551,12 +2311,12 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ BOOL restored = ( w_param == SIZE_RESTORED ); BOOL minimized = ( w_param == SIZE_MINIMIZED ); - llinfos << "WINDOWPROC Size " + LL_INFOS("Window") << "WINDOWPROC Size " << width << "x" << height << " max " << S32(maximized) << " min " << S32(minimized) << " rest " << S32(restored) - << llendl; + << LL_ENDL; } // There's an odd behavior with WM_SIZE that I would call a bug. If @@ -2600,29 +2360,39 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } case WM_SETFOCUS: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETFOCUS"); if (gDebugWindowProc) { - llinfos << "WINDOWPROC SetFocus" << llendl; + LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL; } window_imp->mCallbacks->handleFocus(window_imp); return 0; case WM_KILLFOCUS: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KILLFOCUS"); if (gDebugWindowProc) { - llinfos << "WINDOWPROC KillFocus" << llendl; + LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL; } window_imp->mCallbacks->handleFocusLost(window_imp); return 0; case WM_COPYDATA: - // received a URL - PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT) l_param; - window_imp->mCallbacks->handleDataCopy(window_imp, myCDS->dwData, myCDS->lpData); + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_COPYDATA"); + // received a URL + PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT) l_param; + window_imp->mCallbacks->handleDataCopy(window_imp, myCDS->dwData, myCDS->lpData); + }; return 0; + + break; } + + window_imp->mCallbacks->handlePauseWatchdog(window_imp); } + // pass unhandled messages down to Windows return DefWindowProc(h_wnd, u_msg, w_param, l_param); } @@ -2750,7 +2520,7 @@ BOOL LLWindowWin32::pasteTextFromClipboard(LLWString &dst) if (utf16str) { dst = utf16str_to_wstring(utf16str); - LLWString::removeCRLF(dst); + LLWStringUtil::removeCRLF(dst); GlobalUnlock(h_data); success = TRUE; } @@ -2773,7 +2543,7 @@ BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr) // Provide a copy of the data in Unicode format. LLWString sanitized_string(wstr); - LLWString::addCRLF(sanitized_string); + LLWStringUtil::addCRLF(sanitized_string); llutf16string out_utf16 = wstring_to_utf16str(sanitized_string); const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(WCHAR); @@ -2860,86 +2630,6 @@ BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp ) return success; } - -BOOL LLWindowWin32::sendEmail(const char* address, const char* subject, const char* body_text, - const char* attachment, const char* attachment_displayed_name ) -{ - // Based on "A SendMail() DLL" by Greg Turner, Windows Developer Magazine, Nov. 1997. - // See article for use of GetProcAddress - // No restrictions on use. - - enum SendResult - { - LL_EMAIL_SUCCESS, - LL_EMAIL_MAPI_NOT_INSTALLED, // No MAPI Server (eg Microsoft Exchange) installed - LL_EMAIL_MAPILOAD_FAILED, // Load of MAPI32.DLL failed - LL_EMAIL_SEND_FAILED // The message send itself failed - }; - - SendResult result = LL_EMAIL_SUCCESS; - - U32 mapi_installed = GetProfileInt(L"Mail", L"MAPI", 0); - if( !mapi_installed) - { - result = LL_EMAIL_MAPI_NOT_INSTALLED; - } - else - { - HINSTANCE hMAPIInst = LoadLibrary(L"MAPI32.DLL"); /* Flawfinder: ignore */ - if(!hMAPIInst) - { - result = LL_EMAIL_MAPILOAD_FAILED; - } - else - { - LPMAPISENDMAIL pMAPISendMail = (LPMAPISENDMAIL) GetProcAddress(hMAPIInst, "MAPISendMail"); - - // Send the message - MapiRecipDesc recipients[1]; - recipients[0].ulReserved = 0; - recipients[0].ulRecipClass = MAPI_TO; - recipients[0].lpszName = (char*)address; - recipients[0].lpszAddress = (char*)address; - recipients[0].ulEIDSize = 0; - recipients[0].lpEntryID = 0; - - MapiFileDesc files[1]; - files[0].ulReserved = 0; - files[0].flFlags = 0; // non-OLE file - files[0].nPosition = -1; // Leave file location in email unspecified. - files[0].lpszPathName = (char*)attachment; // Must be fully qualified name, including drive letter. - files[0].lpszFileName = (char*)attachment_displayed_name; // If NULL, uses attachment as displayed name. - files[0].lpFileType = NULL; // Recipient will have to figure out what kind of file this is. - - MapiMessage msg; - memset(&msg, 0, sizeof(msg)); - msg.lpszSubject = (char*)subject; // may be NULL - msg.lpszNoteText = (char*)body_text; - msg.nRecipCount = address ? 1 : 0; - msg.lpRecips = address ? recipients : NULL; - msg.nFileCount = attachment ? 1 : 0; - msg.lpFiles = attachment ? files : NULL; - - U32 success = pMAPISendMail(0, (U32) mWindowHandle, &msg, MAPI_DIALOG|MAPI_LOGON_UI|MAPI_NEW_SESSION, 0); - if(success != SUCCESS_SUCCESS) - { - result = LL_EMAIL_SEND_FAILED; - } - - FreeLibrary(hMAPIInst); - } - } - - return result == LL_EMAIL_SUCCESS; -} - - -S32 LLWindowWin32::stat(const char* file_name, struct stat* stat_info) -{ - llassert( sizeof(struct stat) == sizeof(struct _stat) ); // They are defined identically in sys/stat.h, but I'm paranoid. - return LLFile::stat( file_name, (struct _stat*) stat_info ); -} - void LLWindowWin32::flashIcon(F32 seconds) { FLASHWINFO flash_info; @@ -2966,7 +2656,7 @@ BOOL LLWindowWin32::setGamma(const F32 gamma) { mCurrentGamma = gamma; - llinfos << "Setting gamma to " << gamma << llendl; + LL_DEBUGS("Window") << "Setting gamma to " << gamma << LL_ENDL; for ( int i = 0; i < 256; ++i ) { @@ -2985,6 +2675,16 @@ BOOL LLWindowWin32::setGamma(const F32 gamma) return SetDeviceGammaRamp ( mhDC, mCurrentGammaRamp ); } +void LLWindowWin32::setFSAASamples(const U32 fsaa_samples) +{ + mFSAASamples = fsaa_samples; +} + +U32 LLWindowWin32::getFSAASamples() +{ + return mFSAASamples; +} + LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions) { if (!mSupportedResolutions) @@ -3097,8 +2797,8 @@ BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 re if (!success) { - llwarns << "setDisplayResolution failed, " - << width << "x" << height << "x" << bits << " @ " << refresh << llendl; + LL_WARNS("Window") << "setDisplayResolution failed, " + << width << "x" << height << "x" << bits << " @ " << refresh << LL_ENDL; } return success; @@ -3120,7 +2820,7 @@ BOOL LLWindowWin32::setFullscreenResolution() // protected BOOL LLWindowWin32::resetDisplayResolution() { - llinfos << "resetDisplayResolution START" << llendl; + LL_DEBUGS("Window") << "resetDisplayResolution START" << LL_ENDL; LONG cds_result = ChangeDisplaySettings(NULL, 0); @@ -3128,10 +2828,10 @@ BOOL LLWindowWin32::resetDisplayResolution() if (!success) { - llwarns << "resetDisplayResolution failed" << llendl; + LL_WARNS("Window") << "resetDisplayResolution failed" << LL_ENDL; } - llinfos << "resetDisplayResolution END" << llendl; + LL_DEBUGS("Window") << "resetDisplayResolution END" << LL_ENDL; return success; } @@ -3142,81 +2842,6 @@ void LLWindowWin32::swapBuffers() } -BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, - VOID* pContext ) -{ - HRESULT hr; - - // Obtain an interface to the enumerated joystick. - hr = g_pDI->CreateDevice( pdidInstance->guidInstance, &g_pJoystick, NULL ); - - // If it failed, then we can't use this joystick. (Maybe the user unplugged - // it while we were in the middle of enumerating it.) - if( FAILED(hr) ) - return DIENUM_CONTINUE; - - // Stop enumeration. Note: we're just taking the first joystick we get. You - // could store all the enumerated joysticks and let the user pick. - return DIENUM_STOP; -} - -BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, - VOID* pContext ) -{ - if( pdidoi->dwType & DIDFT_AXIS ) - { - DIPROPRANGE diprg; - diprg.diph.dwSize = sizeof(DIPROPRANGE); - diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); - diprg.diph.dwHow = DIPH_BYID; - diprg.diph.dwObj = pdidoi->dwType; // Specify the enumerated axis - diprg.lMin = -1000; - diprg.lMax = +1000; - - // Set the range for the axis - if( FAILED( g_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) ) - return DIENUM_STOP; - - } - return DIENUM_CONTINUE; -} - -void LLWindowWin32::updateJoystick( ) -{ - HRESULT hr; - DIJOYSTATE js; // DInput joystick state - - if (!g_pJoystick) - return; - hr = g_pJoystick->Poll(); - if ( hr == DIERR_INPUTLOST ) - { - hr = g_pJoystick->Acquire(); - return; - } - else if ( FAILED(hr) ) - return; - - // Get the input's device state - if( FAILED( hr = g_pJoystick->GetDeviceState( sizeof(DIJOYSTATE), &js ) ) ) - return; // The device should have been acquired during the Poll() - - mJoyAxis[0] = js.lX/1000.f; - mJoyAxis[1] = js.lY/1000.f; - mJoyAxis[2] = js.lZ/1000.f; - mJoyAxis[3] = js.lRx/1000.f; - mJoyAxis[4] = js.lRy/1000.f; - mJoyAxis[5] = js.lRz/1000.f; - mJoyAxis[6] = js.rglSlider[0]/1000.f; - mJoyAxis[7] = js.rglSlider[1]/1000.f; - - for (U32 i = 0; i < 16; i++) - { - mJoyButtonState[i] = js.rgbButtons[i]; - } -} - - // // LLSplashScreenImp // @@ -3242,12 +2867,20 @@ void LLSplashScreenWin32::showImpl() } -void LLSplashScreenWin32::updateImpl(const char *mesg) +void LLSplashScreenWin32::updateImpl(const std::string& mesg) { if (!mWindow) return; - WCHAR w_mesg[1024]; - mbstowcs(w_mesg, mesg, 1024); + int output_str_len = MultiByteToWideChar(CP_UTF8, 0, mesg.c_str(), mesg.length(), NULL, 0); + if( output_str_len>1024 ) + return; + + WCHAR w_mesg[1025];//big enought to keep null terminatos + + MultiByteToWideChar (CP_UTF8, 0, mesg.c_str(), mesg.length(), w_mesg, output_str_len); + + //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858 + w_mesg[output_str_len] = 0; SendDlgItemMessage(mWindow, 666, // HACK: text id @@ -3279,7 +2912,7 @@ LRESULT CALLBACK LLSplashScreenWin32::windowProc(HWND h_wnd, UINT u_msg, // Helper Funcs // -S32 OSMessageBoxWin32(const char* text, const char* caption, U32 type) +S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type) { UINT uType; @@ -3300,7 +2933,7 @@ S32 OSMessageBoxWin32(const char* text, const char* caption, U32 type) } // HACK! Doesn't properly handle wide strings! - int retval_win = MessageBoxA(NULL, text, caption, uType); + int retval_win = MessageBoxA(NULL, text.c_str(), caption.c_str(), uType); S32 retval; switch(retval_win) @@ -3326,15 +2959,13 @@ S32 OSMessageBoxWin32(const char* text, const char* caption, U32 type) } -void spawn_web_browser(const char* escaped_url ) +void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url, bool async) { bool found = false; S32 i; for (i = 0; i < gURLProtocolWhitelistCount; i++) { - S32 len = strlen(gURLProtocolWhitelist[i]); /* Flawfinder: ignore */ - if (!strncmp(escaped_url, gURLProtocolWhitelist[i], len) - && escaped_url[len] == ':') + if (escaped_url.find(gURLProtocolWhitelist[i]) == 0) { found = true; break; @@ -3343,84 +2974,48 @@ void spawn_web_browser(const char* escaped_url ) if (!found) { - llwarns << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << llendl; + LL_WARNS("Window") << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; return; } - llinfos << "Opening URL " << escaped_url << llendl; + LL_INFOS("Window") << "Opening URL " << escaped_url << LL_ENDL; - // Figure out the user's default web browser - // HKEY_CLASSES_ROOT\http\shell\open\command - char reg_path_str[256]; /* Flawfinder: ignore */ - snprintf(reg_path_str, sizeof(reg_path_str), "%s\\shell\\open\\command", gURLProtocolWhitelistHandler[i]); /* Flawfinder: ignore */ - WCHAR reg_path_wstr[256]; - mbstowcs(reg_path_wstr, reg_path_str, sizeof(reg_path_wstr)/sizeof(reg_path_wstr[0])); + // replaced ShellExecute code with ShellExecuteEx since ShellExecute doesn't work + // reliablly on Vista. - HKEY key; - WCHAR browser_open_wstr[1024]; - DWORD buffer_length = 1024; - RegOpenKeyEx(HKEY_CLASSES_ROOT, reg_path_wstr, 0, KEY_QUERY_VALUE, &key); - RegQueryValueEx(key, NULL, NULL, NULL, (LPBYTE)browser_open_wstr, &buffer_length); - RegCloseKey(key); + // this is madness.. no, this is.. + LLWString url_wstring = utf8str_to_wstring( escaped_url ); + llutf16string url_utf16 = wstring_to_utf16str( url_wstring ); - // Convert to STL string - LLWString browser_open_wstring = utf16str_to_wstring(browser_open_wstr); - - if (browser_open_wstring.length() < 2) + // let the OS decide what to use to open the URL + SHELLEXECUTEINFO sei = { sizeof( sei ) }; + // NOTE: this assumes that SL will stick around long enough to complete the DDE message exchange + // necessary for ShellExecuteEx to complete + if (async) { - llwarns << "Invalid browser executable in registry " << browser_open_wstring << llendl; - return; + sei.fMask = SEE_MASK_ASYNCOK; } + sei.nShow = SW_SHOWNORMAL; + sei.lpVerb = L"open"; + sei.lpFile = url_utf16.c_str(); + ShellExecuteEx( &sei ); +} - // Extract the process that's supposed to be launched - LLWString browser_executable; - if (browser_open_wstring[0] == '"') - { - // executable is quoted, find the matching quote - size_t quote_pos = browser_open_wstring.find('"', 1); - // copy out the string including both quotes - browser_executable = browser_open_wstring.substr(0, quote_pos+1); - } - else - { - // executable not quoted, find a space - size_t space_pos = browser_open_wstring.find(' ', 1); - browser_executable = browser_open_wstring.substr(0, space_pos); - } - - llinfos << "Browser reg key: " << wstring_to_utf8str(browser_open_wstring) << llendl; - llinfos << "Browser executable: " << wstring_to_utf8str(browser_executable) << llendl; - - // Convert URL to wide string for Windows API - // Assume URL is UTF8, as can come from scripts - LLWString url_wstring = utf8str_to_wstring(escaped_url); - llutf16string url_utf16 = wstring_to_utf16str(url_wstring); +/* + Make the raw keyboard data available - used to poke through to LLQtWebKit so + that Qt/Webkit has access to the virtual keycodes etc. that it needs +*/ +LLSD LLWindowWin32::getNativeKeyData() +{ + LLSD result = LLSD::emptyMap(); - // Convert executable and path to wide string for Windows API - llutf16string browser_exec_utf16 = wstring_to_utf16str(browser_executable); + result["scan_code"] = (S32)mKeyScanCode; + result["virtual_key"] = (S32)mKeyVirtualKey; - // ShellExecute returns HINSTANCE for backwards compatiblity. - // MS docs say to cast to int and compare to 32. - HWND our_window = NULL; - LPCWSTR directory_wstr = NULL; - int retval = (int) ShellExecute(our_window, /* Flawfinder: ignore */ - L"open", - browser_exec_utf16.c_str(), - url_utf16.c_str(), - directory_wstr, - SW_SHOWNORMAL); - if (retval > 32) - { - llinfos << "load_url success with " << retval << llendl; - } - else - { - llinfos << "load_url failure with " << retval << llendl; - } + return result; } - -BOOL LLWindowWin32::dialog_color_picker ( F32 *r, F32 *g, F32 *b ) +BOOL LLWindowWin32::dialogColorPicker( F32 *r, F32 *g, F32 *b ) { BOOL retval = FALSE; @@ -3859,7 +3454,7 @@ void LLWindowWin32::handleCompositionMessage(const U32 indexes) { for (LLWString::const_iterator i = result_string.begin(); i != result_string.end(); i++) { - mPreeditor->handleUnicodeCharHere(*i, FALSE); + mPreeditor->handleUnicodeCharHere(*i); } } @@ -3914,6 +3509,13 @@ static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_leng return wtext.substr(start, end - start); } +// final stage of handling drop requests - both from WM_DROPFILES message +// for files and via IDropTarget interface requests. +LLWindowCallbacks::DragNDropResult LLWindowWin32::completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ) +{ + return mCallbacks->handleDragNDrop( this, gl_coord, mask, action, url ); +} + // Handle WM_IME_REQUEST message. // If it handled the message, returns TRUE. Otherwise, FALSE. // When it handled the message, the value to be returned from @@ -3947,7 +3549,7 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) // WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the // number to getPreeditLocation. - const LLWString & wtext = mPreeditor->getWText(); + const LLWString & wtext = mPreeditor->getPreeditString(); S32 preedit, preedit_length; mPreeditor->getPreeditRange(&preedit, &preedit_length); LLCoordGL caret_coord; @@ -3956,7 +3558,7 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) if (!mPreeditor->getPreeditLocation(position, &caret_coord, &preedit_bounds, &text_control)) { - llwarns << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << llendl; + LL_WARNS("Window") << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << LL_ENDL; return FALSE; } fillCharPosition(caret_coord, preedit_bounds, text_control, char_position); @@ -3974,7 +3576,7 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) case IMR_RECONVERTSTRING: { mPreeditor->resetPreedit(); - const LLWString & wtext = mPreeditor->getWText(); + const LLWString & wtext = mPreeditor->getPreeditString(); S32 select, select_length; mPreeditor->getSelectionRange(&select, &select_length); @@ -4016,7 +3618,7 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) } case IMR_DOCUMENTFEED: { - const LLWString & wtext = mPreeditor->getWText(); + const LLWString & wtext = mPreeditor->getPreeditString(); S32 preedit, preedit_length; mPreeditor->getPreeditRange(&preedit, &preedit_length); @@ -4043,5 +3645,12 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) return FALSE; } +//static +std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList() +{ + // Fonts previously in getFontListSans() have moved to fonts.xml. + return std::vector<std::string>(); +} + #endif // LL_WINDOWS |