From eba6d0236fc9b7f4a54189766709948599d4b8a2 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Wed, 21 Oct 2009 16:01:52 -0700 Subject: Backed out changeset: 57dc52edbbc9 --- indra/llwindow/llwindowcallbacks.cpp | 5 +++ indra/llwindow/llwindowcallbacks.h | 1 + indra/llwindow/llwindowwin32.cpp | 66 +++++++++++++++++++++++++++++++++--- indra/newview/llviewerwindow.cpp | 14 ++++++++ indra/newview/llviewerwindow.h | 3 +- 5 files changed, 84 insertions(+), 5 deletions(-) diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index 72f9997149..fda2c7ee6f 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -163,6 +163,11 @@ void LLWindowCallbacks::handleDataCopy(LLWindow *window, S32 data_type, void *da { } +BOOL LLWindowCallbacks::handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, void *data) +{ + return FALSE; +} + BOOL LLWindowCallbacks::handleTimerEvent(LLWindow *window) { return FALSE; diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index abc66c42a2..e1e257943a 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -68,6 +68,7 @@ public: virtual void handleWindowBlock(LLWindow *window); // window is taking over CPU for a while virtual void handleWindowUnblock(LLWindow *window); // window coming back after taking over CPU for a while virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); + virtual BOOL handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, void *data); virtual BOOL handleTimerEvent(LLWindow *window); virtual BOOL handleDeviceChange(LLWindow *window); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index c608c21d05..94c3e1af8c 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -52,6 +52,7 @@ #include #include // for _spawn #include +#include #include // Require DirectInput version 8 @@ -1348,6 +1349,9 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO } SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this); + + // register this window as handling drag/drop events from the OS + DragAcceptFiles( mWindowHandle, TRUE ); //register joystick timer callback SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer @@ -2333,11 +2337,65 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ return 0; case WM_COPYDATA: - 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); + { + 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; + + case WM_DROPFILES: + { + // HDROP contains what we need + HDROP hdrop = (HDROP)w_param; + + // get location in window space where drop occured and convert to OpenGL coordinate space + POINT pt; + DragQueryPoint( hdrop, &pt ); + LLCoordGL gl_coord; + LLCoordWindow cursor_coord_window( pt.x, pt.y ); + window_imp->convertCoords(cursor_coord_window, &gl_coord); + + // get payload (eventually, this needs to more advanced and grab size of payload dynamically + static char file_name[ 1024 ]; + DragQueryFileA( hdrop, 0, file_name, 1024 ); + void* url = (void*)( file_name ); + + // if it's a .URL or .lnk ("shortcut") file + if ( std::string( file_name ).find( ".lnk" ) != std::string::npos || + std::string( file_name ).find( ".URL" ) != std::string::npos ) + { + // read through file - looks like a 2 line file with second line URL= but who knows.. + std::ifstream file_handle( file_name ); + if ( file_handle.is_open() ) + { + std::string line; + while ( ! file_handle.eof() ) + { + std::getline( file_handle, line ); + if ( ! file_handle.eof() ) + { + std::string prefix( "URL=" ); + if ( line.find( prefix, 0 ) != std::string::npos ) + { + line = line.substr( 4 ); // skip off the URL= bit + strcpy( (char*)url, line.c_str() ); + break; + }; + }; + }; + file_handle.close(); + }; + }; + + MASK mask = gKeyboard->currentMask(TRUE); + if (window_imp->mCallbacks->handleDrop(window_imp, gl_coord, mask, url ) ) + { + return 0; + } + } + break; } window_imp->mCallbacks->handlePauseWatchdog(window_imp); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index c659e58e47..2bda6eddbc 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -815,6 +815,20 @@ BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MAS // Always handled as far as the OS is concerned. return TRUE; } + +BOOL LLViewerWindow::handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, void* data) +{ + LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ ); + + LLUUID object_id = pick_info.getObjectID(); + S32 object_face = pick_info.mObjectFace; + std::string url = std::string( (char*)data ); + + llinfos << "### Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; + + // Always handled as far as the OS is concerned. + return TRUE; +} BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index d7c403739e..44704b99e3 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -170,7 +170,8 @@ public: /*virtual*/ BOOL handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); - /*virtual*/ void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); + /*virtual*/ BOOL handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, void* data); + void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ void handleMouseLeave(LLWindow *window); /*virtual*/ void handleResize(LLWindow *window, S32 x, S32 y); /*virtual*/ void handleFocus(LLWindow *window); -- cgit v1.2.3 From 19fc3fb32c3cd95fcfb5708b59b5620e506c5179 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Wed, 21 Oct 2009 17:40:36 -0700 Subject: Add setting for PrimMediaDragNDrop, and add implementation that sets the current URL and auto play on drop --- indra/newview/app_settings/settings.xml | 11 +++++++++++ indra/newview/llviewerwindow.cpp | 24 +++++++++++++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 91d5e04665..9adf893e4b 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5305,6 +5305,17 @@ Value 13 + PrimMediaDragNDrop + + Comment + Enable drag and drop + Persist + 1 + Type + Boolean + Value + 1 + PrimMediaMaxRetries Comment diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 2bda6eddbc..a080243086 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -79,6 +79,7 @@ #include "timing.h" #include "llviewermenu.h" #include "lltooltip.h" +#include "llmediaentry.h" // newview includes #include "llagent.h" @@ -818,14 +819,27 @@ BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MAS BOOL LLViewerWindow::handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, void* data) { - LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ ); + if (gSavedSettings.getBOOL("PrimMediaDragNDrop")) + { + LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ ); - LLUUID object_id = pick_info.getObjectID(); - S32 object_face = pick_info.mObjectFace; - std::string url = std::string( (char*)data ); + LLUUID object_id = pick_info.getObjectID(); + S32 object_face = pick_info.mObjectFace; + std::string url = std::string( (char*)data ); - llinfos << "### Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; + llinfos << "### Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; + LLVOVolume *obj = dynamic_cast(static_cast(pick_info.getObject())); + if (obj) + { + LLSD media_data; + /// XXX home URL too? + media_data[LLMediaEntry::CURRENT_URL_KEY] = url; + media_data[LLMediaEntry::AUTO_PLAY_KEY] = true; + obj->syncMediaData(object_face, media_data, true, true); + obj->sendMediaDataUpdate(); + } + } // Always handled as far as the OS is concerned. return TRUE; } -- cgit v1.2.3 From caa631bf5b69ef1e39989b8e1e4b3372491cb9b4 Mon Sep 17 00:00:00 2001 From: callum Date: Tue, 27 Oct 2009 17:52:04 -0700 Subject: Added IDropTarget interface. Still lots of cleanup but this works ok. You can drag over from Firefox or IE onto a prim --- indra/llwindow/lldragdropwin32.cpp | 295 ++ indra/llwindow/lldragdropwin32.h | 55 + indra/llwindow/llwindowcallbacks.cpp | 2 +- indra/llwindow/llwindowcallbacks.h | 2 +- indra/llwindow/llwindowwin32.cpp | 7371 +++++++++++++++++----------------- indra/llwindow/llwindowwin32.h | 5 + indra/newview/llviewerwindow.cpp | 4 +- indra/newview/llviewerwindow.h | 2 +- 8 files changed, 4057 insertions(+), 3679 deletions(-) create mode 100644 indra/llwindow/lldragdropwin32.cpp create mode 100644 indra/llwindow/lldragdropwin32.h diff --git a/indra/llwindow/lldragdropwin32.cpp b/indra/llwindow/lldragdropwin32.cpp new file mode 100644 index 0000000000..0daff85395 --- /dev/null +++ b/indra/llwindow/lldragdropwin32.cpp @@ -0,0 +1,295 @@ +/** + * @file lldragdrop32.cpp + * @brief Handler for Windows specific drag and drop (OS to client) code + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#if LL_WINDOWS + +#include "linden_common.h" + +#define WIN32_LEAN_AND_MEAN +#include + +#include "llwindowwin32.h" +#include "llkeyboardwin32.h" +#include "lldragdropwin32.h" + +#include "llwindowcallbacks.h" + +#include +#include +#include +#include +#include + +// FIXME: this should be done in CMake +#pragma comment( lib, "shlwapi.lib" ) + +class LLDragDropWin32Target: + public IDropTarget +{ + public: + LLDragDropWin32Target( HWND hWnd ) : + mWindowHandle( hWnd ), + mRefCount( 0 ) + { + strcpy(szFileDropped,""); + bDropTargetValid = false; + bTextDropped = false; + }; + + /* IUnknown methods */ + STDMETHOD_( ULONG, AddRef )( void ) + { + return ++mRefCount; + }; + + STDMETHOD_( ULONG, Release )( void ) + { + if ( --mRefCount == 0 ) + { + delete this; + return 0; + } + return mRefCount; + }; + + STDMETHOD ( QueryInterface )( REFIID iid, void ** ppvObject ) + { + if ( iid == IID_IUnknown || iid == IID_IDropTarget ) + { + *ppvObject = this; + AddRef(); + return S_OK; + }; + + *ppvObject = NULL; + return E_NOINTERFACE; + }; + + /* IDropTarget methods */ + STDMETHOD (DragEnter)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) + { + HRESULT hr = E_INVALIDARG; + bDropTargetValid = false; + bTextDropped = false; + *pdwEffect=DROPEFFECT_NONE; + + FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; + STGMEDIUM medium; + + if (pDataObj && SUCCEEDED (pDataObj->GetData (&fmte, &medium))) + { + // We can Handle Only one File At a time !!! + if (1 == DragQueryFile ((HDROP)medium.hGlobal,0xFFFFFFFF,NULL,0 )) + { + // Get the File Name + if (DragQueryFileA((HDROP)medium.hGlobal, 0, szFileDropped,MAX_PATH)) + { + if (!PathIsDirectoryA(szFileDropped)) + { + char szTempFile[MAX_PATH]; + _splitpath(szFileDropped,NULL,NULL,NULL,szTempFile); + +// if (!stricmp(szTempFile,".lnk")) +// { +// if (ResolveLink(szFileDropped,szTempFile)) +// { +// strcpy(szFileDropped,szTempFile); +// *pdwEffect=DROPEFFECT_COPY; +// We Want to Create a Copy +// bDropTargetValid = true; +// hr = S_OK; +// } +// } +// else +// { + *pdwEffect=DROPEFFECT_COPY; + //We Want to Create a Copy + bDropTargetValid = true; + hr = S_OK; +// } + } + } + } + + if (medium.pUnkForRelease) + medium.pUnkForRelease->Release (); + else + GlobalFree (medium.hGlobal); + } + else + { + fmte.cfFormat = CF_TEXT; + fmte.ptd = NULL; + fmte.dwAspect = DVASPECT_CONTENT; + fmte.lindex = -1; + fmte.tymed = TYMED_HGLOBAL; + + // Does the drag source provide CF_TEXT ? + if (NOERROR == pDataObj->QueryGetData(&fmte)) + { + bDropTargetValid = true; + bTextDropped = true; + *pdwEffect=DROPEFFECT_COPY; + hr = S_OK; + } + } + return hr; + + + + }; + + STDMETHOD (DragOver)(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) + { + HRESULT hr = S_OK; + if (bDropTargetValid) + *pdwEffect=DROPEFFECT_COPY; + + return hr; + }; + + STDMETHOD (DragLeave)(void) + { + HRESULT hr = S_OK; + strcpy(szFileDropped,""); + return hr; + }; + + STDMETHOD (Drop)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) + { + HRESULT hr = S_OK; + if (bDropTargetValid) + { + *pdwEffect=DROPEFFECT_COPY; + + FORMATETC fmte; + STGMEDIUM medium; + + if (bTextDropped) + { + fmte.cfFormat = CF_TEXT; + fmte.ptd = NULL; + fmte.dwAspect = DVASPECT_CONTENT; + fmte.lindex = -1; + fmte.tymed = TYMED_HGLOBAL; + + hr = pDataObj->GetData(&fmte, &medium); + HGLOBAL hText = medium.hGlobal; + LPSTR lpszText = (LPSTR)GlobalLock(hText); + + LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mWindowHandle, GWL_USERDATA); + if (NULL != window_imp) + { + LLCoordGL gl_coord( pt.x, pt.y); + LLCoordWindow cursor_coord_window( pt.x, pt.y ); + window_imp->convertCoords(cursor_coord_window, &gl_coord); + llinfos << "### (Drop) URL is: " << lpszText << llendl; + llinfos << "### raw coords are: " << pt.x << " x " << pt.y << llendl; + llinfos << "### GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << llendl; + llinfos << llendl; + + MASK mask = gKeyboard->currentMask(TRUE); + window_imp->completeDropRequest( gl_coord, mask, std::string( lpszText ) ); + }; + + GlobalUnlock(hText); + ReleaseStgMedium(&medium); + } + } + return hr; + }; + + private: + ULONG mRefCount; + HWND mWindowHandle; + char szFileDropped[1024]; + bool bDropTargetValid; + bool bTextDropped; + friend class LLWindowWin32; +}; + +LLDragDropWin32::LLDragDropWin32() : + mDropTarget( NULL ), + mDropWindowHandle( NULL ) + +{ +} + +LLDragDropWin32::~LLDragDropWin32() +{ +} + +bool LLDragDropWin32::init( HWND hWnd ) +{ + if (NOERROR != OleInitialize(NULL)) + return FALSE; + + mDropTarget = new LLDragDropWin32Target( hWnd ); + if ( mDropTarget ) + { + HRESULT result = CoLockObjectExternal( mDropTarget, TRUE, TRUE ); + if ( S_OK == result ) + { + result = RegisterDragDrop( hWnd, mDropTarget ); + if ( S_OK != result ) + { + // RegisterDragDrop failed + return false; + }; + + // all ok + mDropWindowHandle = hWnd; + } + else + { + // Unable to lock OLE object + return false; + }; + }; + + // success + return true; +} + +void LLDragDropWin32::reset() +{ + if ( mDropTarget ) + { + CoLockObjectExternal( mDropTarget, FALSE, TRUE ); + RevokeDragDrop( mDropWindowHandle ); + mDropTarget->Release(); + }; + + OleUninitialize(); +} + +#endif diff --git a/indra/llwindow/lldragdropwin32.h b/indra/llwindow/lldragdropwin32.h new file mode 100644 index 0000000000..6137e5eb65 --- /dev/null +++ b/indra/llwindow/lldragdropwin32.h @@ -0,0 +1,55 @@ +/** + * @file lldragdrop32.cpp + * @brief Handler for Windows specific drag and drop (OS to client) code + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLDRAGDROP32_H +#define LL_LLDRAGDROP32_H + +#include +#include +#include +#include + +class LLDragDropWin32 +{ + public: + LLDragDropWin32(); + ~LLDragDropWin32(); + + bool init( HWND hWnd ); + void reset(); + + private: + IDropTarget* mDropTarget; + HWND mDropWindowHandle; +}; + +#endif diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index fda2c7ee6f..1098529e1c 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -163,7 +163,7 @@ void LLWindowCallbacks::handleDataCopy(LLWindow *window, S32 data_type, void *da { } -BOOL LLWindowCallbacks::handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, void *data) +BOOL LLWindowCallbacks::handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, std::string data ) { return FALSE; } diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index e1e257943a..3a09100168 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -68,7 +68,7 @@ public: virtual void handleWindowBlock(LLWindow *window); // window is taking over CPU for a while virtual void handleWindowUnblock(LLWindow *window); // window coming back after taking over CPU for a while virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); - virtual BOOL handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, void *data); + virtual BOOL handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, std::string data); virtual BOOL handleTimerEvent(LLWindow *window); virtual BOOL handleDeviceChange(LLWindow *window); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 94c3e1af8c..da096b9a0a 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -1,2366 +1,2376 @@ -/** - * @file llwindowwin32.cpp - * @brief Platform-dependent implementation of llwindow - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#if LL_WINDOWS && !LL_MESA_HEADLESS - -#include "llwindowwin32.h" - -// LLWindow library includes -#include "llkeyboardwin32.h" -#include "llpreeditor.h" -#include "llwindowcallbacks.h" - -// Linden library includes -#include "llerror.h" -#include "llgl.h" -#include "llstring.h" - -// System includes -#include -#include -#include -#include // for _spawn -#include +/** + * @file llwindowwin32.cpp + * @brief Platform-dependent implementation of llwindow + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#if LL_WINDOWS && !LL_MESA_HEADLESS + +#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" + +// System includes +#include +#include +#include +#include // for _spawn +#include #include -#include - -// Require DirectInput version 8 -#define DIRECTINPUT_VERSION 0x0800 - -#include -#include - -#include "llmemtype.h" -// culled from winuser.h -#ifndef WM_MOUSEWHEEL /* Added to be compatible with later SDK's */ -const S32 WM_MOUSEWHEEL = 0x020A; -#endif -#ifndef WHEEL_DELTA /* Added to be compatible with later SDK's */ -const S32 WHEEL_DELTA = 120; /* Value for rolling one detent */ -#endif -const S32 MAX_MESSAGE_PER_UPDATE = 20; -const S32 BITS_PER_PIXEL = 32; -const S32 MAX_NUM_RESOLUTIONS = 32; -const F32 ICON_FLASH_TIME = 0.5f; - -extern BOOL gDebugWindowProc; - -LPWSTR gIconResource = IDI_APPLICATION; - -LLW32MsgCallback gAsyncMsgCallback = NULL; - -// -// LLWindowWin32 -// - -void show_window_creation_error(const std::string& title) -{ - LL_WARNS("Window") << title << LL_ENDL; -} - -//static -BOOL LLWindowWin32::sIsClassRegistered = FALSE; - -BOOL LLWindowWin32::sLanguageTextInputAllowed = TRUE; -BOOL LLWindowWin32::sWinIMEOpened = FALSE; -HKL LLWindowWin32::sWinInputLocale = 0; -DWORD LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE; -DWORD LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC; -LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1); - -// The following class LLWinImm delegates Windows IMM APIs. -// We need this because some language versions of Windows, -// e.g., US version of Windows XP, doesn't install IMM32.DLL -// as a default, and we can't link against imm32.lib statically. -// I believe DLL loading of this type is best suited to do -// in a static initialization of a class. What I'm not sure is -// whether it follows the Linden Conding Standard... -// See http://wiki.secondlife.com/wiki/Coding_standards#Static_Members - -class LLWinImm -{ -public: - static bool isAvailable() { return sTheInstance.mHImmDll != NULL; } - -public: - // Wrappers for IMM API. - static BOOL isIME(HKL hkl); - static HWND getDefaultIMEWnd(HWND hwnd); - static HIMC getContext(HWND hwnd); - static BOOL releaseContext(HWND hwnd, HIMC himc); - static BOOL getOpenStatus(HIMC himc); - static BOOL setOpenStatus(HIMC himc, BOOL status); - static BOOL getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence); - static BOOL setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence); - static BOOL getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); - static BOOL setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); - static LONG getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length); - static BOOL setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength); - static BOOL setCompositionFont(HIMC himc, LPLOGFONTW logfont); - static BOOL setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form); - static BOOL notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value); - -private: - LLWinImm(); - ~LLWinImm(); - -private: - // Pointers to IMM API. - BOOL (WINAPI *mImmIsIME)(HKL); - HWND (WINAPI *mImmGetDefaultIMEWnd)(HWND); - HIMC (WINAPI *mImmGetContext)(HWND); - BOOL (WINAPI *mImmReleaseContext)(HWND, HIMC); - BOOL (WINAPI *mImmGetOpenStatus)(HIMC); - BOOL (WINAPI *mImmSetOpenStatus)(HIMC, BOOL); - BOOL (WINAPI *mImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD); - BOOL (WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD); - BOOL (WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM); - BOOL (WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM); - LONG (WINAPI *mImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD); - BOOL (WINAPI *mImmSetCompositionString)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD); - BOOL (WINAPI *mImmSetCompositionFont)(HIMC, LPLOGFONTW); - BOOL (WINAPI *mImmSetCandidateWindow)(HIMC, LPCANDIDATEFORM); - BOOL (WINAPI *mImmNotifyIME)(HIMC, DWORD, DWORD, DWORD); - -private: - HMODULE mHImmDll; - static LLWinImm sTheInstance; -}; - -LLWinImm LLWinImm::sTheInstance; - -LLWinImm::LLWinImm() : mHImmDll(NULL) -{ - // Check system metrics - if ( !GetSystemMetrics( SM_DBCSENABLED ) ) - return; - - - mHImmDll = LoadLibraryA("Imm32"); - if (mHImmDll != NULL) - { - mImmIsIME = (BOOL (WINAPI *)(HKL)) GetProcAddress(mHImmDll, "ImmIsIME"); - mImmGetDefaultIMEWnd = (HWND (WINAPI *)(HWND)) GetProcAddress(mHImmDll, "ImmGetDefaultIMEWnd"); - mImmGetContext = (HIMC (WINAPI *)(HWND)) GetProcAddress(mHImmDll, "ImmGetContext"); - mImmReleaseContext = (BOOL (WINAPI *)(HWND, HIMC)) GetProcAddress(mHImmDll, "ImmReleaseContext"); - mImmGetOpenStatus = (BOOL (WINAPI *)(HIMC)) GetProcAddress(mHImmDll, "ImmGetOpenStatus"); - mImmSetOpenStatus = (BOOL (WINAPI *)(HIMC, BOOL)) GetProcAddress(mHImmDll, "ImmSetOpenStatus"); - mImmGetConversionStatus = (BOOL (WINAPI *)(HIMC, LPDWORD, LPDWORD)) GetProcAddress(mHImmDll, "ImmGetConversionStatus"); - mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD)) GetProcAddress(mHImmDll, "ImmSetConversionStatus"); - mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM)) GetProcAddress(mHImmDll, "ImmGetCompositionWindow"); - mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM)) GetProcAddress(mHImmDll, "ImmSetCompositionWindow"); - mImmGetCompositionString= (LONG (WINAPI *)(HIMC, DWORD, LPVOID, DWORD)) GetProcAddress(mHImmDll, "ImmGetCompositionStringW"); - mImmSetCompositionString= (BOOL (WINAPI *)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD)) GetProcAddress(mHImmDll, "ImmSetCompositionStringW"); - mImmSetCompositionFont = (BOOL (WINAPI *)(HIMC, LPLOGFONTW)) GetProcAddress(mHImmDll, "ImmSetCompositionFontW"); - mImmSetCandidateWindow = (BOOL (WINAPI *)(HIMC, LPCANDIDATEFORM)) GetProcAddress(mHImmDll, "ImmSetCandidateWindow"); - mImmNotifyIME = (BOOL (WINAPI *)(HIMC, DWORD, DWORD, DWORD)) GetProcAddress(mHImmDll, "ImmNotifyIME"); - - if (mImmIsIME == NULL || - mImmGetDefaultIMEWnd == NULL || - mImmGetContext == NULL || - mImmReleaseContext == NULL || - mImmGetOpenStatus == NULL || - mImmSetOpenStatus == NULL || - mImmGetConversionStatus == NULL || - mImmSetConversionStatus == NULL || - mImmGetCompostitionWindow == NULL || - mImmSetCompostitionWindow == NULL || - mImmGetCompositionString == NULL || - mImmSetCompositionString == NULL || - mImmSetCompositionFont == NULL || - mImmSetCandidateWindow == NULL || - mImmNotifyIME == NULL) - { - // If any of the above API entires are not found, we can't use IMM API. - // So, turn off the IMM support. We should log some warning message in - // the case, since it is very unusual; these APIs are available from - // the beginning, and all versions of IMM32.DLL should have them all. - // Unfortunately, this code may be executed before initialization of - // the logging channel (llwarns), and we can't do it here... Yes, this - // is one of disadvantages to use static constraction to DLL loading. - FreeLibrary(mHImmDll); - mHImmDll = NULL; - - // If we unload the library, make sure all the function pointers are cleared - mImmIsIME = NULL; - mImmGetDefaultIMEWnd = NULL; - mImmGetContext = NULL; - mImmReleaseContext = NULL; - mImmGetOpenStatus = NULL; - mImmSetOpenStatus = NULL; - mImmGetConversionStatus = NULL; - mImmSetConversionStatus = NULL; - mImmGetCompostitionWindow = NULL; - mImmSetCompostitionWindow = NULL; - mImmGetCompositionString = NULL; - mImmSetCompositionString = NULL; - mImmSetCompositionFont = NULL; - mImmSetCandidateWindow = NULL; - mImmNotifyIME = NULL; - } - } -} - - -// static -BOOL LLWinImm::isIME(HKL hkl) -{ - if ( sTheInstance.mImmIsIME ) - return sTheInstance.mImmIsIME(hkl); - return FALSE; -} - -// static -HIMC LLWinImm::getContext(HWND hwnd) -{ - if ( sTheInstance.mImmGetContext ) - return sTheInstance.mImmGetContext(hwnd); - return 0; -} - -//static -BOOL LLWinImm::releaseContext(HWND hwnd, HIMC himc) -{ - if ( sTheInstance.mImmIsIME ) - return sTheInstance.mImmReleaseContext(hwnd, himc); - return FALSE; -} - -// static -BOOL LLWinImm::getOpenStatus(HIMC himc) -{ - if ( sTheInstance.mImmGetOpenStatus ) - return sTheInstance.mImmGetOpenStatus(himc); - return FALSE; -} - -// static -BOOL LLWinImm::setOpenStatus(HIMC himc, BOOL status) -{ - if ( sTheInstance.mImmSetOpenStatus ) - return sTheInstance.mImmSetOpenStatus(himc, status); - return FALSE; -} - -// static -BOOL LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence) -{ - if ( sTheInstance.mImmGetConversionStatus ) - return sTheInstance.mImmGetConversionStatus(himc, conversion, sentence); - return FALSE; -} - -// static -BOOL LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence) -{ - if ( sTheInstance.mImmSetConversionStatus ) - return sTheInstance.mImmSetConversionStatus(himc, conversion, sentence); - return FALSE; -} - -// static -BOOL LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) -{ - if ( sTheInstance.mImmGetCompostitionWindow ) - return sTheInstance.mImmGetCompostitionWindow(himc, form); - return FALSE; -} - -// static -BOOL LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) -{ - if ( sTheInstance.mImmSetCompostitionWindow ) - return sTheInstance.mImmSetCompostitionWindow(himc, form); - return FALSE; -} - - -// static -LONG LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length) -{ - if ( sTheInstance.mImmGetCompositionString ) - return sTheInstance.mImmGetCompositionString(himc, index, data, length); - return FALSE; -} - - -// static -BOOL LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength) -{ - if ( sTheInstance.mImmSetCompositionString ) - return sTheInstance.mImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength); - return FALSE; -} - -// static -BOOL LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont) -{ - if ( sTheInstance.mImmSetCompositionFont ) - return sTheInstance.mImmSetCompositionFont(himc, pFont); - return FALSE; -} - -// static -BOOL LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form) -{ - if ( sTheInstance.mImmSetCandidateWindow ) - return sTheInstance.mImmSetCandidateWindow(himc, form); - return FALSE; -} - -// static -BOOL LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value) -{ - if ( sTheInstance.mImmNotifyIME ) - return sTheInstance.mImmNotifyIME(himc, action, index, value); - return FALSE; -} - - - - -// ---------------------------------------------------------------------------------------- -LLWinImm::~LLWinImm() -{ - if (mHImmDll != NULL) - { - FreeLibrary(mHImmDll); - mHImmDll = NULL; - } -} - - -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, - U32 fsaa_samples) - : LLWindow(callbacks, fullscreen, flags) -{ - mFSAASamples = fsaa_samples; - mIconResource = gIconResource; - mOverrideAspectRatio = 0.f; - mNativeAspectRatio = 0.f; - mMousePositionModified = FALSE; - mInputProcessingPaused = FALSE; - mPreeditor = NULL; - mhDC = NULL; - mhRC = NULL; - - // Initialize the keyboard - gKeyboard = new LLKeyboardWin32(); - gKeyboard->setCallbacks(callbacks); - - // Initialize (boot strap) the Language text input management, - // based on the system's (user's) default settings. - allowLanguageTextInput(mPreeditor, FALSE); - - WNDCLASS wc; - RECT window_rect; - - // Set the window title - if (title.empty()) - { - mWindowTitle = new WCHAR[50]; - wsprintf(mWindowTitle, L"OpenGL Window"); - } - else - { - mWindowTitle = new WCHAR[256]; // Assume title length < 255 chars. - mbstowcs(mWindowTitle, title.c_str(), 255); - mWindowTitle[255] = 0; - } - - // Set the window class name - if (name.empty()) - { - mWindowClassName = new WCHAR[50]; - wsprintf(mWindowClassName, L"OpenGL Window"); - } - else - { - mWindowClassName = new WCHAR[256]; // Assume title length < 255 chars. - mbstowcs(mWindowClassName, name.c_str(), 255); - mWindowClassName[255] = 0; - } - - - // We're not clipping yet - SetRect( &mOldMouseClip, 0, 0, 0, 0 ); - - // Make an instance of our window then define the window class - mhInstance = GetModuleHandle(NULL); - mWndProc = NULL; - - mSwapMethod = SWAP_METHOD_UNDEFINED; - - // No WPARAM yet. - mLastSizeWParam = 0; - - // Windows GDI rects don't include rightmost pixel - window_rect.left = (long) 0; - window_rect.right = (long) width; - window_rect.top = (long) 0; - window_rect.bottom = (long) height; - - // Grab screen size to sanitize the window - S32 window_border_y = GetSystemMetrics(SM_CYBORDER); - S32 virtual_screen_x = GetSystemMetrics(SM_XVIRTUALSCREEN); - S32 virtual_screen_y = GetSystemMetrics(SM_YVIRTUALSCREEN); - S32 virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); - S32 virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); - - if (x < virtual_screen_x) x = virtual_screen_x; - if (y < virtual_screen_y - window_border_y) y = virtual_screen_y - window_border_y; - - if (x + width > virtual_screen_x + virtual_screen_width) x = virtual_screen_x + virtual_screen_width - width; - if (y + height > virtual_screen_y + virtual_screen_height) y = virtual_screen_y + virtual_screen_height - height; - - if (!sIsClassRegistered) - { - // Force redraw when resized and create a private device context - - // Makes double click messages. - wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; - - // Set message handler function - wc.lpfnWndProc = (WNDPROC) mainWindowProc; - - // unused - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - - wc.hInstance = mhInstance; - wc.hIcon = LoadIcon(mhInstance, mIconResource); - - // We will set the cursor ourselves - wc.hCursor = NULL; - - // background color is not used - if (clearBg) - { - wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); - } - else - { - wc.hbrBackground = (HBRUSH) NULL; - } - - // we don't use windows menus - wc.lpszMenuName = NULL; - - wc.lpszClassName = mWindowClassName; - - if (!RegisterClass(&wc)) - { - OSMessageBox(mCallbacks->translateString("MBRegClassFailed"), - mCallbacks->translateString("MBError"), OSMB_OK); - return; - } - sIsClassRegistered = TRUE; - } - - //----------------------------------------------------------------------- - // Get the current refresh rate - //----------------------------------------------------------------------- - - DEVMODE dev_mode; - DWORD current_refresh; - if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) - { - current_refresh = dev_mode.dmDisplayFrequency; - mNativeAspectRatio = ((F32)dev_mode.dmPelsWidth) / ((F32)dev_mode.dmPelsHeight); - } - else - { - current_refresh = 60; - } - - //----------------------------------------------------------------------- - // Drop resolution and go fullscreen - // use a display mode with our desired size and depth, with a refresh - // rate as close at possible to the users' default - //----------------------------------------------------------------------- - if (mFullscreen) - { - BOOL success = FALSE; - DWORD closest_refresh = 0; - - for (S32 mode_num = 0;; mode_num++) - { - if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) - { - break; - } - - if (dev_mode.dmPelsWidth == width && - dev_mode.dmPelsHeight == height && - dev_mode.dmBitsPerPel == BITS_PER_PIXEL) - { - success = TRUE; - if ((dev_mode.dmDisplayFrequency - current_refresh) - < (closest_refresh - current_refresh)) - { - closest_refresh = dev_mode.dmDisplayFrequency; - } - } - } - - if (closest_refresh == 0) - { - LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; - success = FALSE; - } - - // If we found a good resolution, use it. - if (success) - { - success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); - } - - // Keep a copy of the actual current device mode in case we minimize - // and change the screen resolution. JC - EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); - - // If it failed, we don't want to run fullscreen - if (success) - { - mFullscreen = TRUE; - mFullscreenWidth = dev_mode.dmPelsWidth; - mFullscreenHeight = dev_mode.dmPelsHeight; - mFullscreenBits = dev_mode.dmBitsPerPel; - mFullscreenRefresh = dev_mode.dmDisplayFrequency; - - LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth - << "x" << dev_mode.dmPelsHeight - << "x" << dev_mode.dmBitsPerPel - << " @ " << dev_mode.dmDisplayFrequency - << LL_ENDL; - } - else - { - mFullscreen = FALSE; - mFullscreenWidth = -1; - mFullscreenHeight = -1; - mFullscreenBits = -1; - mFullscreenRefresh = -1; - - std::map args; - args["[WIDTH]"] = llformat("%d", width); - args["[HEIGHT]"] = llformat ("%d", height); - OSMessageBox(mCallbacks->translateString("MBFullScreenErr", args), - mCallbacks->translateString("MBError"), OSMB_OK); - } - } - - // TODO: add this after resolving _WIN32_WINNT issue - // if (!fullscreen) - // { - // TRACKMOUSEEVENT track_mouse_event; - // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); - // track_mouse_event.dwFlags = TME_LEAVE; - // track_mouse_event.hwndTrack = mWindowHandle; - // track_mouse_event.dwHoverTime = HOVER_DEFAULT; - // TrackMouseEvent( &track_mouse_event ); - // } - - - //----------------------------------------------------------------------- - // Create GL drawing context - //----------------------------------------------------------------------- - LLCoordScreen windowPos(x,y); - LLCoordScreen windowSize(window_rect.right - window_rect.left, - window_rect.bottom - window_rect.top); - if (!switchContext(mFullscreen, windowSize, TRUE, &windowPos)) - { - return; - } - - //start with arrow cursor - initCursors(); - setCursor( UI_CURSOR_ARROW ); - - // Initialize (boot strap) the Language text input management, - // based on the system's (or user's) default settings. - allowLanguageTextInput(NULL, FALSE); -} - - -LLWindowWin32::~LLWindowWin32() -{ - delete [] mWindowTitle; - mWindowTitle = NULL; - - delete [] mSupportedResolutions; - mSupportedResolutions = NULL; - - delete mWindowClassName; - mWindowClassName = NULL; -} - -void LLWindowWin32::show() -{ - ShowWindow(mWindowHandle, SW_SHOW); - SetForegroundWindow(mWindowHandle); - SetFocus(mWindowHandle); -} - -void LLWindowWin32::hide() -{ - setMouseClipping(FALSE); - ShowWindow(mWindowHandle, SW_HIDE); -} - -void LLWindowWin32::minimize() -{ - setMouseClipping(FALSE); - showCursor(); - ShowWindow(mWindowHandle, SW_MINIMIZE); -} - - -void LLWindowWin32::restore() -{ - ShowWindow(mWindowHandle, SW_RESTORE); - SetForegroundWindow(mWindowHandle); - SetFocus(mWindowHandle); -} - - -// close() destroys all OS-specific code associated with a window. -// Usually called from LLWindowManager::destroyWindow() -void LLWindowWin32::close() -{ - LL_DEBUGS("Window") << "Closing LLWindowWin32" << LL_ENDL; - // Is window is already closed? - if (!mWindowHandle) - { - return; - } - - // Make sure cursor is visible and we haven't mangled the clipping state. - setMouseClipping(FALSE); - showCursor(); - - // Go back to screen mode written in the registry. - if (mFullscreen) - { - resetDisplayResolution(); - } - - // Clean up remaining GL state - LL_DEBUGS("Window") << "Shutting down GL" << LL_ENDL; - gGLManager.shutdownGL(); - - LL_DEBUGS("Window") << "Releasing Context" << LL_ENDL; - if (mhRC) - { - if (!wglMakeCurrent(NULL, NULL)) - { - LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; - } - - if (!wglDeleteContext(mhRC)) - { - LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; - } - - mhRC = NULL; - } - - // Restore gamma to the system values. - restoreGamma(); - - if (mhDC && !ReleaseDC(mWindowHandle, mhDC)) - { - LL_WARNS("Window") << "Release of ghDC failed" << LL_ENDL; - mhDC = NULL; - } - - LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; - - // Don't process events in our mainWindowProc any longer. - SetWindowLong(mWindowHandle, GWL_USERDATA, NULL); - - // Make sure we don't leave a blank toolbar button. - ShowWindow(mWindowHandle, SW_HIDE); - - // This causes WM_DESTROY to be sent *immediately* - if (!DestroyWindow(mWindowHandle)) - { - OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"), - mCallbacks->translateString("MBShutdownErr"), - OSMB_OK); - } - - mWindowHandle = NULL; -} - -BOOL LLWindowWin32::isValid() -{ - return (mWindowHandle != NULL); -} - -BOOL LLWindowWin32::getVisible() -{ - return (mWindowHandle && IsWindowVisible(mWindowHandle)); -} - -BOOL LLWindowWin32::getMinimized() -{ - return (mWindowHandle && IsIconic(mWindowHandle)); -} - -BOOL LLWindowWin32::getMaximized() -{ - return (mWindowHandle && IsZoomed(mWindowHandle)); -} - -BOOL LLWindowWin32::maximize() -{ - BOOL success = FALSE; - if (!mWindowHandle) return success; - - WINDOWPLACEMENT placement; - placement.length = sizeof(WINDOWPLACEMENT); - - success = GetWindowPlacement(mWindowHandle, &placement); - if (!success) return success; - - placement.showCmd = SW_MAXIMIZE; - - success = SetWindowPlacement(mWindowHandle, &placement); - return success; -} - -BOOL LLWindowWin32::getFullscreen() -{ - return mFullscreen; -} - -BOOL LLWindowWin32::getPosition(LLCoordScreen *position) -{ - RECT window_rect; - - if (!mWindowHandle || - !GetWindowRect(mWindowHandle, &window_rect) || - NULL == position) - { - return FALSE; - } - - position->mX = window_rect.left; - position->mY = window_rect.top; - return TRUE; -} - -BOOL LLWindowWin32::getSize(LLCoordScreen *size) -{ - RECT window_rect; - - if (!mWindowHandle || - !GetWindowRect(mWindowHandle, &window_rect) || - NULL == size) - { - return FALSE; - } - - size->mX = window_rect.right - window_rect.left; - size->mY = window_rect.bottom - window_rect.top; - return TRUE; -} - -BOOL LLWindowWin32::getSize(LLCoordWindow *size) -{ - RECT client_rect; - - if (!mWindowHandle || - !GetClientRect(mWindowHandle, &client_rect) || - NULL == size) - { - return FALSE; - } - - size->mX = client_rect.right - client_rect.left; - size->mY = client_rect.bottom - client_rect.top; - return TRUE; -} - -BOOL LLWindowWin32::setPosition(const LLCoordScreen position) -{ - LLCoordScreen size; - - if (!mWindowHandle) - { - return FALSE; - } - getSize(&size); - moveWindow(position, size); - return TRUE; -} - -BOOL LLWindowWin32::setSize(const LLCoordScreen size) -{ - LLCoordScreen position; - - getPosition(&position); - if (!mWindowHandle) - { - return FALSE; - } - - moveWindow(position, size); - return TRUE; -} - -// changing fullscreen resolution -BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp) -{ - GLuint pixel_format; - DEVMODE dev_mode; - DWORD current_refresh; - DWORD dw_ex_style; - DWORD dw_style; - RECT window_rect; - S32 width = size.mX; - S32 height = size.mY; - BOOL auto_show = FALSE; - - if (mhRC) - { - auto_show = TRUE; - resetDisplayResolution(); - } - - if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) - { - current_refresh = dev_mode.dmDisplayFrequency; - } - else - { - current_refresh = 60; - } - - gGLManager.shutdownGL(); - //destroy gl context - if (mhRC) - { - if (!wglMakeCurrent(NULL, NULL)) - { - LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; - } - - if (!wglDeleteContext(mhRC)) - { - LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; - } - - mhRC = NULL; - } - - if (fullscreen) - { - mFullscreen = TRUE; - BOOL success = FALSE; - DWORD closest_refresh = 0; - - for (S32 mode_num = 0;; mode_num++) - { - if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) - { - break; - } - - if (dev_mode.dmPelsWidth == width && - dev_mode.dmPelsHeight == height && - dev_mode.dmBitsPerPel == BITS_PER_PIXEL) - { - success = TRUE; - if ((dev_mode.dmDisplayFrequency - current_refresh) - < (closest_refresh - current_refresh)) - { - closest_refresh = dev_mode.dmDisplayFrequency; - } - } - } - - if (closest_refresh == 0) - { - LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; - return FALSE; - } - - // If we found a good resolution, use it. - if (success) - { - success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); - } - - // Keep a copy of the actual current device mode in case we minimize - // and change the screen resolution. JC - EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); - - if (success) - { - mFullscreen = TRUE; - mFullscreenWidth = dev_mode.dmPelsWidth; - mFullscreenHeight = dev_mode.dmPelsHeight; - mFullscreenBits = dev_mode.dmBitsPerPel; - mFullscreenRefresh = dev_mode.dmDisplayFrequency; - - LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth - << "x" << dev_mode.dmPelsHeight - << "x" << dev_mode.dmBitsPerPel - << " @ " << dev_mode.dmDisplayFrequency - << LL_ENDL; - - 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; - 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); - } - // If it failed, we don't want to run fullscreen - else - { - mFullscreen = FALSE; - mFullscreenWidth = -1; - mFullscreenHeight = -1; - mFullscreenBits = -1; - mFullscreenRefresh = -1; - - LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL; - return FALSE; - } - } - else - { - mFullscreen = FALSE; - 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; - } - - // don't post quit messages when destroying old windows - mPostQuit = FALSE; - - // create window - DestroyWindow(mWindowHandle); - mWindowHandle = CreateWindowEx(dw_ex_style, - mWindowClassName, - mWindowTitle, - WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, - window_rect.left, // x pos - window_rect.top, // y pos - window_rect.right - window_rect.left, // width - window_rect.bottom - window_rect.top, // height - NULL, - NULL, - mhInstance, - NULL); - - //----------------------------------------------------------------------- - // Create GL drawing context - //----------------------------------------------------------------------- - static PIXELFORMATDESCRIPTOR pfd = - { - sizeof(PIXELFORMATDESCRIPTOR), - 1, - PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, - 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(mCallbacks->translateString("MBDevContextErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - if (!(pixel_format = ChoosePixelFormat(mhDC, &pfd))) - { - close(); - OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - // Verify what pixel format we actually received. - if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), - &pfd)) - { - close(); - OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - if (pfd.cColorBits < 32) - { - close(); - OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"), - mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - if (pfd.cAlphaBits < 8) - { - close(); - OSMessageBox(mCallbacks->translateString("MBAlpha"), - mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - if (!SetPixelFormat(mhDC, pixel_format, &pfd)) - { - close(); - OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - if (!(mhRC = wglCreateContext(mhDC))) - { - close(); - OSMessageBox(mCallbacks->translateString("MBGLContextErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - if (!wglMakeCurrent(mhDC, mhRC)) - { - close(); - OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - gGLManager.initWGL(); - - if (wglChoosePixelFormatARB) - { - // 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++] = 24; - - attrib_list[cur_attrib++] = WGL_ALPHA_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_SAMPLES_ARB; - attrib_list[cur_attrib++] = mFSAASamples; - } - - // 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 FALSE; - } - - if (!num_formats) - { - 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) - { - 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) - { - close(); - 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; - } - } - } - - 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 - - } - ReleaseDC (mWindowHandle, mhDC); // Release The Device Context - mhDC = 0; // Zero The Device Context - } - DestroyWindow (mWindowHandle); // Destroy The Window - - - mWindowHandle = CreateWindowEx(dw_ex_style, - mWindowClassName, - mWindowTitle, - WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, - window_rect.left, // x pos - window_rect.top, // 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(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - if (!SetPixelFormat(mhDC, pixel_format, &pfd)) - { - close(); - OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) - { - switch (swap_method) - { - case WGL_SWAP_EXCHANGE_ARB: - mSwapMethod = SWAP_METHOD_EXCHANGE; - LL_DEBUGS("Window") << "Swap Method: Exchange" << LL_ENDL; - break; - case WGL_SWAP_COPY_ARB: - mSwapMethod = SWAP_METHOD_COPY; - LL_DEBUGS("Window") << "Swap Method: Copy" << LL_ENDL; - break; - case WGL_SWAP_UNDEFINED_ARB: - mSwapMethod = SWAP_METHOD_UNDEFINED; - LL_DEBUGS("Window") << "Swap Method: Undefined" << LL_ENDL; - break; - default: - mSwapMethod = SWAP_METHOD_UNDEFINED; - LL_DEBUGS("Window") << "Swap Method: Unknown" << LL_ENDL; - break; - } - } - } - else - { - LL_WARNS("Window") << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << LL_ENDL; - } - - // Verify what pixel format we actually received. - if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), - &pfd)) - { - close(); - OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - LL_INFOS("Window") << "GL buffer: Color Bits " << S32(pfd.cColorBits) - << " Alpha Bits " << S32(pfd.cAlphaBits) - << " Depth Bits " << S32(pfd.cDepthBits) - << LL_ENDL; - - // make sure we have 32 bits per pixel - if (pfd.cColorBits < 32 || GetDeviceCaps(mhDC, BITSPIXEL) < 32) - { - close(); - OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"), mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - if (pfd.cAlphaBits < 8) - { - close(); - OSMessageBox(mCallbacks->translateString("MBAlpha"), mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - if (!(mhRC = wglCreateContext(mhDC))) - { - close(); - OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - if (!wglMakeCurrent(mhDC, mhRC)) - { - close(); - OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - if (!gGLManager.initGL()) - { - close(); - OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - // Disable vertical sync for swap - if (disable_vsync && wglSwapIntervalEXT) - { - LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL; - wglSwapIntervalEXT(0); - } - else - { - LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL; - } - - SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this); - - // register this window as handling drag/drop events from the OS - DragAcceptFiles( mWindowHandle, TRUE ); - - //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; -} - -void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size ) -{ - if( mIsMouseClipping ) - { - RECT client_rect_in_screen_space; - if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) - { - ClipCursor( &client_rect_in_screen_space ); - } - } - - // 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). - - // 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); -} - -BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position) -{ - LLCoordScreen screen_pos; - - mMousePositionModified = TRUE; - if (!mWindowHandle) - { - return FALSE; - } - - if (!convertCoords(position, &screen_pos)) - { - 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); -} - -BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position) -{ - POINT cursor_point; - LLCoordScreen screen_pos; - - if (!mWindowHandle || - !GetCursorPos(&cursor_point)) - { - return FALSE; - } - - screen_pos.mX = cursor_point.x; - screen_pos.mY = cursor_point.y; - - return convertCoords(screen_pos, position); -} - -void LLWindowWin32::hideCursor() -{ - while (ShowCursor(FALSE) >= 0) - { - // nothing, wait for cursor to push down - } - mCursorHidden = TRUE; - mHideCursorPermanent = TRUE; -} - -void LLWindowWin32::showCursor() -{ - // makes sure the cursor shows up - while (ShowCursor(TRUE) < 0) - { - // do nothing, wait for cursor to pop out - } - mCursorHidden = FALSE; - mHideCursorPermanent = FALSE; -} - -void LLWindowWin32::showCursorFromMouseMove() -{ - if (!mHideCursorPermanent) - { - showCursor(); - } -} - -void LLWindowWin32::hideCursorUntilMouseMove() -{ - if (!mHideCursorPermanent) - { - hideCursor(); - mHideCursorPermanent = FALSE; - } -} - -BOOL LLWindowWin32::isCursorHidden() -{ - return mCursorHidden; -} - - -HCURSOR LLWindowWin32::loadColorCursor(LPCTSTR name) -{ - return (HCURSOR)LoadImage(mhInstance, - name, - IMAGE_CURSOR, - 0, // default width - 0, // default height - LR_DEFAULTCOLOR); -} - - -void LLWindowWin32::initCursors() -{ - mCursor[ UI_CURSOR_ARROW ] = LoadCursor(NULL, IDC_ARROW); - mCursor[ UI_CURSOR_WAIT ] = LoadCursor(NULL, IDC_WAIT); - mCursor[ UI_CURSOR_HAND ] = LoadCursor(NULL, IDC_HAND); - mCursor[ UI_CURSOR_IBEAM ] = LoadCursor(NULL, IDC_IBEAM); - mCursor[ UI_CURSOR_CROSS ] = LoadCursor(NULL, IDC_CROSS); - mCursor[ UI_CURSOR_SIZENWSE ] = LoadCursor(NULL, IDC_SIZENWSE); - mCursor[ UI_CURSOR_SIZENESW ] = LoadCursor(NULL, IDC_SIZENESW); - mCursor[ UI_CURSOR_SIZEWE ] = LoadCursor(NULL, IDC_SIZEWE); - mCursor[ UI_CURSOR_SIZENS ] = LoadCursor(NULL, IDC_SIZENS); - mCursor[ UI_CURSOR_NO ] = LoadCursor(NULL, IDC_NO); - mCursor[ UI_CURSOR_WORKING ] = LoadCursor(NULL, IDC_APPSTARTING); - - HMODULE module = GetModuleHandle(NULL); - mCursor[ UI_CURSOR_TOOLGRAB ] = LoadCursor(module, TEXT("TOOLGRAB")); - mCursor[ UI_CURSOR_TOOLLAND ] = LoadCursor(module, TEXT("TOOLLAND")); - mCursor[ UI_CURSOR_TOOLFOCUS ] = LoadCursor(module, TEXT("TOOLFOCUS")); - mCursor[ UI_CURSOR_TOOLCREATE ] = LoadCursor(module, TEXT("TOOLCREATE")); - mCursor[ UI_CURSOR_ARROWDRAG ] = LoadCursor(module, TEXT("ARROWDRAG")); - mCursor[ UI_CURSOR_ARROWCOPY ] = LoadCursor(module, TEXT("ARROWCOPY")); - mCursor[ UI_CURSOR_ARROWDRAGMULTI ] = LoadCursor(module, TEXT("ARROWDRAGMULTI")); - mCursor[ UI_CURSOR_ARROWCOPYMULTI ] = LoadCursor(module, TEXT("ARROWCOPYMULTI")); - mCursor[ UI_CURSOR_NOLOCKED ] = LoadCursor(module, TEXT("NOLOCKED")); - mCursor[ UI_CURSOR_ARROWLOCKED ]= LoadCursor(module, TEXT("ARROWLOCKED")); - mCursor[ UI_CURSOR_GRABLOCKED ] = LoadCursor(module, TEXT("GRABLOCKED")); - mCursor[ UI_CURSOR_TOOLTRANSLATE ] = LoadCursor(module, TEXT("TOOLTRANSLATE")); - mCursor[ UI_CURSOR_TOOLROTATE ] = LoadCursor(module, TEXT("TOOLROTATE")); - mCursor[ UI_CURSOR_TOOLSCALE ] = LoadCursor(module, TEXT("TOOLSCALE")); - mCursor[ UI_CURSOR_TOOLCAMERA ] = LoadCursor(module, TEXT("TOOLCAMERA")); - mCursor[ UI_CURSOR_TOOLPAN ] = LoadCursor(module, TEXT("TOOLPAN")); - mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN")); - mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3")); - mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE")); - - // Color cursors - 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++ ) - { - if( !mCursor[i] ) - { - mCursor[i] = LoadCursor(NULL, IDC_ARROW); - } - } -} - - - -void LLWindowWin32::setCursor(ECursorType cursor) -{ - if (cursor == UI_CURSOR_ARROW - && mBusyCount > 0) - { - cursor = UI_CURSOR_WORKING; - } - - if( mCurrentCursor != cursor ) - { - mCurrentCursor = cursor; - SetCursor( mCursor[cursor] ); - } -} - -ECursorType LLWindowWin32::getCursor() const -{ - return mCurrentCursor; -} - -void LLWindowWin32::captureMouse() -{ - SetCapture(mWindowHandle); -} - -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); -} - - -void LLWindowWin32::delayInputProcessing() -{ - mInputProcessingPaused = TRUE; -} - -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 ) - { - break; - } - /* Attempted workaround for problem where typing fast and hitting - return would result in only part of the text being sent. JC - - BOOL key_posted = TranslateMessage(&msg); - DispatchMessage(&msg); - msg_count++; - - // If a key was translated, a WM_CHAR might have been posted to the end - // of the event queue. We need it immediately. - if (key_posted && msg.message == WM_KEYDOWN) - { - if (PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - msg_count++; - } - } - */ - mCallbacks->handlePingWatchdog(this, "Main:AsyncCallbackGatherInput"); - // For async host by name support. Really hacky. - if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message)) - { - gAsyncMsgCallback(msg); - } - } - - mInputProcessingPaused = FALSE; - - // clear this once we've processed all mouse messages that might have occurred after - // we slammed the mouse position - 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) - { - if (!window_imp->mWndProc(h_wnd, u_msg, w_param, l_param)) - { - // user has handled window message - return 0; - } - } - - 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)); - - // This doesn't work, as LOWORD returns unsigned short. - //LLCoordWindow window_coord(LOWORD(l_param), HIWORD(l_param)); - LLCoordGL gl_coord; - - // pass along extended flag in mask - MASK mask = (l_param>>16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0; - BOOL eat_keystroke = TRUE; - - switch(u_msg) - { - RECT update_rect; - S32 update_width; - S32 update_height; - - case WM_TIMER: - 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; - window_imp->mCallbacks->handlePaint(window_imp, update_rect.left, update_rect.top, - update_width, update_height); - break; - case WM_PARENTNOTIFY: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PARENTNOTIFY"); - u_msg = u_msg; - break; - - case WM_SETCURSOR: - // This message is sent whenever the cursor is moved in a window. - // You need to set the appropriate cursor appearance. - - // 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] ); - return 0; - } - 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; - BOOL minimized = window_imp->getMinimized(); - - if (gDebugWindowProc) - { - LL_INFOS("Window") << "WINDOWPROC ActivateApp " - << " activating " << S32(activating) - << " minimized " << S32(minimized) - << " fullscreen " << S32(window_imp->mFullscreen) - << LL_ENDL; - } - - if (window_imp->mFullscreen) - { - // When we run fullscreen, restoring or minimizing the app needs - // to switch the screen resolution - if (activating) - { - window_imp->setFullscreenResolution(); - window_imp->restore(); - } - else - { - window_imp->minimize(); - 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); - - BOOL minimized = BOOL(HIWORD(w_param)); - - if (!activating && LLWinImm::isAvailable() && window_imp->mPreeditor) - { - window_imp->interruptLanguageTextInput(); - } - - // JC - I'm not sure why, but if we don't report that we handled the - // WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work - // properly when we run fullscreen. - if (gDebugWindowProc) - { - LL_INFOS("Window") << "WINDOWPROC Activate " - << " activating " << S32(activating) - << " minimized " << S32(minimized) - << LL_ENDL; - } - - // Don't handle this. - break; - } - - case WM_QUERYOPEN: - // TODO: use this to return a nice icon - break; - - case WM_SYSCOMMAND: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSCOMMAND"); - switch(w_param) - { - case SC_KEYMENU: - // Disallow the ALT key from triggering the default system menu. - return 0; - - case SC_SCREENSAVE: - case SC_MONITORPOWER: - // eat screen save messages and prevent them! - return 0; - } - 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)) - { - // Get the app to initiate cleanup. - window_imp->mCallbacks->handleQuit(window_imp); - // The app is responsible for calling destroyWindow when done with GL - } - 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 - } - 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)); - } - 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->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYDOWN"); - { - if (gDebugWindowProc) - { - LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN " - << " key " << S32(w_param) - << LL_ENDL; - } - if(gKeyboard->handleKeyDown(w_param, mask) && eat_keystroke) - { - return 0; - } - // pass on to windows if we didn't handle it - break; - } - case WM_SYSKEYUP: - eat_keystroke = FALSE; - case WM_KEYUP: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP"); - LLFastTimer t2(FTM_KEYHANDLER); - - if (gDebugWindowProc) - { - LL_INFOS("Window") << "Debug WindowProc WM_KEYUP " - << " key " << S32(w_param) - << LL_ENDL; - } - if (gKeyboard->handleKeyUp(w_param, mask) && eat_keystroke) - { - return 0; - } - - // pass on to windows - 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; - // Invoke DefWinProc with the modified LPARAM. - } - 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(); - return 0; - } - 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; - } - 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); - return 0; - } - 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; - if (window_imp->handleImeRequests(w_param, l_param, &result)) - { - return result; - } - } - break; - - case WM_CHAR: - // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need - // to figure out how that works. - Doug - // - // ... Well, I don't think so. - // How it works is explained in Win32 API document, but WM_UNICHAR didn't work - // as specified at least on Windows XP SP1 Japanese version. I have never used - // it since then, and I'm not sure whether it has been fixed now, but I don't think - // 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 - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CHAR"); - if (gDebugWindowProc) - { - LL_INFOS("Window") << "Debug WindowProc WM_CHAR " - << " key " << S32(w_param) - << 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... - window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE)); - return 0; - - case WM_LBUTTONDOWN: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDOWN"); - LLFastTimer t2(FTM_MOUSEHANDLER); - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - window_imp->interruptLanguageTextInput(); - } - - // 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 - // first click changes the cursor position, all subsequent clicks - // will occur at the wrong location. JC - LLCoordWindow cursor_coord_window; - if (window_imp->mMousePositionModified) - { - window_imp->getCursorPosition(&cursor_coord_window); - window_imp->convertCoords(cursor_coord_window, &gl_coord); - } - else - { - 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; - } - } - break; - - case WM_LBUTTONDBLCLK: - //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 - // first click changes the cursor position, all subsequent clicks - // will occur at the wrong location. JC - LLCoordWindow cursor_coord_window; - if (window_imp->mMousePositionModified) - { - window_imp->getCursorPosition(&cursor_coord_window); - window_imp->convertCoords(cursor_coord_window, &gl_coord); - } - else - { - 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; - } - } - break; - - case WM_LBUTTONUP: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONUP"); - LLFastTimer t2(FTM_MOUSEHANDLER); - //if (gDebugClicks) - //{ - // 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. - // If we don't do this, many clicks could get buffered up, and if the - // first click changes the cursor position, all subsequent clicks - // will occur at the wrong location. JC - LLCoordWindow cursor_coord_window; - if (window_imp->mMousePositionModified) - { - window_imp->getCursorPosition(&cursor_coord_window); - window_imp->convertCoords(cursor_coord_window, &gl_coord); - } - else - { - 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; - } - } - break; - - case WM_RBUTTONDBLCLK: - case WM_RBUTTONDOWN: - { - 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 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 - // will occur at the wrong location. JC - LLCoordWindow cursor_coord_window; - if (window_imp->mMousePositionModified) - { - window_imp->getCursorPosition(&cursor_coord_window); - window_imp->convertCoords(cursor_coord_window, &gl_coord); - } - else - { - 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; - } - } - break; - - case WM_RBUTTONUP: - { - 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 - // first click changes the cursor position, all subsequent clicks - // will occur at the wrong location. JC - LLCoordWindow cursor_coord_window; - if (window_imp->mMousePositionModified) - { - window_imp->getCursorPosition(&cursor_coord_window); - window_imp->convertCoords(cursor_coord_window, &gl_coord); - } - else - { - 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; - } - } - break; - - case WM_MBUTTONDOWN: -// case WM_MBUTTONDBLCLK: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONDOWN"); - 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 - // 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 - // will occur at the wrong location. JC - LLCoordWindow cursor_coord_window; - if (window_imp->mMousePositionModified) - { - window_imp->getCursorPosition(&cursor_coord_window); - window_imp->convertCoords(cursor_coord_window, &gl_coord); - } - else - { - 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; - } - } - break; - - case WM_MBUTTONUP: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONUP"); - LLFastTimer t2(FTM_MOUSEHANDLER); - // Because we move the cursor position in tllviewerhe 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 - // will occur at the wrong location. JC - LLCoordWindow cursor_coord_window; - if (window_imp->mMousePositionModified) - { - window_imp->getCursorPosition(&cursor_coord_window); - window_imp->convertCoords(cursor_coord_window, &gl_coord); - } - else - { - 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; - } - } - break; - - case WM_MOUSEWHEEL: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEWHEEL"); - static short z_delta = 0; - - z_delta += HIWORD(w_param); - // cout << "z_delta " << z_delta << endl; - - // current mouse wheels report changes in increments of zDelta (+120, -120) - // Future, higher resolution mouse wheels may report smaller deltas. - // So we sum the deltas and only act when we've exceeded WHEEL_DELTA - // - // If the user rapidly spins the wheel, we can get messages with - // large deltas, like 480 or so. Thus we need to scroll more quickly. - if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta) - { - window_imp->mCallbacks->handleScrollWheel(window_imp, -z_delta / WHEEL_DELTA); - z_delta = 0; - } - return 0; - } - /* - // TODO: add this after resolving _WIN32_WINNT issue - case WM_MOUSELEAVE: - { - window_imp->mCallbacks->handleMouseLeave(window_imp); - - // TRACKMOUSEEVENT track_mouse_event; - // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); - // track_mouse_event.dwFlags = TME_LEAVE; - // track_mouse_event.hwndTrack = h_wnd; - // track_mouse_event.dwHoverTime = HOVER_DEFAULT; - // TrackMouseEvent( &track_mouse_event ); - return 0; - } - */ - // 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); - return 0; - } - - case WM_SIZE: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SIZE"); - S32 width = S32( LOWORD(l_param) ); - S32 height = S32( HIWORD(l_param) ); - - if (gDebugWindowProc) - { - BOOL maximized = ( w_param == SIZE_MAXIMIZED ); - BOOL restored = ( w_param == SIZE_RESTORED ); - BOOL minimized = ( w_param == SIZE_MINIMIZED ); - - LL_INFOS("Window") << "WINDOWPROC Size " - << width << "x" << height - << " max " << S32(maximized) - << " min " << S32(minimized) - << " rest " << S32(restored) - << LL_ENDL; - } - - // There's an odd behavior with WM_SIZE that I would call a bug. If - // the window is maximized, and you call MoveWindow() with a size smaller - // than a maximized window, it ends up sending WM_SIZE with w_param set - // to SIZE_MAXIMIZED -- which isn't true. So the logic below doesn't work. - // (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see - // LLWindowWin32::moveWindow in this file). - - // If we are now restored, but we weren't before, this - // means that the window was un-minimized. - if (w_param == SIZE_RESTORED && window_imp->mLastSizeWParam != SIZE_RESTORED) - { - window_imp->mCallbacks->handleActivate(window_imp, TRUE); - } - - // handle case of window being maximized from fully minimized state - if (w_param == SIZE_MAXIMIZED && window_imp->mLastSizeWParam != SIZE_MAXIMIZED) - { - window_imp->mCallbacks->handleActivate(window_imp, TRUE); - } - - // Also handle the minimization case - if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED) - { - window_imp->mCallbacks->handleActivate(window_imp, FALSE); - } - - // Actually resize all of our views - if (w_param != SIZE_MINIMIZED) - { - // Ignore updates for minimizing and minimized "windows" - window_imp->mCallbacks->handleResize( window_imp, - LOWORD(l_param), - HIWORD(l_param) ); - } - - window_imp->mLastSizeWParam = w_param; - - return 0; - } - - case WM_SETFOCUS: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETFOCUS"); - if (gDebugWindowProc) - { - 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) - { - LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL; - } - window_imp->mCallbacks->handleFocusLost(window_imp); - return 0; - - case WM_COPYDATA: - { - 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; - - case WM_DROPFILES: - { - // HDROP contains what we need - HDROP hdrop = (HDROP)w_param; - - // get location in window space where drop occured and convert to OpenGL coordinate space - POINT pt; - DragQueryPoint( hdrop, &pt ); - LLCoordGL gl_coord; - LLCoordWindow cursor_coord_window( pt.x, pt.y ); - window_imp->convertCoords(cursor_coord_window, &gl_coord); - - // get payload (eventually, this needs to more advanced and grab size of payload dynamically - static char file_name[ 1024 ]; +#include + +// Require DirectInput version 8 +#define DIRECTINPUT_VERSION 0x0800 + +#include +#include + +#include "llmemtype.h" +// culled from winuser.h +#ifndef WM_MOUSEWHEEL /* Added to be compatible with later SDK's */ +const S32 WM_MOUSEWHEEL = 0x020A; +#endif +#ifndef WHEEL_DELTA /* Added to be compatible with later SDK's */ +const S32 WHEEL_DELTA = 120; /* Value for rolling one detent */ +#endif +const S32 MAX_MESSAGE_PER_UPDATE = 20; +const S32 BITS_PER_PIXEL = 32; +const S32 MAX_NUM_RESOLUTIONS = 32; +const F32 ICON_FLASH_TIME = 0.5f; + +extern BOOL gDebugWindowProc; + +LPWSTR gIconResource = IDI_APPLICATION; + +LLW32MsgCallback gAsyncMsgCallback = NULL; + +// +// LLWindowWin32 +// + +void show_window_creation_error(const std::string& title) +{ + LL_WARNS("Window") << title << LL_ENDL; +} + +//static +BOOL LLWindowWin32::sIsClassRegistered = FALSE; + +BOOL LLWindowWin32::sLanguageTextInputAllowed = TRUE; +BOOL LLWindowWin32::sWinIMEOpened = FALSE; +HKL LLWindowWin32::sWinInputLocale = 0; +DWORD LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE; +DWORD LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC; +LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1); + +// The following class LLWinImm delegates Windows IMM APIs. +// We need this because some language versions of Windows, +// e.g., US version of Windows XP, doesn't install IMM32.DLL +// as a default, and we can't link against imm32.lib statically. +// I believe DLL loading of this type is best suited to do +// in a static initialization of a class. What I'm not sure is +// whether it follows the Linden Conding Standard... +// See http://wiki.secondlife.com/wiki/Coding_standards#Static_Members + +class LLWinImm +{ +public: + static bool isAvailable() { return sTheInstance.mHImmDll != NULL; } + +public: + // Wrappers for IMM API. + static BOOL isIME(HKL hkl); + static HWND getDefaultIMEWnd(HWND hwnd); + static HIMC getContext(HWND hwnd); + static BOOL releaseContext(HWND hwnd, HIMC himc); + static BOOL getOpenStatus(HIMC himc); + static BOOL setOpenStatus(HIMC himc, BOOL status); + static BOOL getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence); + static BOOL setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence); + static BOOL getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); + static BOOL setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); + static LONG getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length); + static BOOL setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength); + static BOOL setCompositionFont(HIMC himc, LPLOGFONTW logfont); + static BOOL setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form); + static BOOL notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value); + +private: + LLWinImm(); + ~LLWinImm(); + +private: + // Pointers to IMM API. + BOOL (WINAPI *mImmIsIME)(HKL); + HWND (WINAPI *mImmGetDefaultIMEWnd)(HWND); + HIMC (WINAPI *mImmGetContext)(HWND); + BOOL (WINAPI *mImmReleaseContext)(HWND, HIMC); + BOOL (WINAPI *mImmGetOpenStatus)(HIMC); + BOOL (WINAPI *mImmSetOpenStatus)(HIMC, BOOL); + BOOL (WINAPI *mImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD); + BOOL (WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD); + BOOL (WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM); + BOOL (WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM); + LONG (WINAPI *mImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD); + BOOL (WINAPI *mImmSetCompositionString)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD); + BOOL (WINAPI *mImmSetCompositionFont)(HIMC, LPLOGFONTW); + BOOL (WINAPI *mImmSetCandidateWindow)(HIMC, LPCANDIDATEFORM); + BOOL (WINAPI *mImmNotifyIME)(HIMC, DWORD, DWORD, DWORD); + +private: + HMODULE mHImmDll; + static LLWinImm sTheInstance; +}; + +LLWinImm LLWinImm::sTheInstance; + +LLWinImm::LLWinImm() : mHImmDll(NULL) +{ + // Check system metrics + if ( !GetSystemMetrics( SM_DBCSENABLED ) ) + return; + + + mHImmDll = LoadLibraryA("Imm32"); + if (mHImmDll != NULL) + { + mImmIsIME = (BOOL (WINAPI *)(HKL)) GetProcAddress(mHImmDll, "ImmIsIME"); + mImmGetDefaultIMEWnd = (HWND (WINAPI *)(HWND)) GetProcAddress(mHImmDll, "ImmGetDefaultIMEWnd"); + mImmGetContext = (HIMC (WINAPI *)(HWND)) GetProcAddress(mHImmDll, "ImmGetContext"); + mImmReleaseContext = (BOOL (WINAPI *)(HWND, HIMC)) GetProcAddress(mHImmDll, "ImmReleaseContext"); + mImmGetOpenStatus = (BOOL (WINAPI *)(HIMC)) GetProcAddress(mHImmDll, "ImmGetOpenStatus"); + mImmSetOpenStatus = (BOOL (WINAPI *)(HIMC, BOOL)) GetProcAddress(mHImmDll, "ImmSetOpenStatus"); + mImmGetConversionStatus = (BOOL (WINAPI *)(HIMC, LPDWORD, LPDWORD)) GetProcAddress(mHImmDll, "ImmGetConversionStatus"); + mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD)) GetProcAddress(mHImmDll, "ImmSetConversionStatus"); + mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM)) GetProcAddress(mHImmDll, "ImmGetCompositionWindow"); + mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM)) GetProcAddress(mHImmDll, "ImmSetCompositionWindow"); + mImmGetCompositionString= (LONG (WINAPI *)(HIMC, DWORD, LPVOID, DWORD)) GetProcAddress(mHImmDll, "ImmGetCompositionStringW"); + mImmSetCompositionString= (BOOL (WINAPI *)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD)) GetProcAddress(mHImmDll, "ImmSetCompositionStringW"); + mImmSetCompositionFont = (BOOL (WINAPI *)(HIMC, LPLOGFONTW)) GetProcAddress(mHImmDll, "ImmSetCompositionFontW"); + mImmSetCandidateWindow = (BOOL (WINAPI *)(HIMC, LPCANDIDATEFORM)) GetProcAddress(mHImmDll, "ImmSetCandidateWindow"); + mImmNotifyIME = (BOOL (WINAPI *)(HIMC, DWORD, DWORD, DWORD)) GetProcAddress(mHImmDll, "ImmNotifyIME"); + + if (mImmIsIME == NULL || + mImmGetDefaultIMEWnd == NULL || + mImmGetContext == NULL || + mImmReleaseContext == NULL || + mImmGetOpenStatus == NULL || + mImmSetOpenStatus == NULL || + mImmGetConversionStatus == NULL || + mImmSetConversionStatus == NULL || + mImmGetCompostitionWindow == NULL || + mImmSetCompostitionWindow == NULL || + mImmGetCompositionString == NULL || + mImmSetCompositionString == NULL || + mImmSetCompositionFont == NULL || + mImmSetCandidateWindow == NULL || + mImmNotifyIME == NULL) + { + // If any of the above API entires are not found, we can't use IMM API. + // So, turn off the IMM support. We should log some warning message in + // the case, since it is very unusual; these APIs are available from + // the beginning, and all versions of IMM32.DLL should have them all. + // Unfortunately, this code may be executed before initialization of + // the logging channel (llwarns), and we can't do it here... Yes, this + // is one of disadvantages to use static constraction to DLL loading. + FreeLibrary(mHImmDll); + mHImmDll = NULL; + + // If we unload the library, make sure all the function pointers are cleared + mImmIsIME = NULL; + mImmGetDefaultIMEWnd = NULL; + mImmGetContext = NULL; + mImmReleaseContext = NULL; + mImmGetOpenStatus = NULL; + mImmSetOpenStatus = NULL; + mImmGetConversionStatus = NULL; + mImmSetConversionStatus = NULL; + mImmGetCompostitionWindow = NULL; + mImmSetCompostitionWindow = NULL; + mImmGetCompositionString = NULL; + mImmSetCompositionString = NULL; + mImmSetCompositionFont = NULL; + mImmSetCandidateWindow = NULL; + mImmNotifyIME = NULL; + } + } +} + + +// static +BOOL LLWinImm::isIME(HKL hkl) +{ + if ( sTheInstance.mImmIsIME ) + return sTheInstance.mImmIsIME(hkl); + return FALSE; +} + +// static +HIMC LLWinImm::getContext(HWND hwnd) +{ + if ( sTheInstance.mImmGetContext ) + return sTheInstance.mImmGetContext(hwnd); + return 0; +} + +//static +BOOL LLWinImm::releaseContext(HWND hwnd, HIMC himc) +{ + if ( sTheInstance.mImmIsIME ) + return sTheInstance.mImmReleaseContext(hwnd, himc); + return FALSE; +} + +// static +BOOL LLWinImm::getOpenStatus(HIMC himc) +{ + if ( sTheInstance.mImmGetOpenStatus ) + return sTheInstance.mImmGetOpenStatus(himc); + return FALSE; +} + +// static +BOOL LLWinImm::setOpenStatus(HIMC himc, BOOL status) +{ + if ( sTheInstance.mImmSetOpenStatus ) + return sTheInstance.mImmSetOpenStatus(himc, status); + return FALSE; +} + +// static +BOOL LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence) +{ + if ( sTheInstance.mImmGetConversionStatus ) + return sTheInstance.mImmGetConversionStatus(himc, conversion, sentence); + return FALSE; +} + +// static +BOOL LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence) +{ + if ( sTheInstance.mImmSetConversionStatus ) + return sTheInstance.mImmSetConversionStatus(himc, conversion, sentence); + return FALSE; +} + +// static +BOOL LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) +{ + if ( sTheInstance.mImmGetCompostitionWindow ) + return sTheInstance.mImmGetCompostitionWindow(himc, form); + return FALSE; +} + +// static +BOOL LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) +{ + if ( sTheInstance.mImmSetCompostitionWindow ) + return sTheInstance.mImmSetCompostitionWindow(himc, form); + return FALSE; +} + + +// static +LONG LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length) +{ + if ( sTheInstance.mImmGetCompositionString ) + return sTheInstance.mImmGetCompositionString(himc, index, data, length); + return FALSE; +} + + +// static +BOOL LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength) +{ + if ( sTheInstance.mImmSetCompositionString ) + return sTheInstance.mImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength); + return FALSE; +} + +// static +BOOL LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont) +{ + if ( sTheInstance.mImmSetCompositionFont ) + return sTheInstance.mImmSetCompositionFont(himc, pFont); + return FALSE; +} + +// static +BOOL LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form) +{ + if ( sTheInstance.mImmSetCandidateWindow ) + return sTheInstance.mImmSetCandidateWindow(himc, form); + return FALSE; +} + +// static +BOOL LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value) +{ + if ( sTheInstance.mImmNotifyIME ) + return sTheInstance.mImmNotifyIME(himc, action, index, value); + return FALSE; +} + + + + +// ---------------------------------------------------------------------------------------- +LLWinImm::~LLWinImm() +{ + if (mHImmDll != NULL) + { + FreeLibrary(mHImmDll); + mHImmDll = NULL; + } +} + + +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, + U32 fsaa_samples) + : LLWindow(callbacks, fullscreen, flags) +{ + mFSAASamples = fsaa_samples; + mIconResource = gIconResource; + mOverrideAspectRatio = 0.f; + mNativeAspectRatio = 0.f; + mMousePositionModified = FALSE; + mInputProcessingPaused = FALSE; + mPreeditor = NULL; + 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); + + WNDCLASS wc; + RECT window_rect; + + // Set the window title + if (title.empty()) + { + mWindowTitle = new WCHAR[50]; + wsprintf(mWindowTitle, L"OpenGL Window"); + } + else + { + mWindowTitle = new WCHAR[256]; // Assume title length < 255 chars. + mbstowcs(mWindowTitle, title.c_str(), 255); + mWindowTitle[255] = 0; + } + + // Set the window class name + if (name.empty()) + { + mWindowClassName = new WCHAR[50]; + wsprintf(mWindowClassName, L"OpenGL Window"); + } + else + { + mWindowClassName = new WCHAR[256]; // Assume title length < 255 chars. + mbstowcs(mWindowClassName, name.c_str(), 255); + mWindowClassName[255] = 0; + } + + + // We're not clipping yet + SetRect( &mOldMouseClip, 0, 0, 0, 0 ); + + // Make an instance of our window then define the window class + mhInstance = GetModuleHandle(NULL); + mWndProc = NULL; + + mSwapMethod = SWAP_METHOD_UNDEFINED; + + // No WPARAM yet. + mLastSizeWParam = 0; + + // Windows GDI rects don't include rightmost pixel + window_rect.left = (long) 0; + window_rect.right = (long) width; + window_rect.top = (long) 0; + window_rect.bottom = (long) height; + + // Grab screen size to sanitize the window + S32 window_border_y = GetSystemMetrics(SM_CYBORDER); + S32 virtual_screen_x = GetSystemMetrics(SM_XVIRTUALSCREEN); + S32 virtual_screen_y = GetSystemMetrics(SM_YVIRTUALSCREEN); + S32 virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); + S32 virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); + + if (x < virtual_screen_x) x = virtual_screen_x; + if (y < virtual_screen_y - window_border_y) y = virtual_screen_y - window_border_y; + + if (x + width > virtual_screen_x + virtual_screen_width) x = virtual_screen_x + virtual_screen_width - width; + if (y + height > virtual_screen_y + virtual_screen_height) y = virtual_screen_y + virtual_screen_height - height; + + if (!sIsClassRegistered) + { + // Force redraw when resized and create a private device context + + // Makes double click messages. + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; + + // Set message handler function + wc.lpfnWndProc = (WNDPROC) mainWindowProc; + + // unused + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + + wc.hInstance = mhInstance; + wc.hIcon = LoadIcon(mhInstance, mIconResource); + + // We will set the cursor ourselves + wc.hCursor = NULL; + + // background color is not used + if (clearBg) + { + wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); + } + else + { + wc.hbrBackground = (HBRUSH) NULL; + } + + // we don't use windows menus + wc.lpszMenuName = NULL; + + wc.lpszClassName = mWindowClassName; + + if (!RegisterClass(&wc)) + { + OSMessageBox(mCallbacks->translateString("MBRegClassFailed"), + mCallbacks->translateString("MBError"), OSMB_OK); + return; + } + sIsClassRegistered = TRUE; + } + + //----------------------------------------------------------------------- + // Get the current refresh rate + //----------------------------------------------------------------------- + + DEVMODE dev_mode; + DWORD current_refresh; + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) + { + current_refresh = dev_mode.dmDisplayFrequency; + mNativeAspectRatio = ((F32)dev_mode.dmPelsWidth) / ((F32)dev_mode.dmPelsHeight); + } + else + { + current_refresh = 60; + } + + //----------------------------------------------------------------------- + // Drop resolution and go fullscreen + // use a display mode with our desired size and depth, with a refresh + // rate as close at possible to the users' default + //----------------------------------------------------------------------- + if (mFullscreen) + { + BOOL success = FALSE; + DWORD closest_refresh = 0; + + for (S32 mode_num = 0;; mode_num++) + { + if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) + { + break; + } + + if (dev_mode.dmPelsWidth == width && + dev_mode.dmPelsHeight == height && + dev_mode.dmBitsPerPel == BITS_PER_PIXEL) + { + success = TRUE; + if ((dev_mode.dmDisplayFrequency - current_refresh) + < (closest_refresh - current_refresh)) + { + closest_refresh = dev_mode.dmDisplayFrequency; + } + } + } + + if (closest_refresh == 0) + { + LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; + success = FALSE; + } + + // If we found a good resolution, use it. + if (success) + { + success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); + } + + // Keep a copy of the actual current device mode in case we minimize + // and change the screen resolution. JC + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); + + // If it failed, we don't want to run fullscreen + if (success) + { + mFullscreen = TRUE; + mFullscreenWidth = dev_mode.dmPelsWidth; + mFullscreenHeight = dev_mode.dmPelsHeight; + mFullscreenBits = dev_mode.dmBitsPerPel; + mFullscreenRefresh = dev_mode.dmDisplayFrequency; + + LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth + << "x" << dev_mode.dmPelsHeight + << "x" << dev_mode.dmBitsPerPel + << " @ " << dev_mode.dmDisplayFrequency + << LL_ENDL; + } + else + { + mFullscreen = FALSE; + mFullscreenWidth = -1; + mFullscreenHeight = -1; + mFullscreenBits = -1; + mFullscreenRefresh = -1; + + std::map args; + args["[WIDTH]"] = llformat("%d", width); + args["[HEIGHT]"] = llformat ("%d", height); + OSMessageBox(mCallbacks->translateString("MBFullScreenErr", args), + mCallbacks->translateString("MBError"), OSMB_OK); + } + } + + // TODO: add this after resolving _WIN32_WINNT issue + // if (!fullscreen) + // { + // TRACKMOUSEEVENT track_mouse_event; + // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); + // track_mouse_event.dwFlags = TME_LEAVE; + // track_mouse_event.hwndTrack = mWindowHandle; + // track_mouse_event.dwHoverTime = HOVER_DEFAULT; + // TrackMouseEvent( &track_mouse_event ); + // } + + + //----------------------------------------------------------------------- + // Create GL drawing context + //----------------------------------------------------------------------- + LLCoordScreen windowPos(x,y); + LLCoordScreen windowSize(window_rect.right - window_rect.left, + window_rect.bottom - window_rect.top); + if (!switchContext(mFullscreen, windowSize, TRUE, &windowPos)) + { + return; + } + + //start with arrow cursor + initCursors(); + setCursor( UI_CURSOR_ARROW ); + + // Initialize (boot strap) the Language text input management, + // based on the system's (or user's) default settings. + allowLanguageTextInput(NULL, FALSE); +} + + +LLWindowWin32::~LLWindowWin32() +{ + delete mDragDrop; + + delete [] mWindowTitle; + mWindowTitle = NULL; + + delete [] mSupportedResolutions; + mSupportedResolutions = NULL; + + delete mWindowClassName; + mWindowClassName = NULL; +} + +void LLWindowWin32::show() +{ + ShowWindow(mWindowHandle, SW_SHOW); + SetForegroundWindow(mWindowHandle); + SetFocus(mWindowHandle); +} + +void LLWindowWin32::hide() +{ + setMouseClipping(FALSE); + ShowWindow(mWindowHandle, SW_HIDE); +} + +void LLWindowWin32::minimize() +{ + setMouseClipping(FALSE); + showCursor(); + ShowWindow(mWindowHandle, SW_MINIMIZE); +} + + +void LLWindowWin32::restore() +{ + ShowWindow(mWindowHandle, SW_RESTORE); + SetForegroundWindow(mWindowHandle); + SetFocus(mWindowHandle); +} + + +// close() destroys all OS-specific code associated with a window. +// Usually called from LLWindowManager::destroyWindow() +void LLWindowWin32::close() +{ + 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(); + + // Go back to screen mode written in the registry. + if (mFullscreen) + { + resetDisplayResolution(); + } + + // Clean up remaining GL state + LL_DEBUGS("Window") << "Shutting down GL" << LL_ENDL; + gGLManager.shutdownGL(); + + LL_DEBUGS("Window") << "Releasing Context" << LL_ENDL; + if (mhRC) + { + if (!wglMakeCurrent(NULL, NULL)) + { + LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; + } + + if (!wglDeleteContext(mhRC)) + { + LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; + } + + mhRC = NULL; + } + + // Restore gamma to the system values. + restoreGamma(); + + if (mhDC && !ReleaseDC(mWindowHandle, mhDC)) + { + LL_WARNS("Window") << "Release of ghDC failed" << LL_ENDL; + mhDC = NULL; + } + + LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; + + // Don't process events in our mainWindowProc any longer. + SetWindowLong(mWindowHandle, GWL_USERDATA, NULL); + + // Make sure we don't leave a blank toolbar button. + ShowWindow(mWindowHandle, SW_HIDE); + + // This causes WM_DESTROY to be sent *immediately* + if (!DestroyWindow(mWindowHandle)) + { + OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"), + mCallbacks->translateString("MBShutdownErr"), + OSMB_OK); + } + + mWindowHandle = NULL; +} + +BOOL LLWindowWin32::isValid() +{ + return (mWindowHandle != NULL); +} + +BOOL LLWindowWin32::getVisible() +{ + return (mWindowHandle && IsWindowVisible(mWindowHandle)); +} + +BOOL LLWindowWin32::getMinimized() +{ + return (mWindowHandle && IsIconic(mWindowHandle)); +} + +BOOL LLWindowWin32::getMaximized() +{ + return (mWindowHandle && IsZoomed(mWindowHandle)); +} + +BOOL LLWindowWin32::maximize() +{ + BOOL success = FALSE; + if (!mWindowHandle) return success; + + WINDOWPLACEMENT placement; + placement.length = sizeof(WINDOWPLACEMENT); + + success = GetWindowPlacement(mWindowHandle, &placement); + if (!success) return success; + + placement.showCmd = SW_MAXIMIZE; + + success = SetWindowPlacement(mWindowHandle, &placement); + return success; +} + +BOOL LLWindowWin32::getFullscreen() +{ + return mFullscreen; +} + +BOOL LLWindowWin32::getPosition(LLCoordScreen *position) +{ + RECT window_rect; + + if (!mWindowHandle || + !GetWindowRect(mWindowHandle, &window_rect) || + NULL == position) + { + return FALSE; + } + + position->mX = window_rect.left; + position->mY = window_rect.top; + return TRUE; +} + +BOOL LLWindowWin32::getSize(LLCoordScreen *size) +{ + RECT window_rect; + + if (!mWindowHandle || + !GetWindowRect(mWindowHandle, &window_rect) || + NULL == size) + { + return FALSE; + } + + size->mX = window_rect.right - window_rect.left; + size->mY = window_rect.bottom - window_rect.top; + return TRUE; +} + +BOOL LLWindowWin32::getSize(LLCoordWindow *size) +{ + RECT client_rect; + + if (!mWindowHandle || + !GetClientRect(mWindowHandle, &client_rect) || + NULL == size) + { + return FALSE; + } + + size->mX = client_rect.right - client_rect.left; + size->mY = client_rect.bottom - client_rect.top; + return TRUE; +} + +BOOL LLWindowWin32::setPosition(const LLCoordScreen position) +{ + LLCoordScreen size; + + if (!mWindowHandle) + { + return FALSE; + } + getSize(&size); + moveWindow(position, size); + return TRUE; +} + +BOOL LLWindowWin32::setSize(const LLCoordScreen size) +{ + LLCoordScreen position; + + getPosition(&position); + if (!mWindowHandle) + { + return FALSE; + } + + moveWindow(position, size); + return TRUE; +} + +// changing fullscreen resolution +BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp) +{ + GLuint pixel_format; + DEVMODE dev_mode; + DWORD current_refresh; + DWORD dw_ex_style; + DWORD dw_style; + RECT window_rect; + S32 width = size.mX; + S32 height = size.mY; + BOOL auto_show = FALSE; + + if (mhRC) + { + auto_show = TRUE; + resetDisplayResolution(); + } + + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) + { + current_refresh = dev_mode.dmDisplayFrequency; + } + else + { + current_refresh = 60; + } + + gGLManager.shutdownGL(); + //destroy gl context + if (mhRC) + { + if (!wglMakeCurrent(NULL, NULL)) + { + LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; + } + + if (!wglDeleteContext(mhRC)) + { + LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; + } + + mhRC = NULL; + } + + if (fullscreen) + { + mFullscreen = TRUE; + BOOL success = FALSE; + DWORD closest_refresh = 0; + + for (S32 mode_num = 0;; mode_num++) + { + if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) + { + break; + } + + if (dev_mode.dmPelsWidth == width && + dev_mode.dmPelsHeight == height && + dev_mode.dmBitsPerPel == BITS_PER_PIXEL) + { + success = TRUE; + if ((dev_mode.dmDisplayFrequency - current_refresh) + < (closest_refresh - current_refresh)) + { + closest_refresh = dev_mode.dmDisplayFrequency; + } + } + } + + if (closest_refresh == 0) + { + LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; + return FALSE; + } + + // If we found a good resolution, use it. + if (success) + { + success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); + } + + // Keep a copy of the actual current device mode in case we minimize + // and change the screen resolution. JC + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); + + if (success) + { + mFullscreen = TRUE; + mFullscreenWidth = dev_mode.dmPelsWidth; + mFullscreenHeight = dev_mode.dmPelsHeight; + mFullscreenBits = dev_mode.dmBitsPerPel; + mFullscreenRefresh = dev_mode.dmDisplayFrequency; + + LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth + << "x" << dev_mode.dmPelsHeight + << "x" << dev_mode.dmBitsPerPel + << " @ " << dev_mode.dmDisplayFrequency + << LL_ENDL; + + 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; + 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); + } + // If it failed, we don't want to run fullscreen + else + { + mFullscreen = FALSE; + mFullscreenWidth = -1; + mFullscreenHeight = -1; + mFullscreenBits = -1; + mFullscreenRefresh = -1; + + LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL; + return FALSE; + } + } + else + { + mFullscreen = FALSE; + 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; + } + + // don't post quit messages when destroying old windows + mPostQuit = FALSE; + + // create window + DestroyWindow(mWindowHandle); + mWindowHandle = CreateWindowEx(dw_ex_style, + mWindowClassName, + mWindowTitle, + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, + window_rect.left, // x pos + window_rect.top, // y pos + window_rect.right - window_rect.left, // width + window_rect.bottom - window_rect.top, // height + NULL, + NULL, + mhInstance, + NULL); + + //----------------------------------------------------------------------- + // Create GL drawing context + //----------------------------------------------------------------------- + static PIXELFORMATDESCRIPTOR pfd = + { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + 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(mCallbacks->translateString("MBDevContextErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + if (!(pixel_format = ChoosePixelFormat(mhDC, &pfd))) + { + close(); + OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + // Verify what pixel format we actually received. + if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), + &pfd)) + { + close(); + OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + if (pfd.cColorBits < 32) + { + close(); + OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"), + mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + if (pfd.cAlphaBits < 8) + { + close(); + OSMessageBox(mCallbacks->translateString("MBAlpha"), + mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + if (!SetPixelFormat(mhDC, pixel_format, &pfd)) + { + close(); + OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + if (!(mhRC = wglCreateContext(mhDC))) + { + close(); + OSMessageBox(mCallbacks->translateString("MBGLContextErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + if (!wglMakeCurrent(mhDC, mhRC)) + { + close(); + OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + gGLManager.initWGL(); + + if (wglChoosePixelFormatARB) + { + // 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++] = 24; + + attrib_list[cur_attrib++] = WGL_ALPHA_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_SAMPLES_ARB; + attrib_list[cur_attrib++] = mFSAASamples; + } + + // 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 FALSE; + } + + if (!num_formats) + { + 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) + { + 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) + { + close(); + 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; + } + } + } + + 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 + + } + ReleaseDC (mWindowHandle, mhDC); // Release The Device Context + mhDC = 0; // Zero The Device Context + } + DestroyWindow (mWindowHandle); // Destroy The Window + + + mWindowHandle = CreateWindowEx(dw_ex_style, + mWindowClassName, + mWindowTitle, + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, + window_rect.left, // x pos + window_rect.top, // 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(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + if (!SetPixelFormat(mhDC, pixel_format, &pfd)) + { + close(); + OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) + { + switch (swap_method) + { + case WGL_SWAP_EXCHANGE_ARB: + mSwapMethod = SWAP_METHOD_EXCHANGE; + LL_DEBUGS("Window") << "Swap Method: Exchange" << LL_ENDL; + break; + case WGL_SWAP_COPY_ARB: + mSwapMethod = SWAP_METHOD_COPY; + LL_DEBUGS("Window") << "Swap Method: Copy" << LL_ENDL; + break; + case WGL_SWAP_UNDEFINED_ARB: + mSwapMethod = SWAP_METHOD_UNDEFINED; + LL_DEBUGS("Window") << "Swap Method: Undefined" << LL_ENDL; + break; + default: + mSwapMethod = SWAP_METHOD_UNDEFINED; + LL_DEBUGS("Window") << "Swap Method: Unknown" << LL_ENDL; + break; + } + } + } + else + { + LL_WARNS("Window") << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << LL_ENDL; + } + + // Verify what pixel format we actually received. + if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), + &pfd)) + { + close(); + OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + LL_INFOS("Window") << "GL buffer: Color Bits " << S32(pfd.cColorBits) + << " Alpha Bits " << S32(pfd.cAlphaBits) + << " Depth Bits " << S32(pfd.cDepthBits) + << LL_ENDL; + + // make sure we have 32 bits per pixel + if (pfd.cColorBits < 32 || GetDeviceCaps(mhDC, BITSPIXEL) < 32) + { + close(); + OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"), mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + if (pfd.cAlphaBits < 8) + { + close(); + OSMessageBox(mCallbacks->translateString("MBAlpha"), mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + if (!(mhRC = wglCreateContext(mhDC))) + { + close(); + OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + if (!wglMakeCurrent(mhDC, mhRC)) + { + close(); + OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + if (!gGLManager.initGL()) + { + close(); + OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + // Disable vertical sync for swap + if (disable_vsync && wglSwapIntervalEXT) + { + LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL; + wglSwapIntervalEXT(0); + } + else + { + LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL; + } + + SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this); + + // 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; +} + +void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size ) +{ + if( mIsMouseClipping ) + { + RECT client_rect_in_screen_space; + if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) + { + ClipCursor( &client_rect_in_screen_space ); + } + } + + // 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). + + // 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); +} + +BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position) +{ + LLCoordScreen screen_pos; + + mMousePositionModified = TRUE; + if (!mWindowHandle) + { + return FALSE; + } + + if (!convertCoords(position, &screen_pos)) + { + 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); +} + +BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position) +{ + POINT cursor_point; + LLCoordScreen screen_pos; + + if (!mWindowHandle || + !GetCursorPos(&cursor_point)) + { + return FALSE; + } + + screen_pos.mX = cursor_point.x; + screen_pos.mY = cursor_point.y; + + return convertCoords(screen_pos, position); +} + +void LLWindowWin32::hideCursor() +{ + while (ShowCursor(FALSE) >= 0) + { + // nothing, wait for cursor to push down + } + mCursorHidden = TRUE; + mHideCursorPermanent = TRUE; +} + +void LLWindowWin32::showCursor() +{ + // makes sure the cursor shows up + while (ShowCursor(TRUE) < 0) + { + // do nothing, wait for cursor to pop out + } + mCursorHidden = FALSE; + mHideCursorPermanent = FALSE; +} + +void LLWindowWin32::showCursorFromMouseMove() +{ + if (!mHideCursorPermanent) + { + showCursor(); + } +} + +void LLWindowWin32::hideCursorUntilMouseMove() +{ + if (!mHideCursorPermanent) + { + hideCursor(); + mHideCursorPermanent = FALSE; + } +} + +BOOL LLWindowWin32::isCursorHidden() +{ + return mCursorHidden; +} + + +HCURSOR LLWindowWin32::loadColorCursor(LPCTSTR name) +{ + return (HCURSOR)LoadImage(mhInstance, + name, + IMAGE_CURSOR, + 0, // default width + 0, // default height + LR_DEFAULTCOLOR); +} + + +void LLWindowWin32::initCursors() +{ + mCursor[ UI_CURSOR_ARROW ] = LoadCursor(NULL, IDC_ARROW); + mCursor[ UI_CURSOR_WAIT ] = LoadCursor(NULL, IDC_WAIT); + mCursor[ UI_CURSOR_HAND ] = LoadCursor(NULL, IDC_HAND); + mCursor[ UI_CURSOR_IBEAM ] = LoadCursor(NULL, IDC_IBEAM); + mCursor[ UI_CURSOR_CROSS ] = LoadCursor(NULL, IDC_CROSS); + mCursor[ UI_CURSOR_SIZENWSE ] = LoadCursor(NULL, IDC_SIZENWSE); + mCursor[ UI_CURSOR_SIZENESW ] = LoadCursor(NULL, IDC_SIZENESW); + mCursor[ UI_CURSOR_SIZEWE ] = LoadCursor(NULL, IDC_SIZEWE); + mCursor[ UI_CURSOR_SIZENS ] = LoadCursor(NULL, IDC_SIZENS); + mCursor[ UI_CURSOR_NO ] = LoadCursor(NULL, IDC_NO); + mCursor[ UI_CURSOR_WORKING ] = LoadCursor(NULL, IDC_APPSTARTING); + + HMODULE module = GetModuleHandle(NULL); + mCursor[ UI_CURSOR_TOOLGRAB ] = LoadCursor(module, TEXT("TOOLGRAB")); + mCursor[ UI_CURSOR_TOOLLAND ] = LoadCursor(module, TEXT("TOOLLAND")); + mCursor[ UI_CURSOR_TOOLFOCUS ] = LoadCursor(module, TEXT("TOOLFOCUS")); + mCursor[ UI_CURSOR_TOOLCREATE ] = LoadCursor(module, TEXT("TOOLCREATE")); + mCursor[ UI_CURSOR_ARROWDRAG ] = LoadCursor(module, TEXT("ARROWDRAG")); + mCursor[ UI_CURSOR_ARROWCOPY ] = LoadCursor(module, TEXT("ARROWCOPY")); + mCursor[ UI_CURSOR_ARROWDRAGMULTI ] = LoadCursor(module, TEXT("ARROWDRAGMULTI")); + mCursor[ UI_CURSOR_ARROWCOPYMULTI ] = LoadCursor(module, TEXT("ARROWCOPYMULTI")); + mCursor[ UI_CURSOR_NOLOCKED ] = LoadCursor(module, TEXT("NOLOCKED")); + mCursor[ UI_CURSOR_ARROWLOCKED ]= LoadCursor(module, TEXT("ARROWLOCKED")); + mCursor[ UI_CURSOR_GRABLOCKED ] = LoadCursor(module, TEXT("GRABLOCKED")); + mCursor[ UI_CURSOR_TOOLTRANSLATE ] = LoadCursor(module, TEXT("TOOLTRANSLATE")); + mCursor[ UI_CURSOR_TOOLROTATE ] = LoadCursor(module, TEXT("TOOLROTATE")); + mCursor[ UI_CURSOR_TOOLSCALE ] = LoadCursor(module, TEXT("TOOLSCALE")); + mCursor[ UI_CURSOR_TOOLCAMERA ] = LoadCursor(module, TEXT("TOOLCAMERA")); + mCursor[ UI_CURSOR_TOOLPAN ] = LoadCursor(module, TEXT("TOOLPAN")); + mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN")); + mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3")); + mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE")); + + // Color cursors + 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++ ) + { + if( !mCursor[i] ) + { + mCursor[i] = LoadCursor(NULL, IDC_ARROW); + } + } +} + + + +void LLWindowWin32::setCursor(ECursorType cursor) +{ + if (cursor == UI_CURSOR_ARROW + && mBusyCount > 0) + { + cursor = UI_CURSOR_WORKING; + } + + if( mCurrentCursor != cursor ) + { + mCurrentCursor = cursor; + SetCursor( mCursor[cursor] ); + } +} + +ECursorType LLWindowWin32::getCursor() const +{ + return mCurrentCursor; +} + +void LLWindowWin32::captureMouse() +{ + SetCapture(mWindowHandle); +} + +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); +} + + +void LLWindowWin32::delayInputProcessing() +{ + mInputProcessingPaused = TRUE; +} + +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 ) + { + break; + } + /* Attempted workaround for problem where typing fast and hitting + return would result in only part of the text being sent. JC + + BOOL key_posted = TranslateMessage(&msg); + DispatchMessage(&msg); + msg_count++; + + // If a key was translated, a WM_CHAR might have been posted to the end + // of the event queue. We need it immediately. + if (key_posted && msg.message == WM_KEYDOWN) + { + if (PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + msg_count++; + } + } + */ + mCallbacks->handlePingWatchdog(this, "Main:AsyncCallbackGatherInput"); + // For async host by name support. Really hacky. + if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message)) + { + gAsyncMsgCallback(msg); + } + } + + mInputProcessingPaused = FALSE; + + // clear this once we've processed all mouse messages that might have occurred after + // we slammed the mouse position + 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) + { + if (!window_imp->mWndProc(h_wnd, u_msg, w_param, l_param)) + { + // user has handled window message + return 0; + } + } + + 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)); + + // This doesn't work, as LOWORD returns unsigned short. + //LLCoordWindow window_coord(LOWORD(l_param), HIWORD(l_param)); + LLCoordGL gl_coord; + + // pass along extended flag in mask + MASK mask = (l_param>>16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0; + BOOL eat_keystroke = TRUE; + + switch(u_msg) + { + RECT update_rect; + S32 update_width; + S32 update_height; + + case WM_TIMER: + 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; + window_imp->mCallbacks->handlePaint(window_imp, update_rect.left, update_rect.top, + update_width, update_height); + break; + case WM_PARENTNOTIFY: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PARENTNOTIFY"); + u_msg = u_msg; + break; + + case WM_SETCURSOR: + // This message is sent whenever the cursor is moved in a window. + // You need to set the appropriate cursor appearance. + + // 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] ); + return 0; + } + 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; + BOOL minimized = window_imp->getMinimized(); + + if (gDebugWindowProc) + { + LL_INFOS("Window") << "WINDOWPROC ActivateApp " + << " activating " << S32(activating) + << " minimized " << S32(minimized) + << " fullscreen " << S32(window_imp->mFullscreen) + << LL_ENDL; + } + + if (window_imp->mFullscreen) + { + // When we run fullscreen, restoring or minimizing the app needs + // to switch the screen resolution + if (activating) + { + window_imp->setFullscreenResolution(); + window_imp->restore(); + } + else + { + window_imp->minimize(); + 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); + + BOOL minimized = BOOL(HIWORD(w_param)); + + if (!activating && LLWinImm::isAvailable() && window_imp->mPreeditor) + { + window_imp->interruptLanguageTextInput(); + } + + // JC - I'm not sure why, but if we don't report that we handled the + // WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work + // properly when we run fullscreen. + if (gDebugWindowProc) + { + LL_INFOS("Window") << "WINDOWPROC Activate " + << " activating " << S32(activating) + << " minimized " << S32(minimized) + << LL_ENDL; + } + + // Don't handle this. + break; + } + + case WM_QUERYOPEN: + // TODO: use this to return a nice icon + break; + + case WM_SYSCOMMAND: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSCOMMAND"); + switch(w_param) + { + case SC_KEYMENU: + // Disallow the ALT key from triggering the default system menu. + return 0; + + case SC_SCREENSAVE: + case SC_MONITORPOWER: + // eat screen save messages and prevent them! + return 0; + } + 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)) + { + // Get the app to initiate cleanup. + window_imp->mCallbacks->handleQuit(window_imp); + // The app is responsible for calling destroyWindow when done with GL + } + 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 + } + 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)); + } + 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->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYDOWN"); + { + if (gDebugWindowProc) + { + LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN " + << " key " << S32(w_param) + << LL_ENDL; + } + if(gKeyboard->handleKeyDown(w_param, mask) && eat_keystroke) + { + return 0; + } + // pass on to windows if we didn't handle it + break; + } + case WM_SYSKEYUP: + eat_keystroke = FALSE; + case WM_KEYUP: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP"); + LLFastTimer t2(FTM_KEYHANDLER); + + if (gDebugWindowProc) + { + LL_INFOS("Window") << "Debug WindowProc WM_KEYUP " + << " key " << S32(w_param) + << LL_ENDL; + } + if (gKeyboard->handleKeyUp(w_param, mask) && eat_keystroke) + { + return 0; + } + + // pass on to windows + 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; + // Invoke DefWinProc with the modified LPARAM. + } + 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(); + return 0; + } + 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; + } + 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); + return 0; + } + 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; + if (window_imp->handleImeRequests(w_param, l_param, &result)) + { + return result; + } + } + break; + + case WM_CHAR: + // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need + // to figure out how that works. - Doug + // + // ... Well, I don't think so. + // How it works is explained in Win32 API document, but WM_UNICHAR didn't work + // as specified at least on Windows XP SP1 Japanese version. I have never used + // it since then, and I'm not sure whether it has been fixed now, but I don't think + // 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 + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CHAR"); + if (gDebugWindowProc) + { + LL_INFOS("Window") << "Debug WindowProc WM_CHAR " + << " key " << S32(w_param) + << 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... + window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE)); + return 0; + + case WM_LBUTTONDOWN: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDOWN"); + LLFastTimer t2(FTM_MOUSEHANDLER); + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + window_imp->interruptLanguageTextInput(); + } + + // 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 + // first click changes the cursor position, all subsequent clicks + // will occur at the wrong location. JC + LLCoordWindow cursor_coord_window; + if (window_imp->mMousePositionModified) + { + window_imp->getCursorPosition(&cursor_coord_window); + window_imp->convertCoords(cursor_coord_window, &gl_coord); + } + else + { + 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; + } + } + break; + + case WM_LBUTTONDBLCLK: + //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 + // first click changes the cursor position, all subsequent clicks + // will occur at the wrong location. JC + LLCoordWindow cursor_coord_window; + if (window_imp->mMousePositionModified) + { + window_imp->getCursorPosition(&cursor_coord_window); + window_imp->convertCoords(cursor_coord_window, &gl_coord); + } + else + { + 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; + } + } + break; + + case WM_LBUTTONUP: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONUP"); + LLFastTimer t2(FTM_MOUSEHANDLER); + //if (gDebugClicks) + //{ + // 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. + // If we don't do this, many clicks could get buffered up, and if the + // first click changes the cursor position, all subsequent clicks + // will occur at the wrong location. JC + LLCoordWindow cursor_coord_window; + if (window_imp->mMousePositionModified) + { + window_imp->getCursorPosition(&cursor_coord_window); + window_imp->convertCoords(cursor_coord_window, &gl_coord); + } + else + { + 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; + } + } + break; + + case WM_RBUTTONDBLCLK: + case WM_RBUTTONDOWN: + { + 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 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 + // will occur at the wrong location. JC + LLCoordWindow cursor_coord_window; + if (window_imp->mMousePositionModified) + { + window_imp->getCursorPosition(&cursor_coord_window); + window_imp->convertCoords(cursor_coord_window, &gl_coord); + } + else + { + 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; + } + } + break; + + case WM_RBUTTONUP: + { + 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 + // first click changes the cursor position, all subsequent clicks + // will occur at the wrong location. JC + LLCoordWindow cursor_coord_window; + if (window_imp->mMousePositionModified) + { + window_imp->getCursorPosition(&cursor_coord_window); + window_imp->convertCoords(cursor_coord_window, &gl_coord); + } + else + { + 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; + } + } + break; + + case WM_MBUTTONDOWN: +// case WM_MBUTTONDBLCLK: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONDOWN"); + 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 + // 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 + // will occur at the wrong location. JC + LLCoordWindow cursor_coord_window; + if (window_imp->mMousePositionModified) + { + window_imp->getCursorPosition(&cursor_coord_window); + window_imp->convertCoords(cursor_coord_window, &gl_coord); + } + else + { + 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; + } + } + break; + + case WM_MBUTTONUP: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONUP"); + LLFastTimer t2(FTM_MOUSEHANDLER); + // Because we move the cursor position in tllviewerhe 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 + // will occur at the wrong location. JC + LLCoordWindow cursor_coord_window; + if (window_imp->mMousePositionModified) + { + window_imp->getCursorPosition(&cursor_coord_window); + window_imp->convertCoords(cursor_coord_window, &gl_coord); + } + else + { + 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; + } + } + break; + + case WM_MOUSEWHEEL: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEWHEEL"); + static short z_delta = 0; + + z_delta += HIWORD(w_param); + // cout << "z_delta " << z_delta << endl; + + // current mouse wheels report changes in increments of zDelta (+120, -120) + // Future, higher resolution mouse wheels may report smaller deltas. + // So we sum the deltas and only act when we've exceeded WHEEL_DELTA + // + // If the user rapidly spins the wheel, we can get messages with + // large deltas, like 480 or so. Thus we need to scroll more quickly. + if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta) + { + window_imp->mCallbacks->handleScrollWheel(window_imp, -z_delta / WHEEL_DELTA); + z_delta = 0; + } + return 0; + } + /* + // TODO: add this after resolving _WIN32_WINNT issue + case WM_MOUSELEAVE: + { + window_imp->mCallbacks->handleMouseLeave(window_imp); + + // TRACKMOUSEEVENT track_mouse_event; + // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); + // track_mouse_event.dwFlags = TME_LEAVE; + // track_mouse_event.hwndTrack = h_wnd; + // track_mouse_event.dwHoverTime = HOVER_DEFAULT; + // TrackMouseEvent( &track_mouse_event ); + return 0; + } + */ + // 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); + return 0; + } + + case WM_SIZE: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SIZE"); + S32 width = S32( LOWORD(l_param) ); + S32 height = S32( HIWORD(l_param) ); + + if (gDebugWindowProc) + { + BOOL maximized = ( w_param == SIZE_MAXIMIZED ); + BOOL restored = ( w_param == SIZE_RESTORED ); + BOOL minimized = ( w_param == SIZE_MINIMIZED ); + + LL_INFOS("Window") << "WINDOWPROC Size " + << width << "x" << height + << " max " << S32(maximized) + << " min " << S32(minimized) + << " rest " << S32(restored) + << LL_ENDL; + } + + // There's an odd behavior with WM_SIZE that I would call a bug. If + // the window is maximized, and you call MoveWindow() with a size smaller + // than a maximized window, it ends up sending WM_SIZE with w_param set + // to SIZE_MAXIMIZED -- which isn't true. So the logic below doesn't work. + // (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see + // LLWindowWin32::moveWindow in this file). + + // If we are now restored, but we weren't before, this + // means that the window was un-minimized. + if (w_param == SIZE_RESTORED && window_imp->mLastSizeWParam != SIZE_RESTORED) + { + window_imp->mCallbacks->handleActivate(window_imp, TRUE); + } + + // handle case of window being maximized from fully minimized state + if (w_param == SIZE_MAXIMIZED && window_imp->mLastSizeWParam != SIZE_MAXIMIZED) + { + window_imp->mCallbacks->handleActivate(window_imp, TRUE); + } + + // Also handle the minimization case + if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED) + { + window_imp->mCallbacks->handleActivate(window_imp, FALSE); + } + + // Actually resize all of our views + if (w_param != SIZE_MINIMIZED) + { + // Ignore updates for minimizing and minimized "windows" + window_imp->mCallbacks->handleResize( window_imp, + LOWORD(l_param), + HIWORD(l_param) ); + } + + window_imp->mLastSizeWParam = w_param; + + return 0; + } + + case WM_SETFOCUS: + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETFOCUS"); + if (gDebugWindowProc) + { + 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) + { + LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL; + } + window_imp->mCallbacks->handleFocusLost(window_imp); + return 0; + + case WM_COPYDATA: + { + 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; + + case WM_DROPFILES: + { + // HDROP contains what we need + HDROP hdrop = (HDROP)w_param; + + // get location in window space where drop occured and convert to OpenGL coordinate space + POINT pt; + DragQueryPoint( hdrop, &pt ); + LLCoordGL gl_coord; + LLCoordWindow cursor_coord_window( pt.x, pt.y ); + window_imp->convertCoords(cursor_coord_window, &gl_coord); + + // get payload (eventually, this needs to more advanced and grab size of payload dynamically + static char file_name[ 1024 ]; DragQueryFileA( hdrop, 0, file_name, 1024 ); - void* url = (void*)( file_name ); + void* url = (void*)( file_name ); // if it's a .URL or .lnk ("shortcut") file if ( std::string( file_name ).find( ".lnk" ) != std::string::npos || @@ -2390,1316 +2400,1329 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ }; MASK mask = gKeyboard->currentMask(TRUE); - if (window_imp->mCallbacks->handleDrop(window_imp, gl_coord, mask, url ) ) - { - 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); -} - -BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to) -{ - S32 client_height; - RECT client_rect; - LLCoordWindow window_position; - - if (!mWindowHandle || - !GetClientRect(mWindowHandle, &client_rect) || - NULL == to) - { - return FALSE; - } - - to->mX = from.mX; - client_height = client_rect.bottom - client_rect.top; - to->mY = client_height - from.mY - 1; - - return TRUE; -} - -BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordGL* to) -{ - S32 client_height; - RECT client_rect; - - if (!mWindowHandle || - !GetClientRect(mWindowHandle, &client_rect) || - NULL == to) - { - return FALSE; - } - - to->mX = from.mX; - client_height = client_rect.bottom - client_rect.top; - to->mY = client_height - from.mY - 1; - - return TRUE; -} - -BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordWindow* to) -{ - POINT mouse_point; - - mouse_point.x = from.mX; - mouse_point.y = from.mY; - BOOL result = ScreenToClient(mWindowHandle, &mouse_point); - - if (result) - { - to->mX = mouse_point.x; - to->mY = mouse_point.y; - } - - return result; -} - -BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordScreen *to) -{ - POINT mouse_point; - - mouse_point.x = from.mX; - mouse_point.y = from.mY; - BOOL result = ClientToScreen(mWindowHandle, &mouse_point); - - if (result) - { - to->mX = mouse_point.x; - to->mY = mouse_point.y; - } - - return result; -} - -BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordGL *to) -{ - LLCoordWindow window_coord; - - if (!mWindowHandle || (NULL == to)) - { - return FALSE; - } - - convertCoords(from, &window_coord); - convertCoords(window_coord, to); - return TRUE; -} - -BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordScreen *to) -{ - LLCoordWindow window_coord; - - if (!mWindowHandle || (NULL == to)) - { - return FALSE; - } - - convertCoords(from, &window_coord); - convertCoords(window_coord, to); - return TRUE; -} - - -BOOL LLWindowWin32::isClipboardTextAvailable() -{ - return IsClipboardFormatAvailable(CF_UNICODETEXT); -} - - -BOOL LLWindowWin32::pasteTextFromClipboard(LLWString &dst) -{ - BOOL success = FALSE; - - if (IsClipboardFormatAvailable(CF_UNICODETEXT)) - { - if (OpenClipboard(mWindowHandle)) - { - HGLOBAL h_data = GetClipboardData(CF_UNICODETEXT); - if (h_data) - { - WCHAR *utf16str = (WCHAR*) GlobalLock(h_data); - if (utf16str) - { - dst = utf16str_to_wstring(utf16str); - LLWStringUtil::removeCRLF(dst); - GlobalUnlock(h_data); - success = TRUE; - } - } - CloseClipboard(); - } - } - - return success; -} - - -BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr) -{ - BOOL success = FALSE; - - if (OpenClipboard(mWindowHandle)) - { - EmptyClipboard(); - - // Provide a copy of the data in Unicode format. - LLWString sanitized_string(wstr); - LLWStringUtil::addCRLF(sanitized_string); - llutf16string out_utf16 = wstring_to_utf16str(sanitized_string); - const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(WCHAR); - - // Memory is allocated and then ownership of it is transfered to the system. - HGLOBAL hglobal_copy_utf16 = GlobalAlloc(GMEM_MOVEABLE, size_utf16); - if (hglobal_copy_utf16) - { - WCHAR* copy_utf16 = (WCHAR*) GlobalLock(hglobal_copy_utf16); - if (copy_utf16) - { - memcpy(copy_utf16, out_utf16.c_str(), size_utf16); /* Flawfinder: ignore */ - GlobalUnlock(hglobal_copy_utf16); - - if (SetClipboardData(CF_UNICODETEXT, hglobal_copy_utf16)) - { - success = TRUE; - } - } - } - - CloseClipboard(); - } - - return success; -} - -// Constrains the mouse to the window. -void LLWindowWin32::setMouseClipping( BOOL b ) -{ - if( b != mIsMouseClipping ) - { - BOOL success = FALSE; - - if( b ) - { - GetClipCursor( &mOldMouseClip ); - - RECT client_rect_in_screen_space; - if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) - { - success = ClipCursor( &client_rect_in_screen_space ); - } - } - else - { - // Must restore the old mouse clip, which may be set by another window. - success = ClipCursor( &mOldMouseClip ); - SetRect( &mOldMouseClip, 0, 0, 0, 0 ); - } - - if( success ) - { - mIsMouseClipping = b; - } - } -} - -BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp ) -{ - BOOL success = FALSE; - - RECT client_rect; - if( mWindowHandle && GetClientRect(mWindowHandle, &client_rect) ) - { - POINT top_left; - top_left.x = client_rect.left; - top_left.y = client_rect.top; - ClientToScreen(mWindowHandle, &top_left); - - POINT bottom_right; - bottom_right.x = client_rect.right; - bottom_right.y = client_rect.bottom; - ClientToScreen(mWindowHandle, &bottom_right); - - SetRect( rectp, - top_left.x, - top_left.y, - bottom_right.x, - bottom_right.y ); - - success = TRUE; - } - - return success; -} - -void LLWindowWin32::flashIcon(F32 seconds) -{ - FLASHWINFO flash_info; - - flash_info.cbSize = sizeof(FLASHWINFO); - flash_info.hwnd = mWindowHandle; - flash_info.dwFlags = FLASHW_TRAY; - flash_info.uCount = UINT(seconds / ICON_FLASH_TIME); - flash_info.dwTimeout = DWORD(1000.f * ICON_FLASH_TIME); // milliseconds - FlashWindowEx(&flash_info); -} - -F32 LLWindowWin32::getGamma() -{ - return mCurrentGamma; -} - -BOOL LLWindowWin32::restoreGamma() -{ - return SetDeviceGammaRamp(mhDC, mPrevGammaRamp); -} - -BOOL LLWindowWin32::setGamma(const F32 gamma) -{ - mCurrentGamma = gamma; - - LL_DEBUGS("Window") << "Setting gamma to " << gamma << LL_ENDL; - - for ( int i = 0; i < 256; ++i ) - { - int mult = 256 - ( int ) ( ( gamma - 1.0f ) * 128.0f ); - - int value = mult * i; - - if ( value > 0xffff ) - value = 0xffff; - - mCurrentGammaRamp [ 0 * 256 + i ] = - mCurrentGammaRamp [ 1 * 256 + i ] = - mCurrentGammaRamp [ 2 * 256 + i ] = ( WORD )value; - }; - - 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) - { - mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; - DEVMODE dev_mode; - - mNumSupportedResolutions = 0; - for (S32 mode_num = 0; mNumSupportedResolutions < MAX_NUM_RESOLUTIONS; mode_num++) - { - if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) - { - break; - } - - if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL && - dev_mode.dmPelsWidth >= 800 && - dev_mode.dmPelsHeight >= 600) - { - BOOL resolution_exists = FALSE; - for(S32 i = 0; i < mNumSupportedResolutions; i++) - { - if (mSupportedResolutions[i].mWidth == dev_mode.dmPelsWidth && - mSupportedResolutions[i].mHeight == dev_mode.dmPelsHeight) - { - resolution_exists = TRUE; - } - } - if (!resolution_exists) - { - mSupportedResolutions[mNumSupportedResolutions].mWidth = dev_mode.dmPelsWidth; - mSupportedResolutions[mNumSupportedResolutions].mHeight = dev_mode.dmPelsHeight; - mNumSupportedResolutions++; - } - } - } - } - - num_resolutions = mNumSupportedResolutions; - return mSupportedResolutions; -} - - -F32 LLWindowWin32::getNativeAspectRatio() -{ - if (mOverrideAspectRatio > 0.f) - { - return mOverrideAspectRatio; - } - else if (mNativeAspectRatio > 0.f) - { - // we grabbed this value at startup, based on the user's desktop settings - return mNativeAspectRatio; - } - // RN: this hack presumes that the largest supported resolution is monitor-limited - // and that pixels in that mode are square, therefore defining the native aspect ratio - // of the monitor...this seems to work to a close approximation for most CRTs/LCDs - S32 num_resolutions; - LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); - - return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); -} - -F32 LLWindowWin32::getPixelAspectRatio() -{ - F32 pixel_aspect = 1.f; - if (getFullscreen()) - { - LLCoordScreen screen_size; - getSize(&screen_size); - pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; - } - - return pixel_aspect; -} - -// Change display resolution. Returns true if successful. -// protected -BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh) -{ - DEVMODE dev_mode; - dev_mode.dmSize = sizeof(dev_mode); - BOOL success = FALSE; - - // Don't change anything if we don't have to - if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) - { - if (dev_mode.dmPelsWidth == width && - dev_mode.dmPelsHeight == height && - dev_mode.dmBitsPerPel == bits && - dev_mode.dmDisplayFrequency == refresh ) - { - // ...display mode identical, do nothing - return TRUE; - } - } - - memset(&dev_mode, 0, sizeof(dev_mode)); - dev_mode.dmSize = sizeof(dev_mode); - dev_mode.dmPelsWidth = width; - dev_mode.dmPelsHeight = height; - dev_mode.dmBitsPerPel = bits; - dev_mode.dmDisplayFrequency = refresh; - dev_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; - - // CDS_FULLSCREEN indicates that this is a temporary change to the device mode. - LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN); - - success = (DISP_CHANGE_SUCCESSFUL == cds_result); - - if (!success) - { - LL_WARNS("Window") << "setDisplayResolution failed, " - << width << "x" << height << "x" << bits << " @ " << refresh << LL_ENDL; - } - - return success; -} - -// protected -BOOL LLWindowWin32::setFullscreenResolution() -{ - if (mFullscreen) - { - return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh); - } - else - { - return FALSE; - } -} - -// protected -BOOL LLWindowWin32::resetDisplayResolution() -{ - LL_DEBUGS("Window") << "resetDisplayResolution START" << LL_ENDL; - - LONG cds_result = ChangeDisplaySettings(NULL, 0); - - BOOL success = (DISP_CHANGE_SUCCESSFUL == cds_result); - - if (!success) - { - LL_WARNS("Window") << "resetDisplayResolution failed" << LL_ENDL; - } - - LL_DEBUGS("Window") << "resetDisplayResolution END" << LL_ENDL; - - return success; -} - -void LLWindowWin32::swapBuffers() -{ - SwapBuffers(mhDC); -} - - -// -// LLSplashScreenImp -// -LLSplashScreenWin32::LLSplashScreenWin32() -: mWindow(NULL) -{ -} - -LLSplashScreenWin32::~LLSplashScreenWin32() -{ -} - -void LLSplashScreenWin32::showImpl() -{ - // This appears to work. ??? - HINSTANCE hinst = GetModuleHandle(NULL); - - mWindow = CreateDialog(hinst, - TEXT("SPLASHSCREEN"), - NULL, // no parent - (DLGPROC) LLSplashScreenWin32::windowProc); - ShowWindow(mWindow, SW_SHOW); -} - - -void LLSplashScreenWin32::updateImpl(const std::string& mesg) -{ - if (!mWindow) return; - - WCHAR w_mesg[1024]; - mbstowcs(w_mesg, mesg.c_str(), 1024); - - SendDlgItemMessage(mWindow, - 666, // HACK: text id - WM_SETTEXT, - FALSE, - (LPARAM)w_mesg); -} - - -void LLSplashScreenWin32::hideImpl() -{ - if (mWindow) - { - DestroyWindow(mWindow); - mWindow = NULL; - } -} - - -// static -LRESULT CALLBACK LLSplashScreenWin32::windowProc(HWND h_wnd, UINT u_msg, - WPARAM w_param, LPARAM l_param) -{ - // Just give it to windows - return DefWindowProc(h_wnd, u_msg, w_param, l_param); -} - -// -// Helper Funcs -// - -S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type) -{ - UINT uType; - - switch(type) - { - case OSMB_OK: - uType = MB_OK; - break; - case OSMB_OKCANCEL: - uType = MB_OKCANCEL; - break; - case OSMB_YESNO: - uType = MB_YESNO; - break; - default: - uType = MB_OK; - break; - } - - // HACK! Doesn't properly handle wide strings! - int retval_win = MessageBoxA(NULL, text.c_str(), caption.c_str(), uType); - S32 retval; - - switch(retval_win) - { - case IDYES: - retval = OSBTN_YES; - break; - case IDNO: - retval = OSBTN_NO; - break; - case IDOK: - retval = OSBTN_OK; - break; - case IDCANCEL: - retval = OSBTN_CANCEL; - break; - default: - retval = OSBTN_CANCEL; - break; - } - - return retval; -} - - -void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url ) -{ - bool found = false; - S32 i; - for (i = 0; i < gURLProtocolWhitelistCount; i++) - { - if (escaped_url.find(gURLProtocolWhitelist[i]) == 0) - { - found = true; - break; - } - } - - if (!found) - { - LL_WARNS("Window") << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; - return; - } - - LL_INFOS("Window") << "Opening URL " << escaped_url << LL_ENDL; - - // replaced ShellExecute code with ShellExecuteEx since ShellExecute doesn't work - // reliablly on Vista. - - // this is madness.. no, this is.. - LLWString url_wstring = utf8str_to_wstring( escaped_url ); - llutf16string url_utf16 = wstring_to_utf16str( url_wstring ); - - // let the OS decide what to use to open the URL - SHELLEXECUTEINFO sei = { sizeof( sei ) }; - sei.fMask = SEE_MASK_FLAG_DDEWAIT; - sei.nShow = SW_SHOWNORMAL; - sei.lpVerb = L"open"; - sei.lpFile = url_utf16.c_str(); - ShellExecuteEx( &sei ); - - //// TODO: LEAVING OLD CODE HERE SO I DON'T BONE OTHER MERGES - //// DELETE THIS ONCE THE MERGES ARE DONE - - // Figure out the user's default web browser - // HKEY_CLASSES_ROOT\http\shell\open\command - /* - std::string reg_path_str = gURLProtocolWhitelistHandler[i] + "\\shell\\open\\command"; - WCHAR reg_path_wstr[256]; - mbstowcs( reg_path_wstr, reg_path_str.c_str(), LL_ARRAY_SIZE(reg_path_wstr) ); - - 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); - - // Convert to STL string - LLWString browser_open_wstring = utf16str_to_wstring(browser_open_wstr); - - if (browser_open_wstring.length() < 2) - { - LL_WARNS("Window") << "Invalid browser executable in registry " << browser_open_wstring << LL_ENDL; - return; - } - - // 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); - } - - LL_DEBUGS("Window") << "Browser reg key: " << wstring_to_utf8str(browser_open_wstring) << LL_ENDL; - LL_INFOS("Window") << "Browser executable: " << wstring_to_utf8str(browser_executable) << LL_ENDL; - - // 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); - - // Convert executable and path to wide string for Windows API - llutf16string browser_exec_utf16 = wstring_to_utf16str(browser_executable); - - // 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) - { - LL_DEBUGS("Window") << "load_url success with " << retval << LL_ENDL; - } - else - { - LL_INFOS("Window") << "load_url failure with " << retval << LL_ENDL; - } - */ -} - - -BOOL LLWindowWin32::dialogColorPicker( F32 *r, F32 *g, F32 *b ) -{ - BOOL retval = FALSE; - - static CHOOSECOLOR cc; - static COLORREF crCustColors[16]; - cc.lStructSize = sizeof(CHOOSECOLOR); - cc.hwndOwner = mWindowHandle; - cc.hInstance = NULL; - cc.rgbResult = RGB ((*r * 255.f),(*g *255.f),(*b * 255.f)); - //cc.rgbResult = RGB (0x80,0x80,0x80); - cc.lpCustColors = crCustColors; - cc.Flags = CC_RGBINIT | CC_FULLOPEN; - cc.lCustData = 0; - cc.lpfnHook = NULL; - cc.lpTemplateName = NULL; - - // This call is modal, so pause agent - //send_agent_pause(); // this is in newview and we don't want to set up a dependency - { - retval = ChooseColor(&cc); - } - //send_agent_resume(); // this is in newview and we don't want to set up a dependency - - *b = ((F32)((cc.rgbResult >> 16) & 0xff)) / 255.f; - - *g = ((F32)((cc.rgbResult >> 8) & 0xff)) / 255.f; - - *r = ((F32)(cc.rgbResult & 0xff)) / 255.f; - - return (retval); -} - -void *LLWindowWin32::getPlatformWindow() -{ - return (void*)mWindowHandle; -} - -void LLWindowWin32::bringToFront() -{ - BringWindowToTop(mWindowHandle); -} - -// set (OS) window focus back to the client -void LLWindowWin32::focusClient() -{ - SetFocus ( mWindowHandle ); -} - -void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) -{ - if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable()) - { - return; - } - - if (preeditor != mPreeditor && !b) - { - // This condition may occur with a call to - // setEnabled(BOOL) from LLTextEditor or LLLineEditor - // when the control is not focused. - // We need to silently ignore the case so that - // the language input status of the focused control - // is not disturbed. - return; - } - - // Take care of old and new preeditors. - if (preeditor != mPreeditor || !b) - { - if (sLanguageTextInputAllowed) - { - interruptLanguageTextInput(); - } - mPreeditor = (b ? preeditor : NULL); - } - - sLanguageTextInputAllowed = b; - - if ( sLanguageTextInputAllowed ) - { - // Allowing: Restore the previous IME status, so that the user has a feeling that the previous - // text input continues naturally. Be careful, however, the IME status is meaningful only during the user keeps - // using same Input Locale (aka Keyboard Layout). - if (sWinIMEOpened && GetKeyboardLayout(0) == sWinInputLocale) - { - HIMC himc = LLWinImm::getContext(mWindowHandle); - LLWinImm::setOpenStatus(himc, TRUE); - LLWinImm::setConversionStatus(himc, sWinIMEConversionMode, sWinIMESentenceMode); - LLWinImm::releaseContext(mWindowHandle, himc); - } - } - else - { - // Disallowing: Turn off the IME so that succeeding key events bypass IME and come to us directly. - // However, do it after saving the current IME status. We need to restore the status when - // allowing language text input again. - sWinInputLocale = GetKeyboardLayout(0); - sWinIMEOpened = LLWinImm::isIME(sWinInputLocale); - if (sWinIMEOpened) - { - HIMC himc = LLWinImm::getContext(mWindowHandle); - sWinIMEOpened = LLWinImm::getOpenStatus(himc); - if (sWinIMEOpened) - { - LLWinImm::getConversionStatus(himc, &sWinIMEConversionMode, &sWinIMESentenceMode); - - // We need both ImmSetConversionStatus and ImmSetOpenStatus here to surely disable IME's - // keyboard hooking, because Some IME reacts only on the former and some other on the latter... - LLWinImm::setConversionStatus(himc, IME_CMODE_NOCONVERSION, sWinIMESentenceMode); - LLWinImm::setOpenStatus(himc, FALSE); - } - LLWinImm::releaseContext(mWindowHandle, himc); - } - } -} - -void LLWindowWin32::fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, - CANDIDATEFORM *form) -{ - LLCoordWindow caret_coord, top_left, bottom_right; - convertCoords(caret, &caret_coord); - convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); - convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); - - memset(form, 0, sizeof(CANDIDATEFORM)); - form->dwStyle = CFS_EXCLUDE; - form->ptCurrentPos.x = caret_coord.mX; - form->ptCurrentPos.y = caret_coord.mY; - form->rcArea.left = top_left.mX; - form->rcArea.top = top_left.mY; - form->rcArea.right = bottom_right.mX; - form->rcArea.bottom = bottom_right.mY; -} - - -// Put the IME window at the right place (near current text input). Point coordinates should be the top of the current text line. -void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position ) -{ - if (sLanguageTextInputAllowed && LLWinImm::isAvailable()) - { - HIMC himc = LLWinImm::getContext(mWindowHandle); - - LLCoordWindow win_pos; - convertCoords( position, &win_pos ); - - if ( win_pos.mX >= 0 && win_pos.mY >= 0 && - (win_pos.mX != sWinIMEWindowPosition.mX) || (win_pos.mY != sWinIMEWindowPosition.mY) ) - { - COMPOSITIONFORM ime_form; - memset( &ime_form, 0, sizeof(ime_form) ); - ime_form.dwStyle = CFS_POINT; - ime_form.ptCurrentPos.x = win_pos.mX; - ime_form.ptCurrentPos.y = win_pos.mY; - - LLWinImm::setCompositionWindow( himc, &ime_form ); - - sWinIMEWindowPosition.set( win_pos.mX, win_pos.mY ); - } - - LLWinImm::releaseContext(mWindowHandle, himc); - } -} - - -void LLWindowWin32::fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, - IMECHARPOSITION *char_position) -{ - LLCoordScreen caret_coord, top_left, bottom_right; - convertCoords(caret, &caret_coord); - convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); - convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); - - char_position->pt.x = caret_coord.mX; - char_position->pt.y = top_left.mY; // Windows wants the coordinate of upper left corner of a character... - char_position->cLineHeight = bottom_right.mY - top_left.mY; - char_position->rcDocument.left = top_left.mX; - char_position->rcDocument.top = top_left.mY; - char_position->rcDocument.right = bottom_right.mX; - char_position->rcDocument.bottom = bottom_right.mY; -} - -void LLWindowWin32::fillCompositionLogfont(LOGFONT *logfont) -{ - // Our font is a list of FreeType recognized font files that may - // not have a corresponding ones in Windows' fonts. Hence, we - // can't simply tell Windows which font we are using. We will - // notify a _standard_ font for a current input locale instead. - // We use a hard-coded knowledge about the Windows' standard - // configuration to do so... - - memset(logfont, 0, sizeof(LOGFONT)); - - const WORD lang_id = LOWORD(GetKeyboardLayout(0)); - switch (PRIMARYLANGID(lang_id)) - { - case LANG_CHINESE: - // We need to identify one of two Chinese fonts. - switch (SUBLANGID(lang_id)) - { - case SUBLANG_CHINESE_SIMPLIFIED: - case SUBLANG_CHINESE_SINGAPORE: - logfont->lfCharSet = GB2312_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("SimHei")); - break; - case SUBLANG_CHINESE_TRADITIONAL: - case SUBLANG_CHINESE_HONGKONG: - case SUBLANG_CHINESE_MACAU: - default: - logfont->lfCharSet = CHINESEBIG5_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("MingLiU")); - break; - } - break; - case LANG_JAPANESE: - logfont->lfCharSet = SHIFTJIS_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("MS Gothic")); - break; - case LANG_KOREAN: - logfont->lfCharSet = HANGUL_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("Gulim")); - break; - default: - logfont->lfCharSet = ANSI_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("Tahoma")); - break; - } - - logfont->lfHeight = mPreeditor->getPreeditFontSize(); - logfont->lfWeight = FW_NORMAL; -} - -U32 LLWindowWin32::fillReconvertString(const LLWString &text, - S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string) -{ - const llutf16string text_utf16 = wstring_to_utf16str(text); - const DWORD required_size = sizeof(RECONVERTSTRING) + (text_utf16.length() + 1) * sizeof(WCHAR); - if (reconvert_string && reconvert_string->dwSize >= required_size) - { - const DWORD focus_utf16_at = wstring_utf16_length(text, 0, focus); - const DWORD focus_utf16_length = wstring_utf16_length(text, focus, focus_length); - - reconvert_string->dwVersion = 0; - reconvert_string->dwStrLen = text_utf16.length(); - reconvert_string->dwStrOffset = sizeof(RECONVERTSTRING); - reconvert_string->dwCompStrLen = focus_utf16_length; - reconvert_string->dwCompStrOffset = focus_utf16_at * sizeof(WCHAR); - reconvert_string->dwTargetStrLen = 0; - reconvert_string->dwTargetStrOffset = focus_utf16_at * sizeof(WCHAR); - - const LPWSTR text = (LPWSTR)((BYTE *)reconvert_string + sizeof(RECONVERTSTRING)); - memcpy(text, text_utf16.c_str(), (text_utf16.length() + 1) * sizeof(WCHAR)); - } - return required_size; -} - -void LLWindowWin32::updateLanguageTextInputArea() -{ - if (!mPreeditor || !LLWinImm::isAvailable()) - { - return; - } - - LLCoordGL caret_coord; - LLRect preedit_bounds; - if (mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL)) - { - mLanguageTextInputPointGL = caret_coord; - mLanguageTextInputAreaGL = preedit_bounds; - - CANDIDATEFORM candidate_form; - fillCandidateForm(caret_coord, preedit_bounds, &candidate_form); - - HIMC himc = LLWinImm::getContext(mWindowHandle); - // Win32 document says there may be up to 4 candidate windows. - // This magic number 4 appears only in the document, and - // there are no constant/macro for the value... - for (int i = 3; i >= 0; --i) - { - candidate_form.dwIndex = i; - LLWinImm::setCandidateWindow(himc, &candidate_form); - } - LLWinImm::releaseContext(mWindowHandle, himc); - } -} - -void LLWindowWin32::interruptLanguageTextInput() -{ - if (mPreeditor) - { - if (LLWinImm::isAvailable()) - { - HIMC himc = LLWinImm::getContext(mWindowHandle); - LLWinImm::notifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); - LLWinImm::releaseContext(mWindowHandle, himc); - } - - // Win32 document says there will be no composition string - // after NI_COMPOSITIONSTR returns. The following call to - // resetPreedit should be a NOP unless IME goes mad... - mPreeditor->resetPreedit(); - } -} - -void LLWindowWin32::handleStartCompositionMessage() -{ - // Let IME know the font to use in feedback UI. - LOGFONT logfont; - fillCompositionLogfont(&logfont); - HIMC himc = LLWinImm::getContext(mWindowHandle); - LLWinImm::setCompositionFont(himc, &logfont); - LLWinImm::releaseContext(mWindowHandle, himc); -} - -// Handle WM_IME_COMPOSITION message. - -void LLWindowWin32::handleCompositionMessage(const U32 indexes) -{ - BOOL needs_update = FALSE; - LLWString result_string; - LLWString preedit_string; - S32 preedit_string_utf16_length = 0; - LLPreeditor::segment_lengths_t preedit_segment_lengths; - LLPreeditor::standouts_t preedit_standouts; - - // Step I: Receive details of preedits from IME. - - HIMC himc = LLWinImm::getContext(mWindowHandle); - - if (indexes & GCS_RESULTSTR) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, NULL, 0); - if (size >= 0) - { - const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; - size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, data, size); - if (size > 0) - { - result_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); - } - delete[] data; - needs_update = TRUE; - } - } - - if (indexes & GCS_COMPSTR) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, NULL, 0); - if (size >= 0) - { - const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; - size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, data, size); - if (size > 0) - { - preedit_string_utf16_length = size / sizeof(WCHAR); - preedit_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); - } - delete[] data; - needs_update = TRUE; - } - } - - if ((indexes & GCS_COMPCLAUSE) && preedit_string.length() > 0) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, NULL, 0); - if (size > 0) - { - const LPDWORD data = new DWORD[size / sizeof(DWORD)]; - size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, data, size); - if (size >= sizeof(DWORD) * 2 - && data[0] == 0 && data[size / sizeof(DWORD) - 1] == preedit_string_utf16_length) - { - preedit_segment_lengths.resize(size / sizeof(DWORD) - 1); - S32 offset = 0; - for (U32 i = 0; i < preedit_segment_lengths.size(); i++) - { - const S32 length = wstring_wstring_length_from_utf16_length(preedit_string, offset, data[i + 1] - data[i]); - preedit_segment_lengths[i] = length; - offset += length; - } - } - delete[] data; - } - } - - if ((indexes & GCS_COMPATTR) && preedit_segment_lengths.size() > 1) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, NULL, 0); - if (size > 0) - { - const LPBYTE data = new BYTE[size / sizeof(BYTE)]; - size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, data, size); - if (size == preedit_string_utf16_length) - { - preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); - S32 offset = 0; - for (U32 i = 0; i < preedit_segment_lengths.size(); i++) - { - if (ATTR_TARGET_CONVERTED == data[offset] || ATTR_TARGET_NOTCONVERTED == data[offset]) - { - preedit_standouts[i] = TRUE; - } - offset += wstring_utf16_length(preedit_string, offset, preedit_segment_lengths[i]); - } - } - delete[] data; - } - } - - S32 caret_position = preedit_string.length(); - if (indexes & GCS_CURSORPOS) - { - const S32 caret_position_utf16 = LLWinImm::getCompositionString(himc, GCS_CURSORPOS, NULL, 0); - if (caret_position_utf16 >= 0 && caret_position <= preedit_string_utf16_length) - { - caret_position = wstring_wstring_length_from_utf16_length(preedit_string, 0, caret_position_utf16); - } - } - - if (indexes == 0) - { - // I'm not sure this condition really happens, but - // Windows SDK document says it is an indication - // of "reset everything." - needs_update = TRUE; - } - - LLWinImm::releaseContext(mWindowHandle, himc); - - // Step II: Update the active preeditor. - - if (needs_update) - { - mPreeditor->resetPreedit(); - - if (result_string.length() > 0) - { - for (LLWString::const_iterator i = result_string.begin(); i != result_string.end(); i++) - { - mPreeditor->handleUnicodeCharHere(*i); - } - } - - if (preedit_string.length() == 0) - { - preedit_segment_lengths.clear(); - preedit_standouts.clear(); - } - else - { - if (preedit_segment_lengths.size() == 0) - { - preedit_segment_lengths.assign(1, preedit_string.length()); - } - if (preedit_standouts.size() == 0) - { - preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); - } - } - mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position); - - // Some IME doesn't query char position after WM_IME_COMPOSITION, - // so we need to update them actively. - updateLanguageTextInputArea(); - } -} - -// Given a text and a focus range, find_context finds and returns a -// surrounding context of the focused subtext. A variable pointed -// to by offset receives the offset in llwchars of the beginning of -// the returned context string in the given wtext. - -static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_length, S32 *offset) -{ - static const S32 CONTEXT_EXCESS = 30; // This value is by experiences. - - const S32 e = llmin((S32) wtext.length(), focus + focus_length + CONTEXT_EXCESS); - S32 end = focus + focus_length; - while (end < e && '\n' != wtext[end]) - { - end++; - } - - const S32 s = llmax(0, focus - CONTEXT_EXCESS); - S32 start = focus; - while (start > s && '\n' != wtext[start - 1]) - { - --start; - } - - *offset = start; - return wtext.substr(start, end - start); -} - -// 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 -// the Window Procedure is set to *result. - -BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) -{ - if ( mPreeditor ) - { - switch (request) - { - case IMR_CANDIDATEWINDOW: // http://msdn2.microsoft.com/en-us/library/ms776080.aspx - { - LLCoordGL caret_coord; - LLRect preedit_bounds; - mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL); - - CANDIDATEFORM *const form = (CANDIDATEFORM *)param; - DWORD const dwIndex = form->dwIndex; - fillCandidateForm(caret_coord, preedit_bounds, form); - form->dwIndex = dwIndex; - - *result = 1; - return TRUE; - } - case IMR_QUERYCHARPOSITION: - { - IMECHARPOSITION *const char_position = (IMECHARPOSITION *)param; - - // char_position->dwCharPos counts in number of - // WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the - // number to getPreeditLocation. - - const LLWString & wtext = mPreeditor->getPreeditString(); - S32 preedit, preedit_length; - mPreeditor->getPreeditRange(&preedit, &preedit_length); - LLCoordGL caret_coord; - LLRect preedit_bounds, text_control; - const S32 position = wstring_wstring_length_from_utf16_length(wtext, preedit, char_position->dwCharPos); - - if (!mPreeditor->getPreeditLocation(position, &caret_coord, &preedit_bounds, &text_control)) - { - LL_WARNS("Window") << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << LL_ENDL; - return FALSE; - } - fillCharPosition(caret_coord, preedit_bounds, text_control, char_position); - - *result = 1; - return TRUE; - } - case IMR_COMPOSITIONFONT: - { - fillCompositionLogfont((LOGFONT *)param); - - *result = 1; - return TRUE; - } - case IMR_RECONVERTSTRING: - { - mPreeditor->resetPreedit(); - const LLWString & wtext = mPreeditor->getPreeditString(); - S32 select, select_length; - mPreeditor->getSelectionRange(&select, &select_length); - - S32 context_offset; - const LLWString context = find_context(wtext, select, select_length, &context_offset); - - RECONVERTSTRING * const reconvert_string = (RECONVERTSTRING *)param; - const U32 size = fillReconvertString(context, select - context_offset, select_length, reconvert_string); - if (reconvert_string) - { - if (select_length == 0) - { - // Let the IME to decide the reconversion range, and - // adjust the reconvert_string structure accordingly. - HIMC himc = LLWinImm::getContext(mWindowHandle); - const BOOL adjusted = LLWinImm::setCompositionString(himc, - SCS_QUERYRECONVERTSTRING, reconvert_string, size, NULL, 0); - LLWinImm::releaseContext(mWindowHandle, himc); - if (adjusted) - { - const llutf16string & text_utf16 = wstring_to_utf16str(context); - const S32 new_preedit_start = reconvert_string->dwCompStrOffset / sizeof(WCHAR); - const S32 new_preedit_end = new_preedit_start + reconvert_string->dwCompStrLen; - select = utf16str_wstring_length(text_utf16, new_preedit_start); - select_length = utf16str_wstring_length(text_utf16, new_preedit_end) - select; - select += context_offset; - } - } - mPreeditor->markAsPreedit(select, select_length); - } - - *result = size; - return TRUE; - } - case IMR_CONFIRMRECONVERTSTRING: - { - *result = FALSE; - return TRUE; - } - case IMR_DOCUMENTFEED: - { - const LLWString & wtext = mPreeditor->getPreeditString(); - S32 preedit, preedit_length; - mPreeditor->getPreeditRange(&preedit, &preedit_length); - - S32 context_offset; - LLWString context = find_context(wtext, preedit, preedit_length, &context_offset); - preedit -= context_offset; - if (preedit_length) - { - // IMR_DOCUMENTFEED may be called when we have an active preedit. - // We should pass the context string *excluding* the preedit string. - // Otherwise, some IME are confused. - context.erase(preedit, preedit_length); - } - - RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)param; - *result = fillReconvertString(context, preedit, 0, reconvert_string); - return TRUE; - } - default: - return FALSE; - } - } - - return FALSE; -} - -//static -std::vector LLWindowWin32::getDynamicFallbackFontList() -{ - // Fonts previously in getFontListSans() have moved to fonts.xml. - return std::vector(); -} - - -#endif // LL_WINDOWS + + if ( window_imp->completeDropRequest( gl_coord, mask, (char*)url ) ) + { + 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); +} + +BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to) +{ + S32 client_height; + RECT client_rect; + LLCoordWindow window_position; + + if (!mWindowHandle || + !GetClientRect(mWindowHandle, &client_rect) || + NULL == to) + { + return FALSE; + } + + to->mX = from.mX; + client_height = client_rect.bottom - client_rect.top; + to->mY = client_height - from.mY - 1; + + return TRUE; +} + +BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordGL* to) +{ + S32 client_height; + RECT client_rect; + + if (!mWindowHandle || + !GetClientRect(mWindowHandle, &client_rect) || + NULL == to) + { + return FALSE; + } + + to->mX = from.mX; + client_height = client_rect.bottom - client_rect.top; + to->mY = client_height - from.mY - 1; + + return TRUE; +} + +BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordWindow* to) +{ + POINT mouse_point; + + mouse_point.x = from.mX; + mouse_point.y = from.mY; + BOOL result = ScreenToClient(mWindowHandle, &mouse_point); + + if (result) + { + to->mX = mouse_point.x; + to->mY = mouse_point.y; + } + + return result; +} + +BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordScreen *to) +{ + POINT mouse_point; + + mouse_point.x = from.mX; + mouse_point.y = from.mY; + BOOL result = ClientToScreen(mWindowHandle, &mouse_point); + + if (result) + { + to->mX = mouse_point.x; + to->mY = mouse_point.y; + } + + return result; +} + +BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordGL *to) +{ + LLCoordWindow window_coord; + + if (!mWindowHandle || (NULL == to)) + { + return FALSE; + } + + convertCoords(from, &window_coord); + convertCoords(window_coord, to); + return TRUE; +} + +BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordScreen *to) +{ + LLCoordWindow window_coord; + + if (!mWindowHandle || (NULL == to)) + { + return FALSE; + } + + convertCoords(from, &window_coord); + convertCoords(window_coord, to); + return TRUE; +} + + +BOOL LLWindowWin32::isClipboardTextAvailable() +{ + return IsClipboardFormatAvailable(CF_UNICODETEXT); +} + + +BOOL LLWindowWin32::pasteTextFromClipboard(LLWString &dst) +{ + BOOL success = FALSE; + + if (IsClipboardFormatAvailable(CF_UNICODETEXT)) + { + if (OpenClipboard(mWindowHandle)) + { + HGLOBAL h_data = GetClipboardData(CF_UNICODETEXT); + if (h_data) + { + WCHAR *utf16str = (WCHAR*) GlobalLock(h_data); + if (utf16str) + { + dst = utf16str_to_wstring(utf16str); + LLWStringUtil::removeCRLF(dst); + GlobalUnlock(h_data); + success = TRUE; + } + } + CloseClipboard(); + } + } + + return success; +} + + +BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr) +{ + BOOL success = FALSE; + + if (OpenClipboard(mWindowHandle)) + { + EmptyClipboard(); + + // Provide a copy of the data in Unicode format. + LLWString sanitized_string(wstr); + LLWStringUtil::addCRLF(sanitized_string); + llutf16string out_utf16 = wstring_to_utf16str(sanitized_string); + const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(WCHAR); + + // Memory is allocated and then ownership of it is transfered to the system. + HGLOBAL hglobal_copy_utf16 = GlobalAlloc(GMEM_MOVEABLE, size_utf16); + if (hglobal_copy_utf16) + { + WCHAR* copy_utf16 = (WCHAR*) GlobalLock(hglobal_copy_utf16); + if (copy_utf16) + { + memcpy(copy_utf16, out_utf16.c_str(), size_utf16); /* Flawfinder: ignore */ + GlobalUnlock(hglobal_copy_utf16); + + if (SetClipboardData(CF_UNICODETEXT, hglobal_copy_utf16)) + { + success = TRUE; + } + } + } + + CloseClipboard(); + } + + return success; +} + +// Constrains the mouse to the window. +void LLWindowWin32::setMouseClipping( BOOL b ) +{ + if( b != mIsMouseClipping ) + { + BOOL success = FALSE; + + if( b ) + { + GetClipCursor( &mOldMouseClip ); + + RECT client_rect_in_screen_space; + if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) + { + success = ClipCursor( &client_rect_in_screen_space ); + } + } + else + { + // Must restore the old mouse clip, which may be set by another window. + success = ClipCursor( &mOldMouseClip ); + SetRect( &mOldMouseClip, 0, 0, 0, 0 ); + } + + if( success ) + { + mIsMouseClipping = b; + } + } +} + +BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp ) +{ + BOOL success = FALSE; + + RECT client_rect; + if( mWindowHandle && GetClientRect(mWindowHandle, &client_rect) ) + { + POINT top_left; + top_left.x = client_rect.left; + top_left.y = client_rect.top; + ClientToScreen(mWindowHandle, &top_left); + + POINT bottom_right; + bottom_right.x = client_rect.right; + bottom_right.y = client_rect.bottom; + ClientToScreen(mWindowHandle, &bottom_right); + + SetRect( rectp, + top_left.x, + top_left.y, + bottom_right.x, + bottom_right.y ); + + success = TRUE; + } + + return success; +} + +void LLWindowWin32::flashIcon(F32 seconds) +{ + FLASHWINFO flash_info; + + flash_info.cbSize = sizeof(FLASHWINFO); + flash_info.hwnd = mWindowHandle; + flash_info.dwFlags = FLASHW_TRAY; + flash_info.uCount = UINT(seconds / ICON_FLASH_TIME); + flash_info.dwTimeout = DWORD(1000.f * ICON_FLASH_TIME); // milliseconds + FlashWindowEx(&flash_info); +} + +F32 LLWindowWin32::getGamma() +{ + return mCurrentGamma; +} + +BOOL LLWindowWin32::restoreGamma() +{ + return SetDeviceGammaRamp(mhDC, mPrevGammaRamp); +} + +BOOL LLWindowWin32::setGamma(const F32 gamma) +{ + mCurrentGamma = gamma; + + LL_DEBUGS("Window") << "Setting gamma to " << gamma << LL_ENDL; + + for ( int i = 0; i < 256; ++i ) + { + int mult = 256 - ( int ) ( ( gamma - 1.0f ) * 128.0f ); + + int value = mult * i; + + if ( value > 0xffff ) + value = 0xffff; + + mCurrentGammaRamp [ 0 * 256 + i ] = + mCurrentGammaRamp [ 1 * 256 + i ] = + mCurrentGammaRamp [ 2 * 256 + i ] = ( WORD )value; + }; + + 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) + { + mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; + DEVMODE dev_mode; + + mNumSupportedResolutions = 0; + for (S32 mode_num = 0; mNumSupportedResolutions < MAX_NUM_RESOLUTIONS; mode_num++) + { + if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) + { + break; + } + + if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL && + dev_mode.dmPelsWidth >= 800 && + dev_mode.dmPelsHeight >= 600) + { + BOOL resolution_exists = FALSE; + for(S32 i = 0; i < mNumSupportedResolutions; i++) + { + if (mSupportedResolutions[i].mWidth == dev_mode.dmPelsWidth && + mSupportedResolutions[i].mHeight == dev_mode.dmPelsHeight) + { + resolution_exists = TRUE; + } + } + if (!resolution_exists) + { + mSupportedResolutions[mNumSupportedResolutions].mWidth = dev_mode.dmPelsWidth; + mSupportedResolutions[mNumSupportedResolutions].mHeight = dev_mode.dmPelsHeight; + mNumSupportedResolutions++; + } + } + } + } + + num_resolutions = mNumSupportedResolutions; + return mSupportedResolutions; +} + + +F32 LLWindowWin32::getNativeAspectRatio() +{ + if (mOverrideAspectRatio > 0.f) + { + return mOverrideAspectRatio; + } + else if (mNativeAspectRatio > 0.f) + { + // we grabbed this value at startup, based on the user's desktop settings + return mNativeAspectRatio; + } + // RN: this hack presumes that the largest supported resolution is monitor-limited + // and that pixels in that mode are square, therefore defining the native aspect ratio + // of the monitor...this seems to work to a close approximation for most CRTs/LCDs + S32 num_resolutions; + LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); + + return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); +} + +F32 LLWindowWin32::getPixelAspectRatio() +{ + F32 pixel_aspect = 1.f; + if (getFullscreen()) + { + LLCoordScreen screen_size; + getSize(&screen_size); + pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; + } + + return pixel_aspect; +} + +// Change display resolution. Returns true if successful. +// protected +BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh) +{ + DEVMODE dev_mode; + dev_mode.dmSize = sizeof(dev_mode); + BOOL success = FALSE; + + // Don't change anything if we don't have to + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) + { + if (dev_mode.dmPelsWidth == width && + dev_mode.dmPelsHeight == height && + dev_mode.dmBitsPerPel == bits && + dev_mode.dmDisplayFrequency == refresh ) + { + // ...display mode identical, do nothing + return TRUE; + } + } + + memset(&dev_mode, 0, sizeof(dev_mode)); + dev_mode.dmSize = sizeof(dev_mode); + dev_mode.dmPelsWidth = width; + dev_mode.dmPelsHeight = height; + dev_mode.dmBitsPerPel = bits; + dev_mode.dmDisplayFrequency = refresh; + dev_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; + + // CDS_FULLSCREEN indicates that this is a temporary change to the device mode. + LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN); + + success = (DISP_CHANGE_SUCCESSFUL == cds_result); + + if (!success) + { + LL_WARNS("Window") << "setDisplayResolution failed, " + << width << "x" << height << "x" << bits << " @ " << refresh << LL_ENDL; + } + + return success; +} + +// protected +BOOL LLWindowWin32::setFullscreenResolution() +{ + if (mFullscreen) + { + return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh); + } + else + { + return FALSE; + } +} + +// protected +BOOL LLWindowWin32::resetDisplayResolution() +{ + LL_DEBUGS("Window") << "resetDisplayResolution START" << LL_ENDL; + + LONG cds_result = ChangeDisplaySettings(NULL, 0); + + BOOL success = (DISP_CHANGE_SUCCESSFUL == cds_result); + + if (!success) + { + LL_WARNS("Window") << "resetDisplayResolution failed" << LL_ENDL; + } + + LL_DEBUGS("Window") << "resetDisplayResolution END" << LL_ENDL; + + return success; +} + +void LLWindowWin32::swapBuffers() +{ + SwapBuffers(mhDC); +} + + +// +// LLSplashScreenImp +// +LLSplashScreenWin32::LLSplashScreenWin32() +: mWindow(NULL) +{ +} + +LLSplashScreenWin32::~LLSplashScreenWin32() +{ +} + +void LLSplashScreenWin32::showImpl() +{ + // This appears to work. ??? + HINSTANCE hinst = GetModuleHandle(NULL); + + mWindow = CreateDialog(hinst, + TEXT("SPLASHSCREEN"), + NULL, // no parent + (DLGPROC) LLSplashScreenWin32::windowProc); + ShowWindow(mWindow, SW_SHOW); +} + + +void LLSplashScreenWin32::updateImpl(const std::string& mesg) +{ + if (!mWindow) return; + + WCHAR w_mesg[1024]; + mbstowcs(w_mesg, mesg.c_str(), 1024); + + SendDlgItemMessage(mWindow, + 666, // HACK: text id + WM_SETTEXT, + FALSE, + (LPARAM)w_mesg); +} + + +void LLSplashScreenWin32::hideImpl() +{ + if (mWindow) + { + DestroyWindow(mWindow); + mWindow = NULL; + } +} + + +// static +LRESULT CALLBACK LLSplashScreenWin32::windowProc(HWND h_wnd, UINT u_msg, + WPARAM w_param, LPARAM l_param) +{ + // Just give it to windows + return DefWindowProc(h_wnd, u_msg, w_param, l_param); +} + +// +// Helper Funcs +// + +S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type) +{ + UINT uType; + + switch(type) + { + case OSMB_OK: + uType = MB_OK; + break; + case OSMB_OKCANCEL: + uType = MB_OKCANCEL; + break; + case OSMB_YESNO: + uType = MB_YESNO; + break; + default: + uType = MB_OK; + break; + } + + // HACK! Doesn't properly handle wide strings! + int retval_win = MessageBoxA(NULL, text.c_str(), caption.c_str(), uType); + S32 retval; + + switch(retval_win) + { + case IDYES: + retval = OSBTN_YES; + break; + case IDNO: + retval = OSBTN_NO; + break; + case IDOK: + retval = OSBTN_OK; + break; + case IDCANCEL: + retval = OSBTN_CANCEL; + break; + default: + retval = OSBTN_CANCEL; + break; + } + + return retval; +} + + +void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url ) +{ + bool found = false; + S32 i; + for (i = 0; i < gURLProtocolWhitelistCount; i++) + { + if (escaped_url.find(gURLProtocolWhitelist[i]) == 0) + { + found = true; + break; + } + } + + if (!found) + { + LL_WARNS("Window") << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; + return; + } + + LL_INFOS("Window") << "Opening URL " << escaped_url << LL_ENDL; + + // replaced ShellExecute code with ShellExecuteEx since ShellExecute doesn't work + // reliablly on Vista. + + // this is madness.. no, this is.. + LLWString url_wstring = utf8str_to_wstring( escaped_url ); + llutf16string url_utf16 = wstring_to_utf16str( url_wstring ); + + // let the OS decide what to use to open the URL + SHELLEXECUTEINFO sei = { sizeof( sei ) }; + sei.fMask = SEE_MASK_FLAG_DDEWAIT; + sei.nShow = SW_SHOWNORMAL; + sei.lpVerb = L"open"; + sei.lpFile = url_utf16.c_str(); + ShellExecuteEx( &sei ); + + //// TODO: LEAVING OLD CODE HERE SO I DON'T BONE OTHER MERGES + //// DELETE THIS ONCE THE MERGES ARE DONE + + // Figure out the user's default web browser + // HKEY_CLASSES_ROOT\http\shell\open\command + /* + std::string reg_path_str = gURLProtocolWhitelistHandler[i] + "\\shell\\open\\command"; + WCHAR reg_path_wstr[256]; + mbstowcs( reg_path_wstr, reg_path_str.c_str(), LL_ARRAY_SIZE(reg_path_wstr) ); + + 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); + + // Convert to STL string + LLWString browser_open_wstring = utf16str_to_wstring(browser_open_wstr); + + if (browser_open_wstring.length() < 2) + { + LL_WARNS("Window") << "Invalid browser executable in registry " << browser_open_wstring << LL_ENDL; + return; + } + + // 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); + } + + LL_DEBUGS("Window") << "Browser reg key: " << wstring_to_utf8str(browser_open_wstring) << LL_ENDL; + LL_INFOS("Window") << "Browser executable: " << wstring_to_utf8str(browser_executable) << LL_ENDL; + + // 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); + + // Convert executable and path to wide string for Windows API + llutf16string browser_exec_utf16 = wstring_to_utf16str(browser_executable); + + // 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) + { + LL_DEBUGS("Window") << "load_url success with " << retval << LL_ENDL; + } + else + { + LL_INFOS("Window") << "load_url failure with " << retval << LL_ENDL; + } + */ +} + + +BOOL LLWindowWin32::dialogColorPicker( F32 *r, F32 *g, F32 *b ) +{ + BOOL retval = FALSE; + + static CHOOSECOLOR cc; + static COLORREF crCustColors[16]; + cc.lStructSize = sizeof(CHOOSECOLOR); + cc.hwndOwner = mWindowHandle; + cc.hInstance = NULL; + cc.rgbResult = RGB ((*r * 255.f),(*g *255.f),(*b * 255.f)); + //cc.rgbResult = RGB (0x80,0x80,0x80); + cc.lpCustColors = crCustColors; + cc.Flags = CC_RGBINIT | CC_FULLOPEN; + cc.lCustData = 0; + cc.lpfnHook = NULL; + cc.lpTemplateName = NULL; + + // This call is modal, so pause agent + //send_agent_pause(); // this is in newview and we don't want to set up a dependency + { + retval = ChooseColor(&cc); + } + //send_agent_resume(); // this is in newview and we don't want to set up a dependency + + *b = ((F32)((cc.rgbResult >> 16) & 0xff)) / 255.f; + + *g = ((F32)((cc.rgbResult >> 8) & 0xff)) / 255.f; + + *r = ((F32)(cc.rgbResult & 0xff)) / 255.f; + + return (retval); +} + +void *LLWindowWin32::getPlatformWindow() +{ + return (void*)mWindowHandle; +} + +void LLWindowWin32::bringToFront() +{ + BringWindowToTop(mWindowHandle); +} + +// set (OS) window focus back to the client +void LLWindowWin32::focusClient() +{ + SetFocus ( mWindowHandle ); +} + +void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) +{ + if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable()) + { + return; + } + + if (preeditor != mPreeditor && !b) + { + // This condition may occur with a call to + // setEnabled(BOOL) from LLTextEditor or LLLineEditor + // when the control is not focused. + // We need to silently ignore the case so that + // the language input status of the focused control + // is not disturbed. + return; + } + + // Take care of old and new preeditors. + if (preeditor != mPreeditor || !b) + { + if (sLanguageTextInputAllowed) + { + interruptLanguageTextInput(); + } + mPreeditor = (b ? preeditor : NULL); + } + + sLanguageTextInputAllowed = b; + + if ( sLanguageTextInputAllowed ) + { + // Allowing: Restore the previous IME status, so that the user has a feeling that the previous + // text input continues naturally. Be careful, however, the IME status is meaningful only during the user keeps + // using same Input Locale (aka Keyboard Layout). + if (sWinIMEOpened && GetKeyboardLayout(0) == sWinInputLocale) + { + HIMC himc = LLWinImm::getContext(mWindowHandle); + LLWinImm::setOpenStatus(himc, TRUE); + LLWinImm::setConversionStatus(himc, sWinIMEConversionMode, sWinIMESentenceMode); + LLWinImm::releaseContext(mWindowHandle, himc); + } + } + else + { + // Disallowing: Turn off the IME so that succeeding key events bypass IME and come to us directly. + // However, do it after saving the current IME status. We need to restore the status when + // allowing language text input again. + sWinInputLocale = GetKeyboardLayout(0); + sWinIMEOpened = LLWinImm::isIME(sWinInputLocale); + if (sWinIMEOpened) + { + HIMC himc = LLWinImm::getContext(mWindowHandle); + sWinIMEOpened = LLWinImm::getOpenStatus(himc); + if (sWinIMEOpened) + { + LLWinImm::getConversionStatus(himc, &sWinIMEConversionMode, &sWinIMESentenceMode); + + // We need both ImmSetConversionStatus and ImmSetOpenStatus here to surely disable IME's + // keyboard hooking, because Some IME reacts only on the former and some other on the latter... + LLWinImm::setConversionStatus(himc, IME_CMODE_NOCONVERSION, sWinIMESentenceMode); + LLWinImm::setOpenStatus(himc, FALSE); + } + LLWinImm::releaseContext(mWindowHandle, himc); + } + } +} + +void LLWindowWin32::fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, + CANDIDATEFORM *form) +{ + LLCoordWindow caret_coord, top_left, bottom_right; + convertCoords(caret, &caret_coord); + convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); + convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); + + memset(form, 0, sizeof(CANDIDATEFORM)); + form->dwStyle = CFS_EXCLUDE; + form->ptCurrentPos.x = caret_coord.mX; + form->ptCurrentPos.y = caret_coord.mY; + form->rcArea.left = top_left.mX; + form->rcArea.top = top_left.mY; + form->rcArea.right = bottom_right.mX; + form->rcArea.bottom = bottom_right.mY; +} + + +// Put the IME window at the right place (near current text input). Point coordinates should be the top of the current text line. +void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position ) +{ + if (sLanguageTextInputAllowed && LLWinImm::isAvailable()) + { + HIMC himc = LLWinImm::getContext(mWindowHandle); + + LLCoordWindow win_pos; + convertCoords( position, &win_pos ); + + if ( win_pos.mX >= 0 && win_pos.mY >= 0 && + (win_pos.mX != sWinIMEWindowPosition.mX) || (win_pos.mY != sWinIMEWindowPosition.mY) ) + { + COMPOSITIONFORM ime_form; + memset( &ime_form, 0, sizeof(ime_form) ); + ime_form.dwStyle = CFS_POINT; + ime_form.ptCurrentPos.x = win_pos.mX; + ime_form.ptCurrentPos.y = win_pos.mY; + + LLWinImm::setCompositionWindow( himc, &ime_form ); + + sWinIMEWindowPosition.set( win_pos.mX, win_pos.mY ); + } + + LLWinImm::releaseContext(mWindowHandle, himc); + } +} + + +void LLWindowWin32::fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, + IMECHARPOSITION *char_position) +{ + LLCoordScreen caret_coord, top_left, bottom_right; + convertCoords(caret, &caret_coord); + convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); + convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); + + char_position->pt.x = caret_coord.mX; + char_position->pt.y = top_left.mY; // Windows wants the coordinate of upper left corner of a character... + char_position->cLineHeight = bottom_right.mY - top_left.mY; + char_position->rcDocument.left = top_left.mX; + char_position->rcDocument.top = top_left.mY; + char_position->rcDocument.right = bottom_right.mX; + char_position->rcDocument.bottom = bottom_right.mY; +} + +void LLWindowWin32::fillCompositionLogfont(LOGFONT *logfont) +{ + // Our font is a list of FreeType recognized font files that may + // not have a corresponding ones in Windows' fonts. Hence, we + // can't simply tell Windows which font we are using. We will + // notify a _standard_ font for a current input locale instead. + // We use a hard-coded knowledge about the Windows' standard + // configuration to do so... + + memset(logfont, 0, sizeof(LOGFONT)); + + const WORD lang_id = LOWORD(GetKeyboardLayout(0)); + switch (PRIMARYLANGID(lang_id)) + { + case LANG_CHINESE: + // We need to identify one of two Chinese fonts. + switch (SUBLANGID(lang_id)) + { + case SUBLANG_CHINESE_SIMPLIFIED: + case SUBLANG_CHINESE_SINGAPORE: + logfont->lfCharSet = GB2312_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("SimHei")); + break; + case SUBLANG_CHINESE_TRADITIONAL: + case SUBLANG_CHINESE_HONGKONG: + case SUBLANG_CHINESE_MACAU: + default: + logfont->lfCharSet = CHINESEBIG5_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("MingLiU")); + break; + } + break; + case LANG_JAPANESE: + logfont->lfCharSet = SHIFTJIS_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("MS Gothic")); + break; + case LANG_KOREAN: + logfont->lfCharSet = HANGUL_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("Gulim")); + break; + default: + logfont->lfCharSet = ANSI_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("Tahoma")); + break; + } + + logfont->lfHeight = mPreeditor->getPreeditFontSize(); + logfont->lfWeight = FW_NORMAL; +} + +U32 LLWindowWin32::fillReconvertString(const LLWString &text, + S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string) +{ + const llutf16string text_utf16 = wstring_to_utf16str(text); + const DWORD required_size = sizeof(RECONVERTSTRING) + (text_utf16.length() + 1) * sizeof(WCHAR); + if (reconvert_string && reconvert_string->dwSize >= required_size) + { + const DWORD focus_utf16_at = wstring_utf16_length(text, 0, focus); + const DWORD focus_utf16_length = wstring_utf16_length(text, focus, focus_length); + + reconvert_string->dwVersion = 0; + reconvert_string->dwStrLen = text_utf16.length(); + reconvert_string->dwStrOffset = sizeof(RECONVERTSTRING); + reconvert_string->dwCompStrLen = focus_utf16_length; + reconvert_string->dwCompStrOffset = focus_utf16_at * sizeof(WCHAR); + reconvert_string->dwTargetStrLen = 0; + reconvert_string->dwTargetStrOffset = focus_utf16_at * sizeof(WCHAR); + + const LPWSTR text = (LPWSTR)((BYTE *)reconvert_string + sizeof(RECONVERTSTRING)); + memcpy(text, text_utf16.c_str(), (text_utf16.length() + 1) * sizeof(WCHAR)); + } + return required_size; +} + +void LLWindowWin32::updateLanguageTextInputArea() +{ + if (!mPreeditor || !LLWinImm::isAvailable()) + { + return; + } + + LLCoordGL caret_coord; + LLRect preedit_bounds; + if (mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL)) + { + mLanguageTextInputPointGL = caret_coord; + mLanguageTextInputAreaGL = preedit_bounds; + + CANDIDATEFORM candidate_form; + fillCandidateForm(caret_coord, preedit_bounds, &candidate_form); + + HIMC himc = LLWinImm::getContext(mWindowHandle); + // Win32 document says there may be up to 4 candidate windows. + // This magic number 4 appears only in the document, and + // there are no constant/macro for the value... + for (int i = 3; i >= 0; --i) + { + candidate_form.dwIndex = i; + LLWinImm::setCandidateWindow(himc, &candidate_form); + } + LLWinImm::releaseContext(mWindowHandle, himc); + } +} + +void LLWindowWin32::interruptLanguageTextInput() +{ + if (mPreeditor) + { + if (LLWinImm::isAvailable()) + { + HIMC himc = LLWinImm::getContext(mWindowHandle); + LLWinImm::notifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); + LLWinImm::releaseContext(mWindowHandle, himc); + } + + // Win32 document says there will be no composition string + // after NI_COMPOSITIONSTR returns. The following call to + // resetPreedit should be a NOP unless IME goes mad... + mPreeditor->resetPreedit(); + } +} + +void LLWindowWin32::handleStartCompositionMessage() +{ + // Let IME know the font to use in feedback UI. + LOGFONT logfont; + fillCompositionLogfont(&logfont); + HIMC himc = LLWinImm::getContext(mWindowHandle); + LLWinImm::setCompositionFont(himc, &logfont); + LLWinImm::releaseContext(mWindowHandle, himc); +} + +// Handle WM_IME_COMPOSITION message. + +void LLWindowWin32::handleCompositionMessage(const U32 indexes) +{ + BOOL needs_update = FALSE; + LLWString result_string; + LLWString preedit_string; + S32 preedit_string_utf16_length = 0; + LLPreeditor::segment_lengths_t preedit_segment_lengths; + LLPreeditor::standouts_t preedit_standouts; + + // Step I: Receive details of preedits from IME. + + HIMC himc = LLWinImm::getContext(mWindowHandle); + + if (indexes & GCS_RESULTSTR) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, NULL, 0); + if (size >= 0) + { + const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; + size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, data, size); + if (size > 0) + { + result_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); + } + delete[] data; + needs_update = TRUE; + } + } + + if (indexes & GCS_COMPSTR) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, NULL, 0); + if (size >= 0) + { + const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; + size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, data, size); + if (size > 0) + { + preedit_string_utf16_length = size / sizeof(WCHAR); + preedit_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); + } + delete[] data; + needs_update = TRUE; + } + } + + if ((indexes & GCS_COMPCLAUSE) && preedit_string.length() > 0) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, NULL, 0); + if (size > 0) + { + const LPDWORD data = new DWORD[size / sizeof(DWORD)]; + size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, data, size); + if (size >= sizeof(DWORD) * 2 + && data[0] == 0 && data[size / sizeof(DWORD) - 1] == preedit_string_utf16_length) + { + preedit_segment_lengths.resize(size / sizeof(DWORD) - 1); + S32 offset = 0; + for (U32 i = 0; i < preedit_segment_lengths.size(); i++) + { + const S32 length = wstring_wstring_length_from_utf16_length(preedit_string, offset, data[i + 1] - data[i]); + preedit_segment_lengths[i] = length; + offset += length; + } + } + delete[] data; + } + } + + if ((indexes & GCS_COMPATTR) && preedit_segment_lengths.size() > 1) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, NULL, 0); + if (size > 0) + { + const LPBYTE data = new BYTE[size / sizeof(BYTE)]; + size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, data, size); + if (size == preedit_string_utf16_length) + { + preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); + S32 offset = 0; + for (U32 i = 0; i < preedit_segment_lengths.size(); i++) + { + if (ATTR_TARGET_CONVERTED == data[offset] || ATTR_TARGET_NOTCONVERTED == data[offset]) + { + preedit_standouts[i] = TRUE; + } + offset += wstring_utf16_length(preedit_string, offset, preedit_segment_lengths[i]); + } + } + delete[] data; + } + } + + S32 caret_position = preedit_string.length(); + if (indexes & GCS_CURSORPOS) + { + const S32 caret_position_utf16 = LLWinImm::getCompositionString(himc, GCS_CURSORPOS, NULL, 0); + if (caret_position_utf16 >= 0 && caret_position <= preedit_string_utf16_length) + { + caret_position = wstring_wstring_length_from_utf16_length(preedit_string, 0, caret_position_utf16); + } + } + + if (indexes == 0) + { + // I'm not sure this condition really happens, but + // Windows SDK document says it is an indication + // of "reset everything." + needs_update = TRUE; + } + + LLWinImm::releaseContext(mWindowHandle, himc); + + // Step II: Update the active preeditor. + + if (needs_update) + { + mPreeditor->resetPreedit(); + + if (result_string.length() > 0) + { + for (LLWString::const_iterator i = result_string.begin(); i != result_string.end(); i++) + { + mPreeditor->handleUnicodeCharHere(*i); + } + } + + if (preedit_string.length() == 0) + { + preedit_segment_lengths.clear(); + preedit_standouts.clear(); + } + else + { + if (preedit_segment_lengths.size() == 0) + { + preedit_segment_lengths.assign(1, preedit_string.length()); + } + if (preedit_standouts.size() == 0) + { + preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); + } + } + mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position); + + // Some IME doesn't query char position after WM_IME_COMPOSITION, + // so we need to update them actively. + updateLanguageTextInputArea(); + } +} + +// Given a text and a focus range, find_context finds and returns a +// surrounding context of the focused subtext. A variable pointed +// to by offset receives the offset in llwchars of the beginning of +// the returned context string in the given wtext. + +static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_length, S32 *offset) +{ + static const S32 CONTEXT_EXCESS = 30; // This value is by experiences. + + const S32 e = llmin((S32) wtext.length(), focus + focus_length + CONTEXT_EXCESS); + S32 end = focus + focus_length; + while (end < e && '\n' != wtext[end]) + { + end++; + } + + const S32 s = llmax(0, focus - CONTEXT_EXCESS); + S32 start = focus; + while (start > s && '\n' != wtext[start - 1]) + { + --start; + } + + *offset = start; + return wtext.substr(start, end - start); +} + +// final stage of handling drop requests - both from WM_DROPFILES message +// for files and via IDropTarget interface requests. +BOOL LLWindowWin32::completeDropRequest( const LLCoordGL gl_coord, const MASK mask, const std::string url ) +{ + if ( mCallbacks->handleDrop( this, gl_coord, mask, url ) ) + { + return TRUE; + }; + + return FALSE; +}; + +// 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 +// the Window Procedure is set to *result. + +BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) +{ + if ( mPreeditor ) + { + switch (request) + { + case IMR_CANDIDATEWINDOW: // http://msdn2.microsoft.com/en-us/library/ms776080.aspx + { + LLCoordGL caret_coord; + LLRect preedit_bounds; + mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL); + + CANDIDATEFORM *const form = (CANDIDATEFORM *)param; + DWORD const dwIndex = form->dwIndex; + fillCandidateForm(caret_coord, preedit_bounds, form); + form->dwIndex = dwIndex; + + *result = 1; + return TRUE; + } + case IMR_QUERYCHARPOSITION: + { + IMECHARPOSITION *const char_position = (IMECHARPOSITION *)param; + + // char_position->dwCharPos counts in number of + // WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the + // number to getPreeditLocation. + + const LLWString & wtext = mPreeditor->getPreeditString(); + S32 preedit, preedit_length; + mPreeditor->getPreeditRange(&preedit, &preedit_length); + LLCoordGL caret_coord; + LLRect preedit_bounds, text_control; + const S32 position = wstring_wstring_length_from_utf16_length(wtext, preedit, char_position->dwCharPos); + + if (!mPreeditor->getPreeditLocation(position, &caret_coord, &preedit_bounds, &text_control)) + { + LL_WARNS("Window") << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << LL_ENDL; + return FALSE; + } + fillCharPosition(caret_coord, preedit_bounds, text_control, char_position); + + *result = 1; + return TRUE; + } + case IMR_COMPOSITIONFONT: + { + fillCompositionLogfont((LOGFONT *)param); + + *result = 1; + return TRUE; + } + case IMR_RECONVERTSTRING: + { + mPreeditor->resetPreedit(); + const LLWString & wtext = mPreeditor->getPreeditString(); + S32 select, select_length; + mPreeditor->getSelectionRange(&select, &select_length); + + S32 context_offset; + const LLWString context = find_context(wtext, select, select_length, &context_offset); + + RECONVERTSTRING * const reconvert_string = (RECONVERTSTRING *)param; + const U32 size = fillReconvertString(context, select - context_offset, select_length, reconvert_string); + if (reconvert_string) + { + if (select_length == 0) + { + // Let the IME to decide the reconversion range, and + // adjust the reconvert_string structure accordingly. + HIMC himc = LLWinImm::getContext(mWindowHandle); + const BOOL adjusted = LLWinImm::setCompositionString(himc, + SCS_QUERYRECONVERTSTRING, reconvert_string, size, NULL, 0); + LLWinImm::releaseContext(mWindowHandle, himc); + if (adjusted) + { + const llutf16string & text_utf16 = wstring_to_utf16str(context); + const S32 new_preedit_start = reconvert_string->dwCompStrOffset / sizeof(WCHAR); + const S32 new_preedit_end = new_preedit_start + reconvert_string->dwCompStrLen; + select = utf16str_wstring_length(text_utf16, new_preedit_start); + select_length = utf16str_wstring_length(text_utf16, new_preedit_end) - select; + select += context_offset; + } + } + mPreeditor->markAsPreedit(select, select_length); + } + + *result = size; + return TRUE; + } + case IMR_CONFIRMRECONVERTSTRING: + { + *result = FALSE; + return TRUE; + } + case IMR_DOCUMENTFEED: + { + const LLWString & wtext = mPreeditor->getPreeditString(); + S32 preedit, preedit_length; + mPreeditor->getPreeditRange(&preedit, &preedit_length); + + S32 context_offset; + LLWString context = find_context(wtext, preedit, preedit_length, &context_offset); + preedit -= context_offset; + if (preedit_length) + { + // IMR_DOCUMENTFEED may be called when we have an active preedit. + // We should pass the context string *excluding* the preedit string. + // Otherwise, some IME are confused. + context.erase(preedit, preedit_length); + } + + RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)param; + *result = fillReconvertString(context, preedit, 0, reconvert_string); + return TRUE; + } + default: + return FALSE; + } + } + + return FALSE; +} + +//static +std::vector LLWindowWin32::getDynamicFallbackFontList() +{ + // Fonts previously in getFontListSans() have moved to fonts.xml. + return std::vector(); +} + + +#endif // LL_WINDOWS diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index e14324c9f1..1382cf93a2 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -39,6 +39,7 @@ #include #include "llwindow.h" +#include "lldragdropwin32.h" // Hack for async host by name #define LL_WM_HOST_RESOLVED (WM_APP + 1) @@ -112,6 +113,8 @@ public: /*virtual*/ void interruptLanguageTextInput(); /*virtual*/ void spawnWebBrowser(const std::string& escaped_url); + BOOL completeDropRequest( const LLCoordGL gl_coord, const MASK mask, const std::string url ); + static std::vector getDynamicFallbackFontList(); protected: @@ -206,6 +209,8 @@ protected: LLPreeditor *mPreeditor; + LLDragDropWin32* mDragDrop; + friend class LLWindowManager; }; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index a080243086..220f90c2f5 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -817,7 +817,7 @@ BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MAS return TRUE; } -BOOL LLViewerWindow::handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, void* data) +BOOL LLViewerWindow::handleDrop( LLWindow *window, LLCoordGL pos, MASK mask, std::string data ) { if (gSavedSettings.getBOOL("PrimMediaDragNDrop")) { @@ -825,7 +825,7 @@ BOOL LLViewerWindow::handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, voi LLUUID object_id = pick_info.getObjectID(); S32 object_face = pick_info.mObjectFace; - std::string url = std::string( (char*)data ); + std::string url = data; llinfos << "### Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 44704b99e3..cf024df9bf 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -170,7 +170,7 @@ public: /*virtual*/ BOOL handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); - /*virtual*/ BOOL handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, void* data); + /*virtual*/ BOOL handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, std::string data); void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ void handleMouseLeave(LLWindow *window); /*virtual*/ void handleResize(LLWindow *window, S32 x, S32 y); -- cgit v1.2.3 From 66ce1b04297cd48520e666a3fa903af143f89c57 Mon Sep 17 00:00:00 2001 From: callum Date: Mon, 2 Nov 2009 15:05:38 -0800 Subject: Added CMake file for new cpp/h file --- indra/llwindow/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index 7b1cab696f..b4a3f74451 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -102,11 +102,13 @@ if (WINDOWS) llwindowwin32.cpp lldxhardware.cpp llkeyboardwin32.cpp + lldragdropwin32.cpp ) list(APPEND llwindow_HEADER_FILES llwindowwin32.h lldxhardware.h llkeyboardwin32.h + lldragdropwin32.h ) list(APPEND llwindow_LINK_LIBRARIES comdlg32 # Common Dialogs for ChooseColor -- cgit v1.2.3 From 996740607a11ac7f8633f12b65ead0508e1435fa Mon Sep 17 00:00:00 2001 From: callum Date: Tue, 3 Nov 2009 09:33:21 -0800 Subject: Convert screen coordinates from IDropAction to window coordinates. --- indra/llwindow/lldragdropwin32.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/indra/llwindow/lldragdropwin32.cpp b/indra/llwindow/lldragdropwin32.cpp index 0daff85395..d05dbf19a5 100644 --- a/indra/llwindow/lldragdropwin32.cpp +++ b/indra/llwindow/lldragdropwin32.cpp @@ -209,11 +209,18 @@ class LLDragDropWin32Target: LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mWindowHandle, GWL_USERDATA); if (NULL != window_imp) { - LLCoordGL gl_coord( pt.x, pt.y); - LLCoordWindow cursor_coord_window( pt.x, pt.y ); + LLCoordGL gl_coord( 0, 0 ); + + POINT pt2; + pt2.x = pt.x; + pt2.y = pt.y; + ScreenToClient( mWindowHandle, &pt2 ); + + LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); window_imp->convertCoords(cursor_coord_window, &gl_coord); llinfos << "### (Drop) URL is: " << lpszText << llendl; llinfos << "### raw coords are: " << pt.x << " x " << pt.y << llendl; + llinfos << "### window coords are: " << pt2.x << " x " << pt2.y << llendl; llinfos << "### GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << llendl; llinfos << llendl; -- cgit v1.2.3 From 4f0731d722c41b6717d08b8165e941a06edd3a1f Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Thu, 5 Nov 2009 17:51:04 -0800 Subject: make drop add media if not there, navigate if already there --- indra/newview/llviewerwindow.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index b43479689f..ead99613fb 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -831,12 +831,27 @@ BOOL LLViewerWindow::handleDrop( LLWindow *window, LLCoordGL pos, MASK mask, st LLVOVolume *obj = dynamic_cast(static_cast(pick_info.getObject())); if (obj) { - LLSD media_data; - /// XXX home URL too? - media_data[LLMediaEntry::CURRENT_URL_KEY] = url; - media_data[LLMediaEntry::AUTO_PLAY_KEY] = true; - obj->syncMediaData(object_face, media_data, true, true); - obj->sendMediaDataUpdate(); + LLTextureEntry *te = obj->getTE(object_face); + if (te) + { + if (! te->hasMedia()) + { + // Create new media entry + LLSD media_data; + // XXX Should we really do Home URL too? + media_data[LLMediaEntry::HOME_URL_KEY] = url; + media_data[LLMediaEntry::CURRENT_URL_KEY] = url; + media_data[LLMediaEntry::AUTO_PLAY_KEY] = true; + obj->syncMediaData(object_face, media_data, true, true); + // XXX This shouldn't be necessary, should it ?!? + obj->getMediaImpl(object_face)->navigateReload(); + obj->sendMediaDataUpdate(); + } + else { + // just navigate to the URL + obj->getMediaImpl(object_face)->navigateTo(url); + } + } } } // Always handled as far as the OS is concerned. -- cgit v1.2.3 From bf5ce0fcbd9a71ce1372db0f42395ba47747fd78 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Thu, 12 Nov 2009 11:06:29 -0800 Subject: Change 'handleDrop()' API to 'handleDragNDrop', which now takes a "drop" BOOL --- indra/llwindow/lldragdropwin32.cpp | 18 ++++++++++++++++- indra/llwindow/llwindowcallbacks.cpp | 2 +- indra/llwindow/llwindowcallbacks.h | 2 +- indra/llwindow/llwindowwin32.cpp | 13 ++++-------- indra/llwindow/llwindowwin32.h | 2 +- indra/newview/llviewerwindow.cpp | 39 +++++++++++++++++++++--------------- indra/newview/llviewerwindow.h | 2 +- 7 files changed, 48 insertions(+), 30 deletions(-) diff --git a/indra/llwindow/lldragdropwin32.cpp b/indra/llwindow/lldragdropwin32.cpp index d05dbf19a5..879f2d2b90 100644 --- a/indra/llwindow/lldragdropwin32.cpp +++ b/indra/llwindow/lldragdropwin32.cpp @@ -171,6 +171,22 @@ class LLDragDropWin32Target: STDMETHOD (DragOver)(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) { HRESULT hr = S_OK; + // XXX MAJOR MAJOR HACK! + LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mWindowHandle, GWL_USERDATA); + if (NULL != window_imp) + { + LLCoordGL gl_coord( 0, 0 ); + + POINT pt2; + pt2.x = pt.x; + pt2.y = pt.y; + ScreenToClient( mWindowHandle, &pt2 ); + + LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); + window_imp->convertCoords(cursor_coord_window, &gl_coord); + MASK mask = gKeyboard->currentMask(TRUE); + bDropTargetValid = window_imp->completeDragNDropRequest( gl_coord, mask, FALSE, std::string( "" ) ); + } if (bDropTargetValid) *pdwEffect=DROPEFFECT_COPY; @@ -225,7 +241,7 @@ class LLDragDropWin32Target: llinfos << llendl; MASK mask = gKeyboard->currentMask(TRUE); - window_imp->completeDropRequest( gl_coord, mask, std::string( lpszText ) ); + window_imp->completeDragNDropRequest( gl_coord, mask, TRUE, std::string( lpszText ) ); }; GlobalUnlock(hText); diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index 1098529e1c..b8927a1ac4 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -163,7 +163,7 @@ void LLWindowCallbacks::handleDataCopy(LLWindow *window, S32 data_type, void *da { } -BOOL LLWindowCallbacks::handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, std::string data ) +BOOL LLWindowCallbacks::handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data ) { return FALSE; } diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 3a09100168..8e7605a650 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -68,7 +68,7 @@ public: virtual void handleWindowBlock(LLWindow *window); // window is taking over CPU for a while virtual void handleWindowUnblock(LLWindow *window); // window coming back after taking over CPU for a while virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); - virtual BOOL handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, std::string data); + virtual BOOL handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data); virtual BOOL handleTimerEvent(LLWindow *window); virtual BOOL handleDeviceChange(LLWindow *window); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index da096b9a0a..eda8cf15b0 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -2401,7 +2401,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ MASK mask = gKeyboard->currentMask(TRUE); - if ( window_imp->completeDropRequest( gl_coord, mask, (char*)url ) ) + if ( window_imp->completeDragNDropRequest( gl_coord, mask, true, (char*)url ) ) { return 0; }; @@ -3578,15 +3578,10 @@ static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_leng // final stage of handling drop requests - both from WM_DROPFILES message // for files and via IDropTarget interface requests. -BOOL LLWindowWin32::completeDropRequest( const LLCoordGL gl_coord, const MASK mask, const std::string url ) +BOOL LLWindowWin32::completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, BOOL drop, const std::string url ) { - if ( mCallbacks->handleDrop( this, gl_coord, mask, url ) ) - { - return TRUE; - }; - - return FALSE; -}; + return mCallbacks->handleDragNDrop( this, gl_coord, mask, drop, url ); +} // Handle WM_IME_REQUEST message. // If it handled the message, returns TRUE. Otherwise, FALSE. diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 1382cf93a2..e99c26b7f1 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -113,7 +113,7 @@ public: /*virtual*/ void interruptLanguageTextInput(); /*virtual*/ void spawnWebBrowser(const std::string& escaped_url); - BOOL completeDropRequest( const LLCoordGL gl_coord, const MASK mask, const std::string url ); + BOOL completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, BOOL drop, const std::string url ); static std::vector getDynamicFallbackFontList(); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 06d6819b5e..d2f81f21ac 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -819,8 +819,9 @@ BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MAS return TRUE; } -BOOL LLViewerWindow::handleDrop( LLWindow *window, LLCoordGL pos, MASK mask, std::string data ) +BOOL LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data ) { + BOOL result = FALSE; if (gSavedSettings.getBOOL("PrimMediaDragNDrop")) { LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ ); @@ -837,28 +838,34 @@ BOOL LLViewerWindow::handleDrop( LLWindow *window, LLCoordGL pos, MASK mask, st LLTextureEntry *te = obj->getTE(object_face); if (te) { - if (! te->hasMedia()) + if (drop) { - // Create new media entry - LLSD media_data; - // XXX Should we really do Home URL too? - media_data[LLMediaEntry::HOME_URL_KEY] = url; - media_data[LLMediaEntry::CURRENT_URL_KEY] = url; - media_data[LLMediaEntry::AUTO_PLAY_KEY] = true; - obj->syncMediaData(object_face, media_data, true, true); - // XXX This shouldn't be necessary, should it ?!? - obj->getMediaImpl(object_face)->navigateReload(); - obj->sendMediaDataUpdate(); + if (! te->hasMedia()) + { + // Create new media entry + LLSD media_data; + // XXX Should we really do Home URL too? + media_data[LLMediaEntry::HOME_URL_KEY] = url; + media_data[LLMediaEntry::CURRENT_URL_KEY] = url; + media_data[LLMediaEntry::AUTO_PLAY_KEY] = true; + obj->syncMediaData(object_face, media_data, true, true); + // XXX This shouldn't be necessary, should it ?!? + obj->getMediaImpl(object_face)->navigateReload(); + obj->sendMediaDataUpdate(); + } + else { + // just navigate to the URL + obj->getMediaImpl(object_face)->navigateTo(url); + } } else { - // just navigate to the URL - obj->getMediaImpl(object_face)->navigateTo(url); + // XXX TODO: make object glow? Hard because how do we "unglow?" } + result = TRUE; } } } - // Always handled as far as the OS is concerned. - return TRUE; + return result; } BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index cdc9eb4786..d7cfcff925 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -170,7 +170,7 @@ public: /*virtual*/ BOOL handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); - /*virtual*/ BOOL handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, std::string data); + /*virtual*/ BOOL handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data); void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ void handleMouseLeave(LLWindow *window); /*virtual*/ void handleResize(LLWindow *window, S32 x, S32 y); -- cgit v1.2.3 From 778005a350308d51f114ece74b4e7f3e7af3d37e Mon Sep 17 00:00:00 2001 From: callum Date: Fri, 13 Nov 2009 17:43:55 -0800 Subject: Reworked IDropTarget COM interface impl - now much cleaner and doesn't crash! --- indra/llwindow/lldragdropwin32.cpp | 287 +++++++++++++++++-------------------- indra/llwindow/lldragdropwin32.h | 8 +- 2 files changed, 135 insertions(+), 160 deletions(-) diff --git a/indra/llwindow/lldragdropwin32.cpp b/indra/llwindow/lldragdropwin32.cpp index d05dbf19a5..aac68e71af 100644 --- a/indra/llwindow/lldragdropwin32.cpp +++ b/indra/llwindow/lldragdropwin32.cpp @@ -34,216 +34,183 @@ #include "linden_common.h" -#define WIN32_LEAN_AND_MEAN -#include - #include "llwindowwin32.h" #include "llkeyboardwin32.h" -#include "lldragdropwin32.h" - #include "llwindowcallbacks.h" - -#include -#include -#include -#include -#include - -// FIXME: this should be done in CMake -#pragma comment( lib, "shlwapi.lib" ) +#include "lldragdropwin32.h" class LLDragDropWin32Target: public IDropTarget { public: + //////////////////////////////////////////////////////////////////////////////// + // LLDragDropWin32Target( HWND hWnd ) : - mWindowHandle( hWnd ), - mRefCount( 0 ) + mRefCount( 1 ), + mAppWindowHandle( hWnd ), + mAllowDrop( false) { - strcpy(szFileDropped,""); - bDropTargetValid = false; - bTextDropped = false; }; - /* IUnknown methods */ - STDMETHOD_( ULONG, AddRef )( void ) + //////////////////////////////////////////////////////////////////////////////// + // + ULONG __stdcall AddRef( void ) { - return ++mRefCount; + return InterlockedIncrement( &mRefCount ); }; - STDMETHOD_( ULONG, Release )( void ) + //////////////////////////////////////////////////////////////////////////////// + // + ULONG __stdcall Release( void ) { - if ( --mRefCount == 0 ) + LONG count = InterlockedDecrement( &mRefCount ); + + if ( count == 0 ) { delete this; return 0; } - return mRefCount; + else + { + return count; + }; }; - STDMETHOD ( QueryInterface )( REFIID iid, void ** ppvObject ) + //////////////////////////////////////////////////////////////////////////////// + // + HRESULT __stdcall QueryInterface( REFIID iid, void** ppvObject ) { if ( iid == IID_IUnknown || iid == IID_IDropTarget ) { - *ppvObject = this; AddRef(); + *ppvObject = this; return S_OK; + } + else + { + *ppvObject = 0; + return E_NOINTERFACE; }; - - *ppvObject = NULL; - return E_NOINTERFACE; }; - - /* IDropTarget methods */ - STDMETHOD (DragEnter)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) + + //////////////////////////////////////////////////////////////////////////////// + // + HRESULT __stdcall DragEnter( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ) { - HRESULT hr = E_INVALIDARG; - bDropTargetValid = false; - bTextDropped = false; - *pdwEffect=DROPEFFECT_NONE; - - FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; - STGMEDIUM medium; - - if (pDataObj && SUCCEEDED (pDataObj->GetData (&fmte, &medium))) - { - // We can Handle Only one File At a time !!! - if (1 == DragQueryFile ((HDROP)medium.hGlobal,0xFFFFFFFF,NULL,0 )) - { - // Get the File Name - if (DragQueryFileA((HDROP)medium.hGlobal, 0, szFileDropped,MAX_PATH)) - { - if (!PathIsDirectoryA(szFileDropped)) - { - char szTempFile[MAX_PATH]; - _splitpath(szFileDropped,NULL,NULL,NULL,szTempFile); - -// if (!stricmp(szTempFile,".lnk")) -// { -// if (ResolveLink(szFileDropped,szTempFile)) -// { -// strcpy(szFileDropped,szTempFile); -// *pdwEffect=DROPEFFECT_COPY; -// We Want to Create a Copy -// bDropTargetValid = true; -// hr = S_OK; -// } -// } -// else -// { - *pdwEffect=DROPEFFECT_COPY; - //We Want to Create a Copy - bDropTargetValid = true; - hr = S_OK; -// } - } - } - } - - if (medium.pUnkForRelease) - medium.pUnkForRelease->Release (); - else - GlobalFree (medium.hGlobal); - } - else + FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + + // support CF_TEXT using a HGLOBAL? + if ( S_OK == pDataObject->QueryGetData( &fmtetc ) ) { - fmte.cfFormat = CF_TEXT; - fmte.ptd = NULL; - fmte.dwAspect = DVASPECT_CONTENT; - fmte.lindex = -1; - fmte.tymed = TYMED_HGLOBAL; - - // Does the drag source provide CF_TEXT ? - if (NOERROR == pDataObj->QueryGetData(&fmte)) - { - bDropTargetValid = true; - bTextDropped = true; - *pdwEffect=DROPEFFECT_COPY; - hr = S_OK; - } - } - return hr; + mAllowDrop = true; + *pdwEffect = DROPEFFECT_COPY; + SetFocus( mAppWindowHandle ); + } + else + { + mAllowDrop = false; + *pdwEffect = DROPEFFECT_NONE; + }; + return S_OK; }; - STDMETHOD (DragOver)(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) + //////////////////////////////////////////////////////////////////////////////// + // + HRESULT __stdcall DragOver( DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ) { - HRESULT hr = S_OK; - if (bDropTargetValid) - *pdwEffect=DROPEFFECT_COPY; + if ( mAllowDrop ) + { + *pdwEffect = DROPEFFECT_COPY; + } + else + { + *pdwEffect = DROPEFFECT_NONE; + }; - return hr; + return S_OK; }; - STDMETHOD (DragLeave)(void) + //////////////////////////////////////////////////////////////////////////////// + // + HRESULT __stdcall DragLeave( void ) { - HRESULT hr = S_OK; - strcpy(szFileDropped,""); - return hr; + return S_OK; }; - STDMETHOD (Drop)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) + //////////////////////////////////////////////////////////////////////////////// + // + HRESULT __stdcall Drop( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ) { - HRESULT hr = S_OK; - if (bDropTargetValid) + if ( mAllowDrop ) { - *pdwEffect=DROPEFFECT_COPY; - - FORMATETC fmte; - STGMEDIUM medium; + // construct a FORMATETC object + FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - if (bTextDropped) + // do we have text? + if( S_OK == pDataObject->QueryGetData( &fmtetc ) ) { - fmte.cfFormat = CF_TEXT; - fmte.ptd = NULL; - fmte.dwAspect = DVASPECT_CONTENT; - fmte.lindex = -1; - fmte.tymed = TYMED_HGLOBAL; - - hr = pDataObj->GetData(&fmte, &medium); - HGLOBAL hText = medium.hGlobal; - LPSTR lpszText = (LPSTR)GlobalLock(hText); - - LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mWindowHandle, GWL_USERDATA); - if (NULL != window_imp) + STGMEDIUM stgmed; + if( S_OK == pDataObject->GetData( &fmtetc, &stgmed ) ) { - LLCoordGL gl_coord( 0, 0 ); - - POINT pt2; - pt2.x = pt.x; - pt2.y = pt.y; - ScreenToClient( mWindowHandle, &pt2 ); - - LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); - window_imp->convertCoords(cursor_coord_window, &gl_coord); - llinfos << "### (Drop) URL is: " << lpszText << llendl; - llinfos << "### raw coords are: " << pt.x << " x " << pt.y << llendl; - llinfos << "### window coords are: " << pt2.x << " x " << pt2.y << llendl; - llinfos << "### GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << llendl; - llinfos << llendl; - - MASK mask = gKeyboard->currentMask(TRUE); - window_imp->completeDropRequest( gl_coord, mask, std::string( lpszText ) ); + // note: data is in an HGLOBAL - not 'regular' memory + PVOID data = GlobalLock( stgmed.hGlobal ); + + // window impl stored in Window data (neat!) + LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong( mAppWindowHandle, GWL_USERDATA ); + if ( NULL != window_imp ) + { + LLCoordGL gl_coord( 0, 0 ); + + POINT pt_client; + pt_client.x = pt.x; + pt_client.y = pt.y; + ScreenToClient( mAppWindowHandle, &pt_client ); + + LLCoordWindow cursor_coord_window( pt_client.x, pt_client.y ); + window_imp->convertCoords(cursor_coord_window, &gl_coord); + llinfos << "### (Drop) URL is: " << data << llendl; + llinfos << "### raw coords are: " << pt.x << " x " << pt.y << llendl; + llinfos << "### client coords are: " << pt_client.x << " x " << pt_client.y << llendl; + llinfos << "### GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << llendl; + llinfos << llendl; + + // no keyboard modifier option yet but we could one day + MASK mask = gKeyboard->currentMask( TRUE ); + + // actually do the drop + window_imp->completeDropRequest( gl_coord, mask, std::string( (char*)data ) ); + }; + + GlobalUnlock( stgmed.hGlobal ); + + ReleaseStgMedium( &stgmed ); }; + }; - GlobalUnlock(hText); - ReleaseStgMedium(&medium); - } + *pdwEffect = DROPEFFECT_COPY; } - return hr; + else + { + *pdwEffect = DROPEFFECT_NONE; + }; + + return S_OK; }; - + + //////////////////////////////////////////////////////////////////////////////// + // private: - ULONG mRefCount; - HWND mWindowHandle; - char szFileDropped[1024]; - bool bDropTargetValid; - bool bTextDropped; + LONG mRefCount; + HWND mAppWindowHandle; + bool mAllowDrop; friend class LLWindowWin32; }; +//////////////////////////////////////////////////////////////////////////////// +// LLDragDropWin32::LLDragDropWin32() : mDropTarget( NULL ), mDropWindowHandle( NULL ) @@ -251,19 +218,23 @@ LLDragDropWin32::LLDragDropWin32() : { } +//////////////////////////////////////////////////////////////////////////////// +// LLDragDropWin32::~LLDragDropWin32() { } +//////////////////////////////////////////////////////////////////////////////// +// bool LLDragDropWin32::init( HWND hWnd ) { - if (NOERROR != OleInitialize(NULL)) + if ( NOERROR != OleInitialize( NULL ) ) return FALSE; mDropTarget = new LLDragDropWin32Target( hWnd ); if ( mDropTarget ) { - HRESULT result = CoLockObjectExternal( mDropTarget, TRUE, TRUE ); + HRESULT result = CoLockObjectExternal( mDropTarget, TRUE, FALSE ); if ( S_OK == result ) { result = RegisterDragDrop( hWnd, mDropTarget ); @@ -287,12 +258,14 @@ bool LLDragDropWin32::init( HWND hWnd ) return true; } +//////////////////////////////////////////////////////////////////////////////// +// void LLDragDropWin32::reset() { if ( mDropTarget ) { - CoLockObjectExternal( mDropTarget, FALSE, TRUE ); RevokeDragDrop( mDropWindowHandle ); + CoLockObjectExternal( mDropTarget, FALSE, TRUE ); mDropTarget->Release(); }; diff --git a/indra/llwindow/lldragdropwin32.h b/indra/llwindow/lldragdropwin32.h index 6137e5eb65..624f4ad24b 100644 --- a/indra/llwindow/lldragdropwin32.h +++ b/indra/llwindow/lldragdropwin32.h @@ -33,10 +33,10 @@ #ifndef LL_LLDRAGDROP32_H #define LL_LLDRAGDROP32_H +#if LL_WINDOWS + #include #include -#include -#include class LLDragDropWin32 { @@ -52,4 +52,6 @@ class LLDragDropWin32 HWND mDropWindowHandle; }; -#endif +#endif // LL_WINDOWS + +#endif // LL_LLDRAGDROP32_H -- cgit v1.2.3 From 4419e367bcbe8c1b248e88eab8096f0b8ac4707c Mon Sep 17 00:00:00 2001 From: callum Date: Wed, 18 Nov 2009 21:15:44 -0800 Subject: Add support for removing the Windows specific drag/drop code from the codebase via a new CMake file (DragDrop.cmake). --- indra/cmake/DragDrop.cmake | 25 +++++++++++++++++++++++++ indra/llwindow/CMakeLists.txt | 1 + indra/llwindow/lldragdropwin32.cpp | 7 ++++++- indra/llwindow/lldragdropwin32.h | 29 ++++++++++++++++++++++++++--- indra/newview/CMakeLists.txt | 1 + 5 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 indra/cmake/DragDrop.cmake diff --git a/indra/cmake/DragDrop.cmake b/indra/cmake/DragDrop.cmake new file mode 100644 index 0000000000..a2d7df1312 --- /dev/null +++ b/indra/cmake/DragDrop.cmake @@ -0,0 +1,25 @@ +# -*- cmake -*- + +if (VIEWER) + + OPTION (OS_DRAG_DROP + "Build the viewer with OS level drag and drop turned on or off" + OFF) + + if (OS_DRAG_DROP) + + if (WINDOWS) + add_definitions(-DLL_OS_DRAGDROP_ENABLED=1) + endif (WINDOWS) + + if (DARWIN) + add_definitions(-DLL_OS_DRAGDROP_ENABLED=0) + endif (DARWIN) + + if (LINUX) + add_definitions(-DLL_OS_DRAGDROP_ENABLED=0) + endif (LINUX) + + endif (OS_DRAG_DROP) + +endif (VIEWER) diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index b4a3f74451..77c6fa57b6 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -12,6 +12,7 @@ project(llwindow) include(00-Common) include(DirectX) +include(DragDrop) include(LLCommon) include(LLImage) include(LLMath) diff --git a/indra/llwindow/lldragdropwin32.cpp b/indra/llwindow/lldragdropwin32.cpp index aac68e71af..471c88675d 100644 --- a/indra/llwindow/lldragdropwin32.cpp +++ b/indra/llwindow/lldragdropwin32.cpp @@ -32,6 +32,8 @@ #if LL_WINDOWS +#if LL_OS_DRAGDROP_ENABLED + #include "linden_common.h" #include "llwindowwin32.h" @@ -272,4 +274,7 @@ void LLDragDropWin32::reset() OleUninitialize(); } -#endif +#endif // LL_OS_DRAGDROP_ENABLED + +#endif // LL_WINDOWS + diff --git a/indra/llwindow/lldragdropwin32.h b/indra/llwindow/lldragdropwin32.h index 624f4ad24b..26c8e4aeff 100644 --- a/indra/llwindow/lldragdropwin32.h +++ b/indra/llwindow/lldragdropwin32.h @@ -30,11 +30,13 @@ * $/LicenseInfo$ */ +#if LL_WINDOWS + +#if LL_OS_DRAGDROP_ENABLED + #ifndef LL_LLDRAGDROP32_H #define LL_LLDRAGDROP32_H -#if LL_WINDOWS - #include #include @@ -51,7 +53,28 @@ class LLDragDropWin32 IDropTarget* mDropTarget; HWND mDropWindowHandle; }; +#endif // LL_LLDRAGDROP32_H -#endif // LL_WINDOWS +#else // LL_OS_DRAGDROP_ENABLED +#ifndef LL_LLDRAGDROP32_H +#define LL_LLDRAGDROP32_H + +#include +#include + +// imposter class that does nothing +class LLDragDropWin32 +{ + public: + LLDragDropWin32() {}; + ~LLDragDropWin32() {}; + + bool init( HWND hWnd ) { return false; }; + void reset() { }; +}; #endif // LL_LLDRAGDROP32_H + +#endif // LL_OS_DRAGDROP_ENABLED + +#endif // LL_WINDOWS diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b129bca1f3..352e9a9382 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -7,6 +7,7 @@ include(Boost) include(BuildVersion) include(DBusGlib) include(DirectX) +include(DragDrop) include(ELFIO) include(FMOD) include(OPENAL) -- cgit v1.2.3 From 9e53ad6111ce0e15cb10f2ffb47fee8b48d1c3db Mon Sep 17 00:00:00 2001 From: callum Date: Wed, 18 Nov 2009 21:17:39 -0800 Subject: Doh! Update the CMake file that controls drag and drop to turn it ON --- indra/cmake/DragDrop.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/cmake/DragDrop.cmake b/indra/cmake/DragDrop.cmake index a2d7df1312..739d011813 100644 --- a/indra/cmake/DragDrop.cmake +++ b/indra/cmake/DragDrop.cmake @@ -4,7 +4,7 @@ if (VIEWER) OPTION (OS_DRAG_DROP "Build the viewer with OS level drag and drop turned on or off" - OFF) + ON) if (OS_DRAG_DROP) -- cgit v1.2.3 From d4ba73ed721fa0811474fc53300f560539d38018 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Thu, 19 Nov 2009 09:24:26 -0800 Subject: Fix merge error --- indra/llwindow/lldragdropwin32.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/indra/llwindow/lldragdropwin32.cpp b/indra/llwindow/lldragdropwin32.cpp index 4fc64f2f69..b39cd83698 100644 --- a/indra/llwindow/lldragdropwin32.cpp +++ b/indra/llwindow/lldragdropwin32.cpp @@ -124,7 +124,7 @@ class LLDragDropWin32Target: if ( mAllowDrop ) { // XXX MAJOR MAJOR HACK! - LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mWindowHandle, GWL_USERDATA); + LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mAppWindowHandle, GWL_USERDATA); if (NULL != window_imp) { LLCoordGL gl_coord( 0, 0 ); @@ -132,12 +132,12 @@ class LLDragDropWin32Target: POINT pt2; pt2.x = pt.x; pt2.y = pt.y; - ScreenToClient( mWindowHandle, &pt2 ); + ScreenToClient( mAppWindowHandle, &pt2 ); LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); window_imp->convertCoords(cursor_coord_window, &gl_coord); MASK mask = gKeyboard->currentMask(TRUE); - bDropTargetValid = window_imp->completeDragNDropRequest( gl_coord, mask, FALSE, std::string( "" ) ); + window_imp->completeDragNDropRequest( gl_coord, mask, FALSE, std::string( "" ) ); } *pdwEffect = DROPEFFECT_COPY; } -- cgit v1.2.3 From dbe1f9755896e41e2064a3ee69725d753c67921f Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Mon, 23 Nov 2009 17:18:54 -0800 Subject: Highlight the object if it is being dragged over and can be dropped upon --- indra/newview/llviewerwindow.cpp | 10 ++++++++-- indra/newview/llviewerwindow.h | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 55e66e1138..17b9490f63 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -833,7 +833,8 @@ BOOL LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mas llinfos << "### Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; LLVOVolume *obj = dynamic_cast(static_cast(pick_info.getObject())); - if (obj) + gPipeline.setHighlightObject(NULL); + if (obj && obj->permModify()) { LLTextureEntry *te = obj->getTE(object_face); if (te) @@ -859,11 +860,16 @@ BOOL LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mas } } else { - // XXX TODO: make object glow? Hard because how do we "unglow?" + mDragHoveredObject = obj; + // Make the object glow + gPipeline.setHighlightObject(mDragHoveredObject->mDrawable); } result = TRUE; } } + else { + mDragHoveredObject = NULL; + } } return result; } diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 311fea3508..428c602b73 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -474,6 +474,9 @@ protected: static std::string sSnapshotDir; static std::string sMovieBaseName; + +private: + LLPointer mDragHoveredObject; }; void toggle_flying(void*); -- cgit v1.2.3 From 8d84b7ae4062d8680aae2bb8325813bdac0335ed Mon Sep 17 00:00:00 2001 From: callum Date: Tue, 24 Nov 2009 18:31:30 -0800 Subject: Add support for changing OS cursor when mouse passes over a prim you can drop on versus one you can't. --- indra/llwindow/lldragdropwin32.cpp | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/indra/llwindow/lldragdropwin32.cpp b/indra/llwindow/lldragdropwin32.cpp index a10cfbf12f..6024931092 100644 --- a/indra/llwindow/lldragdropwin32.cpp +++ b/indra/llwindow/lldragdropwin32.cpp @@ -125,23 +125,29 @@ class LLDragDropWin32Target: { if ( mAllowDrop ) { - // XXX MAJOR MAJOR HACK! - LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mAppWindowHandle, GWL_USERDATA); - if (NULL != window_imp) - { - LLCoordGL gl_coord( 0, 0 ); - - POINT pt2; - pt2.x = pt.x; - pt2.y = pt.y; - ScreenToClient( mAppWindowHandle, &pt2 ); + bool allowed_to_drop = false; - LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); - window_imp->convertCoords(cursor_coord_window, &gl_coord); - MASK mask = gKeyboard->currentMask(TRUE); - window_imp->completeDragNDropRequest( gl_coord, mask, FALSE, std::string( "" ) ); - } - *pdwEffect = DROPEFFECT_COPY; + // XXX MAJOR MAJOR HACK! + LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mAppWindowHandle, GWL_USERDATA); + if (NULL != window_imp) + { + LLCoordGL gl_coord( 0, 0 ); + + POINT pt2; + pt2.x = pt.x; + pt2.y = pt.y; + ScreenToClient( mAppWindowHandle, &pt2 ); + + LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); + window_imp->convertCoords(cursor_coord_window, &gl_coord); + MASK mask = gKeyboard->currentMask(TRUE); + allowed_to_drop = window_imp->completeDragNDropRequest( gl_coord, mask, FALSE, std::string( "" ) ); + } + + if ( allowed_to_drop ) + *pdwEffect = DROPEFFECT_COPY; + else + *pdwEffect = DROPEFFECT_NONE; } else { -- cgit v1.2.3 From e2e7d544b6a114e70e3b46f516a4f0e8d7db4bd1 Mon Sep 17 00:00:00 2001 From: callum Date: Tue, 24 Nov 2009 20:20:53 -0800 Subject: Added support for dropping SURLs onto viewer Does right thing when logged in - needs some work at login page Removed (commented out) WM_DROPFILES code for now --- indra/llwindow/lldragdropwin32.cpp | 103 ++++++++++++++++++---------------- indra/llwindow/llwindowcallbacks.cpp | 2 +- indra/llwindow/llwindowcallbacks.h | 2 +- indra/llwindow/llwindowwin32.cpp | 105 ++++++++++++++++++----------------- indra/llwindow/llwindowwin32.h | 2 +- indra/newview/llviewerwindow.cpp | 10 +++- indra/newview/llviewerwindow.h | 2 +- 7 files changed, 121 insertions(+), 105 deletions(-) diff --git a/indra/llwindow/lldragdropwin32.cpp b/indra/llwindow/lldragdropwin32.cpp index 6024931092..74f96f6da3 100644 --- a/indra/llwindow/lldragdropwin32.cpp +++ b/indra/llwindow/lldragdropwin32.cpp @@ -54,6 +54,10 @@ class LLDragDropWin32Target: { }; + virtual ~LLDragDropWin32Target() + { + }; + //////////////////////////////////////////////////////////////////////////////// // ULONG __stdcall AddRef( void ) @@ -105,6 +109,20 @@ class LLDragDropWin32Target: if ( S_OK == pDataObject->QueryGetData( &fmtetc ) ) { mAllowDrop = true; + mDropUrl = std::string(); + mIsSlurl = false; + + STGMEDIUM stgmed; + if( S_OK == pDataObject->GetData( &fmtetc, &stgmed ) ) + { + PVOID data = GlobalLock( stgmed.hGlobal ); + mDropUrl = std::string( (char*)data ); + + mIsSlurl = ( mDropUrl.find( "slurl.com" ) != std::string::npos ); + + GlobalUnlock( stgmed.hGlobal ); + ReleaseStgMedium( &stgmed ); + }; *pdwEffect = DROPEFFECT_COPY; @@ -125,8 +143,6 @@ class LLDragDropWin32Target: { if ( mAllowDrop ) { - bool allowed_to_drop = false; - // XXX MAJOR MAJOR HACK! LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mAppWindowHandle, GWL_USERDATA); if (NULL != window_imp) @@ -141,13 +157,17 @@ class LLDragDropWin32Target: LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); window_imp->convertCoords(cursor_coord_window, &gl_coord); MASK mask = gKeyboard->currentMask(TRUE); - allowed_to_drop = window_imp->completeDragNDropRequest( gl_coord, mask, FALSE, std::string( "" ) ); - } - if ( allowed_to_drop ) - *pdwEffect = DROPEFFECT_COPY; - else - *pdwEffect = DROPEFFECT_NONE; + bool allowed_to_drop = window_imp->completeDragNDropRequest( gl_coord, mask, FALSE, std::string( "" ), mIsSlurl ); + if ( allowed_to_drop ) + *pdwEffect = DROPEFFECT_COPY; + else + *pdwEffect = DROPEFFECT_NONE; + + // special case for SLURLs - you can always drop them on the client window and we need a different cursor + if ( mIsSlurl ) + *pdwEffect = DROPEFFECT_LINK; + }; } else { @@ -161,6 +181,7 @@ class LLDragDropWin32Target: // HRESULT __stdcall DragLeave( void ) { + mDropUrl = std::string(); return S_OK; }; @@ -170,48 +191,30 @@ class LLDragDropWin32Target: { if ( mAllowDrop ) { - // construct a FORMATETC object - FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - - // do we have text? - if( S_OK == pDataObject->QueryGetData( &fmtetc ) ) + // window impl stored in Window data (neat!) + LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong( mAppWindowHandle, GWL_USERDATA ); + if ( NULL != window_imp ) { - STGMEDIUM stgmed; - if( S_OK == pDataObject->GetData( &fmtetc, &stgmed ) ) - { - // note: data is in an HGLOBAL - not 'regular' memory - PVOID data = GlobalLock( stgmed.hGlobal ); - - // window impl stored in Window data (neat!) - LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong( mAppWindowHandle, GWL_USERDATA ); - if ( NULL != window_imp ) - { - LLCoordGL gl_coord( 0, 0 ); - - POINT pt_client; - pt_client.x = pt.x; - pt_client.y = pt.y; - ScreenToClient( mAppWindowHandle, &pt_client ); - - LLCoordWindow cursor_coord_window( pt_client.x, pt_client.y ); - window_imp->convertCoords(cursor_coord_window, &gl_coord); - llinfos << "### (Drop) URL is: " << data << llendl; - llinfos << "### raw coords are: " << pt.x << " x " << pt.y << llendl; - llinfos << "### client coords are: " << pt_client.x << " x " << pt_client.y << llendl; - llinfos << "### GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << llendl; - llinfos << llendl; - - // no keyboard modifier option yet but we could one day - MASK mask = gKeyboard->currentMask( TRUE ); - - // actually do the drop - window_imp->completeDragNDropRequest( gl_coord, mask, TRUE, std::string( (char*)data ) ); - }; - - GlobalUnlock( stgmed.hGlobal ); - - ReleaseStgMedium( &stgmed ); - }; + LLCoordGL gl_coord( 0, 0 ); + + POINT pt_client; + pt_client.x = pt.x; + pt_client.y = pt.y; + ScreenToClient( mAppWindowHandle, &pt_client ); + + LLCoordWindow cursor_coord_window( pt_client.x, pt_client.y ); + window_imp->convertCoords(cursor_coord_window, &gl_coord); + llinfos << "### (Drop) URL is: " << mDropUrl << llendl; + llinfos << "### raw coords are: " << pt.x << " x " << pt.y << llendl; + llinfos << "### client coords are: " << pt_client.x << " x " << pt_client.y << llendl; + llinfos << "### GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << llendl; + llinfos << llendl; + + // no keyboard modifier option yet but we could one day + MASK mask = gKeyboard->currentMask( TRUE ); + + // actually do the drop + window_imp->completeDragNDropRequest( gl_coord, mask, TRUE, mDropUrl, mIsSlurl ); }; *pdwEffect = DROPEFFECT_COPY; @@ -230,6 +233,8 @@ class LLDragDropWin32Target: LONG mRefCount; HWND mAppWindowHandle; bool mAllowDrop; + std::string mDropUrl; + bool mIsSlurl; friend class LLWindowWin32; }; diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index b8927a1ac4..3b0aeeab1f 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -163,7 +163,7 @@ void LLWindowCallbacks::handleDataCopy(LLWindow *window, S32 data_type, void *da { } -BOOL LLWindowCallbacks::handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data ) +BOOL LLWindowCallbacks::handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data, BOOL is_slurl ) { return FALSE; } diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 8e7605a650..1b4a6cbda2 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -68,7 +68,7 @@ public: virtual void handleWindowBlock(LLWindow *window); // window is taking over CPU for a while virtual void handleWindowUnblock(LLWindow *window); // window coming back after taking over CPU for a while virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); - virtual BOOL handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data); + virtual BOOL handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data, BOOL is_slurl); virtual BOOL handleTimerEvent(LLWindow *window); virtual BOOL handleDeviceChange(LLWindow *window); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index eda8cf15b0..78bc3b9c58 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -2355,57 +2355,60 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ }; return 0; - case WM_DROPFILES: - { - // HDROP contains what we need - HDROP hdrop = (HDROP)w_param; - - // get location in window space where drop occured and convert to OpenGL coordinate space - POINT pt; - DragQueryPoint( hdrop, &pt ); - LLCoordGL gl_coord; - LLCoordWindow cursor_coord_window( pt.x, pt.y ); - window_imp->convertCoords(cursor_coord_window, &gl_coord); - - // get payload (eventually, this needs to more advanced and grab size of payload dynamically - static char file_name[ 1024 ]; - DragQueryFileA( hdrop, 0, file_name, 1024 ); - void* url = (void*)( file_name ); - - // if it's a .URL or .lnk ("shortcut") file - if ( std::string( file_name ).find( ".lnk" ) != std::string::npos || - std::string( file_name ).find( ".URL" ) != std::string::npos ) - { - // read through file - looks like a 2 line file with second line URL= but who knows.. - std::ifstream file_handle( file_name ); - if ( file_handle.is_open() ) - { - std::string line; - while ( ! file_handle.eof() ) - { - std::getline( file_handle, line ); - if ( ! file_handle.eof() ) - { - std::string prefix( "URL=" ); - if ( line.find( prefix, 0 ) != std::string::npos ) - { - line = line.substr( 4 ); // skip off the URL= bit - strcpy( (char*)url, line.c_str() ); - break; - }; - }; - }; - file_handle.close(); - }; - }; + // only useful for droppnig files - could be used for file upload dialog one day + //case WM_DROPFILES: + // { + // // HDROP contains what we need + // HDROP hdrop = (HDROP)w_param; + + // // get location in window space where drop occured and convert to OpenGL coordinate space + // POINT pt; + // DragQueryPoint( hdrop, &pt ); + // LLCoordGL gl_coord; + // LLCoordWindow cursor_coord_window( pt.x, pt.y ); + // window_imp->convertCoords(cursor_coord_window, &gl_coord); + + // // get payload (eventually, this needs to more advanced and grab size of payload dynamically + // static char file_name[ 1024 ]; + // DragQueryFileA( hdrop, 0, file_name, 1024 ); + // void* url = (void*)( file_name ); + + // // if it's a .URL or .lnk ("shortcut") file + // if ( std::string( file_name ).find( ".lnk" ) != std::string::npos || + // std::string( file_name ).find( ".URL" ) != std::string::npos ) + // { + // // read through file - looks like a 2 line file with second line URL= but who knows.. + // std::ifstream file_handle( file_name ); + // if ( file_handle.is_open() ) + // { + // std::string line; + // while ( ! file_handle.eof() ) + // { + // std::getline( file_handle, line ); + // if ( ! file_handle.eof() ) + // { + // std::string prefix( "URL=" ); + // if ( line.find( prefix, 0 ) != std::string::npos ) + // { + // line = line.substr( 4 ); // skip off the URL= bit + // strcpy( (char*)url, line.c_str() ); + // break; + // }; + // }; + // }; + // file_handle.close(); + // }; + // }; + + // MASK mask = gKeyboard->currentMask(TRUE); + + // if ( window_imp->completeDragNDropRequest( gl_coord, mask, true, (char*)url, false ) ) + // { + // return 0; + // }; + // } - MASK mask = gKeyboard->currentMask(TRUE); - if ( window_imp->completeDragNDropRequest( gl_coord, mask, true, (char*)url ) ) - { - return 0; - }; - } break; } @@ -3578,9 +3581,9 @@ static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_leng // final stage of handling drop requests - both from WM_DROPFILES message // for files and via IDropTarget interface requests. -BOOL LLWindowWin32::completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, BOOL drop, const std::string url ) +BOOL LLWindowWin32::completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, BOOL drop, const std::string url, BOOL is_slurl ) { - return mCallbacks->handleDragNDrop( this, gl_coord, mask, drop, url ); + return mCallbacks->handleDragNDrop( this, gl_coord, mask, drop, url, is_slurl ); } // Handle WM_IME_REQUEST message. diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index e99c26b7f1..7f7acd5751 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -113,7 +113,7 @@ public: /*virtual*/ void interruptLanguageTextInput(); /*virtual*/ void spawnWebBrowser(const std::string& escaped_url); - BOOL completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, BOOL drop, const std::string url ); + BOOL completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, BOOL drop, const std::string url, BOOL is_slurl ); static std::vector getDynamicFallbackFontList(); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 17b9490f63..dd84140d5b 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -80,6 +80,7 @@ #include "llviewermenu.h" #include "lltooltip.h" #include "llmediaentry.h" +#include "llurldispatcher.h" // newview includes #include "llagent.h" @@ -819,11 +820,18 @@ BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MAS return TRUE; } -BOOL LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data ) +BOOL LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data, BOOL slurl ) { BOOL result = FALSE; if (gSavedSettings.getBOOL("PrimMediaDragNDrop")) { + // special case SLURLs + if ( slurl ) + { + LLURLDispatcher::dispatch( data, NULL, true ); + return TRUE; + }; + LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ ); LLUUID object_id = pick_info.getObjectID(); diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 428c602b73..4296495067 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -170,7 +170,7 @@ public: /*virtual*/ BOOL handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); - /*virtual*/ BOOL handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data); + /*virtual*/ BOOL handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data, BOOL slurl); void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ void handleMouseLeave(LLWindow *window); /*virtual*/ void handleResize(LLWindow *window, S32 x, S32 y); -- cgit v1.2.3 From 97af20b4ba4a400569e99a616fc026190d3eec6c Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Wed, 25 Nov 2009 09:52:20 -0800 Subject: Change drag highlighting to use LLSelectMgr::{un}highlightObjectOnly() instead of gPipeline.setHighlightObject(). The latter seems a little buggy. --- indra/newview/llviewerwindow.cpp | 14 ++++++++++---- indra/newview/llviewerwindow.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 17b9490f63..cc74c1fbe2 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -833,7 +833,7 @@ BOOL LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mas llinfos << "### Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; LLVOVolume *obj = dynamic_cast(static_cast(pick_info.getObject())); - gPipeline.setHighlightObject(NULL); + if (obj && obj->permModify()) { LLTextureEntry *te = obj->getTE(object_face); @@ -858,19 +858,25 @@ BOOL LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mas // just navigate to the URL obj->getMediaImpl(object_face)->navigateTo(url); } + LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); + mDragHoveredObject = NULL; } else { mDragHoveredObject = obj; - // Make the object glow - gPipeline.setHighlightObject(mDragHoveredObject->mDrawable); + // Highlight the dragged object + LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject); } result = TRUE; } } - else { + + if (!result && !mDragHoveredObject.isNull()) + { + LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); mDragHoveredObject = NULL; } } + return result; } diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 428c602b73..c3aa1b2407 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -476,6 +476,7 @@ protected: static std::string sMovieBaseName; private: + // Object temporarily hovered over while dragging LLPointer mDragHoveredObject; }; -- cgit v1.2.3 From e0a7b7608f087b7d3a4b91ba7868e0a5c04aaa86 Mon Sep 17 00:00:00 2001 From: callum Date: Mon, 30 Nov 2009 20:19:39 -0800 Subject: Add support for dropping a region SLURL on login page and populating the UI --- indra/newview/llpanellogin.cpp | 15 +++++++++++++++ indra/newview/llpanellogin.h | 3 ++- indra/newview/llviewerwindow.cpp | 6 +++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index d2a17dbd97..ba3782bf53 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -682,6 +682,21 @@ void LLPanelLogin::refreshLocation( bool force_visible ) #endif } +// static +void LLPanelLogin::updateLocationUI() +{ + std::string sim_string = LLURLSimString::sInstance.mSimString; + if (!sim_string.empty()) + { + // Replace "" with this region name + LLComboBox* combo = sInstance->getChild("start_location_combo"); + combo->remove(2); + combo->add( sim_string ); + combo->setTextEntry(sim_string); + combo->setCurrentByIndex( 2 ); + } +} + // static void LLPanelLogin::closePanel() { diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index acb2001c22..8f24450c08 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -70,6 +70,7 @@ public: static void addServer(const std::string& server, S32 domain_name); static void refreshLocation( bool force_visible ); + static void updateLocationUI(); static void getFields(std::string *firstname, std::string *lastname, std::string *password); @@ -99,7 +100,7 @@ private: static void onPassKey(LLLineEditor* caller, void* user_data); static void onSelectServer(LLUICtrl*, void*); static void onServerComboLostFocus(LLFocusableElement*); - + private: LLPointer mLogoImage; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index f953a45890..31b30344be 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -50,6 +50,7 @@ #include "llviewquery.h" #include "llxmltree.h" +#include "llslurl.h" //#include "llviewercamera.h" #include "llrender.h" @@ -828,9 +829,12 @@ BOOL LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mas if (gSavedSettings.getBOOL("PrimMediaDragNDrop")) { // special case SLURLs - if ( slurl ) + if ( drop && slurl ) { LLURLDispatcher::dispatch( data, NULL, true ); + LLURLSimString::setString( LLSLURL::stripProtocol( data ) ); + LLPanelLogin::refreshLocation( true ); + LLPanelLogin::updateLocationUI(); return TRUE; }; -- cgit v1.2.3 From c272582ab78d43c595eefb843126c999c09dfd4f Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Thu, 3 Dec 2009 11:48:28 -0800 Subject: Change API to no longer include slurl argument (its a platform-agnostic policy), add some code (not working yet) to implement DND on the mac --- indra/llwindow/llwindowcallbacks.cpp | 4 +- indra/llwindow/llwindowcallbacks.h | 11 ++++- indra/llwindow/llwindowmacosx.cpp | 96 +++++++++++++++++++++++++++++++++--- indra/llwindow/llwindowmacosx.h | 13 +++-- indra/newview/llviewerwindow.cpp | 22 ++++++--- indra/newview/llviewerwindow.h | 2 +- 6 files changed, 125 insertions(+), 23 deletions(-) diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index 3b0aeeab1f..a6d2352732 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -163,9 +163,9 @@ void LLWindowCallbacks::handleDataCopy(LLWindow *window, S32 data_type, void *da { } -BOOL LLWindowCallbacks::handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data, BOOL is_slurl ) +LLWindowCallbacks::DragNDropResult LLWindowCallbacks::handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data ) { - return FALSE; + return LLWindowCallbacks::DND_NONE; } BOOL LLWindowCallbacks::handleTimerEvent(LLWindow *window) diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 1b4a6cbda2..a109879da7 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -68,10 +68,17 @@ public: virtual void handleWindowBlock(LLWindow *window); // window is taking over CPU for a while virtual void handleWindowUnblock(LLWindow *window); // window coming back after taking over CPU for a while virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); - virtual BOOL handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data, BOOL is_slurl); virtual BOOL handleTimerEvent(LLWindow *window); virtual BOOL handleDeviceChange(LLWindow *window); - + + enum DragNDropResult { + DND_NONE = 0, // No drop allowed + DND_MOVE, // Drop accepted would result in a "move" operation + DND_COPY, // Drop accepted would result in a "copy" operation + DND_LINK // Drop accepted would result in a "link" operation + }; + virtual DragNDropResult handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data); + virtual void handlePingWatchdog(LLWindow *window, const char * msg); virtual void handlePauseWatchdog(LLWindow *window); virtual void handleResumeWatchdog(LLWindow *window); diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index af9a30cb25..0acda8ab3a 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -499,8 +499,9 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits // Set up window event handlers (some window-related events ONLY go to window handlers.) InstallStandardEventHandler(GetWindowEventTarget(mWindow)); - InstallWindowEventHandler (mWindow, mEventHandlerUPP, GetEventTypeCount (WindowHandlerEventList), WindowHandlerEventList, (void*)this, &mWindowHandlerRef); // add event handler - + InstallWindowEventHandler(mWindow, mEventHandlerUPP, GetEventTypeCount (WindowHandlerEventList), WindowHandlerEventList, (void*)this, &mWindowHandlerRef); // add event handler + InstallTrackingHandler( dragTrackingHandler, mWindow, (void*)this ); + InstallReceiveHandler( dragReceiveHandler, mWindow, (void*)this ); } { @@ -2172,11 +2173,8 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e } else { - MASK mask = 0; - if(modifiers & shiftKey) { mask |= MASK_SHIFT; } - if(modifiers & (cmdKey | controlKey)) { mask |= MASK_CONTROL; } - if(modifiers & optionKey) { mask |= MASK_ALT; } - + MASK mask = LLWindowMacOSX::modifiersToMask(modifiers); + llassert( actualType == typeUnicodeText ); // The result is a UTF16 buffer. Pass the characters in turn to handleUnicodeChar. @@ -3377,3 +3375,87 @@ std::vector LLWindowMacOSX::getDynamicFallbackFontList() return std::vector(); } +// static +MASK LLWindowMacOSX::modifiersToMask(SInt16 modifiers) +{ + MASK mask = 0; + if(modifiers & shiftKey) { mask |= MASK_SHIFT; } + if(modifiers & (cmdKey | controlKey)) { mask |= MASK_CONTROL; } + if(modifiers & optionKey) { mask |= MASK_ALT; } + return mask; +} + +OSErr LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, + void * handlerRefCon, DragRef theDrag) +{ + LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; + return self->handleDragNDrop(theDrag, false); +} + +OSErr LLWindowMacOSX::dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, + DragRef theDrag) +{ + LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; + return self->handleDragNDrop(theDrag, true); + +} + +OSErr LLWindowMacOSX::handleDragNDrop(DragRef theDrag, bool drop) +{ + OSErr result = noErr; + + UInt16 num_items = 0; + ::CountDragItems(theDrag, &num_items); + if (1 == num_items) + { + SInt16 modifiers, mouseDownModifiers, mouseUpModifiers; + ::GetDragModifiers(theDrag, &modifiers, &mouseDownModifiers, &mouseUpModifiers); + MASK mask = LLWindowMacOSX::modifiersToMask(modifiers); + + Point mouse_point; + // This will return the mouse point in global screen coords + ::GetDragMouse(theDrag, &mouse_point, NULL); + LLCoordScreen screen_coords(mouse_point.v, mouse_point.h); + LLCoordGL gl_pos; + convertCoords(screen_coords, &gl_pos); + + DragItemRef theItemRef; + ::GetDragItemReferenceNumber(theDrag, 0, &theItemRef); + + UInt16 numFlavors = 0; + ::CountDragItemFlavors(theDrag, theItemRef, &numFlavors); + + FlavorType theType = kScrapFlavorTypeUnicode; + std::string url; + for (UInt16 i=0; ihandleDragNDrop(this, gl_pos, mask, drop, url); + + if (LLWindowCallbacks::DND_NONE == res) + { + result = dragNotAcceptedErr; + } + } + else { + result = dragNotAcceptedErr; + } + + return result; +} + diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 17074080eb..24e44417f5 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -160,8 +160,12 @@ protected: void adjustCursorDecouple(bool warpingMouse = false); void fixWindowSize(void); void stopDockTileBounce(); - - + static MASK modifiersToMask(SInt16 modifiers); + static OSErr dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, + void * handlerRefCon, DragRef theDrag); + static OSErr dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, DragRef theDrag); + OSErr handleDragNDrop(DragRef theDrag, bool drop); + // // Platform specific variables // @@ -198,13 +202,16 @@ protected: NMRec mBounceRec; LLTimer mBounceTimer; - // Imput method management through Text Service Manager. + // Input method management through Text Service Manager. TSMDocumentID mTSMDocument; BOOL mLanguageTextInputAllowed; ScriptCode mTSMScriptCode; LangCode mTSMLangCode; LLPreeditor* mPreeditor; + // Storage for drag data + char mDragData[1024]; + static BOOL sUseMultGL; friend class LLWindowManager; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index f953a45890..fe6c9439bb 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -822,16 +822,16 @@ BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MAS return TRUE; } -BOOL LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data, BOOL slurl ) +LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data) { - BOOL result = FALSE; + LLWindowCallbacks::DragNDropResult result = LLWindowCallbacks::DND_NONE; if (gSavedSettings.getBOOL("PrimMediaDragNDrop")) { // special case SLURLs - if ( slurl ) + if ( std::string::npos != data.find("slurl.com") ) { LLURLDispatcher::dispatch( data, NULL, true ); - return TRUE; + return LLWindowCallbacks::DND_MOVE; }; LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ ); @@ -863,24 +863,30 @@ BOOL LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mas // XXX This shouldn't be necessary, should it ?!? obj->getMediaImpl(object_face)->navigateReload(); obj->sendMediaDataUpdate(); + + result = LLWindowCallbacks::DND_COPY; } else { // just navigate to the URL obj->getMediaImpl(object_face)->navigateTo(url); + + result = LLWindowCallbacks::DND_LINK; } LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); mDragHoveredObject = NULL; + } else { mDragHoveredObject = obj; // Highlight the dragged object LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject); + + result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK; } - result = TRUE; } } - if (!result && !mDragHoveredObject.isNull()) + if (result == LLWindowCallbacks::DND_NONE && !mDragHoveredObject.isNull()) { LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); mDragHoveredObject = NULL; @@ -3312,8 +3318,8 @@ LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_trans } else { - llwarns << "List of last picks is empty" << llendl; - llwarns << "Using stub pick" << llendl; + lldebugs << "List of last picks is empty" << llendl; + lldebugs << "Using stub pick" << llendl; mLastPick = LLPickInfo(); } diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 11d19cf24d..dc58292a6a 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -170,7 +170,7 @@ public: /*virtual*/ BOOL handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); - /*virtual*/ BOOL handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data, BOOL slurl); + /*virtual*/ LLWindowCallbacks::DragNDropResult handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data); void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ void handleMouseLeave(LLWindow *window); /*virtual*/ void handleResize(LLWindow *window, S32 x, S32 y); -- cgit v1.2.3 From ff53d4ff9b497f4f0f30035d7e02e6df290db6a4 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Thu, 3 Dec 2009 12:19:02 -0800 Subject: Fix Windows build based on API change to handleDragNDrop() --- indra/llwindow/lldragdropwin32.cpp | 4 ++-- indra/llwindow/llwindowwin32.cpp | 4 ++-- indra/llwindow/llwindowwin32.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/indra/llwindow/lldragdropwin32.cpp b/indra/llwindow/lldragdropwin32.cpp index 74f96f6da3..a96f04ff1f 100644 --- a/indra/llwindow/lldragdropwin32.cpp +++ b/indra/llwindow/lldragdropwin32.cpp @@ -158,7 +158,7 @@ class LLDragDropWin32Target: window_imp->convertCoords(cursor_coord_window, &gl_coord); MASK mask = gKeyboard->currentMask(TRUE); - bool allowed_to_drop = window_imp->completeDragNDropRequest( gl_coord, mask, FALSE, std::string( "" ), mIsSlurl ); + bool allowed_to_drop = window_imp->completeDragNDropRequest( gl_coord, mask, FALSE, std::string( "" ) ); if ( allowed_to_drop ) *pdwEffect = DROPEFFECT_COPY; else @@ -214,7 +214,7 @@ class LLDragDropWin32Target: MASK mask = gKeyboard->currentMask( TRUE ); // actually do the drop - window_imp->completeDragNDropRequest( gl_coord, mask, TRUE, mDropUrl, mIsSlurl ); + window_imp->completeDragNDropRequest( gl_coord, mask, TRUE, mDropUrl ); }; *pdwEffect = DROPEFFECT_COPY; diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 78bc3b9c58..dc1e2c017c 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -3581,9 +3581,9 @@ static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_leng // final stage of handling drop requests - both from WM_DROPFILES message // for files and via IDropTarget interface requests. -BOOL LLWindowWin32::completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, BOOL drop, const std::string url, BOOL is_slurl ) +BOOL LLWindowWin32::completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, BOOL drop, const std::string url ) { - return mCallbacks->handleDragNDrop( this, gl_coord, mask, drop, url, is_slurl ); + return mCallbacks->handleDragNDrop( this, gl_coord, mask, drop, url ); } // Handle WM_IME_REQUEST message. diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 7f7acd5751..e99c26b7f1 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -113,7 +113,7 @@ public: /*virtual*/ void interruptLanguageTextInput(); /*virtual*/ void spawnWebBrowser(const std::string& escaped_url); - BOOL completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, BOOL drop, const std::string url, BOOL is_slurl ); + BOOL completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, BOOL drop, const std::string url ); static std::vector getDynamicFallbackFontList(); -- cgit v1.2.3 From bfe66526c83d260d3e69971d30786d1e061c2c47 Mon Sep 17 00:00:00 2001 From: Monroe Linden Date: Thu, 3 Dec 2009 17:01:58 -0800 Subject: Rewrote LLWindowMacOSX::handleDragNDrop() to use pasteboard manager instead of old, busted scrap manager to extract the data. Also fixed a mouse coordinate issue that caused drag tracking to be off. --- indra/llwindow/llwindowmacosx.cpp | 141 +++++++++++++++++++++++++------------- indra/llwindow/llwindowmacosx.h | 3 - 2 files changed, 92 insertions(+), 52 deletions(-) diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 0acda8ab3a..87296b1202 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -3386,75 +3386,118 @@ MASK LLWindowMacOSX::modifiersToMask(SInt16 modifiers) } OSErr LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, - void * handlerRefCon, DragRef theDrag) + void * handlerRefCon, DragRef drag) { + OSErr result = noErr; LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; - return self->handleDragNDrop(theDrag, false); + + lldebugs << "drag tracking handler, message = " << message << llendl; + + switch(message) + { + case kDragTrackingInWindow: + result = self->handleDragNDrop(drag, false); + break; + + case kDragTrackingEnterHandler: + case kDragTrackingLeaveHandler: + // TODO: We probably want to do something clever for these (at least for the LeaveHandler). + break; + + default: + break; + } + + return result; } OSErr LLWindowMacOSX::dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, - DragRef theDrag) + DragRef drag) { LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; - return self->handleDragNDrop(theDrag, true); + return self->handleDragNDrop(drag, true); } -OSErr LLWindowMacOSX::handleDragNDrop(DragRef theDrag, bool drop) +OSErr LLWindowMacOSX::handleDragNDrop(DragRef drag, bool drop) { - OSErr result = noErr; + OSErr result = dragNotAcceptedErr; // overall function result + OSErr err = noErr; // for local error handling + + // Get the mouse position and modifiers of this drag. + SInt16 modifiers, mouseDownModifiers, mouseUpModifiers; + ::GetDragModifiers(drag, &modifiers, &mouseDownModifiers, &mouseUpModifiers); + MASK mask = LLWindowMacOSX::modifiersToMask(modifiers); + + Point mouse_point; + // This will return the mouse point in global screen coords + ::GetDragMouse(drag, &mouse_point, NULL); + LLCoordScreen screen_coords(mouse_point.h, mouse_point.v); + LLCoordGL gl_pos; + convertCoords(screen_coords, &gl_pos); - UInt16 num_items = 0; - ::CountDragItems(theDrag, &num_items); - if (1 == num_items) + // Look at the pasteboard and try to extract an URL from it + PasteboardRef pasteboard; + if(GetDragPasteboard(drag, &pasteboard) == noErr) { - SInt16 modifiers, mouseDownModifiers, mouseUpModifiers; - ::GetDragModifiers(theDrag, &modifiers, &mouseDownModifiers, &mouseUpModifiers); - MASK mask = LLWindowMacOSX::modifiersToMask(modifiers); - - Point mouse_point; - // This will return the mouse point in global screen coords - ::GetDragMouse(theDrag, &mouse_point, NULL); - LLCoordScreen screen_coords(mouse_point.v, mouse_point.h); - LLCoordGL gl_pos; - convertCoords(screen_coords, &gl_pos); - - DragItemRef theItemRef; - ::GetDragItemReferenceNumber(theDrag, 0, &theItemRef); + ItemCount num_items = 0; + // Treat an error here as an item count of 0 + (void)PasteboardGetItemCount(pasteboard, &num_items); - UInt16 numFlavors = 0; - ::CountDragItemFlavors(theDrag, theItemRef, &numFlavors); - - FlavorType theType = kScrapFlavorTypeUnicode; - std::string url; - for (UInt16 i=0; ihandleDragNDrop(this, gl_pos, mask, drop, url); - - if (LLWindowCallbacks::DND_NONE == res) - { - result = dragNotAcceptedErr; + if(flavors != NULL) + { + CFRelease(flavors); + } + + if(data != NULL) + { + std::string url; + url.assign((char*)CFDataGetBytePtr(data), CFDataGetLength(data)); + CFRelease(data); + + if(!url.empty()) + { + LLWindowCallbacks::DragNDropResult res = + mCallbacks->handleDragNDrop(this, gl_pos, mask, drop, url); + + if (LLWindowCallbacks::DND_NONE != res) + { + result = noErr; + } + } + } } } - else { - result = dragNotAcceptedErr; - } return result; } diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 24e44417f5..23e33a6e07 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -209,9 +209,6 @@ protected: LangCode mTSMLangCode; LLPreeditor* mPreeditor; - // Storage for drag data - char mDragData[1024]; - static BOOL sUseMultGL; friend class LLWindowManager; -- cgit v1.2.3 From fe0b027d4d7381a532bb0f14f64ecffdeb7190b6 Mon Sep 17 00:00:00 2001 From: Monroe Linden Date: Thu, 3 Dec 2009 17:40:58 -0800 Subject: Added the LLWindowCallbacks::DragNDropAction enum, and made the mac implementation and the cross-platform window callbacks use it (instead of 'bool drop'). This will break the windows impl until someone fixes it to match. --- indra/llwindow/llwindowcallbacks.cpp | 2 +- indra/llwindow/llwindowcallbacks.h | 9 ++- indra/llwindow/llwindowmacosx.cpp | 13 ++-- indra/llwindow/llwindowmacosx.h | 3 +- indra/newview/llviewerwindow.cpp | 122 ++++++++++++++++++++--------------- indra/newview/llviewerwindow.h | 2 +- 6 files changed, 91 insertions(+), 60 deletions(-) diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index a6d2352732..6d9f012cc3 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -163,7 +163,7 @@ void LLWindowCallbacks::handleDataCopy(LLWindow *window, S32 data_type, void *da { } -LLWindowCallbacks::DragNDropResult LLWindowCallbacks::handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data ) +LLWindowCallbacks::DragNDropResult LLWindowCallbacks::handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, DragNDropAction action, std::string data ) { return LLWindowCallbacks::DND_NONE; } diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index a109879da7..42add8dde0 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -70,6 +70,13 @@ public: virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); virtual BOOL handleTimerEvent(LLWindow *window); virtual BOOL handleDeviceChange(LLWindow *window); + + enum DragNDropAction { + DNDA_START_TRACKING = 0,// Start tracking an incoming drag + DNDA_TRACK, // User is dragging an incoming drag around the window + DNDA_STOP_TRACKING, // User is no longer dragging an incoming drag around the window (may have either cancelled or dropped on the window) + DNDA_DROPPED // User dropped an incoming drag on the window (this is the "commit" event) + }; enum DragNDropResult { DND_NONE = 0, // No drop allowed @@ -77,7 +84,7 @@ public: DND_COPY, // Drop accepted would result in a "copy" operation DND_LINK // Drop accepted would result in a "link" operation }; - virtual DragNDropResult handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data); + virtual DragNDropResult handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, DragNDropAction action, std::string data); virtual void handlePingWatchdog(LLWindow *window, const char * msg); virtual void handlePauseWatchdog(LLWindow *window); diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 87296b1202..02fa9df22d 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -3396,12 +3396,15 @@ OSErr LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef switch(message) { case kDragTrackingInWindow: - result = self->handleDragNDrop(drag, false); + result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_TRACK); break; case kDragTrackingEnterHandler: + result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_START_TRACKING); + break; + case kDragTrackingLeaveHandler: - // TODO: We probably want to do something clever for these (at least for the LeaveHandler). + result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_STOP_TRACKING); break; default: @@ -3415,11 +3418,11 @@ OSErr LLWindowMacOSX::dragReceiveHandler(WindowRef theWindow, void * handlerRefC DragRef drag) { LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; - return self->handleDragNDrop(drag, true); + return self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_DROPPED); } -OSErr LLWindowMacOSX::handleDragNDrop(DragRef drag, bool drop) +OSErr LLWindowMacOSX::handleDragNDrop(DragRef drag, LLWindowCallbacks::DragNDropAction action) { OSErr result = dragNotAcceptedErr; // overall function result OSErr err = noErr; // for local error handling @@ -3488,7 +3491,7 @@ OSErr LLWindowMacOSX::handleDragNDrop(DragRef drag, bool drop) if(!url.empty()) { LLWindowCallbacks::DragNDropResult res = - mCallbacks->handleDragNDrop(this, gl_pos, mask, drop, url); + mCallbacks->handleDragNDrop(this, gl_pos, mask, action, url); if (LLWindowCallbacks::DND_NONE != res) { diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 23e33a6e07..6af54c5471 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -34,6 +34,7 @@ #define LL_LLWINDOWMACOSX_H #include "llwindow.h" +#include "llwindowcallbacks.h" #include "lltimer.h" @@ -164,7 +165,7 @@ protected: static OSErr dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, void * handlerRefCon, DragRef theDrag); static OSErr dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, DragRef theDrag); - OSErr handleDragNDrop(DragRef theDrag, bool drop); + OSErr handleDragNDrop(DragRef theDrag, LLWindowCallbacks::DragNDropAction action); // // Platform specific variables diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index e80a2ae11c..fed676775c 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -823,71 +823,91 @@ BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MAS return TRUE; } -LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data) +LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data) { LLWindowCallbacks::DragNDropResult result = LLWindowCallbacks::DND_NONE; if (gSavedSettings.getBOOL("PrimMediaDragNDrop")) { - // special case SLURLs - if ( drop && std::string::npos != data.find("slurl.com") ) + + switch(action) { - LLURLDispatcher::dispatch( data, NULL, true ); - LLURLSimString::setString( LLSLURL::stripProtocol( data ) ); - LLPanelLogin::refreshLocation( true ); - LLPanelLogin::updateLocationUI(); - return LLWindowCallbacks::DND_MOVE; - }; + // Much of the handling for these two cases is the same. + case LLWindowCallbacks::DNDA_TRACK: + case LLWindowCallbacks::DNDA_DROPPED: + { + bool drop = (LLWindowCallbacks::DNDA_DROPPED == action); + + // special case SLURLs + if ( drop && std::string::npos != data.find("slurl.com") ) + { + LLURLDispatcher::dispatch( data, NULL, true ); + LLURLSimString::setString( LLSLURL::stripProtocol( data ) ); + LLPanelLogin::refreshLocation( true ); + LLPanelLogin::updateLocationUI(); + return LLWindowCallbacks::DND_MOVE; + }; - LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ ); + LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ ); - LLUUID object_id = pick_info.getObjectID(); - S32 object_face = pick_info.mObjectFace; - std::string url = data; + LLUUID object_id = pick_info.getObjectID(); + S32 object_face = pick_info.mObjectFace; + std::string url = data; - llinfos << "### Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; + llinfos << "### Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; - LLVOVolume *obj = dynamic_cast(static_cast(pick_info.getObject())); - - if (obj && obj->permModify()) - { - LLTextureEntry *te = obj->getTE(object_face); - if (te) - { - if (drop) + LLVOVolume *obj = dynamic_cast(static_cast(pick_info.getObject())); + + if (obj && obj->permModify()) { - if (! te->hasMedia()) + LLTextureEntry *te = obj->getTE(object_face); + if (te) { - // Create new media entry - LLSD media_data; - // XXX Should we really do Home URL too? - media_data[LLMediaEntry::HOME_URL_KEY] = url; - media_data[LLMediaEntry::CURRENT_URL_KEY] = url; - media_data[LLMediaEntry::AUTO_PLAY_KEY] = true; - obj->syncMediaData(object_face, media_data, true, true); - // XXX This shouldn't be necessary, should it ?!? - obj->getMediaImpl(object_face)->navigateReload(); - obj->sendMediaDataUpdate(); - - result = LLWindowCallbacks::DND_COPY; - } - else { - // just navigate to the URL - obj->getMediaImpl(object_face)->navigateTo(url); - - result = LLWindowCallbacks::DND_LINK; + if (drop) + { + if (! te->hasMedia()) + { + // Create new media entry + LLSD media_data; + // XXX Should we really do Home URL too? + media_data[LLMediaEntry::HOME_URL_KEY] = url; + media_data[LLMediaEntry::CURRENT_URL_KEY] = url; + media_data[LLMediaEntry::AUTO_PLAY_KEY] = true; + obj->syncMediaData(object_face, media_data, true, true); + // XXX This shouldn't be necessary, should it ?!? + obj->getMediaImpl(object_face)->navigateReload(); + obj->sendMediaDataUpdate(); + + result = LLWindowCallbacks::DND_COPY; + } + else { + // just navigate to the URL + obj->getMediaImpl(object_face)->navigateTo(url); + + result = LLWindowCallbacks::DND_LINK; + } + LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); + mDragHoveredObject = NULL; + + } + else { + mDragHoveredObject = obj; + // Highlight the dragged object + LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject); + + result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK; + } } - LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); - mDragHoveredObject = NULL; - - } - else { - mDragHoveredObject = obj; - // Highlight the dragged object - LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject); - - result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK; } } + break; + + case LLWindowCallbacks::DNDA_START_TRACKING: + // No special handling here yet -- we'll actually start tracking on the first DNDA_TRACK event. + break; + + case LLWindowCallbacks::DNDA_STOP_TRACKING: + // The cleanup case below will make sure things are unhilighted if necessary. + break; } if (result == LLWindowCallbacks::DND_NONE && !mDragHoveredObject.isNull()) diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 2543d1096f..e209ff1ad9 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -170,7 +170,7 @@ public: /*virtual*/ BOOL handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); - /*virtual*/ LLWindowCallbacks::DragNDropResult handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, BOOL drop, std::string data); + /*virtual*/ LLWindowCallbacks::DragNDropResult handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data); void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ void handleMouseLeave(LLWindow *window); /*virtual*/ void handleResize(LLWindow *window, S32 x, S32 y); -- cgit v1.2.3 From 4c33c54ce03bffd3ad75be3dccaed2d26a68e157 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Thu, 3 Dec 2009 19:02:12 -0800 Subject: Fix windows build to now use DragNDropAction instead of a bool 'drop' --- indra/llwindow/lldragdropwin32.cpp | 95 +++++++++++++++++++++++++++++++------- indra/llwindow/llwindowwin32.cpp | 4 +- indra/llwindow/llwindowwin32.h | 3 +- 3 files changed, 83 insertions(+), 19 deletions(-) diff --git a/indra/llwindow/lldragdropwin32.cpp b/indra/llwindow/lldragdropwin32.cpp index a96f04ff1f..4865570f07 100644 --- a/indra/llwindow/lldragdropwin32.cpp +++ b/indra/llwindow/lldragdropwin32.cpp @@ -117,15 +117,45 @@ class LLDragDropWin32Target: { PVOID data = GlobalLock( stgmed.hGlobal ); mDropUrl = std::string( (char*)data ); - - mIsSlurl = ( mDropUrl.find( "slurl.com" ) != std::string::npos ); + // XXX MAJOR MAJOR HACK! + LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mAppWindowHandle, GWL_USERDATA); + if (NULL != window_imp) + { + LLCoordGL gl_coord( 0, 0 ); + + POINT pt2; + pt2.x = pt.x; + pt2.y = pt.y; + ScreenToClient( mAppWindowHandle, &pt2 ); + + LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); + window_imp->convertCoords(cursor_coord_window, &gl_coord); + MASK mask = gKeyboard->currentMask(TRUE); + + LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( gl_coord, mask, + LLWindowCallbacks::DNDA_START_TRACKING, mDropUrl ); + + switch (result) + { + case LLWindowCallbacks::DND_COPY: + *pdwEffect = DROPEFFECT_COPY; + break; + case LLWindowCallbacks::DND_LINK: + *pdwEffect = DROPEFFECT_LINK; + break; + case LLWindowCallbacks::DND_MOVE: + *pdwEffect = DROPEFFECT_MOVE; + break; + case LLWindowCallbacks::DND_NONE: + default: + *pdwEffect = DROPEFFECT_NONE; + break; + } + }; GlobalUnlock( stgmed.hGlobal ); ReleaseStgMedium( &stgmed ); }; - - *pdwEffect = DROPEFFECT_COPY; - SetFocus( mAppWindowHandle ); } else @@ -158,15 +188,25 @@ class LLDragDropWin32Target: window_imp->convertCoords(cursor_coord_window, &gl_coord); MASK mask = gKeyboard->currentMask(TRUE); - bool allowed_to_drop = window_imp->completeDragNDropRequest( gl_coord, mask, FALSE, std::string( "" ) ); - if ( allowed_to_drop ) + LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( gl_coord, mask, + LLWindowCallbacks::DNDA_TRACK, std::string( "" ) ); + + switch (result) + { + case LLWindowCallbacks::DND_COPY: *pdwEffect = DROPEFFECT_COPY; - else - *pdwEffect = DROPEFFECT_NONE; - - // special case for SLURLs - you can always drop them on the client window and we need a different cursor - if ( mIsSlurl ) + break; + case LLWindowCallbacks::DND_LINK: *pdwEffect = DROPEFFECT_LINK; + break; + case LLWindowCallbacks::DND_MOVE: + *pdwEffect = DROPEFFECT_MOVE; + break; + case LLWindowCallbacks::DND_NONE: + default: + *pdwEffect = DROPEFFECT_NONE; + break; + } }; } else @@ -181,7 +221,14 @@ class LLDragDropWin32Target: // HRESULT __stdcall DragLeave( void ) { - mDropUrl = std::string(); + // XXX MAJOR MAJOR HACK! + LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mAppWindowHandle, GWL_USERDATA); + if (NULL != window_imp) + { + LLCoordGL gl_coord( 0, 0 ); + MASK mask = gKeyboard->currentMask(TRUE); + window_imp->completeDragNDropRequest( gl_coord, mask, LLWindowCallbacks::DNDA_STOP_TRACKING, mDropUrl ); + }; return S_OK; }; @@ -214,10 +261,26 @@ class LLDragDropWin32Target: MASK mask = gKeyboard->currentMask( TRUE ); // actually do the drop - window_imp->completeDragNDropRequest( gl_coord, mask, TRUE, mDropUrl ); - }; + LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( gl_coord, mask, + LLWindowCallbacks::DNDA_DROPPED, mDropUrl ); - *pdwEffect = DROPEFFECT_COPY; + switch (result) + { + case LLWindowCallbacks::DND_COPY: + *pdwEffect = DROPEFFECT_COPY; + break; + case LLWindowCallbacks::DND_LINK: + *pdwEffect = DROPEFFECT_LINK; + break; + case LLWindowCallbacks::DND_MOVE: + *pdwEffect = DROPEFFECT_MOVE; + break; + case LLWindowCallbacks::DND_NONE: + default: + *pdwEffect = DROPEFFECT_NONE; + break; + } + }; } else { diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index dc1e2c017c..322b9c9a01 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -3581,9 +3581,9 @@ static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_leng // final stage of handling drop requests - both from WM_DROPFILES message // for files and via IDropTarget interface requests. -BOOL LLWindowWin32::completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, BOOL drop, const std::string url ) +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, drop, url ); + return mCallbacks->handleDragNDrop( this, gl_coord, mask, action, url ); } // Handle WM_IME_REQUEST message. diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index e99c26b7f1..3e907cde00 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -39,6 +39,7 @@ #include #include "llwindow.h" +#include "llwindowcallbacks.h" #include "lldragdropwin32.h" // Hack for async host by name @@ -113,7 +114,7 @@ public: /*virtual*/ void interruptLanguageTextInput(); /*virtual*/ void spawnWebBrowser(const std::string& escaped_url); - BOOL completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, BOOL drop, const std::string url ); + LLWindowCallbacks::DragNDropResult completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ); static std::vector getDynamicFallbackFontList(); -- cgit v1.2.3 From 064c9be9aedf238530ccdc941861fd057580e5b1 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Wed, 16 Dec 2009 18:56:01 -0800 Subject: Don't allow drag if the cap URL is empty or if the whitelist does not pass --- indra/newview/llviewerwindow.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 5d2ca331d6..e3de2891a1 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -827,9 +827,9 @@ BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MAS LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data) { LLWindowCallbacks::DragNDropResult result = LLWindowCallbacks::DND_NONE; + if (gSavedSettings.getBOOL("PrimMediaDragNDrop")) { - switch(action) { // Much of the handling for these two cases is the same. @@ -854,11 +854,11 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi S32 object_face = pick_info.mObjectFace; std::string url = data; - llinfos << "### Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; + lldebugs << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; LLVOVolume *obj = dynamic_cast(static_cast(pick_info.getObject())); - if (obj && obj->permModify()) + if (obj && obj->permModify() && !obj->getRegion()->getCapability("ObjectMedia").empty()) { LLTextureEntry *te = obj->getTE(object_face); if (te) @@ -881,10 +881,14 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi result = LLWindowCallbacks::DND_COPY; } else { - // just navigate to the URL - obj->getMediaImpl(object_face)->navigateTo(url); + // Check the whitelist + if (te->getMediaData()->checkCandidateUrl(url)) + { + // just navigate to the URL + obj->getMediaImpl(object_face)->navigateTo(url); - result = LLWindowCallbacks::DND_LINK; + result = LLWindowCallbacks::DND_LINK; + } } LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); mDragHoveredObject = NULL; -- cgit v1.2.3 From 3b110e76332712e7efb7972fb27324a763596b6c Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Fri, 18 Dec 2009 15:52:45 -0800 Subject: Fix crash when DnD onto an item with media but no impl --- indra/newview/llviewerwindow.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 6c73cc18db..08f598b288 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -875,7 +875,8 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi media_data[LLMediaEntry::AUTO_PLAY_KEY] = true; obj->syncMediaData(object_face, media_data, true, true); // XXX This shouldn't be necessary, should it ?!? - obj->getMediaImpl(object_face)->navigateReload(); + if (obj->getMediaImpl(object_face)) + obj->getMediaImpl(object_face)->navigateReload(); obj->sendMediaDataUpdate(); result = LLWindowCallbacks::DND_COPY; @@ -885,8 +886,20 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi if (te->getMediaData()->checkCandidateUrl(url)) { // just navigate to the URL - obj->getMediaImpl(object_face)->navigateTo(url); - + if (obj->getMediaImpl(object_face)) + { + obj->getMediaImpl(object_face)->navigateTo(url); + } + else { + // This is very strange. Navigation should + // happen via the Impl, but we don't have one. + // This sends it to the server, which /should/ + // trigger us getting it. Hopefully. + LLSD media_data; + media_data[LLMediaEntry::CURRENT_URL_KEY] = url; + obj->syncMediaData(object_face, media_data, true, true); + obj->sendMediaDataUpdate(); + } result = LLWindowCallbacks::DND_LINK; } } -- cgit v1.2.3 From 9204681c31184c4c76c8f41c48da76e174e3276a Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Fri, 18 Dec 2009 16:21:57 -0800 Subject: Fix slurl crashing, fix slurls highlighting objects, fix overlapping objects not "unhighlighting" --- indra/newview/llpanellogin.cpp | 2 ++ indra/newview/llviewerwindow.cpp | 24 +++++++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index cdfa64ba57..ce83ab3e37 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -688,6 +688,8 @@ void LLPanelLogin::refreshLocation( bool force_visible ) // static void LLPanelLogin::updateLocationUI() { + if (!sInstance) return; + std::string sim_string = LLURLSimString::sInstance.mSimString; if (!sim_string.empty()) { diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 08f598b288..71fe8dd773 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -839,12 +839,15 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi bool drop = (LLWindowCallbacks::DNDA_DROPPED == action); // special case SLURLs - if ( drop && std::string::npos != data.find("slurl.com") ) + if (std::string::npos != data.find("slurl.com") ) { - LLURLDispatcher::dispatch( data, NULL, true ); - LLURLSimString::setString( LLSLURL::stripProtocol( data ) ); - LLPanelLogin::refreshLocation( true ); - LLPanelLogin::updateLocationUI(); + if (drop) + { + LLURLDispatcher::dispatch( data, NULL, true ); + LLURLSimString::setString( LLSLURL::stripProtocol( data ) ); + LLPanelLogin::refreshLocation( true ); + LLPanelLogin::updateLocationUI(); + } return LLWindowCallbacks::DND_MOVE; }; @@ -908,10 +911,13 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi } else { - mDragHoveredObject = obj; - // Highlight the dragged object - LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject); - + if ( obj != mDragHoveredObject) + { + // Highlight the dragged object + LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); + mDragHoveredObject = obj; + LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject); + } result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK; } } -- cgit v1.2.3 From 75c1fb26649df73770459a31641c434e156e2c17 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Tue, 5 Jan 2010 15:03:27 -0800 Subject: Build fix: add missing #include --- indra/newview/llviewerwindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 21bf567b0c..313f728489 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -83,6 +83,7 @@ #include "lltooltip.h" #include "llmediaentry.h" #include "llurldispatcher.h" +#include "llurlsimstring.h" // newview includes #include "llagent.h" -- cgit v1.2.3 From e57f6a5cee1cf03df2bf43cd7a8b2c42c3918f8b Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Thu, 7 Jan 2010 14:21:57 -0800 Subject: Fix drag and drop for windows. Makes Win32 state machine behave more like Mac. --- indra/llwindow/lldragdropwin32.cpp | 2 +- indra/newview/llviewerwindow.cpp | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/indra/llwindow/lldragdropwin32.cpp b/indra/llwindow/lldragdropwin32.cpp index 4865570f07..1e10626e8a 100644 --- a/indra/llwindow/lldragdropwin32.cpp +++ b/indra/llwindow/lldragdropwin32.cpp @@ -189,7 +189,7 @@ class LLDragDropWin32Target: MASK mask = gKeyboard->currentMask(TRUE); LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( gl_coord, mask, - LLWindowCallbacks::DNDA_TRACK, std::string( "" ) ); + LLWindowCallbacks::DNDA_TRACK, mDropUrl ); switch (result) { diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 02b8158188..81fcfc13c2 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -835,6 +835,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi // Much of the handling for these two cases is the same. case LLWindowCallbacks::DNDA_TRACK: case LLWindowCallbacks::DNDA_DROPPED: + case LLWindowCallbacks::DNDA_START_TRACKING: { bool drop = (LLWindowCallbacks::DNDA_DROPPED == action); @@ -925,10 +926,6 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi } break; - case LLWindowCallbacks::DNDA_START_TRACKING: - // No special handling here yet -- we'll actually start tracking on the first DNDA_TRACK event. - break; - case LLWindowCallbacks::DNDA_STOP_TRACKING: // The cleanup case below will make sure things are unhilighted if necessary. break; -- cgit v1.2.3 From 1500e90eccf237fb50f901528c5dc9d747f6d2f0 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Fri, 8 Jan 2010 15:11:03 -0800 Subject: Make sure mac build honors compile-time flag that en/disables OS drag and drop. Also fixed the cmake file to properly set LL_OS_DRAGDROP_ENABLED. --- indra/cmake/DragDrop.cmake | 6 ++---- indra/llwindow/llwindowmacosx.cpp | 5 +++++ indra/llwindow/llwindowmacosx.h | 3 +++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/indra/cmake/DragDrop.cmake b/indra/cmake/DragDrop.cmake index 739d011813..e56264f187 100644 --- a/indra/cmake/DragDrop.cmake +++ b/indra/cmake/DragDrop.cmake @@ -2,9 +2,7 @@ if (VIEWER) - OPTION (OS_DRAG_DROP - "Build the viewer with OS level drag and drop turned on or off" - ON) + set(OS_DRAG_DROP ON CACHE BOOL "Build the viewer with OS level drag and drop turned on or off") if (OS_DRAG_DROP) @@ -13,7 +11,7 @@ if (VIEWER) endif (WINDOWS) if (DARWIN) - add_definitions(-DLL_OS_DRAGDROP_ENABLED=0) + add_definitions(-DLL_OS_DRAGDROP_ENABLED=1) endif (DARWIN) if (LINUX) diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index ffc44a1e84..dc5a98756a 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -500,8 +500,10 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits // Set up window event handlers (some window-related events ONLY go to window handlers.) InstallStandardEventHandler(GetWindowEventTarget(mWindow)); InstallWindowEventHandler(mWindow, mEventHandlerUPP, GetEventTypeCount (WindowHandlerEventList), WindowHandlerEventList, (void*)this, &mWindowHandlerRef); // add event handler +#if LL_OS_DRAGDROP_ENABLED InstallTrackingHandler( dragTrackingHandler, mWindow, (void*)this ); InstallReceiveHandler( dragReceiveHandler, mWindow, (void*)this ); +#endif // LL_OS_DRAGDROP_ENABLED } { @@ -3387,6 +3389,8 @@ MASK LLWindowMacOSX::modifiersToMask(SInt16 modifiers) return mask; } +#if LL_OS_DRAGDROP_ENABLED + OSErr LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, void * handlerRefCon, DragRef drag) { @@ -3507,3 +3511,4 @@ OSErr LLWindowMacOSX::handleDragNDrop(DragRef drag, LLWindowCallbacks::DragNDrop return result; } +#endif // LL_OS_DRAGDROP_ENABLED diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index bd3e46ebb4..09b8891db0 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -161,10 +161,13 @@ protected: void fixWindowSize(void); void stopDockTileBounce(); static MASK modifiersToMask(SInt16 modifiers); + +#if LL_OS_DRAGDROP_ENABLED static OSErr dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, void * handlerRefCon, DragRef theDrag); static OSErr dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, DragRef theDrag); OSErr handleDragNDrop(DragRef theDrag, LLWindowCallbacks::DragNDropAction action); +#endif // LL_OS_DRAGDROP_ENABLED // // Platform specific variables -- cgit v1.2.3 From e31d695247f89df1490afb4b9581f562fa99617c Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Fri, 8 Jan 2010 15:11:15 -0800 Subject: get rid of commented-out code --- indra/llwindow/llwindowwin32.cpp | 54 ---------------------------------------- 1 file changed, 54 deletions(-) diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 439c10c95c..ed39786b37 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -2376,60 +2376,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ }; return 0; - // only useful for droppnig files - could be used for file upload dialog one day - //case WM_DROPFILES: - // { - // // HDROP contains what we need - // HDROP hdrop = (HDROP)w_param; - - // // get location in window space where drop occured and convert to OpenGL coordinate space - // POINT pt; - // DragQueryPoint( hdrop, &pt ); - // LLCoordGL gl_coord; - // LLCoordWindow cursor_coord_window( pt.x, pt.y ); - // window_imp->convertCoords(cursor_coord_window, &gl_coord); - - // // get payload (eventually, this needs to more advanced and grab size of payload dynamically - // static char file_name[ 1024 ]; - // DragQueryFileA( hdrop, 0, file_name, 1024 ); - // void* url = (void*)( file_name ); - - // // if it's a .URL or .lnk ("shortcut") file - // if ( std::string( file_name ).find( ".lnk" ) != std::string::npos || - // std::string( file_name ).find( ".URL" ) != std::string::npos ) - // { - // // read through file - looks like a 2 line file with second line URL= but who knows.. - // std::ifstream file_handle( file_name ); - // if ( file_handle.is_open() ) - // { - // std::string line; - // while ( ! file_handle.eof() ) - // { - // std::getline( file_handle, line ); - // if ( ! file_handle.eof() ) - // { - // std::string prefix( "URL=" ); - // if ( line.find( prefix, 0 ) != std::string::npos ) - // { - // line = line.substr( 4 ); // skip off the URL= bit - // strcpy( (char*)url, line.c_str() ); - // break; - // }; - // }; - // }; - // file_handle.close(); - // }; - // }; - - // MASK mask = gKeyboard->currentMask(TRUE); - - // if ( window_imp->completeDragNDropRequest( gl_coord, mask, true, (char*)url, false ) ) - // { - // return 0; - // }; - // } - - break; } -- cgit v1.2.3 From a74d494dd7c13e0307ee5ba526ba021583b1f2b5 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Mon, 11 Jan 2010 16:41:08 -0800 Subject: Fix unposted bug: drag feedback didn't check whitelist http://codereview.lindenlab.com/274039/show --- indra/newview/llviewerwindow.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 81fcfc13c2..5dd640539f 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -912,14 +912,18 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi } else { - if ( obj != mDragHoveredObject) + // Check the whitelist, if there's media (otherwise just show it) + if (te->getMediaData() == NULL || te->getMediaData()->checkCandidateUrl(url)) { - // Highlight the dragged object - LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); - mDragHoveredObject = obj; - LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject); + if ( obj != mDragHoveredObject) + { + // Highlight the dragged object + LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); + mDragHoveredObject = obj; + LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject); + } + result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK; } - result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK; } } } -- cgit v1.2.3 From a3ca95e3bd0e288792f6024d9487d618730fd40f Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Mon, 11 Jan 2010 17:26:28 -0800 Subject: Fix that stops "Start Location" corruption if you drag an invalid http://slurl.com SLURL onto the login page --- indra/newview/llviewerwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 81fcfc13c2..c5c9e49934 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -840,7 +840,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi bool drop = (LLWindowCallbacks::DNDA_DROPPED == action); // special case SLURLs - if (std::string::npos != data.find("slurl.com") ) + if ( LLSLURL::isSLURL( data ) ) { if (drop) { -- cgit v1.2.3 From b06d655727c15530c1f65ccea83ab911f42e04ff Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Mon, 11 Jan 2010 18:44:00 -0800 Subject: Add cursor-change override while dragging on the mac This changes the setCursor() call in LLWindowMacOSX to be ignored if we're currently dragging via the OS http://codereview.lindenlab.com/273045 --- indra/llwindow/llwindowmacosx.cpp | 38 ++++++++++++++++++++++++++++++++++++-- indra/llwindow/llwindowmacosx.h | 2 ++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index dc5a98756a..783d1f39ca 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -278,6 +278,8 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, mMoveEventCampartorUPP = NewEventComparatorUPP(staticMoveEventComparator); mGlobalHandlerRef = NULL; mWindowHandlerRef = NULL; + + mDragOverrideCursor = -1; // We're not clipping yet SetRect( &mOldMouseClip, 0, 0, 0, 0 ); @@ -2795,6 +2797,8 @@ void LLWindowMacOSX::setCursor(ECursorType cursor) { OSStatus result = noErr; + if (mDragOverrideCursor != -1) return; + if (cursor == UI_CURSOR_ARROW && mBusyCount > 0) { @@ -3499,10 +3503,40 @@ OSErr LLWindowMacOSX::handleDragNDrop(DragRef drag, LLWindowCallbacks::DragNDrop LLWindowCallbacks::DragNDropResult res = mCallbacks->handleDragNDrop(this, gl_pos, mask, action, url); - if (LLWindowCallbacks::DND_NONE != res) + switch (res) { + case LLWindowCallbacks::DND_NONE: // No drop allowed + if (action == LLWindowCallbacks::DNDA_TRACK) + { + mDragOverrideCursor = kThemeNotAllowedCursor; + } + else { + mDragOverrideCursor = -1; + } + break; + case LLWindowCallbacks::DND_MOVE: // Drop accepted would result in a "move" operation + mDragOverrideCursor = kThemePointingHandCursor; + result = noErr; + break; + case LLWindowCallbacks::DND_COPY: // Drop accepted would result in a "copy" operation + mDragOverrideCursor = kThemeCopyArrowCursor; + result = noErr; + break; + case LLWindowCallbacks::DND_LINK: // Drop accepted would result in a "link" operation: + mDragOverrideCursor = kThemeAliasArrowCursor; + result = noErr; + break; + default: + mDragOverrideCursor = -1; + break; + } + if (mDragOverrideCursor == -1) { - result = noErr; + SetThemeCursor(kThemeArrowCursor); + } + else { + SetThemeCursor(mDragOverrideCursor); } + } } } diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 09b8891db0..377f10b6d4 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -201,6 +201,8 @@ protected: U32 mFSAASamples; BOOL mForceRebuild; + S32 mDragOverrideCursor; + F32 mBounceTime; NMRec mBounceRec; LLTimer mBounceTimer; -- cgit v1.2.3 From df69302cd2f00dd44b5b34aeb3ba896ce7548556 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Tue, 12 Jan 2010 11:31:07 -0800 Subject: Add restoring of previous cursor to mac impl http://codereview.lindenlab.com/273045 --- indra/llwindow/llwindowmacosx.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 783d1f39ca..9ccd4c7f97 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -2797,8 +2797,14 @@ void LLWindowMacOSX::setCursor(ECursorType cursor) { OSStatus result = noErr; - if (mDragOverrideCursor != -1) return; - + if (mDragOverrideCursor != -1) + { + // A drag is in progress...remember the requested cursor and we'll + // restore it when it is done + mCurrentCursor = cursor; + return; + } + if (cursor == UI_CURSOR_ARROW && mBusyCount > 0) { @@ -3529,11 +3535,19 @@ OSErr LLWindowMacOSX::handleDragNDrop(DragRef drag, LLWindowCallbacks::DragNDrop mDragOverrideCursor = -1; break; } + // This overrides the cursor being set by setCursor. + // This is a bit of a hack workaround because lots of areas + // within the viewer just blindly set the cursor. if (mDragOverrideCursor == -1) { - SetThemeCursor(kThemeArrowCursor); + // Restore the cursor + ECursorType temp_cursor = mCurrentCursor; + // get around the "setting the same cursor" code in setCursor() + mCurrentCursor = UI_CURSOR_COUNT; + setCursor(temp_cursor); } else { + // Override the cursor SetThemeCursor(mDragOverrideCursor); } -- cgit v1.2.3 From fae9c8fe864278b20dfdb7caae3fbc50c779947b Mon Sep 17 00:00:00 2001 From: Monroe Linden Date: Mon, 18 Jan 2010 17:58:12 -0800 Subject: Added getNativeKeyData() function to LLWindow and LLWindowMacOSX. Added an LLSD argument to LLPluginClassMedia::keyEvent() and LLPluginClassMedia::textInput() which contains the native key data. Made LLViewerMediaImpl retrieve the native key data and pass it to keyEvent and textInput. Added a native_key_data parameter to the text_event and key_event messages. Made the webkit plugin extract the native_key_data parameter and pass it to the internal keyEvent() and unicodeInput() functions. Fixed LLMediaPluginTest to match function signature change to LLPluginClassMedia::keyEvent(). --- indra/llplugin/llpluginclassmedia.cpp | 6 +- indra/llplugin/llpluginclassmedia.h | 4 +- indra/llwindow/llwindow.h | 4 ++ indra/llwindow/llwindowmacosx.cpp | 69 +++++++++++++++++++++- indra/llwindow/llwindowmacosx.h | 5 ++ indra/media_plugins/webkit/media_plugin_webkit.cpp | 14 +++-- indra/newview/llviewermedia.cpp | 12 +++- indra/test_apps/llplugintest/llmediaplugintest.cpp | 4 +- 8 files changed, 103 insertions(+), 15 deletions(-) diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 3d2eaed5c5..609e198db2 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -469,7 +469,7 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int sendMessage(message); } -bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers) +bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data) { bool result = true; @@ -526,6 +526,7 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie message.setValueS32("key", key_code); message.setValue("modifiers", translateModifiers(modifiers)); + message.setValueLLSD("native_key_data", native_key_data); sendMessage(message); } @@ -544,12 +545,13 @@ void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers) sendMessage(message); } -bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers) +bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event"); message.setValue("text", text); message.setValue("modifiers", translateModifiers(modifiers)); + message.setValueLLSD("native_key_data", native_key_data); sendMessage(message); diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index ebb9099576..58e91fa0b4 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -114,12 +114,12 @@ public: KEY_EVENT_REPEAT }EKeyEventType; - bool keyEvent(EKeyEventType type, int key_code, MASK modifiers); + bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data); void scrollEvent(int x, int y, MASK modifiers); // Text may be unicode (utf8 encoded) - bool textInput(const std::string &text, MASK modifiers); + bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data); void loadURI(const std::string &uri); diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 127dbf45e0..55b221e716 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -37,6 +37,7 @@ #include "llcoord.h" #include "llstring.h" #include "llcursortypes.h" +#include "llsd.h" class LLSplashScreen; class LLPreeditor; @@ -162,6 +163,9 @@ public: virtual void spawnWebBrowser(const std::string& escaped_url) {}; static std::vector getDynamicFallbackFontList(); + + // Provide native key event data + virtual LLSD getNativeKeyData() { return LLSD::emptyMap(); } protected: LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags); diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index ed62faece6..84105ef126 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -260,6 +260,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, mTSMScriptCode = 0; mTSMLangCode = 0; mPreeditor = NULL; + mRawKeyEvent = NULL; mFSAASamples = fsaa_samples; mForceRebuild = FALSE; @@ -2135,10 +2136,11 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e { UInt32 modifiers = 0; + // First, process the raw event. { - EventRef rawEvent; - + EventRef rawEvent = NULL; + // Get the original event and extract the modifier keys, so we can ignore command-key events. if (GetEventParameter(event, kEventParamTextInputSendKeyboardEvent, typeEventRef, NULL, sizeof(rawEvent), NULL, &rawEvent) == noErr) { @@ -2147,6 +2149,9 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e // and call this function recursively to handle the raw key event. eventHandler (myHandler, rawEvent); + + // save the raw event until we're done processing the unicode input as well. + mRawKeyEvent = rawEvent; } } @@ -2200,6 +2205,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e delete[] buffer; } + mRawKeyEvent = NULL; result = err; } break; @@ -2274,6 +2280,9 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e GetEventParameter (event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode); GetEventParameter (event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); + // save the raw event so getNativeKeyData can use it. + mRawKeyEvent = event; + // printf("key event, key code = 0x%08x, char code = 0x%02x (%c), modifiers = 0x%08x\n", keyCode, charCode, (char)charCode, modifiers); // fflush(stdout); @@ -2369,6 +2378,8 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e result = eventNotHandledErr; break; } + + mRawKeyEvent = NULL; } break; @@ -3201,6 +3212,60 @@ void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url) } } +LLSD LLWindowMacOSX::getNativeKeyData() +{ + LLSD result = LLSD::emptyMap(); + + if(mRawKeyEvent) + { + char char_code = 0; + UInt32 key_code = 0; + UInt32 modifiers = 0; + UInt32 keyboard_type = 0; + + GetEventParameter (mRawKeyEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &char_code); + GetEventParameter (mRawKeyEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &key_code); + GetEventParameter (mRawKeyEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); + GetEventParameter (mRawKeyEvent, kEventParamKeyboardType, typeUInt32, NULL, sizeof(UInt32), NULL, &keyboard_type); + + result["char_code"] = (S32)char_code; + result["key_code"] = (S32)key_code; + result["modifiers"] = (S32)modifiers; + result["keyboard_type"] = (S32)keyboard_type; + +#if 0 + // This causes trouble for control characters -- apparently character codes less than 32 (escape, control-A, etc) + // cause llsd serialization to create XML that the llsd deserializer won't parse! + std::string unicode; + OSStatus err = noErr; + EventParamType actualType = typeUTF8Text; + UInt32 actualSize = 0; + char *buffer = NULL; + + err = GetEventParameter (mRawKeyEvent, kEventParamKeyUnicodes, typeUTF8Text, &actualType, 0, &actualSize, NULL); + if(err == noErr) + { + // allocate a buffer and get the actual data. + buffer = new char[actualSize]; + err = GetEventParameter (mRawKeyEvent, kEventParamKeyUnicodes, typeUTF8Text, &actualType, actualSize, &actualSize, buffer); + if(err == noErr) + { + unicode.assign(buffer, actualSize); + } + delete[] buffer; + } + + result["unicode"] = unicode; +#endif + + } + + + lldebugs << "native key data is: " << result << llendl; + + return result; +} + BOOL LLWindowMacOSX::dialogColorPicker( F32 *r, F32 *g, F32 *b) { diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index fbfa07fab4..7f27c64712 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -119,6 +119,10 @@ public: static std::vector getDynamicFallbackFontList(); + // Provide native key event data + /*virtual*/ LLSD getNativeKeyData(); + + protected: LLWindowMacOSX(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, @@ -208,6 +212,7 @@ protected: friend class LLWindowManager; static WindowRef sMediaWindow; + EventRef mRawKeyEvent; }; diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index 084cdd9561..3248f1dab5 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -464,7 +464,7 @@ private: //////////////////////////////////////////////////////////////////////////////// // - void keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers) + void keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) { int llqt_key; @@ -515,6 +515,8 @@ private: } // std::cerr << "keypress, original code = 0x" << std::hex << key << ", converted code = 0x" << std::hex << llqt_key << std::dec << std::endl; + + std::cerr << "key event " << (int)key_event << ", native_key_data = " << native_key_data << std::endl; if(llqt_key != 0) { @@ -526,10 +528,12 @@ private: //////////////////////////////////////////////////////////////////////////////// // - void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers) + void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) { LLWString wstr = utf8str_to_wstring(utf8str); + std::cerr << "unicode input, native_key_data = " << native_key_data << std::endl; + unsigned int i; for(i=0; i < wstr.size(); i++) { @@ -843,6 +847,7 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) std::string event = message_in.getValue("event"); S32 key = message_in.getValueS32("key"); std::string modifiers = message_in.getValue("modifiers"); + LLSD native_key_data = message_in.getValueLLSD("native_key_data"); // Treat unknown events as key-up for safety. LLQtWebKit::EKeyEvent key_event = LLQtWebKit::KE_KEY_UP; @@ -855,14 +860,15 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) key_event = LLQtWebKit::KE_KEY_REPEAT; } - keyEvent(key_event, key, decodeModifiers(modifiers)); + keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data); } else if(message_name == "text_event") { std::string text = message_in.getValue("text"); std::string modifiers = message_in.getValue("modifiers"); + LLSD native_key_data = message_in.getValueLLSD("native_key_data"); - unicodeInput(text, decodeModifiers(modifiers)); + unicodeInput(text, decodeModifiers(modifiers), native_key_data); } if(message_name == "edit_cut") { diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index ef596f9297..86fbecf4fa 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -57,6 +57,7 @@ #include "llkeyboard.h" #include "llmutelist.h" //#include "llfirstuse.h" +#include "llwindow.h" #include // for SkinFolder listener #include @@ -1824,9 +1825,12 @@ bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) if(!result) { - result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask); + + LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); + + result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data); // Since the viewer internal event dispatching doesn't give us key-up events, simulate one here. - (void)mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask); + (void)mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data); } } @@ -1844,7 +1848,9 @@ bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) if (uni_char >= 32 // discard 'control' characters && uni_char != 127) // SDL thinks this is 'delete' - yuck. { - mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE)); + LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); + + mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data); } } diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp index d183aac208..0ff53f3e00 100644 --- a/indra/test_apps/llplugintest/llmediaplugintest.cpp +++ b/indra/test_apps/llplugintest/llmediaplugintest.cpp @@ -1169,8 +1169,8 @@ void LLMediaPluginTest::keyboard( int key ) exit( 0 ); }; - mSelectedPanel->mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_DOWN, key, 0 ); - mSelectedPanel->mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_UP, key, 0 ); + mSelectedPanel->mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_DOWN, key, 0 , LLSD()); + mSelectedPanel->mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_UP, key, 0, LLSD()); }; //////////////////////////////////////////////////////////////////////////////// -- cgit v1.2.3 From 228d37a8d72146d9baed57c7406a9324ce8c0175 Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Tue, 19 Jan 2010 11:52:41 -0800 Subject: Fix for EXT-4191 - Drag and Drop viewer resolves some slurls to "//" --- indra/newview/llviewerwindow.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 45e153049b..d4ffe70f24 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -824,8 +824,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi { if (drop) { - LLURLDispatcher::dispatch( data, NULL, true ); - LLURLSimString::setString( LLSLURL::stripProtocol( data ) ); + LLURLSimString::setStringRaw( LLSLURL::stripProtocol( data ) ); LLPanelLogin::refreshLocation( true ); LLPanelLogin::updateLocationUI(); } -- cgit v1.2.3 From 95fc42c3219151d085f139a8f239bdc5fb6b30f3 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 19 Jan 2010 15:19:11 -0500 Subject: Ensure Lynx's Boost patch is in place -- Windows --- install.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.xml b/install.xml index 5069e44d46..5cb960c506 100644 --- a/install.xml +++ b/install.xml @@ -214,9 +214,9 @@ windows md5sum - 6746ae9fd9aff98b15f7b9f0f40334ab + acbf7a4165a917a4e087879d1756b355 url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-windows-20091204.tar.bz2 + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-windows-20100119.tar.bz2 -- cgit v1.2.3 From dab8a89df68fe29ce3794d7763e9890da5ff7ed2 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 19 Jan 2010 12:23:25 -0800 Subject: Ensure Lynx's Boost patch is in place -- linux, linux64 --- install.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/install.xml b/install.xml index fdd7458384..e94654e175 100644 --- a/install.xml +++ b/install.xml @@ -200,16 +200,16 @@ linux md5sum - 7085044567999489d82b9ed28f16e480 + ee8e1b4bbcf137a84d6a85a1c51386ff url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-linux-20091202.tar.bz2 + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-linux-20100119.tar.bz2 linux64 md5sum - b4aeefcba3d749f1e9f2a12c6f70192b + af4badd6b2c10bc4db82ff1256695892 url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-linux64-20091202.tar.bz2 + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-linux64-20100119.tar.bz2 windows -- cgit v1.2.3 From 56c021f606d249e4b7ba334809b0332fe2fdcc11 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 19 Jan 2010 15:28:10 -0500 Subject: Ensure Lynx's Boost patch is in place -- darwin --- install.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.xml b/install.xml index fdd7458384..e08676d869 100644 --- a/install.xml +++ b/install.xml @@ -193,9 +193,9 @@ darwin md5sum - 609c469ee1857723260b5a9943b9c2c1 + 84821102cb819257a66c8f38732647fc url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-darwin-20091202.tar.bz2 + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-darwin-20100119.tar.bz2 linux -- cgit v1.2.3 From 572b8fc518ee45cdf5403f58b18e0000868696cb Mon Sep 17 00:00:00 2001 From: Monroe Linden Date: Tue, 19 Jan 2010 21:55:51 -0800 Subject: Changes to llqtwebkit keyboard event api. Reference to new mac build of llqtwebkit (from revision 5e61bf24915f in https://hg.lindenlab.com/monroe/llqtwebkit-4.6). --- indra/llplugin/llpluginclassmedia.cpp | 6 +- indra/media_plugins/webkit/media_plugin_webkit.cpp | 109 +++++++++------------ install.xml | 4 +- 3 files changed, 52 insertions(+), 67 deletions(-) diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 609e198db2..adc0b3467d 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -682,13 +682,13 @@ LLPluginClassMedia::ETargetType getTargetTypeFromLLQtWebkit(int target_type) // so that we don't expose the llqtwebkit header in viewer code switch (target_type) { - case LinkTargetType::LTT_TARGET_NONE: + case LLQtWebKit::LTT_TARGET_NONE: return LLPluginClassMedia::TARGET_NONE; - case LinkTargetType::LTT_TARGET_BLANK: + case LLQtWebKit::LTT_TARGET_BLANK: return LLPluginClassMedia::TARGET_BLANK; - case LinkTargetType::LTT_TARGET_EXTERNAL: + case LLQtWebKit::LTT_TARGET_EXTERNAL: return LLPluginClassMedia::TARGET_EXTERNAL; default: diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index 3248f1dab5..e95e9e3b34 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -466,62 +466,43 @@ private: // void keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) { - int llqt_key; - // The incoming values for 'key' will be the ones from indra_constants.h - // the outgoing values are the ones from llqtwebkit.h + std::string utf8_text; + + if(key < KEY_SPECIAL) + { + // Low-ascii characters need to get passed through. + utf8_text = (char)key; + } + // Any special-case handling we want to do for particular keys... switch((KEY)key) { - // This is the list that the llqtwebkit implementation actually maps into Qt keys. -// case KEY_XXX: llqt_key = LL_DOM_VK_CANCEL; break; -// case KEY_XXX: llqt_key = LL_DOM_VK_HELP; break; - case KEY_BACKSPACE: llqt_key = LL_DOM_VK_BACK_SPACE; break; - case KEY_TAB: llqt_key = LL_DOM_VK_TAB; break; -// case KEY_XXX: llqt_key = LL_DOM_VK_CLEAR; break; - case KEY_RETURN: llqt_key = LL_DOM_VK_RETURN; break; - case KEY_PAD_RETURN: llqt_key = LL_DOM_VK_ENTER; break; - case KEY_SHIFT: llqt_key = LL_DOM_VK_SHIFT; break; - case KEY_CONTROL: llqt_key = LL_DOM_VK_CONTROL; break; - case KEY_ALT: llqt_key = LL_DOM_VK_ALT; break; -// case KEY_XXX: llqt_key = LL_DOM_VK_PAUSE; break; - case KEY_CAPSLOCK: llqt_key = LL_DOM_VK_CAPS_LOCK; break; - case KEY_ESCAPE: llqt_key = LL_DOM_VK_ESCAPE; break; - case KEY_PAGE_UP: llqt_key = LL_DOM_VK_PAGE_UP; break; - case KEY_PAGE_DOWN: llqt_key = LL_DOM_VK_PAGE_DOWN; break; - case KEY_END: llqt_key = LL_DOM_VK_END; break; - case KEY_HOME: llqt_key = LL_DOM_VK_HOME; break; - case KEY_LEFT: llqt_key = LL_DOM_VK_LEFT; break; - case KEY_UP: llqt_key = LL_DOM_VK_UP; break; - case KEY_RIGHT: llqt_key = LL_DOM_VK_RIGHT; break; - case KEY_DOWN: llqt_key = LL_DOM_VK_DOWN; break; -// case KEY_XXX: llqt_key = LL_DOM_VK_PRINTSCREEN; break; - case KEY_INSERT: llqt_key = LL_DOM_VK_INSERT; break; - case KEY_DELETE: llqt_key = LL_DOM_VK_DELETE; break; -// case KEY_XXX: llqt_key = LL_DOM_VK_CONTEXT_MENU; break; + // ASCII codes for some standard keys + case LLQtWebKit::KEY_BACKSPACE: utf8_text = (char)8; break; + case LLQtWebKit::KEY_TAB: utf8_text = (char)9; break; + case LLQtWebKit::KEY_RETURN: utf8_text = (char)13; break; + case LLQtWebKit::KEY_PAD_RETURN: utf8_text = (char)13; break; + case LLQtWebKit::KEY_ESCAPE: utf8_text = (char)27; break; - default: - if(key < KEY_SPECIAL) - { - // Pass the incoming key through -- it should be regular ASCII, which should be correct for webkit. - llqt_key = key; - } - else - { - // Don't pass through untranslated special keys -- they'll be all wrong. - llqt_key = 0; - } + default: break; } -// std::cerr << "keypress, original code = 0x" << std::hex << key << ", converted code = 0x" << std::hex << llqt_key << std::dec << std::endl; - - std::cerr << "key event " << (int)key_event << ", native_key_data = " << native_key_data << std::endl; +// std::cerr << "key event " << (int)key_event << ", native_key_data = " << native_key_data << std::endl; + + uint32_t native_scan_code = 0; + uint32_t native_virtual_key = 0; + uint32_t native_modifiers = 0; - if(llqt_key != 0) + if(native_key_data.isMap()) { - LLQtWebKit::getInstance()->keyEvent( mBrowserWindowId, key_event, llqt_key, modifiers); + native_scan_code = (uint32_t)(native_key_data["key_code"].asInteger()); + native_virtual_key = (uint32_t)(native_key_data["char_code"].asInteger()); + native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); } + + LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); checkEditState(); }; @@ -529,27 +510,31 @@ private: //////////////////////////////////////////////////////////////////////////////// // void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) - { - LLWString wstr = utf8str_to_wstring(utf8str); + { + uint32_t key = LLQtWebKit::KEY_NONE; - std::cerr << "unicode input, native_key_data = " << native_key_data << std::endl; +// std::cerr << "unicode input, native_key_data = " << native_key_data << std::endl; - unsigned int i; - for(i=0; i < wstr.size(); i++) + if(utf8str.size() == 1) { -// std::cerr << "unicode input, code = 0x" << std::hex << (unsigned long)(wstr[i]) << std::dec << std::endl; - - if(wstr[i] == 32) - { - // For some reason, the webkit plugin really wants the space bar to come in through the key-event path, not the unicode path. - LLQtWebKit::getInstance()->keyEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_DOWN, 32, modifiers); - LLQtWebKit::getInstance()->keyEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_UP, 32, modifiers); - } - else - { - LLQtWebKit::getInstance()->unicodeInput(mBrowserWindowId, wstr[i], modifiers); - } + // The only way a utf8 string can be one byte long is if it's actually a single 7-bit ascii character. + // In this case, use it as the key value. + key = utf8str[0]; + } + + uint32_t native_scan_code = 0; + uint32_t native_virtual_key = 0; + uint32_t native_modifiers = 0; + + if(native_key_data.isMap()) + { + native_scan_code = (uint32_t)(native_key_data["key_code"].asInteger()); + native_virtual_key = (uint32_t)(native_key_data["char_code"].asInteger()); + native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); } + + LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_DOWN, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); + LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_UP, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); checkEditState(); }; diff --git a/install.xml b/install.xml index ef24263972..81064c6306 100644 --- a/install.xml +++ b/install.xml @@ -948,9 +948,9 @@ anguage Infrstructure (CLI) international standard darwin md5sum - 2eb58f544c0d912aa382de2c947be7f1 + 02d3d8171fff0c673f900f1d1a53046a url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-4.6-darwin-20100104.tar.bz2 + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-4.6-darwin-20100119.tar.bz2 linux -- cgit v1.2.3 From ae079af48d8ab6b1939168b0a2ac95876da66d24 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Wed, 20 Jan 2010 09:55:36 -0800 Subject: Add another setting controlling whether SLURL drag-and-drop performs a teleport --- indra/newview/app_settings/settings.xml | 13 ++- indra/newview/llviewerwindow.cpp | 146 +++++++++++++++++--------------- 2 files changed, 90 insertions(+), 69 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 9f261978e6..6096504b96 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5552,7 +5552,7 @@ PrimMediaDragNDrop Comment - Enable drag and drop + Enable drag and drop of URLs onto prim faces Persist 1 Type @@ -10786,6 +10786,17 @@ Value 0 + SLURLDragNDrop + + Comment + Enable drag and drop of SLURLs onto the viewer + Persist + 1 + Type + Boolean + Value + 1 + soundsbeacon Comment diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 45e153049b..e743d3419e 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -808,7 +808,10 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi { LLWindowCallbacks::DragNDropResult result = LLWindowCallbacks::DND_NONE; - if (gSavedSettings.getBOOL("PrimMediaDragNDrop")) + const bool prim_media_dnd_enabled = gSavedSettings.getBOOL("PrimMediaDragNDrop"); + const bool slurl_dnd_enabled = gSavedSettings.getBOOL("SLURLDragNDrop"); + + if ( prim_media_dnd_enabled || slurl_dnd_enabled ) { switch(action) { @@ -819,90 +822,96 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi { bool drop = (LLWindowCallbacks::DNDA_DROPPED == action); - // special case SLURLs - if ( LLSLURL::isSLURL( data ) ) + if (slurl_dnd_enabled) { - if (drop) + // special case SLURLs + if ( LLSLURL::isSLURL( data ) ) { - LLURLDispatcher::dispatch( data, NULL, true ); - LLURLSimString::setString( LLSLURL::stripProtocol( data ) ); - LLPanelLogin::refreshLocation( true ); - LLPanelLogin::updateLocationUI(); - } - return LLWindowCallbacks::DND_MOVE; - }; + if (drop) + { + LLURLDispatcher::dispatch( data, NULL, true ); + LLURLSimString::setString( LLSLURL::stripProtocol( data ) ); + LLPanelLogin::refreshLocation( true ); + LLPanelLogin::updateLocationUI(); + } + return LLWindowCallbacks::DND_MOVE; + }; + } - LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ ); + if (prim_media_dnd_enabled) + { + LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ ); - LLUUID object_id = pick_info.getObjectID(); - S32 object_face = pick_info.mObjectFace; - std::string url = data; + LLUUID object_id = pick_info.getObjectID(); + S32 object_face = pick_info.mObjectFace; + std::string url = data; - lldebugs << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; + lldebugs << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; - LLVOVolume *obj = dynamic_cast(static_cast(pick_info.getObject())); + LLVOVolume *obj = dynamic_cast(static_cast(pick_info.getObject())); - if (obj && obj->permModify() && !obj->getRegion()->getCapability("ObjectMedia").empty()) - { - LLTextureEntry *te = obj->getTE(object_face); - if (te) + if (obj && obj->permModify() && !obj->getRegion()->getCapability("ObjectMedia").empty()) { - if (drop) + LLTextureEntry *te = obj->getTE(object_face); + if (te) { - if (! te->hasMedia()) + if (drop) { - // Create new media entry - LLSD media_data; - // XXX Should we really do Home URL too? - media_data[LLMediaEntry::HOME_URL_KEY] = url; - media_data[LLMediaEntry::CURRENT_URL_KEY] = url; - media_data[LLMediaEntry::AUTO_PLAY_KEY] = true; - obj->syncMediaData(object_face, media_data, true, true); - // XXX This shouldn't be necessary, should it ?!? - if (obj->getMediaImpl(object_face)) - obj->getMediaImpl(object_face)->navigateReload(); - obj->sendMediaDataUpdate(); - - result = LLWindowCallbacks::DND_COPY; - } - else { - // Check the whitelist - if (te->getMediaData()->checkCandidateUrl(url)) + if (! te->hasMedia()) { - // just navigate to the URL + // Create new media entry + LLSD media_data; + // XXX Should we really do Home URL too? + media_data[LLMediaEntry::HOME_URL_KEY] = url; + media_data[LLMediaEntry::CURRENT_URL_KEY] = url; + media_data[LLMediaEntry::AUTO_PLAY_KEY] = true; + obj->syncMediaData(object_face, media_data, true, true); + // XXX This shouldn't be necessary, should it ?!? if (obj->getMediaImpl(object_face)) + obj->getMediaImpl(object_face)->navigateReload(); + obj->sendMediaDataUpdate(); + + result = LLWindowCallbacks::DND_COPY; + } + else { + // Check the whitelist + if (te->getMediaData()->checkCandidateUrl(url)) { - obj->getMediaImpl(object_face)->navigateTo(url); + // just navigate to the URL + if (obj->getMediaImpl(object_face)) + { + obj->getMediaImpl(object_face)->navigateTo(url); + } + else { + // This is very strange. Navigation should + // happen via the Impl, but we don't have one. + // This sends it to the server, which /should/ + // trigger us getting it. Hopefully. + LLSD media_data; + media_data[LLMediaEntry::CURRENT_URL_KEY] = url; + obj->syncMediaData(object_face, media_data, true, true); + obj->sendMediaDataUpdate(); + } + result = LLWindowCallbacks::DND_LINK; } - else { - // This is very strange. Navigation should - // happen via the Impl, but we don't have one. - // This sends it to the server, which /should/ - // trigger us getting it. Hopefully. - LLSD media_data; - media_data[LLMediaEntry::CURRENT_URL_KEY] = url; - obj->syncMediaData(object_face, media_data, true, true); - obj->sendMediaDataUpdate(); - } - result = LLWindowCallbacks::DND_LINK; } - } - LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); - mDragHoveredObject = NULL; + LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); + mDragHoveredObject = NULL; - } - else { - // Check the whitelist, if there's media (otherwise just show it) - if (te->getMediaData() == NULL || te->getMediaData()->checkCandidateUrl(url)) - { - if ( obj != mDragHoveredObject) + } + else { + // Check the whitelist, if there's media (otherwise just show it) + if (te->getMediaData() == NULL || te->getMediaData()->checkCandidateUrl(url)) { - // Highlight the dragged object - LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); - mDragHoveredObject = obj; - LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject); + if ( obj != mDragHoveredObject) + { + // Highlight the dragged object + LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); + mDragHoveredObject = obj; + LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject); + } + result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK; } - result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK; } } } @@ -915,7 +924,8 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi break; } - if (result == LLWindowCallbacks::DND_NONE && !mDragHoveredObject.isNull()) + if (prim_media_dnd_enabled && + result == LLWindowCallbacks::DND_NONE && !mDragHoveredObject.isNull()) { LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); mDragHoveredObject = NULL; -- cgit v1.2.3 From 5d8de7b7200c514bb874e4f60581c6df6cf3be5a Mon Sep 17 00:00:00 2001 From: Erica Date: Thu, 21 Jan 2010 10:52:58 -0800 Subject: getting chiclet stuff out of test floater since it causes a crash --- .../skins/default/xui/en/floater_test_checkbox.xml | 79 ---------------------- 1 file changed, 79 deletions(-) diff --git a/indra/newview/skins/default/xui/en/floater_test_checkbox.xml b/indra/newview/skins/default/xui/en/floater_test_checkbox.xml index 042b4226c3..9977e85a9d 100644 --- a/indra/newview/skins/default/xui/en/floater_test_checkbox.xml +++ b/indra/newview/skins/default/xui/en/floater_test_checkbox.xml @@ -71,83 +71,4 @@ name="font_checkbox" top_pad="14" width="150" /> - - - - - - - - - - - - - - - -- cgit v1.2.3 From 337716d946cf4ece8ba59cce82bd51b3c2148f75 Mon Sep 17 00:00:00 2001 From: richard Date: Fri, 22 Jan 2010 16:51:13 -0800 Subject: LLPointer cleanup and fix for EXT-4413 reviewed by Rick --- indra/llcommon/llpointer.h | 1 - indra/llcommon/llrefcount.cpp | 11 +++ indra/llcommon/llrefcount.h | 14 ++-- indra/llui/llspinctrl.cpp | 16 ++-- indra/llui/llspinctrl.h | 5 +- indra/llui/llstyle.h | 4 +- indra/llui/lltextbase.cpp | 49 +++++------- indra/llui/lltextbase.h | 19 +++-- indra/llui/lltexteditor.cpp | 8 +- indra/llui/llui.cpp | 18 ++--- indra/llui/lluicolortable.h | 2 +- indra/llui/lluiimage.cpp | 4 +- indra/llxuixml/llinitparam.cpp | 12 ++- indra/llxuixml/llinitparam.h | 3 +- indra/llxuixml/lluicolor.cpp | 14 ++-- indra/llxuixml/lluicolor.h | 8 +- indra/newview/llavatarlist.h | 10 +-- indra/newview/llavatarlistitem.cpp | 88 +++++++++------------- indra/newview/llavatarlistitem.h | 15 +++- indra/newview/llexpandabletextbox.cpp | 6 +- indra/newview/llviewertexteditor.cpp | 2 +- .../default/xui/en/widgets/avatar_list_item.xml | 44 +++++++++++ 22 files changed, 195 insertions(+), 158 deletions(-) create mode 100644 indra/newview/skins/default/xui/en/widgets/avatar_list_item.xml diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index 2c37eadcc6..e6c736a263 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -95,7 +95,6 @@ public: bool notNull() const { return (mPointer != NULL); } operator Type*() const { return mPointer; } - operator const Type*() const { return mPointer; } bool operator !=(Type* ptr) const { return (mPointer != ptr); } bool operator ==(Type* ptr) const { return (mPointer == ptr); } bool operator ==(const LLPointer& ptr) const { return (mPointer == ptr.mPointer); } diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp index 33b6875fb0..c90b52f482 100644 --- a/indra/llcommon/llrefcount.cpp +++ b/indra/llcommon/llrefcount.cpp @@ -35,6 +35,17 @@ #include "llerror.h" +LLRefCount::LLRefCount(const LLRefCount& other) +: mRef(0) +{ +} + +LLRefCount& LLRefCount::operator=(const LLRefCount&) +{ + // do nothing, since ref count is specific to *this* reference + return *this; +} + LLRefCount::LLRefCount() : mRef(0) { diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index 9ab844eb22..a18f6706a9 100644 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -41,22 +41,20 @@ class LL_COMMON_API LLRefCount { -private: - LLRefCount(const LLRefCount& other); // no implementation -private: - LLRefCount& operator=(const LLRefCount&); // no implementation protected: + LLRefCount(const LLRefCount& other); + LLRefCount& operator=(const LLRefCount&); virtual ~LLRefCount(); // use unref() public: LLRefCount(); - void ref() + void ref() const { mRef++; } - S32 unref() + S32 unref() const { llassert(mRef >= 1); if (0 == --mRef) @@ -67,13 +65,15 @@ public: return mRef; } + //NOTE: when passing around a const LLRefCount object, this can return different results + // at different types, since mRef is mutable S32 getNumRefs() const { return mRef; } private: - S32 mRef; + mutable S32 mRef; }; #endif diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp index 20a1ab7af3..28f3788817 100644 --- a/indra/llui/llspinctrl.cpp +++ b/indra/llui/llspinctrl.cpp @@ -270,13 +270,19 @@ void LLSpinCtrl::clear() mbHasBeenSet = FALSE; } - +void LLSpinCtrl::updateLabelColor() +{ + if( mLabelBox ) + { + mLabelBox->setColor( getEnabled() ? mTextEnabledColor.get() : mTextDisabledColor.get() ); + } +} void LLSpinCtrl::updateEditor() { LLLocale locale(LLLocale::USER_LOCALE); - // Don't display very small negative values as -0.000 + // Don't display very small negative valu es as -0.000 F32 displayed_value = clamp_precision((F32)getValue().asReal(), mPrecision); // if( S32( displayed_value * pow( 10, mPrecision ) ) == 0 ) @@ -339,10 +345,7 @@ void LLSpinCtrl::setEnabled(BOOL b) { LLView::setEnabled( b ); mEditor->setEnabled( b ); - if( mLabelBox ) - { - mLabelBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() ); - } + updateLabelColor(); } @@ -390,6 +393,7 @@ void LLSpinCtrl::setLabel(const LLStringExplicit& label) { llwarns << "Attempting to set label on LLSpinCtrl constructed without one " << getName() << llendl; } + updateLabelColor(); } void LLSpinCtrl::setAllowEdit(BOOL allow_edit) diff --git a/indra/llui/llspinctrl.h b/indra/llui/llspinctrl.h index 0e610b7741..00d6f86f83 100644 --- a/indra/llui/llspinctrl.h +++ b/indra/llui/llspinctrl.h @@ -81,8 +81,8 @@ public: virtual void setPrecision(S32 precision); void setLabel(const LLStringExplicit& label); - void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; } - void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; } + void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; updateLabelColor(); } + void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; updateLabelColor();} void setAllowEdit(BOOL allow_edit); virtual void onTabInto(); @@ -103,6 +103,7 @@ public: void onDownBtn(const LLSD& data); private: + void updateLabelColor(); void updateEditor(); void reportInvalidData(); diff --git a/indra/llui/llstyle.h b/indra/llui/llstyle.h index ee9ca730e9..2067e8e8be 100644 --- a/indra/llui/llstyle.h +++ b/indra/llui/llstyle.h @@ -59,11 +59,12 @@ public: void setColor(const LLColor4 &color) { mColor = color; } const LLColor4& getReadOnlyColor() const { return mReadOnlyColor; } + void setReadOnlyColor(const LLColor4& color) { mReadOnlyColor = color; } BOOL isVisible() const; void setVisible(BOOL is_visible); - LLFontGL::ShadowType getShadowType() { return mDropShadow; } + LLFontGL::ShadowType getShadowType() const { return mDropShadow; } void setFont(const LLFontGL* font); const LLFontGL* getFont() const; @@ -116,5 +117,6 @@ private: }; typedef LLPointer LLStyleSP; +typedef LLPointer LLStyleConstSP; #endif // LL_LLSTYLE_H diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 17aecaf32f..885a830c9f 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -291,9 +291,13 @@ bool LLTextBase::truncate() return did_truncate; } -LLStyle::Params LLTextBase::getDefaultStyle() +LLStyle::Params LLTextBase::getDefaultStyleParams() { - return LLStyle::Params().color(mFgColor.get()).readonly_color(mReadOnlyFgColor.get()).font(mDefaultFont).drop_shadow(mFontShadow); + return LLStyle::Params() + .color(LLUIColor(&mFgColor)) + .readonly_color(LLUIColor(&mReadOnlyFgColor)) + .font(mDefaultFont) + .drop_shadow(mFontShadow); } void LLTextBase::onValueChange(S32 start, S32 end) @@ -619,7 +623,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s else { // create default editable segment to hold new text - default_segment = new LLNormalTextSegment( new LLStyle(getDefaultStyle()), pos, pos + insert_len, *this); + default_segment = new LLNormalTextSegment( LLStyleConstSP(new LLStyle(getDefaultStyleParams())), pos, pos + insert_len, *this); } // shift remaining segments to right @@ -743,7 +747,7 @@ void LLTextBase::createDefaultSegment() // ensures that there is always at least one segment if (mSegments.empty()) { - LLTextSegmentPtr default_segment = new LLNormalTextSegment( new LLStyle(getDefaultStyle()), 0, getLength() + 1, *this); + LLTextSegmentPtr default_segment = new LLNormalTextSegment( LLStyleConstSP(new LLStyle(getDefaultStyleParams())), 0, getLength() + 1, *this); mSegments.insert(default_segment); default_segment->linkToDocument(this); } @@ -1510,16 +1514,7 @@ std::string LLTextBase::getText() const void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params) { LLStyle::Params style_params(input_params); - style_params.fillFrom(getDefaultStyle()); - - if (!style_params.font.isProvided()) - { - style_params.font = mDefaultFont; - } - if (!style_params.drop_shadow.isProvided()) - { - style_params.drop_shadow = mFontShadow; - } + style_params.fillFrom(getDefaultStyleParams()); S32 part = (S32)LLTextParser::WHOLE; if(mParseHTML) @@ -1536,13 +1531,7 @@ void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, c LLStyle::Params link_params = style_params; link_params.color = match.getColor(); link_params.readonly_color = match.getColor(); - // apply font name from requested style_params - std::string font_name = LLFontGL::nameFromFont(style_params.font()); - std::string font_size = LLFontGL::sizeFromFont(style_params.font()); - link_params.font.name(font_name); - link_params.font.size(font_size); link_params.font.style("UNDERLINE"); - link_params.link_href = match.getUrl(); // output the text before the Url @@ -1611,9 +1600,9 @@ void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, c } } -void LLTextBase::appendAndHighlightText(const std::string &new_text, bool prepend_newline, S32 highlight_part, const LLStyle::Params& stylep) +void LLTextBase::appendAndHighlightText(const std::string &new_text, bool prepend_newline, S32 highlight_part, const LLStyle::Params& style_params) { - if (new_text.empty()) return; + if (new_text.empty()) return; // Save old state S32 selection_start = mSelectionStart; @@ -1631,7 +1620,7 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, bool prepen if (mParseHighlights && highlight) { - LLStyle::Params highlight_params = stylep; + LLStyle::Params highlight_params(style_params); LLSD pieces = highlight->parsePartialLineHighlights(new_text, highlight_params.color(), (LLTextParser::EHighlightPosition)highlight_part); for (S32 i = 0; i < pieces.size(); i++) @@ -1651,7 +1640,7 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, bool prepen wide_text = utf8str_to_wstring(pieces[i]["text"].asString()); } S32 cur_length = getLength(); - LLTextSegmentPtr segmentp = new LLNormalTextSegment(new LLStyle(highlight_params), cur_length, cur_length + wide_text.size(), *this); + LLTextSegmentPtr segmentp = new LLNormalTextSegment(LLStyleConstSP(new LLStyle(highlight_params)), cur_length, cur_length + wide_text.size(), *this); segment_vec_t segments; segments.push_back(segmentp); insertStringNoUndo(cur_length, wide_text, &segments); @@ -1675,7 +1664,7 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, bool prepen segment_vec_t segments; S32 segment_start = old_length; S32 segment_end = old_length + wide_text.size(); - segments.push_back(new LLNormalTextSegment(new LLStyle(stylep), segment_start, segment_end, *this )); + segments.push_back(new LLNormalTextSegment(LLStyleConstSP(new LLStyle(style_params)), segment_start, segment_end, *this )); insertStringNoUndo(getLength(), wide_text, &segments); } @@ -1719,7 +1708,7 @@ void LLTextBase::replaceUrlLabel(const std::string &url, for (it = mSegments.begin(); it != mSegments.end(); ++it) { LLTextSegment *seg = *it; - const LLStyleSP style = seg->getStyle(); + LLStyleConstSP style = seg->getStyle(); // update segment start/end length in case we replaced text earlier S32 seg_length = seg->getEnd() - seg->getStart(); @@ -2212,9 +2201,9 @@ bool LLTextSegment::canEdit() const { return false; } void LLTextSegment::unlinkFromDocument(LLTextBase*) {} void LLTextSegment::linkToDocument(LLTextBase*) {} const LLColor4& LLTextSegment::getColor() const { return LLColor4::white; } -void LLTextSegment::setColor(const LLColor4 &color) {} -const LLStyleSP LLTextSegment::getStyle() const {static LLStyleSP sp(new LLStyle()); return sp; } -void LLTextSegment::setStyle(const LLStyleSP &style) {} +//void LLTextSegment::setColor(const LLColor4 &color) {} +LLStyleConstSP LLTextSegment::getStyle() const {static LLStyleConstSP sp(new LLStyle()); return sp; } +void LLTextSegment::setStyle(LLStyleConstSP &style) {} void LLTextSegment::setToken( LLKeywordToken* token ) {} LLKeywordToken* LLTextSegment::getToken() const { return NULL; } void LLTextSegment::setToolTip( const std::string &msg ) {} @@ -2239,7 +2228,7 @@ BOOL LLTextSegment::hasMouseCapture() { return FALSE; } // LLNormalTextSegment // -LLNormalTextSegment::LLNormalTextSegment( const LLStyleSP& style, S32 start, S32 end, LLTextBase& editor ) +LLNormalTextSegment::LLNormalTextSegment( LLStyleConstSP& style, S32 start, S32 end, LLTextBase& editor ) : LLTextSegment(start, end), mStyle( style ), mToken(NULL), diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 038b9eaa62..5526667166 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -184,7 +184,6 @@ public: bool scrolledToEnd(); const LLFontGL* getDefaultFont() const { return mDefaultFont; } - LLStyle::Params getDefaultStyle(); public: // Fired when a URL link is clicked @@ -281,7 +280,8 @@ protected: void createDefaultSegment(); virtual void updateSegments(); void insertSegment(LLTextSegmentPtr segment_to_insert); - + LLStyle::Params getDefaultStyleParams(); + // manage lines S32 getLineStart( S32 line ) const; S32 getLineEnd( S32 line ) const; @@ -388,9 +388,9 @@ public: virtual void linkToDocument(class LLTextBase* editor); virtual const LLColor4& getColor() const; - virtual void setColor(const LLColor4 &color); - virtual const LLStyleSP getStyle() const; - virtual void setStyle(const LLStyleSP &style); + //virtual void setColor(const LLColor4 &color); + virtual LLStyleConstSP getStyle() const; + virtual void setStyle(LLStyleConstSP &style); virtual void setToken( LLKeywordToken* token ); virtual LLKeywordToken* getToken() const; virtual void setToolTip(const std::string& tooltip); @@ -426,7 +426,7 @@ protected: class LLNormalTextSegment : public LLTextSegment { public: - LLNormalTextSegment( const LLStyleSP& style, S32 start, S32 end, LLTextBase& editor ); + LLNormalTextSegment( LLStyleConstSP& style, S32 start, S32 end, LLTextBase& editor ); LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); ~LLNormalTextSegment(); @@ -436,9 +436,8 @@ public: /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect); /*virtual*/ bool canEdit() const { return true; } /*virtual*/ const LLColor4& getColor() const { return mStyle->getColor(); } - /*virtual*/ void setColor(const LLColor4 &color) { mStyle->setColor(color); } - /*virtual*/ const LLStyleSP getStyle() const { return mStyle; } - /*virtual*/ void setStyle(const LLStyleSP &style) { mStyle = style; } + /*virtual*/ LLStyleConstSP getStyle() const { return mStyle; } + /*virtual*/ void setStyle(LLStyleConstSP &style) { mStyle = style; } /*virtual*/ void setToken( LLKeywordToken* token ) { mToken = token; } /*virtual*/ LLKeywordToken* getToken() const { return mToken; } /*virtual*/ BOOL getToolTip( std::string& msg ) const; @@ -456,7 +455,7 @@ protected: protected: class LLTextBase& mEditor; - LLStyleSP mStyle; + LLStyleConstSP mStyle; S32 mFontHeight; LLKeywordToken* mToken; std::string mTooltip; diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index f2c3879a6c..93ce7a4bea 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -2390,7 +2390,7 @@ void LLTextEditor::replaceUrlLabel(const std::string &url, for (it = mSegments.begin(); it != mSegments.end(); ++it) { LLTextSegment *seg = *it; - const LLStyleSP style = seg->getStyle(); + LLStyleConstSP style = seg->getStyle(); // update segment start/end length in case we replaced text earlier S32 seg_length = seg->getEnd() - seg->getStart(); @@ -2559,13 +2559,15 @@ void LLTextEditor::updateLinkSegments() // if the link's label (what the user can edit) is a valid Url, // then update the link's HREF to be the same as the label text. // This lets users edit Urls in-place. - LLStyleSP style = static_cast(segment->getStyle()); + LLStyleConstSP style = segment->getStyle(); + LLStyle* new_style = new LLStyle(*style); LLWString url_label = wtext.substr(segment->getStart(), segment->getEnd()-segment->getStart()); if (LLUrlRegistry::instance().hasUrl(url_label)) { std::string new_url = wstring_to_utf8str(url_label); LLStringUtil::trim(new_url); - style->setLinkHREF(new_url); + new_style->setLinkHREF(new_url); + segment->setStyle(LLStyleConstSP(new_style)); } } } diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index d0ed3b6fca..76f07373b4 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -1911,10 +1911,10 @@ namespace LLInitParam void TypedParam::setBlockFromValue() { LLColor4 color = mData.mValue.get(); - red = color.mV[VRED]; - green = color.mV[VGREEN]; - blue = color.mV[VBLUE]; - alpha = color.mV[VALPHA]; + red.set(color.mV[VRED], false); + green.set(color.mV[VGREEN], false); + blue.set(color.mV[VBLUE], false); + alpha.set(color.mV[VALPHA], false); control.set("", false); } @@ -1965,9 +1965,9 @@ namespace LLInitParam { if (mData.mValue) { - name = LLFontGL::nameFromFont(mData.mValue); - size = LLFontGL::sizeFromFont(mData.mValue); - style = LLFontGL::getStringFromStyle(mData.mValue->getFontDesc().getStyle()); + name.set(LLFontGL::nameFromFont(mData.mValue), false); + size.set(LLFontGL::sizeFromFont(mData.mValue), false); + style.set(LLFontGL::getStringFromStyle(mData.mValue->getFontDesc().getStyle()), false); } } @@ -2073,8 +2073,8 @@ namespace LLInitParam void TypedParam::setBlockFromValue() { - x = mData.mValue.mX; - y = mData.mValue.mY; + x.set(mData.mValue.mX, false); + y.set(mData.mValue.mY, false); } diff --git a/indra/llui/lluicolortable.h b/indra/llui/lluicolortable.h index 59be0c4f9a..c87695f456 100644 --- a/indra/llui/lluicolortable.h +++ b/indra/llui/lluicolortable.h @@ -94,7 +94,7 @@ private: bool loadFromFilename(const std::string& filename); // consider using sorted vector, can be much faster - typedef std::map string_color_map_t; + typedef std::map string_color_map_t; void clearTable(string_color_map_t& table); void setColor(const std::string& name, const LLColor4& color, string_color_map_t& table); diff --git a/indra/llui/lluiimage.cpp b/indra/llui/lluiimage.cpp index 966d919dc7..8cd6460b66 100644 --- a/indra/llui/lluiimage.cpp +++ b/indra/llui/lluiimage.cpp @@ -182,11 +182,11 @@ namespace LLInitParam { if (mData.mValue == NULL) { - name = "none"; + name.set("none", false); } else { - name = mData.mValue->getName(); + name.set(mData.mValue->getName(), false); } } diff --git a/indra/llxuixml/llinitparam.cpp b/indra/llxuixml/llinitparam.cpp index 4c050844f8..424a9fae8e 100644 --- a/indra/llxuixml/llinitparam.cpp +++ b/indra/llxuixml/llinitparam.cpp @@ -84,8 +84,7 @@ namespace LLInitParam // BaseBlock // BaseBlock::BaseBlock() - : mLastChangedParam(0), - mChangeVersion(0) + : mChangeVersion(0) {} BaseBlock::~BaseBlock() @@ -347,7 +346,6 @@ namespace LLInitParam if (deserialize_func && deserialize_func(*paramp, p, name_stack, name_stack.first == name_stack.second ? -1 : name_stack.first->second)) { - mLastChangedParam = (*it)->mParamHandle; return true; } } @@ -416,8 +414,10 @@ namespace LLInitParam void BaseBlock::setLastChangedParam(const Param& last_param, bool user_provided) { - mLastChangedParam = getHandleFromParam(&last_param); - mChangeVersion++; + if (user_provided) + { + mChangeVersion++; + } } const std::string& BaseBlock::getParamName(const BlockDescriptor& block_data, const Param* paramp) const @@ -471,7 +471,6 @@ namespace LLInitParam { Param* paramp = getParamFromHandle(it->mParamHandle); param_changed |= merge_func(*paramp, *other_paramp, true); - mLastChangedParam = it->mParamHandle; } } return param_changed; @@ -492,7 +491,6 @@ namespace LLInitParam { Param* paramp = getParamFromHandle(it->mParamHandle); param_changed |= merge_func(*paramp, *other_paramp, false); - mLastChangedParam = it->mParamHandle; } } return param_changed; diff --git a/indra/llxuixml/llinitparam.h b/indra/llxuixml/llinitparam.h index 7e1e4a3d21..529fae18c0 100644 --- a/indra/llxuixml/llinitparam.h +++ b/indra/llxuixml/llinitparam.h @@ -470,7 +470,6 @@ namespace LLInitParam // Blocks can override this to do custom tracking of changes virtual void setLastChangedParam(const Param& last_param, bool user_provided); - const Param* getLastChangedParam() const { return mLastChangedParam ? getParamFromHandle(mLastChangedParam) : NULL; } S32 getLastChangeVersion() const { return mChangeVersion; } bool isDefault() const { return mChangeVersion == 0; } @@ -505,7 +504,6 @@ namespace LLInitParam bool fillFromImpl(BlockDescriptor& block_data, const BaseBlock& other); // can be updated in getters - mutable param_handle_t mLastChangedParam; mutable S32 mChangeVersion; BlockDescriptor* mBlockDescriptor; // most derived block descriptor @@ -1732,6 +1730,7 @@ namespace LLInitParam void set(value_assignment_t val, bool flag_as_provided = true) { Param::enclosingBlock().setLastChangedParam(*this, flag_as_provided); + // set param version number to be up to date, so we ignore block contents mData.mLastParamVersion = BaseBlock::getLastChangeVersion(); diff --git a/indra/llxuixml/lluicolor.cpp b/indra/llxuixml/lluicolor.cpp index 424d878a6b..0049ec055c 100644 --- a/indra/llxuixml/lluicolor.cpp +++ b/indra/llxuixml/lluicolor.cpp @@ -16,13 +16,15 @@ LLUIColor::LLUIColor() { } -LLUIColor::LLUIColor(const LLColor4* color) - :mColorPtr(color) + +LLUIColor::LLUIColor(const LLColor4& color) +: mColor(color), + mColorPtr(NULL) { } -LLUIColor::LLUIColor(const LLColor4& color) - :mColor(color), mColorPtr(NULL) +LLUIColor::LLUIColor(const LLUIColor* color) +: mColorPtr(color) { } @@ -32,14 +34,14 @@ void LLUIColor::set(const LLColor4& color) mColorPtr = NULL; } -void LLUIColor::set(const LLColor4* color) +void LLUIColor::set(const LLUIColor* color) { mColorPtr = color; } const LLColor4& LLUIColor::get() const { - return (mColorPtr == NULL ? mColor : *mColorPtr); + return (mColorPtr == NULL ? mColor : mColorPtr->get()); } LLUIColor::operator const LLColor4& () const diff --git a/indra/llxuixml/lluicolor.h b/indra/llxuixml/lluicolor.h index bb0f786326..0ef2f78b24 100644 --- a/indra/llxuixml/lluicolor.h +++ b/indra/llxuixml/lluicolor.h @@ -22,11 +22,11 @@ class LLUIColor { public: LLUIColor(); - LLUIColor(const LLColor4* color); LLUIColor(const LLColor4& color); + LLUIColor(const LLUIColor* color); void set(const LLColor4& color); - void set(const LLColor4* color); + void set(const LLUIColor* color); const LLColor4& get() const; @@ -38,7 +38,7 @@ public: private: friend struct LLInitParam::ParamCompare; - const LLColor4* mColorPtr; + const LLUIColor* mColorPtr; LLColor4 mColor; }; @@ -47,7 +47,7 @@ namespace LLInitParam template<> struct ParamCompare { - static bool equals(const class LLUIColor& a, const class LLUIColor& b); + static bool equals(const LLUIColor& a, const LLUIColor& b); }; } diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h index a58a562378..aeed4fee08 100644 --- a/indra/newview/llavatarlist.h +++ b/indra/newview/llavatarlist.h @@ -57,11 +57,11 @@ public: struct Params : public LLInitParam::Block { - Optional ignore_online_status; // show all items as online - Optional show_last_interaction_time; // show most recent interaction time. *HACK: move this to a derived class - Optional show_info_btn; - Optional show_profile_btn; - Optional show_speaking_indicator; + Optional ignore_online_status, // show all items as online + show_last_interaction_time, // show most recent interaction time. *HACK: move this to a derived class + show_info_btn, + show_profile_btn, + show_speaking_indicator; Params(); }; diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp index 66ab32f3e8..26a39532dd 100644 --- a/indra/newview/llavatarlistitem.cpp +++ b/indra/newview/llavatarlistitem.cpp @@ -48,6 +48,17 @@ S32 LLAvatarListItem::sLeftPadding = 0; S32 LLAvatarListItem::sRightNamePadding = 0; S32 LLAvatarListItem::sChildrenWidths[LLAvatarListItem::ALIC_COUNT]; +static LLWidgetNameRegistry::StaticRegistrar sRegisterAvatarListItemParams(&typeid(LLAvatarListItem::Params), "avatar_list_item"); + +LLAvatarListItem::Params::Params() +: default_style("default_style"), + voice_call_invited_style("voice_call_invited_style"), + voice_call_joined_style("voice_call_joined_style"), + voice_call_left_style("voice_call_left_style"), + online_style("online_style"), + offline_style("offline_style") +{}; + LLAvatarListItem::LLAvatarListItem(bool not_from_ui_factory/* = true*/) : LLPanel(), @@ -166,9 +177,30 @@ void LLAvatarListItem::setHighlight(const std::string& highlight) void LLAvatarListItem::setState(EItemState item_style) { - item_style_map_t& item_styles_params_map = getItemStylesParams(); + const LLAvatarListItem::Params& params = LLUICtrlFactory::getDefaultParams(); - mAvatarNameStyle = item_styles_params_map[item_style]; + switch(item_style) + { + default: + case IS_DEFAULT: + mAvatarNameStyle = params.default_style(); + break; + case IS_VOICE_INVITED: + mAvatarNameStyle = params.voice_call_invited_style(); + break; + case IS_VOICE_JOINED: + mAvatarNameStyle = params.voice_call_joined_style(); + break; + case IS_VOICE_LEFT: + mAvatarNameStyle = params.voice_call_left_style(); + break; + case IS_ONLINE: + mAvatarNameStyle = params.online_style(); + break; + case IS_OFFLINE: + mAvatarNameStyle = params.offline_style(); + break; + } // *NOTE: You cannot set the style on a text box anymore, you must // rebuild the text. This will cause problems if the text contains @@ -352,58 +384,6 @@ std::string LLAvatarListItem::formatSeconds(U32 secs) return getString(fmt, args); } -// static -LLAvatarListItem::item_style_map_t& LLAvatarListItem::getItemStylesParams() -{ - static item_style_map_t item_styles_params_map; - if (!item_styles_params_map.empty()) return item_styles_params_map; - - LLPanel::Params params = LLUICtrlFactory::getDefaultParams(); - LLPanel* params_panel = LLUICtrlFactory::create(params); - - BOOL sucsess = LLUICtrlFactory::instance().buildPanel(params_panel, "panel_avatar_list_item_params.xml"); - - if (sucsess) - { - - item_styles_params_map.insert( - std::make_pair(IS_DEFAULT, - params_panel->getChild("default_style")->getDefaultStyle())); - - item_styles_params_map.insert( - std::make_pair(IS_VOICE_INVITED, - params_panel->getChild("voice_call_invited_style")->getDefaultStyle())); - - item_styles_params_map.insert( - std::make_pair(IS_VOICE_JOINED, - params_panel->getChild("voice_call_joined_style")->getDefaultStyle())); - - item_styles_params_map.insert( - std::make_pair(IS_VOICE_LEFT, - params_panel->getChild("voice_call_left_style")->getDefaultStyle())); - - item_styles_params_map.insert( - std::make_pair(IS_ONLINE, - params_panel->getChild("online_style")->getDefaultStyle())); - - item_styles_params_map.insert( - std::make_pair(IS_OFFLINE, - params_panel->getChild("offline_style")->getDefaultStyle())); - } - else - { - item_styles_params_map.insert(std::make_pair(IS_DEFAULT, LLStyle::Params())); - item_styles_params_map.insert(std::make_pair(IS_VOICE_INVITED, LLStyle::Params())); - item_styles_params_map.insert(std::make_pair(IS_VOICE_JOINED, LLStyle::Params())); - item_styles_params_map.insert(std::make_pair(IS_VOICE_LEFT, LLStyle::Params())); - item_styles_params_map.insert(std::make_pair(IS_ONLINE, LLStyle::Params())); - item_styles_params_map.insert(std::make_pair(IS_OFFLINE, LLStyle::Params())); - } - if (params_panel) params_panel->die(); - - return item_styles_params_map; -} - // static LLAvatarListItem::icon_color_map_t& LLAvatarListItem::getItemIconColorMap() { diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h index 479a4833cb..9f81aa0804 100644 --- a/indra/newview/llavatarlistitem.h +++ b/indra/newview/llavatarlistitem.h @@ -46,6 +46,18 @@ class LLAvatarIconCtrl; class LLAvatarListItem : public LLPanel, public LLFriendObserver { public: + struct Params : public LLInitParam::Block + { + Optional default_style, + voice_call_invited_style, + voice_call_joined_style, + voice_call_left_style, + online_style, + offline_style; + + Params(); + }; + typedef enum e_item_state_type { IS_DEFAULT, IS_VOICE_INVITED, @@ -143,9 +155,6 @@ private: std::string formatSeconds(U32 secs); - typedef std::map item_style_map_t; - static item_style_map_t& getItemStylesParams(); - typedef std::map icon_color_map_t; static icon_color_map_t& getItemIconColorMap(); diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp index 9f6412c0ab..77b3a48cef 100644 --- a/indra/newview/llexpandabletextbox.cpp +++ b/indra/newview/llexpandabletextbox.cpp @@ -169,8 +169,7 @@ void LLExpandableTextBox::LLTextBoxEx::showExpandText() std::pair visible_lines = getVisibleLines(true); S32 last_line = visible_lines.second - 1; - LLStyle::Params expander_style = getDefaultStyle(); - expander_style.font.name(LLFontGL::nameFromFont(expander_style.font)); + LLStyle::Params expander_style(getDefaultStyleParams()); expander_style.font.style = "UNDERLINE"; expander_style.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); LLExpanderSegment* expanderp = new LLExpanderSegment(new LLStyle(expander_style), getLineStart(last_line), getLength() + 1, mExpanderLabel, *this); @@ -186,8 +185,7 @@ void LLExpandableTextBox::LLTextBoxEx::hideExpandText() if (mExpanderVisible) { // this will overwrite the expander segment and all text styling with a single style - LLNormalTextSegment* segmentp = new LLNormalTextSegment( - new LLStyle(getDefaultStyle()), 0, getLength() + 1, *this); + LLNormalTextSegment* segmentp = new LLNormalTextSegment(LLStyleConstSP(new LLStyle(getDefaultStyleParams())), 0, getLength() + 1, *this); insertSegment(segmentp); mExpanderVisible = false; diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 300aea1620..94c257fe8c 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -247,7 +247,7 @@ public: return FALSE; } - /*virtual*/ const LLStyleSP getStyle() const { return mStyle; } + /*virtual*/ LLStyleConstSP getStyle() const { return mStyle; } private: LLUIImagePtr mImage; diff --git a/indra/newview/skins/default/xui/en/widgets/avatar_list_item.xml b/indra/newview/skins/default/xui/en/widgets/avatar_list_item.xml new file mode 100644 index 0000000000..1a9a882c7b --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/avatar_list_item.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From 955c0cc5a9ab8fb9eda7a6c20cd7bd09c2fd9369 Mon Sep 17 00:00:00 2001 From: richard Date: Fri, 22 Jan 2010 17:17:12 -0800 Subject: wrong param names for avatar list item colors reviewed by Rick --- .../skins/default/xui/en/widgets/avatar_list_item.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/indra/newview/skins/default/xui/en/widgets/avatar_list_item.xml b/indra/newview/skins/default/xui/en/widgets/avatar_list_item.xml index 1a9a882c7b..ed8df69bf4 100644 --- a/indra/newview/skins/default/xui/en/widgets/avatar_list_item.xml +++ b/indra/newview/skins/default/xui/en/widgets/avatar_list_item.xml @@ -10,35 +10,35 @@ + color="DkGray"/> + color="0.5 0.5 0.5 0.5"/> + color="white"/> + color="LtGray_50"/> + color="white"/> + color="0.5 0.5 0.5 1.0"/> -- cgit v1.2.3 From ae9449bff10d8c2247ae28044af50870c6a782eb Mon Sep 17 00:00:00 2001 From: Erica Date: Fri, 22 Jan 2010 23:04:59 -0800 Subject: Group profile layout now resizes with the viewer window. Gave extra room to each accordion panel, and tweaked the layout a bit. --- .../skins/default/xui/en/panel_group_general.xml | 87 +++++--- .../default/xui/en/panel_group_info_sidetray.xml | 163 ++++++++------ .../default/xui/en/panel_group_land_money.xml | 104 ++++----- .../skins/default/xui/en/panel_group_notices.xml | 82 +++---- .../skins/default/xui/en/panel_group_roles.xml | 247 ++++++++++++--------- .../skins/default/xui/en/panel_side_tray.xml | 2 +- 6 files changed, 395 insertions(+), 290 deletions(-) diff --git a/indra/newview/skins/default/xui/en/panel_group_general.xml b/indra/newview/skins/default/xui/en/panel_group_general.xml index af73faf9a1..96185bad56 100644 --- a/indra/newview/skins/default/xui/en/panel_group_general.xml +++ b/indra/newview/skins/default/xui/en/panel_group_general.xml @@ -1,12 +1,11 @@ + name="general_tab"> The General tab contains general information about this group, a list of members, general Group Preferences and member options. @@ -25,12 +24,14 @@ Hover your mouse over the options for more help. type="string" follows="left|top|right" left="5" - height="60" + height="150" layout="topleft" max_length="511" name="charter" top="5" right="-1" + bg_readonly_color="DkGray2" + text_readonly_color="White" word_wrap="true"> Group Charter @@ -38,8 +39,8 @@ Hover your mouse over the options for more help. column_padding="0" draw_heading="true" follows="left|top|right" - heading_height="20" - height="156" + heading_height="23" + height="200" layout="topleft" left="0" right="-1" @@ -60,17 +61,29 @@ Hover your mouse over the options for more help. height="12" layout="left|top|right" left="5" + text_color="EmphasisColor" + name="my_group_settngs_label" + top_pad="10" + width="300"> + Me + + - My Title + My title: @@ -79,7 +92,7 @@ Hover your mouse over the options for more help. font="SansSerifSmall" label="Receive group notices" layout="topleft" - left="5" + left="10" name="receive_notices" tool_tip="Sets whether you want to receive Notices from this group. Uncheck this box if this group is spamming you." top_pad="5" @@ -88,36 +101,46 @@ Hover your mouse over the options for more help. height="16" label="Show in my profile" layout="topleft" - left="5" + left="10" name="list_groups_in_profile" tool_tip="Sets whether you want to show this group in your profile" top_pad="5" width="295" /> - + top_pad="5"> + + Group + - + + diff --git a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml index 673052c3b5..4e017819c1 100644 --- a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml +++ b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml @@ -2,17 +2,17 @@ + width="313"> - There are unsaved changes to the current tab + There are unsaved changes @@ -26,6 +26,14 @@ background_visible="true" name="group_join_free"> Free + + - + + Aspect ratio + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/panel_preferences_alerts.xml b/indra/newview/skins/default/xui/en/panel_preferences_alerts.xml index ace8281b4e..188fd3b7bc 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_alerts.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_alerts.xml @@ -1,7 +1,7 @@ @@ -32,7 +32,7 @@ - Always show these notifications: + Always show: @@ -81,17 +76,13 @@ enabled_control="FirstSelectedEnabledPopups" follows="top|left" height="23" - image_disabled="PushButton_Disabled" - image_disabled_selected="PushButton_Disabled" image_overlay="Arrow_Down" - image_selected="PushButton_Selected" - image_unselected="PushButton_Off" hover_glow_amount="0.15" layout="topleft" - left_pad="50" + left_pad="40" name="disable_this_popup" top_delta="0" - width="43"> + width="40"> @@ -99,21 +90,20 @@ type="string" length="1" follows="top|left" - font="SansSerifBold" height="12" layout="topleft" - left="30" + left="10" name="dont_show_label" - top_pad="10" + top_pad="-10" width="450"> - Never show these notifications: + Never show: diff --git a/indra/newview/skins/default/xui/en/panel_preferences_general.xml b/indra/newview/skins/default/xui/en/panel_preferences_general.xml index 22c75a595e..099c789e4b 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_general.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_general.xml @@ -89,11 +89,12 @@ (Requires restart) @@ -179,7 +180,7 @@ left_pad="5" name="show_location_checkbox" top_delta="5" - width="256" /> + width="256" /> + width="75" /> + width="75" /> + value="2" + width="160" /> Busy mode response: @@ -336,18 +336,16 @@ text_readonly_color="LabelDisabledColor" bg_writeable_color="LtGray" use_ellipses="false" - bg_visible="true" - border_visible="true" hover="false" commit_on_focus_lost = "true" follows="left|top" - height="50" + height="60" layout="topleft" left="50" name="busy_response" - width="400" + width="440" word_wrap="true"> log_in_to_change - + diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml index c01a032209..8bff865eb1 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml @@ -33,16 +33,15 @@ - - Aspect ratio - - - - - - - - - - -- cgit v1.2.3 From e918089f592da2094e6b23a146e0e30b711562dc Mon Sep 17 00:00:00 2001 From: Sergei Litovchuk Date: Thu, 4 Feb 2010 17:04:27 +0200 Subject: Fixed critical bug (EXT-4827) [NUX] The Places Panel should default to the Landmarks tab with the Library expanded. - Added Library tab set open by default with Landmarks category fetch from Library. --HG-- branch : product-engine --- indra/newview/llpanellandmarks.cpp | 22 ++++++++++++++-------- indra/newview/llpanellandmarks.h | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 47feef496a..7c1b0f6234 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -171,8 +171,6 @@ BOOL LLLandmarksPanel::postBuild() initLandmarksInventoryPanel(); initMyInventoryPanel(); initLibraryInventoryPanel(); - getChild("tab_favorites")->setDisplayChildren(true); - getChild("tab_landmarks")->setDisplayChildren(true); return TRUE; } @@ -462,7 +460,7 @@ void LLLandmarksPanel::initFavoritesInventoryPanel() initLandmarksPanel(mFavoritesInventoryPanel); mFavoritesInventoryPanel->getFilter()->setEmptyLookupMessage("FavoritesNoMatchingItems"); - initAccordion("tab_favorites", mFavoritesInventoryPanel); + initAccordion("tab_favorites", mFavoritesInventoryPanel, true); } void LLLandmarksPanel::initLandmarksInventoryPanel() @@ -481,7 +479,7 @@ void LLLandmarksPanel::initLandmarksInventoryPanel() // subscribe to have auto-rename functionality while creating New Folder mLandmarksInventoryPanel->setSelectCallback(boost::bind(&LLInventoryPanel::onSelectionChange, mLandmarksInventoryPanel, _1, _2)); - initAccordion("tab_landmarks", mLandmarksInventoryPanel); + initAccordion("tab_landmarks", mLandmarksInventoryPanel, true); } void LLLandmarksPanel::initMyInventoryPanel() @@ -490,7 +488,7 @@ void LLLandmarksPanel::initMyInventoryPanel() initLandmarksPanel(mMyInventoryPanel); - initAccordion("tab_inventory", mMyInventoryPanel); + initAccordion("tab_inventory", mMyInventoryPanel, false); } void LLLandmarksPanel::initLibraryInventoryPanel() @@ -499,7 +497,15 @@ void LLLandmarksPanel::initLibraryInventoryPanel() initLandmarksPanel(mLibraryInventoryPanel); - initAccordion("tab_library", mLibraryInventoryPanel); + // We want to fetch only "Landmarks" category from the library. + const LLUUID &landmarks_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false, true); + if (landmarks_cat.notNull()) + { + gInventory.startBackgroundFetch(landmarks_cat); + } + + // Expanding "Library" tab for new users who have no landmarks in "My Inventory". + initAccordion("tab_library", mLibraryInventoryPanel, true); } void LLLandmarksPanel::initLandmarksPanel(LLPlacesInventoryPanel* inventory_list) @@ -526,14 +532,14 @@ void LLLandmarksPanel::initLandmarksPanel(LLPlacesInventoryPanel* inventory_list inventory_list->saveFolderState(); } -void LLLandmarksPanel::initAccordion(const std::string& accordion_tab_name, LLPlacesInventoryPanel* inventory_list) +void LLLandmarksPanel::initAccordion(const std::string& accordion_tab_name, LLPlacesInventoryPanel* inventory_list, bool expand_tab) { LLAccordionCtrlTab* accordion_tab = getChild(accordion_tab_name); mAccordionTabs.push_back(accordion_tab); accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLLandmarksPanel::onAccordionExpandedCollapsed, this, _2, inventory_list)); - accordion_tab->setDisplayChildren(false); + accordion_tab->setDisplayChildren(expand_tab); } void LLLandmarksPanel::onAccordionExpandedCollapsed(const LLSD& param, LLPlacesInventoryPanel* inventory_list) diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index 96b790844c..cbbd10ac26 100644 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -110,7 +110,7 @@ private: void initMyInventoryPanel(); void initLibraryInventoryPanel(); void initLandmarksPanel(LLPlacesInventoryPanel* inventory_list); - void initAccordion(const std::string& accordion_tab_name, LLPlacesInventoryPanel* inventory_list); + void initAccordion(const std::string& accordion_tab_name, LLPlacesInventoryPanel* inventory_list, bool expand_tab); void onAccordionExpandedCollapsed(const LLSD& param, LLPlacesInventoryPanel* inventory_list); void deselectOtherThan(const LLPlacesInventoryPanel* inventory_list); -- cgit v1.2.3 From 41c6155f13dbb9ed8bc136bc3350bc8fc87e7f56 Mon Sep 17 00:00:00 2001 From: Ychebotarev ProductEngine Date: Thu, 4 Feb 2010 17:11:08 +0200 Subject: fix for normal EXT-3807 ABOUT LAND/OBJECTS: (i) icon is badly positioned --HG-- branch : product-engine --- indra/newview/llnamelistctrl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index 8c875c9b63..d579058c32 100644 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -152,6 +152,7 @@ BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask) if (avatar_id.notNull()) { // ...valid avatar id + LLScrollListCell* hit_cell = hit_item->getColumn(column_index); if (hit_cell) { @@ -162,8 +163,8 @@ BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask) localRectToScreen(cell_rect, &sticky_rect); // Spawn at right side of cell - LLCoordGL pos( sticky_rect.mRight - 16, sticky_rect.mTop + (sticky_rect.getHeight()-16)/2 ); LLPointer icon = LLUI::getUIImage("Info_Small"); + LLCoordGL pos( sticky_rect.mRight - 16, sticky_rect.mTop - (sticky_rect.getHeight() - icon->getHeight())/2 ); // Should we show a group or an avatar inspector? bool is_group = hit_item->getValue()["is_group"].asBoolean(); -- cgit v1.2.3 From d2d192060993d938a2fd131f8872a60b678e4a04 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 4 Feb 2010 10:20:31 -0500 Subject: For EXT-4855: Crash on onWearableAssetFetch. Prevent late-arriving wearables from touching a deleted object. --- indra/newview/llappearancemgr.cpp | 47 +++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 585d42f66d..0fe236c056 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -321,7 +321,7 @@ public: ~LLWearableHoldingPattern(); bool pollCompletion(); - bool isDone(); + bool isFetchCompleted(); bool isTimedOut(); typedef std::list found_list_t; @@ -330,10 +330,12 @@ public: LLInventoryModel::item_array_t mGestItems; S32 mResolved; LLTimer mWaitTime; + bool mFired; }; LLWearableHoldingPattern::LLWearableHoldingPattern(): - mResolved(0) + mResolved(0), + mFired(false) { } @@ -341,31 +343,34 @@ LLWearableHoldingPattern::~LLWearableHoldingPattern() { } -bool LLWearableHoldingPattern::isDone() +bool LLWearableHoldingPattern::isFetchCompleted() { - if (mResolved >= (S32)mFoundList.size()) - return true; // have everything we were waiting for - else if (isTimedOut()) - { - llwarns << "Exceeded max wait time, updating appearance based on what has arrived" << llendl; - return true; - } - return false; - + return (mResolved >= (S32)mFoundList.size()); // have everything we were waiting for? } bool LLWearableHoldingPattern::isTimedOut() { - static F32 max_wait_time = 15.0; // give up if wearable fetches haven't completed in max_wait_time seconds. + static F32 max_wait_time = 20.0; // give up if wearable fetches haven't completed in max_wait_time seconds. return mWaitTime.getElapsedTimeF32() > max_wait_time; } bool LLWearableHoldingPattern::pollCompletion() { - bool done = isDone(); - llinfos << "polling, done status: " << done << " elapsed " << mWaitTime.getElapsedTimeF32() << llendl; + bool completed = isFetchCompleted(); + bool timed_out = isTimedOut(); + bool done = completed || timed_out; + + llinfos << "polling, done status: " << completed << " timed out? " << timed_out << " elapsed " << mWaitTime.getElapsedTimeF32() << llendl; + if (done) { + mFired = true; + + if (timed_out) + { + llwarns << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << llendl; + } + // Activate all gestures in this folder if (mGestItems.count() > 0) { @@ -397,7 +402,11 @@ bool LLWearableHoldingPattern::pollCompletion() LLAgentWearables::userUpdateAttachments(mObjItems); } - delete this; + if (completed) + { + // Only safe to delete if all wearable callbacks completed. + delete this; + } } return done; } @@ -432,7 +441,11 @@ static void removeDuplicateItems(LLInventoryModel::item_array_t& items) static void onWearableAssetFetch(LLWearable* wearable, void* data) { LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data; - + if (holder->mFired) + { + llwarns << "called after holder fired" << llendl; + } + if(wearable) { for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin(); -- cgit v1.2.3 From f2bb59300a0f17e10857b3fffebe669878f0fe50 Mon Sep 17 00:00:00 2001 From: Igor Borovkov Date: Thu, 4 Feb 2010 17:26:44 +0200 Subject: fixed duplicating of log records for EXT-4777 Implement saving and loading chat history for Nearby Chat (both plain text and widgeted chat) --HG-- branch : product-engine --- indra/newview/llnearbychat.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index acb28bd46f..8fc11d3929 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -200,11 +200,16 @@ void LLNearbyChat::addMessage(const LLChat& chat,bool archive,const LLSD &args) mMessageArchive.push_back(chat); if(mMessageArchive.size()>200) mMessageArchive.erase(mMessageArchive.begin()); + } - if (gSavedPerAccountSettings.getBOOL("LogChat")) - { - LLLogChat::saveHistory("chat", chat.mFromName, chat.mFromID, chat.mText); - } + if (args["do_not_log"].asBoolean()) + { + return; + } + + if (gSavedPerAccountSettings.getBOOL("LogChat")) + { + LLLogChat::saveHistory("chat", chat.mFromName, chat.mFromID, chat.mText); } } @@ -275,6 +280,9 @@ void LLNearbyChat::processChatHistoryStyleUpdate(const LLSD& newvalue) void LLNearbyChat::loadHistory() { + LLSD do_not_log; + do_not_log["do_not_log"] = true; + std::list history; LLLogChat::loadAllHistory("chat", history); @@ -295,7 +303,7 @@ void LLNearbyChat::loadHistory() chat.mFromID = from_id; chat.mText = msg[IM_TEXT].asString(); chat.mTimeStr = msg[IM_TIME].asString(); - addMessage(chat); + addMessage(chat, true, do_not_log); it++; } -- cgit v1.2.3 From c99fb12b3d300705dbf6eb68b1a3f22927d4d221 Mon Sep 17 00:00:00 2001 From: Dmitry Zaporozhan Date: Thu, 4 Feb 2010 17:25:30 +0200 Subject: Update for low bug EXT-4951 - Redundant edit box context menu in list items in Panel Picks/Classifieds Disabled edit box context menu in classified list items. --HG-- branch : product-engine --- indra/newview/skins/default/xui/en/panel_classifieds_list_item.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/skins/default/xui/en/panel_classifieds_list_item.xml b/indra/newview/skins/default/xui/en/panel_classifieds_list_item.xml index b881719e3a..0c1418fc2d 100644 --- a/indra/newview/skins/default/xui/en/panel_classifieds_list_item.xml +++ b/indra/newview/skins/default/xui/en/panel_classifieds_list_item.xml @@ -64,6 +64,7 @@ layout="topleft" left="103" name="description" + textbox.mouse_opaque="false" top_pad="0" width="178" word_wrap="true" /> -- cgit v1.2.3 From 78200e2c1c1bc2e53f694b2ae086f486a7f0095c Mon Sep 17 00:00:00 2001 From: Alexei Arabadji Date: Thu, 4 Feb 2010 19:10:24 +0200 Subject: =?UTF-8?q?fixed=20EXT-4893=20=E2=80=9C'Add=20friend'=20available?= =?UTF-8?q?=20for=20friends=20in=20group/conference=20sessions=E2=80=9D,?= =?UTF-8?q?=20corrected=20condition=20for=20enable=20'add=20friend'=20menu?= =?UTF-8?q?=20item;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --HG-- branch : product-engine --- indra/newview/llparticipantlist.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index ad47e351ee..1c4004c37a 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -584,7 +584,7 @@ bool LLParticipantList::LLParticipantListMenu::enableContextMenuItem(const LLSD& { std::string item = userdata.asString(); if (item == "can_mute_text" || "can_block" == item || "can_share" == item || "can_im" == item - || "can_pay" == item || "can_add" == item) + || "can_pay" == item) { return mUUIDs.front() != gAgentID; } @@ -619,7 +619,7 @@ bool LLParticipantList::LLParticipantListMenu::enableContextMenuItem(const LLSD& for (;id != uuids_end; ++id) { - if ( LLAvatarActions::isFriend(*id) ) + if ( *id == gAgentID || LLAvatarActions::isFriend(*id) ) { result = false; break; -- cgit v1.2.3 From 3fa2acc0df76b3dd81e295a28bfb463f863a9e49 Mon Sep 17 00:00:00 2001 From: Vadim Savchuk Date: Thu, 4 Feb 2010 19:21:12 +0200 Subject: Fixed bug EXT-4806 (Snapshot floater has preview offset). Removed incorrect vertical offset modification in compact mode. --HG-- branch : product-engine --- indra/newview/llfloatersnapshot.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index b6e9fb3f6c..a0031f0193 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -2084,10 +2084,6 @@ void LLFloaterSnapshot::draw() S32 offset_x = (getRect().getWidth() - previewp->getThumbnailWidth()) / 2 ; S32 offset_y = thumbnail_rect.mBottom + (thumbnail_rect.getHeight() - previewp->getThumbnailHeight()) / 2 ; - if (! gSavedSettings.getBOOL("AdvanceSnapshot")) - { - offset_y += getUIWinHeightShort() - getUIWinHeightLong(); - } glMatrixMode(GL_MODELVIEW); gl_draw_scaled_image(offset_x, offset_y, -- cgit v1.2.3 From 1bc67a9d725b88a0ebdde77cef928abd33fa9cf6 Mon Sep 17 00:00:00 2001 From: richard Date: Thu, 4 Feb 2010 10:25:31 -0800 Subject: EXT-4625 - Chat bar doesn't display trailing character on some strings reviewed by Leyla --- indra/llrender/llfontgl.cpp | 24 ++++++++++++++++++++---- indra/llui/lllineeditor.cpp | 6 +++++- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 1de1d6ded4..b6a6b448ee 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -601,14 +601,20 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_ { llwchar wch = wchars[i]; - F32 char_width = mFontFreetype->getXAdvance(wch); + const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch); + + // last character uses character width, since the whole character needs to be visible + // other characters just use advance + F32 width = (i == start) + ? (F32)(fgi->mWidth + fgi->mXBearing) // use actual width for last character + : fgi->mXAdvance; // use advance for all other characters - if( scaled_max_pixels < (total_width + char_width) ) + if( scaled_max_pixels < (total_width + width) ) { break; } - total_width += char_width; + total_width += width; drawable_chars++; if( max_chars >= 0 && drawable_chars >= max_chars ) @@ -626,7 +632,17 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_ total_width = llround(total_width); } - return start_pos - drawable_chars; + if (drawable_chars == 0) + { + return start_pos; // just draw last character + } + else + { + // if only 1 character is drawable, we want to return start_pos as the first character to draw + // if 2 are drawable, return start_pos and character before start_pos, etc. + return start_pos + 1 - drawable_chars; + } + } S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round) const diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index cb5aea272d..2cdcd3345e 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -422,12 +422,16 @@ void LLLineEditor::setCursor( S32 pos ) S32 old_cursor_pos = getCursor(); mCursorPos = llclamp( pos, 0, mText.length()); + // position of end of next character after cursor S32 pixels_after_scroll = findPixelNearestPos(); if( pixels_after_scroll > mTextRightEdge ) { S32 width_chars_to_left = mGLFont->getWidth(mText.getWString().c_str(), 0, mScrollHPos); S32 last_visible_char = mGLFont->maxDrawableChars(mText.getWString().c_str(), llmax(0.f, (F32)(mTextRightEdge - mTextLeftEdge + width_chars_to_left))); - S32 min_scroll = mGLFont->firstDrawableChar(mText.getWString().c_str(), (F32)(mTextRightEdge - mTextLeftEdge), mText.length(), getCursor()); + // character immediately to left of cursor should be last one visible (SCROLL_INCREMENT_ADD will scroll in more characters) + // or first character if cursor is at beginning + S32 new_last_visible_char = llmax(0, getCursor() - 1); + S32 min_scroll = mGLFont->firstDrawableChar(mText.getWString().c_str(), (F32)(mTextRightEdge - mTextLeftEdge), mText.length(), new_last_visible_char); if (old_cursor_pos == last_visible_char) { mScrollHPos = llmin(mText.length(), llmax(min_scroll, mScrollHPos + SCROLL_INCREMENT_ADD)); -- cgit v1.2.3 From b2f0169a764119ad6b51ad0df964309ca7458278 Mon Sep 17 00:00:00 2001 From: Eugene Mutavchi Date: Thu, 4 Feb 2010 20:40:30 +0200 Subject: Fixed normal bug EXT-4627(Nearby Chat floater in Mouselook breaks ability to type & use gestures) --HG-- branch : product-engine --- indra/newview/llbottomtray.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index 4c8cec3d30..92c00efe99 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -80,6 +80,14 @@ public: { mNearbyChatBar = getChild("chat_bar"); mGesturePanel = getChild("gesture_panel"); + + // Hide "show_nearby_chat" button + LLLineEditor* chat_box = mNearbyChatBar->getChatBox(); + LLUICtrl* show_btn = mNearbyChatBar->getChild("show_nearby_chat"); + S32 delta_width = show_btn->getRect().getWidth(); + show_btn->setVisible(FALSE); + chat_box->reshape(chat_box->getRect().getWidth() + delta_width, chat_box->getRect().getHeight()); + return TRUE; } -- cgit v1.2.3 From 3f0762f65ad8ba9d4f854378ca2d2dd826470f4e Mon Sep 17 00:00:00 2001 From: Eugene Mutavchi Date: Thu, 4 Feb 2010 20:40:30 +0200 Subject: Fixed normal bug EXT-4307 (There are no text context menues for Search text field and for IM text field) --HG-- branch : product-engine --- indra/llui/lllineeditor.cpp | 42 ++++++++++++++++++++++++++++++++++- indra/llui/lllineeditor.h | 9 +++++++- indra/newview/llbottomtray.cpp | 2 ++ indra/newview/lllocationinputctrl.cpp | 1 + 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index eb2b4f7705..00376cc4dd 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -55,6 +55,7 @@ #include "llui.h" #include "lluictrlfactory.h" #include "llclipboard.h" +#include "llmenugl.h" // // Imported globals @@ -164,7 +165,8 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) mTentativeFgColor(p.text_tentative_color()), mHighlightColor(p.highlight_color()), mPreeditBgColor(p.preedit_bg_color()), - mGLFont(p.font) + mGLFont(p.font), + mContextMenuHandle() { llassert( mMaxLengthBytes > 0 ); @@ -191,6 +193,12 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) setCursor(mText.length()); setPrevalidate(p.prevalidate_callback()); + + LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile + ("menu_text_editor.xml", + LLMenuGL::sMenuContainer, + LLMenuHolderGL::child_registry_t::instance()); + setContextMenu(menu); } LLLineEditor::~LLLineEditor() @@ -663,6 +671,16 @@ BOOL LLLineEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) return TRUE; } +BOOL LLLineEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + setFocus(TRUE); + if (!LLUICtrl::handleRightMouseDown(x, y, mask)) + { + showContextMenu(x, y); + } + return TRUE; +} + BOOL LLLineEditor::handleHover(S32 x, S32 y, MASK mask) { BOOL handled = FALSE; @@ -2560,3 +2578,25 @@ LLWString LLLineEditor::getConvertedText() const } return text; } + +void LLLineEditor::showContextMenu(S32 x, S32 y) +{ + LLContextMenu* menu = static_cast(mContextMenuHandle.get()); + + if (menu) + { + gEditMenuHandler = this; + + S32 screen_x, screen_y; + localPointToScreen(x, y, &screen_x, &screen_y); + menu->show(screen_x, screen_y); + } +} + +void LLLineEditor::setContextMenu(LLContextMenu* new_context_menu) +{ + if (new_context_menu) + mContextMenuHandle = new_context_menu->getHandle(); + else + mContextMenuHandle.markDead(); +} diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 49e9539b16..a06a317f76 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -56,6 +56,7 @@ class LLFontGL; class LLLineEditorRollback; class LLButton; +class LLContextMenu; typedef boost::function LLLinePrevalidateFunc; @@ -113,6 +114,7 @@ protected: LLLineEditor(const Params&); friend class LLUICtrlFactory; friend class LLFloaterEditUI; + void showContextMenu(S32 x, S32 y); public: virtual ~LLLineEditor(); @@ -122,6 +124,7 @@ public: /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleDoubleClick(S32 x,S32 y,MASK mask); /*virtual*/ BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask ); /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char); /*virtual*/ void onMouseCaptureLost(); @@ -249,7 +252,9 @@ public: void updateHistory(); // stores current line in history void setReplaceNewlinesWithSpaces(BOOL replace); - + + void setContextMenu(LLContextMenu* new_context_menu); + private: // private helper methods @@ -348,6 +353,8 @@ protected: std::vector mPreeditPositions; LLPreeditor::standouts_t mPreeditStandouts; + LLHandle mContextMenuHandle; + private: // Instances that by default point to the statics but can be overidden in XML. LLPointer mBgImage; diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index 92c00efe99..93b708f299 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -441,6 +441,8 @@ BOOL LLBottomTray::postBuild() mObjectDefaultWidthMap[RS_BUTTON_CAMERA] = mCamPanel->getRect().getWidth(); mObjectDefaultWidthMap[RS_BUTTON_SPEAK] = mSpeakPanel->getRect().getWidth(); + mNearbyChatBar->getChatBox()->setContextMenu(NULL); + return TRUE; } diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 4f40a0a532..1b7ad6ab7e 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -227,6 +227,7 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) params.commit_on_focus_lost(false); params.follows.flags(FOLLOWS_ALL); mTextEntry = LLUICtrlFactory::create(params); + mTextEntry->setContextMenu(NULL); addChild(mTextEntry); // LLLineEditor is replaced with LLLocationLineEditor -- cgit v1.2.3 From 558cd44e6be87c661a873bb96918265282de361b Mon Sep 17 00:00:00 2001 From: Eugene Mutavchi Date: Thu, 4 Feb 2010 20:40:30 +0200 Subject: Fixed low bug EXT-4184 (Fav bar: drop landmark pointer is visible badly) --HG-- branch : product-engine --- indra/newview/llfavoritesbar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 90f6438980..0f52b30567 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -628,8 +628,8 @@ void LLFavoritesBarCtrl::draw() if (mShowDragMarker) { - S32 w = mImageDragIndication->getWidth() / 2; - S32 h = mImageDragIndication->getHeight() / 2; + S32 w = mImageDragIndication->getWidth(); + S32 h = mImageDragIndication->getHeight(); if (mLandingTab) { -- cgit v1.2.3 From f60afe790b156051f1da72abea2ea64731c704ac Mon Sep 17 00:00:00 2001 From: Eugene Mutavchi Date: Thu, 4 Feb 2010 21:22:05 +0200 Subject: Fixed major bug EXT-4853 (Color Picker - Arrow Used to Select Color Density is Nearly Invisible) --HG-- branch : product-engine --- indra/newview/llfloatercolorpicker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp index 73b79d8e13..b65457c4eb 100644 --- a/indra/newview/llfloatercolorpicker.cpp +++ b/indra/newview/llfloatercolorpicker.cpp @@ -586,7 +586,7 @@ void LLFloaterColorPicker::draw() gl_triangle_2d ( startX, startY, startX + mLumMarkerSize, startY - mLumMarkerSize, startX + mLumMarkerSize, startY + mLumMarkerSize, - LLColor4 ( 0.0f, 0.0f, 0.0f, 1.0f ), TRUE ); + LLColor4 ( 0.75f, 0.75f, 0.75f, 1.0f ), TRUE ); // draw luminance slider outline gl_rect_2d ( mLumRegionLeft, -- cgit v1.2.3 From 9dd41cdceed43f1ffea14355c1b26c40db7b3591 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Thu, 4 Feb 2010 11:24:54 -0800 Subject: EXT-3144 EXT-4226: Re-employ tentative state for individual items in media settings Review #95 This change undoes some prior change that seems to not allow showing media data for multiple selection. There was all of this code put in to support displaying tentative state for media, but code was added to basically override it. Perhaps the reason was tentative state items were not ignored on apply...this change does that. --- indra/newview/llfloatermediasettings.cpp | 13 +-- indra/newview/llpanelmediasettingsgeneral.cpp | 37 ++++---- indra/newview/llpanelmediasettingsgeneral.h | 3 +- indra/newview/llpanelmediasettingspermissions.cpp | 95 ++++++++++++-------- indra/newview/llpanelmediasettingspermissions.h | 3 +- indra/newview/llpanelmediasettingssecurity.cpp | 100 +++++++++++----------- indra/newview/llpanelmediasettingssecurity.h | 5 +- indra/newview/llselectmgr.cpp | 95 ++++++++++---------- indra/newview/llselectmgr.h | 3 +- 9 files changed, 189 insertions(+), 165 deletions(-) diff --git a/indra/newview/llfloatermediasettings.cpp b/indra/newview/llfloatermediasettings.cpp index 976af121ae..7388f7ea3f 100644 --- a/indra/newview/llfloatermediasettings.cpp +++ b/indra/newview/llfloatermediasettings.cpp @@ -149,13 +149,14 @@ void LLFloaterMediaSettings::apply() { LLSD settings; sInstance->mPanelMediaSettingsGeneral->preApply(); - sInstance->mPanelMediaSettingsGeneral->getValues( settings ); + sInstance->mPanelMediaSettingsGeneral->getValues( settings, false ); sInstance->mPanelMediaSettingsSecurity->preApply(); - sInstance->mPanelMediaSettingsSecurity->getValues( settings ); + sInstance->mPanelMediaSettingsSecurity->getValues( settings, false ); sInstance->mPanelMediaSettingsPermissions->preApply(); - sInstance->mPanelMediaSettingsPermissions->getValues( settings ); - LLSelectMgr::getInstance()->selectionSetMedia( LLTextureEntry::MF_HAS_MEDIA ); - LLSelectMgr::getInstance()->selectionSetMediaData(settings); + sInstance->mPanelMediaSettingsPermissions->getValues( settings, false ); + + LLSelectMgr::getInstance()->selectionSetMedia( LLTextureEntry::MF_HAS_MEDIA, settings ); + sInstance->mPanelMediaSettingsGeneral->postApply(); sInstance->mPanelMediaSettingsSecurity->postApply(); sInstance->mPanelMediaSettingsPermissions->postApply(); @@ -176,6 +177,8 @@ void LLFloaterMediaSettings::onClose(bool app_quitting) //static void LLFloaterMediaSettings::initValues( const LLSD& media_settings, bool editable ) { + if (sInstance->hasFocus()) return; + sInstance->clearValues(editable); // update all panels with values from simulator sInstance->mPanelMediaSettingsGeneral-> diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp index f574f55beb..f601a8d51c 100644 --- a/indra/newview/llpanelmediasettingsgeneral.cpp +++ b/indra/newview/llpanelmediasettingsgeneral.cpp @@ -250,18 +250,18 @@ bool LLPanelMediaSettingsGeneral::isMultiple() //////////////////////////////////////////////////////////////////////////////// // static -void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& media_settings ,bool editable) +void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& _media_settings, bool editable) { LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; self->mMediaEditable = editable; + LLSD media_settings = _media_settings; + if ( LLPanelMediaSettingsGeneral::isMultiple() ) { - self->clearValues(self, self->mMediaEditable); - // only show multiple - self->mHomeURL->setText(LLTrans::getString("Multiple Media")); - self->mCurrentURL->setText(LLTrans::getString("Multiple Media")); - return; + // *HACK: "edit" the incoming media_settings + media_settings[LLMediaEntry::CURRENT_URL_KEY] = LLTrans::getString("Multiple Media"); + media_settings[LLMediaEntry::HOME_URL_KEY] = LLTrans::getString("Multiple Media"); } std::string base_key( "" ); @@ -286,7 +286,7 @@ void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& media_ { LLMediaEntry::WIDTH_PIXELS_KEY, self->mWidthPixels, "LLSpinCtrl" }, { "", NULL , "" } }; - + for( int i = 0; data_set[ i ].key_name.length() > 0; ++i ) { base_key = std::string( data_set[ i ].key_name ); @@ -405,20 +405,21 @@ void LLPanelMediaSettingsGeneral::preApply() //////////////////////////////////////////////////////////////////////////////// // -void LLPanelMediaSettingsGeneral::getValues( LLSD &fill_me_in ) +void LLPanelMediaSettingsGeneral::getValues( LLSD &fill_me_in, bool include_tentative ) { - fill_me_in[LLMediaEntry::AUTO_LOOP_KEY] = (LLSD::Boolean)mAutoLoop->getValue(); - fill_me_in[LLMediaEntry::AUTO_PLAY_KEY] = (LLSD::Boolean)mAutoPlay->getValue(); - fill_me_in[LLMediaEntry::AUTO_SCALE_KEY] = (LLSD::Boolean)mAutoScale->getValue(); - fill_me_in[LLMediaEntry::AUTO_ZOOM_KEY] = (LLSD::Boolean)mAutoZoom->getValue(); + if (include_tentative || !mAutoLoop->getTentative()) fill_me_in[LLMediaEntry::AUTO_LOOP_KEY] = (LLSD::Boolean)mAutoLoop->getValue(); + if (include_tentative || !mAutoPlay->getTentative()) fill_me_in[LLMediaEntry::AUTO_PLAY_KEY] = (LLSD::Boolean)mAutoPlay->getValue(); + if (include_tentative || !mAutoScale->getTentative()) fill_me_in[LLMediaEntry::AUTO_SCALE_KEY] = (LLSD::Boolean)mAutoScale->getValue(); + if (include_tentative || !mAutoZoom->getTentative()) fill_me_in[LLMediaEntry::AUTO_ZOOM_KEY] = (LLSD::Boolean)mAutoZoom->getValue(); //Don't fill in current URL: this is only supposed to get changed via navigate - // fill_me_in[LLMediaEntry::CURRENT_URL_KEY] = mCurrentURL->getValue(); - fill_me_in[LLMediaEntry::HEIGHT_PIXELS_KEY] = (LLSD::Integer)mHeightPixels->getValue(); + // if (include_tentative || !mCurrentURL->getTentative()) fill_me_in[LLMediaEntry::CURRENT_URL_KEY] = mCurrentURL->getValue(); + if (include_tentative || !mHeightPixels->getTentative()) fill_me_in[LLMediaEntry::HEIGHT_PIXELS_KEY] = (LLSD::Integer)mHeightPixels->getValue(); // Don't fill in the home URL if it is the special "Multiple Media" string! - if (LLTrans::getString("Multiple Media") != mHomeURL->getValue()) - fill_me_in[LLMediaEntry::HOME_URL_KEY] = (LLSD::String)mHomeURL->getValue(); - fill_me_in[LLMediaEntry::FIRST_CLICK_INTERACT_KEY] = (LLSD::Boolean)mFirstClick->getValue(); - fill_me_in[LLMediaEntry::WIDTH_PIXELS_KEY] = (LLSD::Integer)mWidthPixels->getValue(); + if ((include_tentative || !mHomeURL->getTentative()) + && LLTrans::getString("Multiple Media") != mHomeURL->getValue()) + fill_me_in[LLMediaEntry::HOME_URL_KEY] = (LLSD::String)mHomeURL->getValue(); + if (include_tentative || !mFirstClick->getTentative()) fill_me_in[LLMediaEntry::FIRST_CLICK_INTERACT_KEY] = (LLSD::Boolean)mFirstClick->getValue(); + if (include_tentative || !mWidthPixels->getTentative()) fill_me_in[LLMediaEntry::WIDTH_PIXELS_KEY] = (LLSD::Integer)mWidthPixels->getValue(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llpanelmediasettingsgeneral.h b/indra/newview/llpanelmediasettingsgeneral.h index 5f90321362..a3f0990f35 100644 --- a/indra/newview/llpanelmediasettingsgeneral.h +++ b/indra/newview/llpanelmediasettingsgeneral.h @@ -54,7 +54,8 @@ public: // Hook that the floater calls before applying changes from the panel void preApply(); // Function that asks the panel to fill in values associated with the panel - void getValues(LLSD &fill_me_in); + // 'include_tentative' means fill in tentative values as well, otherwise do not + void getValues(LLSD &fill_me_in, bool include_tentative = true); // Hook that the floater calls after applying changes to the panel void postApply(); diff --git a/indra/newview/llpanelmediasettingspermissions.cpp b/indra/newview/llpanelmediasettingspermissions.cpp index a23aed2e98..e5caaaaffc 100644 --- a/indra/newview/llpanelmediasettingspermissions.cpp +++ b/indra/newview/llpanelmediasettingspermissions.cpp @@ -149,27 +149,6 @@ void LLPanelMediaSettingsPermissions::clearValues( void* userdata, bool editable void LLPanelMediaSettingsPermissions::initValues( void* userdata, const LLSD& media_settings , bool editable) { LLPanelMediaSettingsPermissions *self =(LLPanelMediaSettingsPermissions *)userdata; - - if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo ) - { - if(LLFloaterMediaSettings::getInstance()->mMultipleMedia) - { - self->clearValues(self, editable); - // only show multiple - return; - } - - } - else - { - if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) - { - self->clearValues(self, editable); - // only show multiple - return; - } - - } std::string base_key( "" ); std::string tentative_key( "" ); @@ -215,7 +194,29 @@ void LLPanelMediaSettingsPermissions::initValues( void* userdata, const LLSD& me data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); }; }; - + + // *NOTE: If any of a particular flavor is tentative, we have to disable + // them all because of an architectural issue: namely that we represent + // these as a bit field, and we can't selectively apply only one bit to all selected + // faces if they don't match. Also see the *NOTE below. + if ( self->mPermsOwnerInteract->getTentative() || + self->mPermsGroupInteract->getTentative() || + self->mPermsWorldInteract->getTentative()) + { + self->mPermsOwnerInteract->setEnabled(false); + self->mPermsGroupInteract->setEnabled(false); + self->mPermsWorldInteract->setEnabled(false); + } + if ( self->mPermsOwnerControl->getTentative() || + self->mPermsGroupControl->getTentative() || + self->mPermsWorldControl->getTentative()) + { + self->mPermsOwnerControl->setEnabled(false); + self->mPermsGroupControl->setEnabled(false); + self->mPermsWorldControl->setEnabled(false); + } + + self->childSetEnabled("media_perms_label_owner", editable ); self->childSetText("media_perms_label_owner", LLTrans::getString("Media Perms Owner") ); self->childSetEnabled("media_perms_label_group", editable ); @@ -233,29 +234,47 @@ void LLPanelMediaSettingsPermissions::preApply() //////////////////////////////////////////////////////////////////////////////// // -void LLPanelMediaSettingsPermissions::getValues( LLSD &fill_me_in ) +void LLPanelMediaSettingsPermissions::getValues( LLSD &fill_me_in, bool include_tentative ) { // moved over from the 'General settings' tab - fill_me_in[LLMediaEntry::CONTROLS_KEY] = (LLSD::Integer)mControls->getCurrentIndex(); - - // *NOTE: For some reason, gcc does not like these symbol references in the - // expressions below (inside the static_casts). I have NO idea why :(. - // For some reason, assigning them to const temp vars here fixes the link - // error. Bizarre. - const U8 none = LLMediaEntry::PERM_NONE; - const U8 owner = LLMediaEntry::PERM_OWNER; - const U8 group = LLMediaEntry::PERM_GROUP; - const U8 anyone = LLMediaEntry::PERM_ANYONE; - const LLSD::Integer control = static_cast( + if (include_tentative || !mControls->getTentative()) fill_me_in[LLMediaEntry::CONTROLS_KEY] = (LLSD::Integer)mControls->getCurrentIndex(); + + // *NOTE: For some reason, gcc does not like these symbol references in the + // expressions below (inside the static_casts). I have NO idea why :(. + // For some reason, assigning them to const temp vars here fixes the link + // error. Bizarre. + const U8 none = LLMediaEntry::PERM_NONE; + const U8 owner = LLMediaEntry::PERM_OWNER; + const U8 group = LLMediaEntry::PERM_GROUP; + const U8 anyone = LLMediaEntry::PERM_ANYONE; + const LLSD::Integer control = static_cast( (mPermsOwnerControl->getValue() ? owner : none ) | (mPermsGroupControl->getValue() ? group: none ) | (mPermsWorldControl->getValue() ? anyone : none )); - const LLSD::Integer interact = static_cast( - (mPermsOwnerInteract->getValue() ? owner: none ) | + const LLSD::Integer interact = static_cast( + (mPermsOwnerInteract->getValue() ? owner: none ) | (mPermsGroupInteract->getValue() ? group : none ) | (mPermsWorldInteract->getValue() ? anyone : none )); - fill_me_in[LLMediaEntry::PERMS_CONTROL_KEY] = control; - fill_me_in[LLMediaEntry::PERMS_INTERACT_KEY] = interact; + + // *TODO: This will fill in the values of all permissions values, even if + // one or more is tentative. This is not quite the user expectation...what + // it should do is only change the bit that was made "untentative", but in + // a multiple-selection situation, this isn't possible given the architecture + // for how settings are applied. + if (include_tentative || + !mPermsOwnerControl->getTentative() || + !mPermsGroupControl->getTentative() || + !mPermsWorldControl->getTentative()) + { + fill_me_in[LLMediaEntry::PERMS_CONTROL_KEY] = control; + } + if (include_tentative || + !mPermsOwnerInteract->getTentative() || + !mPermsGroupInteract->getTentative() || + !mPermsWorldInteract->getTentative()) + { + fill_me_in[LLMediaEntry::PERMS_INTERACT_KEY] = interact; + } } diff --git a/indra/newview/llpanelmediasettingspermissions.h b/indra/newview/llpanelmediasettingspermissions.h index bd0c3b8ab5..858544605c 100644 --- a/indra/newview/llpanelmediasettingspermissions.h +++ b/indra/newview/llpanelmediasettingspermissions.h @@ -57,7 +57,8 @@ public: // Hook that the floater calls before applying changes from the panel void preApply(); // Function that asks the panel to fill in values associated with the panel - void getValues(LLSD &fill_me_in); + // 'include_tentative' means fill in tentative values as well, otherwise do not + void getValues(LLSD &fill_me_in, bool include_tentative = true); // Hook that the floater calls after applying changes to the panel void postApply(); diff --git a/indra/newview/llpanelmediasettingssecurity.cpp b/indra/newview/llpanelmediasettingssecurity.cpp index 81842e3851..1b1346c41a 100644 --- a/indra/newview/llpanelmediasettingssecurity.cpp +++ b/indra/newview/llpanelmediasettingssecurity.cpp @@ -94,27 +94,6 @@ void LLPanelMediaSettingsSecurity::draw() void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media_settings , bool editable) { LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; - - if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo ) - { - if(LLFloaterMediaSettings::getInstance()->mMultipleMedia) - { - self->clearValues(self, editable); - // only show multiple - return; - } - - } - else - { - if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) - { - self->clearValues(self, editable); - // only show multiple - return; - } - - } std::string base_key( "" ); std::string tentative_key( "" ); @@ -136,6 +115,8 @@ void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media base_key = std::string( data_set[ i ].key_name ); tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ); + bool enabled_overridden = false; + // TODO: CP - I bet there is a better way to do this using Boost if ( media_settings[ base_key ].isDefined() ) { @@ -150,20 +131,31 @@ void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media // get control LLScrollListCtrl* list = static_cast< LLScrollListCtrl* >( data_set[ i ].ctrl_ptr ); list->deleteAllItems(); - + // points to list of white list URLs LLSD url_list = media_settings[ base_key ]; - - // iterate over them and add to scroll list - LLSD::array_iterator iter = url_list.beginArray(); - while( iter != url_list.endArray() ) + + // better be the whitelist + llassert(data_set[ i ].ctrl_ptr == self->mWhiteListList); + + // If tentative, don't add entries + if (media_settings[ tentative_key ].asBoolean()) { - std::string entry = *iter; - self->addWhiteListEntry( entry ); - ++iter; - }; + self->mWhiteListList->setEnabled(false); + enabled_overridden = true; + } + else { + // iterate over them and add to scroll list + LLSD::array_iterator iter = url_list.beginArray(); + while( iter != url_list.endArray() ) + { + std::string entry = *iter; + self->addWhiteListEntry( entry ); + ++iter; + } + } }; - data_set[ i ].ctrl_ptr->setEnabled(editable); + if ( ! enabled_overridden) data_set[ i ].ctrl_ptr->setEnabled(editable); data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); }; }; @@ -192,25 +184,29 @@ void LLPanelMediaSettingsSecurity::preApply() //////////////////////////////////////////////////////////////////////////////// // -void LLPanelMediaSettingsSecurity::getValues( LLSD &fill_me_in ) +void LLPanelMediaSettingsSecurity::getValues( LLSD &fill_me_in, bool include_tentative ) { - fill_me_in[LLMediaEntry::WHITELIST_ENABLE_KEY] = (LLSD::Boolean)mEnableWhiteList->getValue(); - - // iterate over white list and extract items - std::vector< LLScrollListItem* > whitelist_items = mWhiteListList->getAllData(); - std::vector< LLScrollListItem* >::iterator iter = whitelist_items.begin(); - - // *NOTE: need actually set the key to be an emptyArray(), or the merge - // we do with this LLSD will think there's nothing to change. - fill_me_in[LLMediaEntry::WHITELIST_KEY] = LLSD::emptyArray(); - while( iter != whitelist_items.end() ) - { - LLScrollListCell* cell = (*iter)->getColumn( ENTRY_COLUMN ); - std::string whitelist_url = cell->getValue().asString(); - - fill_me_in[ LLMediaEntry::WHITELIST_KEY ].append( whitelist_url ); - ++iter; - }; + if (include_tentative || !mEnableWhiteList->getTentative()) + fill_me_in[LLMediaEntry::WHITELIST_ENABLE_KEY] = (LLSD::Boolean)mEnableWhiteList->getValue(); + + if (include_tentative || !mWhiteListList->getTentative()) + { + // iterate over white list and extract items + std::vector< LLScrollListItem* > whitelist_items = mWhiteListList->getAllData(); + std::vector< LLScrollListItem* >::iterator iter = whitelist_items.begin(); + + // *NOTE: need actually set the key to be an emptyArray(), or the merge + // we do with this LLSD will think there's nothing to change. + fill_me_in[LLMediaEntry::WHITELIST_KEY] = LLSD::emptyArray(); + while( iter != whitelist_items.end() ) + { + LLScrollListCell* cell = (*iter)->getColumn( ENTRY_COLUMN ); + std::string whitelist_url = cell->getValue().asString(); + + fill_me_in[ LLMediaEntry::WHITELIST_KEY ].append( whitelist_url ); + ++iter; + }; + } } //////////////////////////////////////////////////////////////////////////////// @@ -247,6 +243,10 @@ const std::string LLPanelMediaSettingsSecurity::makeValidUrl( const std::string& // white list list box widget and build a list to test against. bool LLPanelMediaSettingsSecurity::urlPassesWhiteList( const std::string& test_url ) { + // If the whitlelist list is tentative, it means we have multiple settings. + // In that case, we have no choice but to return true + if ( mWhiteListList->getTentative() ) return true; + // the checkUrlAgainstWhitelist(..) function works on a vector // of strings for the white list entries - in this panel, the white list // is stored in the widgets themselves so we need to build something compatible. @@ -330,7 +330,7 @@ void LLPanelMediaSettingsSecurity::addWhiteListEntry( const std::string& entry ) // always add in the entry itself row[ "columns" ][ ENTRY_COLUMN ][ "type" ] = "text"; row[ "columns" ][ ENTRY_COLUMN ][ "value" ] = entry; - + // add to the white list scroll box mWhiteListList->addElement( row ); }; diff --git a/indra/newview/llpanelmediasettingssecurity.h b/indra/newview/llpanelmediasettingssecurity.h index 66ccb23f46..94f2fdc89c 100644 --- a/indra/newview/llpanelmediasettingssecurity.h +++ b/indra/newview/llpanelmediasettingssecurity.h @@ -53,11 +53,12 @@ public: // Hook that the floater calls before applying changes from the panel void preApply(); // Function that asks the panel to fill in values associated with the panel - void getValues(LLSD &fill_me_in); + // 'include_tentative' means fill in tentative values as well, otherwise do not + void getValues(LLSD &fill_me_in, bool include_tentative = true); // Hook that the floater calls after applying changes to the panel void postApply(); - static void initValues( void* userdata, const LLSD& media_settings,bool editable ); + static void initValues( void* userdata, const LLSD& media_settings, bool editable); static void clearValues( void* userdata, bool editable); void addWhiteListEntry( const std::string& url ); void setParent( LLFloaterMediaSettings* parent ); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index bf08756051..9540894646 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -41,6 +41,7 @@ #include "lldbstrings.h" #include "lleconomy.h" #include "llgl.h" +#include "llmediaentry.h" #include "llrender.h" #include "llnotifications.h" #include "llpermissions.h" @@ -1739,70 +1740,70 @@ void LLSelectMgr::selectionSetFullbright(U8 fullbright) getSelection()->applyToObjects(&sendfunc); } -void LLSelectMgr::selectionSetMedia(U8 media_type) -{ - - struct f : public LLSelectedTEFunctor - { - U8 mMediaFlags; - f(const U8& t) : mMediaFlags(t) {} - bool apply(LLViewerObject* object, S32 te) - { - if (object->permModify()) - { - // update viewer has media - object->setTEMediaFlags(te, mMediaFlags); - } - return true; - } - } setfunc(media_type); - getSelection()->applyToTEs(&setfunc); - struct f2 : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* object) - { - if (object->permModify()) - { - object->sendTEUpdate(); - } - return true; - } - } func2; - mSelectedObjects->applyToObjects( &func2 ); -} - // This function expects media_data to be a map containing relevant // media data name/value pairs (e.g. home_url, etc.) -void LLSelectMgr::selectionSetMediaData(const LLSD &media_data) -{ - +void LLSelectMgr::selectionSetMedia(U8 media_type, const LLSD &media_data) +{ struct f : public LLSelectedTEFunctor { + U8 mMediaFlags; const LLSD &mMediaData; - f(const LLSD& t) : mMediaData(t) {} + f(const U8& t, const LLSD& d) : mMediaFlags(t), mMediaData(d) {} bool apply(LLViewerObject* object, S32 te) { if (object->permModify()) { - LLVOVolume *vo = dynamic_cast(object); - if (NULL != vo) - { - vo->syncMediaData(te, mMediaData, true/*merge*/, true/*ignore_agent*/); - } + // If we are adding media, then check the current state of the + // media data on this face. + // - If it does not have media, AND we are NOT setting the HOME URL, then do NOT add media to this + // face. + // - If it does not have media, and we ARE setting the HOME URL, add media to this face. + // - If it does already have media, add/update media to/on this face + // If we are removing media, just do it (ignore the passed-in LLSD). + if (mMediaFlags & LLTextureEntry::MF_HAS_MEDIA) + { + llassert(mMediaData.isMap()); + const LLTextureEntry *texture_entry = object->getTE(te); + if (!mMediaData.isMap() || + (NULL != texture_entry) && !texture_entry->hasMedia() && !mMediaData.has(LLMediaEntry::HOME_URL_KEY)) + { + // skip adding/updating media + } + else { + // Add/update media + object->setTEMediaFlags(te, mMediaFlags); + LLVOVolume *vo = dynamic_cast(object); + llassert(NULL != vo); + if (NULL != vo) + { + vo->syncMediaData(te, mMediaData, true/*merge*/, true/*ignore_agent*/); + } + } + } + else + { + // delete media (or just set the flags) + object->setTEMediaFlags(te, mMediaFlags); + } } return true; } - } setfunc(media_data); + } setfunc(media_type, media_data); getSelection()->applyToTEs(&setfunc); - + struct f2 : public LLSelectedObjectFunctor { virtual bool apply(LLViewerObject* object) { if (object->permModify()) { - LLVOVolume *vo = dynamic_cast(object); - if (NULL != vo) + object->sendTEUpdate(); + LLVOVolume *vo = dynamic_cast(object); + llassert(NULL != vo); + // It's okay to skip this object if hasMedia() is false... + // the sendTEUpdate() above would remove all media data if it were + // there. + if (NULL != vo && vo->hasMedia()) { // Send updated media data FOR THE ENTIRE OBJECT vo->sendMediaDataUpdate(); @@ -1811,11 +1812,9 @@ void LLSelectMgr::selectionSetMediaData(const LLSD &media_data) return true; } } func2; - getSelection()->applyToObjects(&func2); + mSelectedObjects->applyToObjects( &func2 ); } - - void LLSelectMgr::selectionSetGlow(F32 glow) { struct f1 : public LLSelectedTEFunctor diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index f8ecfd0674..00474827ca 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -502,8 +502,7 @@ public: void selectionSetTexGen( U8 texgen ); void selectionSetShiny( U8 shiny ); void selectionSetFullbright( U8 fullbright ); - void selectionSetMedia( U8 media_type ); - void selectionSetMediaData(const LLSD &media_data); // NOTE: modifies media_data!!! + void selectionSetMedia( U8 media_type, const LLSD &media_data ); void selectionSetClickAction(U8 action); void selectionSetIncludeInSearch(bool include_in_search); void selectionSetGlow(const F32 glow); -- cgit v1.2.3 From c58e152236abfc1c414eb6c64783334ca9555b58 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 4 Feb 2010 14:29:43 -0500 Subject: EXT-4801 : hitting trash button for trashed items does not delete item EXT-4957 : add const correctness for LLFolderViewEventListener::isItemRemovable This checkin affects several files but is a lot less scary than it looks. It's mostly to add const correctness, and to rename isInTrash to isItemInTrash so that its naming is consistent with isItemRemovable/isItemMovable. The only functionality change is to disable the trash button when an item is already in the trash. --- indra/newview/llfolderview.cpp | 3 +-- indra/newview/llfoldervieweventlistener.h | 3 ++- indra/newview/llinventorybridge.cpp | 38 +++++++++++++++---------------- indra/newview/llinventorybridge.h | 10 ++++---- indra/newview/llpanelmaininventory.cpp | 6 ++++- indra/newview/llpanelobjectinventory.cpp | 10 ++++---- indra/newview/llplacesinventorybridge.cpp | 2 +- 7 files changed, 39 insertions(+), 33 deletions(-) diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index c6135d3bc3..5c65b2c293 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -1272,8 +1272,7 @@ BOOL LLFolderView::canCut() const const LLFolderViewItem* item = *selected_it; const LLFolderViewEventListener* listener = item->getListener(); - // *WARKAROUND: it is too many places where the "isItemRemovable" method should be changed with "const" modifier - if (!listener || !(const_cast(listener))->isItemRemovable()) + if (!listener || !listener->isItemRemovable()) { return FALSE; } diff --git a/indra/newview/llfoldervieweventlistener.h b/indra/newview/llfoldervieweventlistener.h index d6c4459e6f..12e100caf4 100644 --- a/indra/newview/llfoldervieweventlistener.h +++ b/indra/newview/llfoldervieweventlistener.h @@ -73,7 +73,8 @@ public: virtual BOOL isItemRenameable() const = 0; virtual BOOL renameItem(const std::string& new_name) = 0; virtual BOOL isItemMovable( void ) const = 0; // Can be moved to another folder - virtual BOOL isItemRemovable( void ) = 0; // Can be destroyed + virtual BOOL isItemRemovable( void ) const = 0; // Can be destroyed + virtual BOOL isItemInTrash( void) const { return FALSE; } // TODO: make into pure virtual. virtual BOOL removeItem() = 0; virtual void removeBatch(LLDynamicArray& batch) = 0; virtual void move( LLFolderViewEventListener* parent_listener ) = 0; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index ab178b4007..3a630650c5 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -174,7 +174,7 @@ time_t LLInvFVBridge::getCreationDate() const } // Can be destroyed (or moved to trash) -BOOL LLInvFVBridge::isItemRemovable() +BOOL LLInvFVBridge::isItemRemovable() const { const LLInventoryModel* model = getInventoryModel(); if(!model) @@ -605,7 +605,7 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) lldebugs << "LLInvFVBridge::buildContextMenu()" << llendl; std::vector items; std::vector disabled_items; - if(isInTrash()) + if(isItemInTrash()) { items.push_back(std::string("Purge Item")); if (!isItemRemovable()) @@ -670,7 +670,7 @@ LLInventoryModel* LLInvFVBridge::getInventoryModel() const return panel ? panel->getModel() : NULL; } -BOOL LLInvFVBridge::isInTrash() const +BOOL LLInvFVBridge::isItemInTrash() const { LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; @@ -680,7 +680,7 @@ BOOL LLInvFVBridge::isInTrash() const BOOL LLInvFVBridge::isLinkedObjectInTrash() const { - if (isInTrash()) return TRUE; + if (isItemInTrash()) return TRUE; const LLInventoryObject *obj = getInventoryObject(); if (obj && obj->getIsLinkType()) @@ -1412,7 +1412,7 @@ public: }; // Can be destroyed (or moved to trash) -BOOL LLFolderBridge::isItemRemovable() +BOOL LLFolderBridge::isItemRemovable() const { LLInventoryModel* model = getInventoryModel(); if(!model) @@ -3208,7 +3208,7 @@ void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) lldebugs << "LLTextureBridge::buildContextMenu()" << llendl; std::vector items; std::vector disabled_items; - if(isInTrash()) + if(isItemInTrash()) { items.push_back(std::string("Purge Item")); if (!isItemRemovable()) @@ -3302,7 +3302,7 @@ void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) std::vector items; std::vector disabled_items; - if(isInTrash()) + if(isItemInTrash()) { items.push_back(std::string("Purge Item")); if (!isItemRemovable()) @@ -3351,7 +3351,7 @@ void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) std::vector disabled_items; lldebugs << "LLLandmarkBridge::buildContextMenu()" << llendl; - if(isInTrash()) + if(isItemInTrash()) { items.push_back(std::string("Purge Item")); if (!isItemRemovable()) @@ -3576,7 +3576,7 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) std::vector items; std::vector disabled_items; - if(isInTrash()) + if(isItemInTrash()) { items.push_back(std::string("Purge Item")); if (!isItemRemovable()) @@ -3841,7 +3841,7 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) lldebugs << "LLGestureBridge::buildContextMenu()" << llendl; std::vector items; std::vector disabled_items; - if(isInTrash()) + if(isItemInTrash()) { items.push_back(std::string("Purge Item")); if (!isItemRemovable()) @@ -3905,7 +3905,7 @@ void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) std::vector disabled_items; lldebugs << "LLAnimationBridge::buildContextMenu()" << llendl; - if(isInTrash()) + if(isItemInTrash()) { items.push_back(std::string("Purge Item")); if (!isItemRemovable()) @@ -4184,7 +4184,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { std::vector items; std::vector disabled_items; - if(isInTrash()) + if(isItemInTrash()) { items.push_back(std::string("Purge Item")); if (!isItemRemovable()) @@ -4220,7 +4220,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { items.push_back(std::string("Detach From Yourself")); } - else if (!isInTrash() && !isLinkedObjectInTrash() && !isLinkedObjectMissing()) + else if (!isItemInTrash() && !isLinkedObjectInTrash() && !isLinkedObjectMissing()) { items.push_back(std::string("Attach Separator")); items.push_back(std::string("Object Wear")); @@ -4558,7 +4558,7 @@ void LLWearableBridge::openItem() LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); } /* - if( isInTrash() ) + if( isItemInTrash() ) { LLNotificationsUtil::add("CannotWearTrash"); } @@ -4600,7 +4600,7 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) lldebugs << "LLWearableBridge::buildContextMenu()" << llendl; std::vector items; std::vector disabled_items; - if(isInTrash()) + if(isItemInTrash()) { items.push_back(std::string("Purge Item")); if (!isItemRemovable()) @@ -5195,7 +5195,7 @@ void LLLSLTextBridgeAction::doIt() } -BOOL LLWearableBridgeAction::isInTrash() const +BOOL LLWearableBridgeAction::isItemInTrash() const { if(!mModel) return FALSE; const LLUUID trash_id = mModel->findCategoryUUIDForType(LLFolderType::FT_TRASH); @@ -5243,7 +5243,7 @@ void LLWearableBridgeAction::wearOnAvatar() //virtual void LLWearableBridgeAction::doIt() { - if(isInTrash()) + if(isItemInTrash()) { LLNotificationsUtil::add("CannotWearTrash"); } @@ -5308,7 +5308,7 @@ void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Find Original")); disabled_items.push_back(std::string("Find Original")); - if(isInTrash()) + if(isItemInTrash()) { items.push_back(std::string("Purge Item")); if (!isItemRemovable()) @@ -5359,7 +5359,7 @@ void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) std::vector items; std::vector disabled_items; - if(isInTrash()) + if(isItemInTrash()) { items.push_back(std::string("Purge Item")); if (!isItemRemovable()) diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 6fffec96a0..6e256edc05 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -158,8 +158,10 @@ public: virtual void showProperties(); virtual BOOL isItemRenameable() const { return TRUE; } //virtual BOOL renameItem(const std::string& new_name) {} - virtual BOOL isItemRemovable(); + virtual BOOL isItemRemovable() const; virtual BOOL isItemMovable() const; + virtual BOOL isItemInTrash() const; + //virtual BOOL removeItem() = 0; virtual void removeBatch(LLDynamicArray& batch); virtual void move(LLFolderViewEventListener* new_parent_bridge) {} @@ -185,13 +187,13 @@ public: // Allow context menus to be customized for side panel. bool isInOutfitsSidePanel() const; + protected: LLInvFVBridge(LLInventoryPanel* inventory, const LLUUID& uuid); LLInventoryObject* getInventoryObject() const; LLInventoryModel* getInventoryModel() const; - BOOL isInTrash() const; BOOL isLinkedObjectInTrash() const; // Is this obj or its baseobj in the trash? BOOL isLinkedObjectMissing() const; // Is this a linked obj whose baseobj is not in inventory? @@ -306,7 +308,7 @@ public: EDragAndDropType cargo_type, void* cargo_data); - virtual BOOL isItemRemovable(); + virtual BOOL isItemRemovable() const; virtual BOOL isItemMovable() const ; virtual BOOL isUpToDate() const; virtual BOOL isItemCopyable() const; @@ -786,7 +788,7 @@ protected: LLWearableBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){} - BOOL isInTrash() const; + BOOL isItemInTrash() const; // return true if the item is in agent inventory. if false, it // must be lost or in the inventory library. BOOL isAgentInventory() const; diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index a5a61f0c7b..1895993a8e 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -1071,7 +1071,11 @@ BOOL LLPanelMainInventory::isActionEnabled(const LLSD& userdata) { const LLUUID &item_id = (*iter); LLFolderViewItem *item = folder->getItemByID(item_id); - can_delete &= item->getListener()->isItemRemovable(); + const LLFolderViewEventListener *listener = item->getListener(); + llassert(listener); + if (!listener) return FALSE; + can_delete &= listener->isItemRemovable(); + can_delete &= !listener->isItemInTrash(); } return can_delete; } diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 5c5c35141e..e8ae006968 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -117,7 +117,7 @@ public: virtual BOOL isItemRenameable() const; virtual BOOL renameItem(const std::string& new_name); virtual BOOL isItemMovable() const; - virtual BOOL isItemRemovable(); + virtual BOOL isItemRemovable() const; virtual BOOL removeItem(); virtual void removeBatch(LLDynamicArray& batch); virtual void move(LLFolderViewEventListener* parent_listener); @@ -412,9 +412,9 @@ BOOL LLTaskInvFVBridge::isItemMovable() const return TRUE; } -BOOL LLTaskInvFVBridge::isItemRemovable() +BOOL LLTaskInvFVBridge::isItemRemovable() const { - LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + const LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); if(object && (object->permModify() || object->permYouOwner())) { @@ -710,7 +710,7 @@ public: virtual BOOL isItemRenameable() const; // virtual BOOL isItemCopyable() const { return FALSE; } virtual BOOL renameItem(const std::string& new_name); - virtual BOOL isItemRemovable(); + virtual BOOL isItemRemovable() const; virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual BOOL hasChildren() const; virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const; @@ -742,7 +742,7 @@ BOOL LLTaskCategoryBridge::renameItem(const std::string& new_name) return FALSE; } -BOOL LLTaskCategoryBridge::isItemRemovable() +BOOL LLTaskCategoryBridge::isItemRemovable() const { return FALSE; } diff --git a/indra/newview/llplacesinventorybridge.cpp b/indra/newview/llplacesinventorybridge.cpp index 83443687c9..4fe69f295c 100644 --- a/indra/newview/llplacesinventorybridge.cpp +++ b/indra/newview/llplacesinventorybridge.cpp @@ -66,7 +66,7 @@ void LLPlacesLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) std::vector items; std::vector disabled_items; - if(isInTrash()) + if(isItemInTrash()) { items.push_back(std::string("Purge Item")); if (!isItemRemovable()) -- cgit v1.2.3 From b4d61b6e63dd04f8b67edcf32ea513295843157b Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Thu, 4 Feb 2010 14:53:18 -0500 Subject: EXT-4003 Appearance problemw earing City Chic Female - probably param related cross-wearable params are fun! Values were not being updated properly for parameters that cross multiple wearables. Created a few functions to ensure that these values get updated and made them called from LLAgentWearables::wearableUpdated(). Also prevented cross-wearable params from writing back to the avatar, as they are being driven by another wearable. Code reviewed by Bigpapi --- indra/newview/llagentwearables.cpp | 2 ++ indra/newview/lldriverparam.cpp | 33 +++++++++++++++++++++++++++++++++ indra/newview/lldriverparam.h | 3 +++ indra/newview/llviewervisualparam.h | 1 + indra/newview/llvoavatarself.cpp | 1 + indra/newview/llwearable.cpp | 24 +++++++++++++++++++++++- indra/newview/llwearable.h | 3 ++- 7 files changed, 65 insertions(+), 2 deletions(-) diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index b0ff3a5626..4724bb9ada 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -761,6 +761,8 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable) wearable->refreshName(); wearable->setLabelUpdated(); + wearable->pullCrossWearableValues(); + // Hack pt 2. If the wearable we just loaded has definition version 24, // then force a re-save of this wearable after slamming the version number to 22. // This number was incorrectly incremented for internal builds before release, and diff --git a/indra/newview/lldriverparam.cpp b/indra/newview/lldriverparam.cpp index 3961afe9af..8ebfa471f3 100644 --- a/indra/newview/lldriverparam.cpp +++ b/indra/newview/lldriverparam.cpp @@ -39,6 +39,7 @@ #include "llvoavatarself.h" #include "llagent.h" #include "llwearable.h" +#include "llagentwearables.h" //----------------------------------------------------------------------------- // LLDriverParamInfo @@ -528,6 +529,38 @@ void LLDriverParam::resetDrivenParams() mDriven.reserve(getInfo()->mDrivenInfoList.size()); } +void LLDriverParam::updateCrossDrivenParams(EWearableType driven_type) +{ + bool needs_update = (getWearableType()==driven_type); + + // if the driver has a driven entry for the passed-in wearable type, we need to refresh the value + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + { + LLDrivenEntry* driven = &(*iter); + if (driven && driven->mParam && driven->mParam->getCrossWearable() && driven->mParam->getWearableType() == driven_type) + { + needs_update = true; + } + } + + + if (needs_update) + { + EWearableType driver_type = (EWearableType)getWearableType(); + + // If we've gotten here, we've added a new wearable of type "type" + // Thus this wearable needs to get updates from the driver wearable. + // The call to setVisualParamWeight seems redundant, but is necessary + // as the number of driven wearables has changed since the last update. -Nyx + LLWearable *wearable = gAgentWearables.getTopWearable(driver_type); + if (wearable) + { + wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID), false); + } + } +} + + //----------------------------------------------------------------------------- // getDrivenWeight() //----------------------------------------------------------------------------- diff --git a/indra/newview/lldriverparam.h b/indra/newview/lldriverparam.h index 4e2daf5ba7..e963a2d55a 100644 --- a/indra/newview/lldriverparam.h +++ b/indra/newview/lldriverparam.h @@ -34,6 +34,7 @@ #define LL_LLDRIVERPARAM_H #include "llviewervisualparam.h" +#include "llwearabledictionary.h" class LLVOAvatar; class LLWearable; @@ -93,6 +94,7 @@ public: void setWearable(LLWearable *wearablep); void setAvatar(LLVOAvatar *avatarp); + void updateCrossDrivenParams(EWearableType driven_type); /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const; @@ -112,6 +114,7 @@ public: /*virtual*/ LLVector3 getVertexDistortion(S32 index, LLPolyMesh *poly_mesh); /*virtual*/ const LLVector3* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh); /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh); + protected: F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight); void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake); diff --git a/indra/newview/llviewervisualparam.h b/indra/newview/llviewervisualparam.h index 3550a46fbf..1a3975eb99 100644 --- a/indra/newview/llviewervisualparam.h +++ b/indra/newview/llviewervisualparam.h @@ -111,6 +111,7 @@ public: F32 getSimpleMax() const { return getInfo()->mSimpleMax; } BOOL getCrossWearable() const { return getInfo()->mCrossWearable; } + }; #endif // LL_LLViewerVisualParam_H diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index ecd6b05ded..b1ea8a1bbb 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -1966,6 +1966,7 @@ void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug) // Don't know if this is needed updateMeshTextures(); + } //----------------------------------------------------------------------------- diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index d093031bea..acfbc23f62 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -625,7 +625,9 @@ void LLWearable::writeToAvatar() // Pull params for( LLVisualParam* param = avatar->getFirstVisualParam(); param; param = avatar->getNextVisualParam() ) { - if( (((LLViewerVisualParam*)param)->getWearableType() == mType) ) + // cross-wearable parameters are not authoritative, as they are driven by a different wearable. So don't copy the values to the + // avatar object if cross wearable. Cross wearable params get their values from the avatar, they shouldn't write the other way. + if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (!((LLViewerVisualParam*)param)->getCrossWearable()) ) { S32 param_id = param->getID(); F32 weight = getVisualParamWeight(param_id); @@ -1085,6 +1087,26 @@ void LLWearable::destroyTextures() mSavedTEMap.clear(); } +void LLWearable::pullCrossWearableValues() +{ + // scan through all of the avatar's visual parameters + LLVOAvatar* avatar = gAgent.getAvatarObject(); + for (LLViewerVisualParam* param = (LLViewerVisualParam*) avatar->getFirstVisualParam(); + param; + param = (LLViewerVisualParam*) avatar->getNextVisualParam()) + { + if( param ) + { + LLDriverParam *driver_param = dynamic_cast(param); + if(driver_param) + { + // parameter is a driver parameter, have it update its + driver_param->updateCrossDrivenParams(getType()); + } + } + } +} + void LLWearable::setLabelUpdated() const { diff --git a/indra/newview/llwearable.h b/indra/newview/llwearable.h index dae983bcf3..7bd5305079 100644 --- a/indra/newview/llwearable.h +++ b/indra/newview/llwearable.h @@ -128,6 +128,7 @@ public: void revertValues(); void saveValues(); + void pullCrossWearableValues(); BOOL isOnTop() const; @@ -145,7 +146,7 @@ private: void createLayers(S32 te); void createVisualParams(); void syncImages(te_map_t &src, te_map_t &dst); - void destroyTextures(); + void destroyTextures(); static S32 sCurrentDefinitionVersion; // Depends on the current state of the avatar_lad.xml. S32 mDefinitionVersion; // Depends on the state of the avatar_lad.xml when this asset was created. -- cgit v1.2.3 From 973e2143d23cad915a320dceccf4c2708e1cfa2e Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 4 Feb 2010 15:22:39 -0500 Subject: EXT-4902: Assert crash after detaching all and removing all clothes. Turned overzealous assert into a warning. --- indra/newview/llinventorybridge.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index ab178b4007..1414e9ca83 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -4916,7 +4916,12 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable, } // Find and remove this item from the COF. + // FIXME 2.1 - call removeCOFItemLinks in llappearancemgr instead. LLInventoryModel::item_array_t items = gInventory.collectLinkedItems(item_id, LLAppearanceManager::instance().getCOF()); + if (items.size() != 1) + { + llwarns << "Found " << items.size() << " COF links to " << item_id.asString() << ", expected 1" << llendl; + } llassert(items.size() == 1); // Should always have one and only one item linked to this in the COF. for (LLInventoryModel::item_array_t::const_iterator iter = items.begin(); iter != items.end(); -- cgit v1.2.3 From b3f4c6fb7ad79501fa91e14cc93ef3dcd1cce8ae Mon Sep 17 00:00:00 2001 From: "Eric M. Tulla (BigPapi)" Date: Thu, 4 Feb 2010 15:52:07 -0500 Subject: EXT-4841 - Expand one of the outfits in the outfits tab for new users so they can get a sense of their contents. Also moved the My Outfits autopopulation from the library out of where it was done before (as a result of initial wearables message) to be done in the idle login during the precaching state. -Reviewed by Nyx --- indra/newview/llagentwearables.cpp | 7 ------- indra/newview/llpaneloutfitsinventory.cpp | 21 +++++++++++++++++++++ indra/newview/llstartup.cpp | 11 +++++++++++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 41f2ff29e6..acbf02678c 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -927,13 +927,6 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs if (mInitialWearablesUpdateReceived) return; mInitialWearablesUpdateReceived = true; - - // If this is the very first time the user has logged into viewer2+ (from a legacy viewer, or new account) - // then auto-populate outfits from the library into the My Outfits folder. - if (LLInventoryModel::getIsFirstTimeInViewer2() || gSavedSettings.getBOOL("MyOutfitsAutofill")) - { - gAgentWearables.populateMyOutfitsFolder(); - } LLUUID agent_id; gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index cf903958ee..c2f2d32142 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -159,6 +159,27 @@ void LLPanelOutfitsInventory::onOpen(const LLSD& key) // Make sure we know which tab is selected, update the filter, // and update verbs. onTabChange(); + + // Auto open the first outfit newly created so new users can see sample outfit contents + static bool should_open_outfit = true; + if (should_open_outfit && gAgent.isFirstLogin()) + { + LLInventoryPanel* outfits_panel = getChild(OUTFITS_TAB_NAME); + if (outfits_panel) + { + LLUUID my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + LLFolderViewFolder* my_outfits_folder = outfits_panel->getRootFolder()->getFolderByID(my_outfits_id); + if (my_outfits_folder) + { + LLFolderViewFolder* first_outfit = dynamic_cast(my_outfits_folder->getFirstChild()); + if (first_outfit) + { + first_outfit->setOpen(TRUE); + } + } + } + } + should_open_outfit = false; } void LLPanelOutfitsInventory::updateVerbs() diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 9fda77fe74..a402dfc3d1 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1876,6 +1876,17 @@ bool idle_startup() LLViewerShaderMgr::instance()->setShaders(); } } + + // If this is the very first time the user has logged into viewer2+ (from a legacy viewer, or new account) + // then auto-populate outfits from the library into the My Outfits folder. + static bool check_populate_my_outfits = true; + if (check_populate_my_outfits && + (LLInventoryModel::getIsFirstTimeInViewer2() + || gSavedSettings.getBOOL("MyOutfitsAutofill"))) + { + gAgentWearables.populateMyOutfitsFolder(); + } + check_populate_my_outfits = false; return TRUE; } -- cgit v1.2.3 From a165279acd57c6c0e2e6492b7de39a9e614327af Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 4 Feb 2010 16:20:43 -0500 Subject: EXT-4902: Assert crash after detaching all and removing all clothes. --- indra/newview/llinventorybridge.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 1414e9ca83..35a45a89be 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -4922,7 +4922,6 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable, { llwarns << "Found " << items.size() << " COF links to " << item_id.asString() << ", expected 1" << llendl; } - llassert(items.size() == 1); // Should always have one and only one item linked to this in the COF. for (LLInventoryModel::item_array_t::const_iterator iter = items.begin(); iter != items.end(); ++iter) @@ -4958,7 +4957,10 @@ void LLWearableBridge::removeAllClothesFromAvatar() // Find and remove this item from the COF. LLInventoryModel::item_array_t items = gInventory.collectLinkedItems( item_id, LLAppearanceManager::instance().getCOF()); - llassert(items.size() == 1); // Should always have one and only one item linked to this in the COF. + if (items.size() != 1) + { + llwarns << "Found " << items.size() << " COF links to " << item_id.asString() << ", expected 1" << llendl; + } for (LLInventoryModel::item_array_t::const_iterator iter = items.begin(); iter != items.end(); ++iter) -- cgit v1.2.3 From b94e5b597a0fb0ca667d50c4a2324025faa308f6 Mon Sep 17 00:00:00 2001 From: "Mark Palange (Mani)" Date: Thu, 4 Feb 2010 13:39:51 -0800 Subject: Backed out changeset: b579077ebc79 I gave lynx a bad review. :( I didn't know about the setting FirstLoginThisInstall. I'm backing out lynx's change, then re-fixing EXT-4237. --- indra/newview/app_settings/settings.xml | 6 +++--- indra/newview/llappviewer.cpp | 2 +- indra/newview/llpanellogin.cpp | 4 ++-- indra/newview/llstartup.cpp | 5 ++--- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 3b9b3a51d5..62197406b6 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2817,16 +2817,16 @@ Value 0 - HadFirstSuccessfulLogin + FirstRunThisInstall Comment - Specifies whether you have successfully logged in at least once before + Specifies that you have not run the viewer since you installed the latest update Persist 1 Type Boolean Value - 0 + 1 FirstSelectedDisabledPopups diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 2f90885df3..2d694eefd3 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2611,7 +2611,7 @@ void LLAppViewer::handleViewerCrash() gDebugInfo["StartupState"] = LLStartUp::getStartupStateString(); gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer) LLMemory::getCurrentRSS() >> 10; gDebugInfo["FirstLogin"] = (LLSD::Boolean) gAgent.isFirstLogin(); - gDebugInfo["HadFirstSuccessfulLogin"] = gSavedSettings.getBOOL("HadFirstSuccessfulLogin"); + gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall"); if(gLogoutInProgress) { diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index df9002facc..af9e791223 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -676,7 +676,7 @@ void LLPanelLogin::refreshLocation( bool force_visible ) // Don't show on first run after install // Otherwise ShowStartLocation defaults to true. show_start = gSavedSettings.getBOOL("ShowStartLocation") - && gSavedSettings.getBOOL("HadFirstSuccessfulLogin"); + && !gSavedSettings.getBOOL("FirstRunThisInstall"); } sInstance->childSetVisible("start_location_combo", show_start); @@ -847,7 +847,7 @@ void LLPanelLogin::loadLoginPage() oStr << "&auto_login=TRUE"; } if (gSavedSettings.getBOOL("ShowStartLocation") - && gSavedSettings.getBOOL("HadFirstSuccessfulLogin")) + && !gSavedSettings.getBOOL("FirstRunThisInstall")) { oStr << "&show_start_location=TRUE"; } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 5cca87bd71..522adc05ce 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -773,6 +773,8 @@ bool idle_startup() LLPanelLogin::giveFocus(); + gSavedSettings.setBOOL("FirstRunThisInstall", FALSE); + LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input } else @@ -2010,9 +2012,6 @@ bool idle_startup() LLStartUp::setStartupState( STATE_STARTED ); - // Mark that we have successfully logged in at least once - gSavedSettings.setBOOL("HadFirstSuccessfulLogin", TRUE); - // Unmute audio if desired and setup volumes. // Unmute audio if desired and setup volumes. // This is a not-uncommon crash site, so surround it with -- cgit v1.2.3 From 643b014fb858ec547663536dc649d845d2722ed2 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 4 Feb 2010 16:43:46 -0500 Subject: EXT-4990 : "Find Original" should be enabled for links in the trash EXT-4988 : Centralize right-click menu options when items are in trash This change is a lot less scary than it looks. There is a bit of minor cosmetic cleanup (e.g. typedefing a commonly-used vector), and I've eliminated code duplication since, previously, every item/listener type had its own purge/restore item dialog; these are now handled in one central function. I also moved "Find Original" above Purge/RestoreItem so that it appears first in the trash menu; this does not affect other menu options. The functionality change from this checkin is to enable "Find Original" for link items in the trash. --- indra/newview/llinventorybridge.cpp | 178 ++++++++------------- indra/newview/llinventorybridge.h | 22 +-- .../skins/default/xui/en/menu_inventory.xml | 16 +- 3 files changed, 85 insertions(+), 131 deletions(-) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 3a630650c5..cdc3650366 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -461,8 +461,8 @@ BOOL LLInvFVBridge::isClipboardPasteableAsLink() const } void hide_context_entries(LLMenuGL& menu, - const std::vector &entries_to_show, - const std::vector &disabled_entries) + const menuentry_vec_t &entries_to_show, + const menuentry_vec_t &disabled_entries) { const LLView::child_list_t *list = menu.getChildList(); @@ -480,7 +480,7 @@ void hide_context_entries(LLMenuGL& menu, bool found = false; - std::vector::const_iterator itor2; + menuentry_vec_t::const_iterator itor2; for (itor2 = entries_to_show.begin(); itor2 != entries_to_show.end(); ++itor2) { if (*itor2 == name) @@ -508,8 +508,8 @@ void hide_context_entries(LLMenuGL& menu, // Helper for commonly-used entries void LLInvFVBridge::getClipboardEntries(bool show_asset_id, - std::vector &items, - std::vector &disabled_items, U32 flags) + menuentry_vec_t &items, + menuentry_vec_t &disabled_items, U32 flags) { const LLInventoryObject *obj = getInventoryObject(); @@ -603,16 +603,11 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { lldebugs << "LLInvFVBridge::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; + menuentry_vec_t items; + menuentry_vec_t disabled_items; if(isItemInTrash()) { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - items.push_back(std::string("Restore Item")); + addTrashContextMenuOptions(items, disabled_items); } else { @@ -624,6 +619,27 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) hide_context_entries(menu, items, disabled_items); } +void LLInvFVBridge::addTrashContextMenuOptions(menuentry_vec_t &items, + menuentry_vec_t &disabled_items) +{ + const LLInventoryObject *obj = getInventoryObject(); + if (obj && obj->getIsLinkType()) + { + items.push_back(std::string("Find Original")); + if (isLinkedObjectMissing()) + { + disabled_items.push_back(std::string("Find Original")); + } + } + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + items.push_back(std::string("Restore Item")); +} + + // *TODO: remove this BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const { @@ -2439,7 +2455,7 @@ void LLFolderBridge::staticFolderOptionsMenu() void LLFolderBridge::folderOptionsMenu() { - std::vector disabled_items; + menuentry_vec_t disabled_items; LLInventoryModel* model = getInventoryModel(); if(!model) return; @@ -2572,7 +2588,7 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) lldebugs << "LLFolderBridge::buildContextMenu()" << llendl; -// std::vector disabled_items; +// menuentry_vec_t disabled_items; LLInventoryModel* model = getInventoryModel(); if(!model) return; const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); @@ -2589,17 +2605,11 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // This is the trash. mItems.push_back(std::string("Empty Trash")); } - else if(model->isObjectDescendentOf(mUUID, trash_id)) + else if(isItemInTrash()) { // This is a folder in the trash. mItems.clear(); // clear any items that used to exist - mItems.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - mDisabledItems.push_back(std::string("Purge Item")); - } - - mItems.push_back(std::string("Restore Item")); + addTrashContextMenuOptions(mItems, mDisabledItems); } else if(isAgentInventory()) // do not allow creating in library { @@ -3206,17 +3216,11 @@ bool LLTextureBridge::canSaveTexture(void) void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { lldebugs << "LLTextureBridge::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; + menuentry_vec_t items; + menuentry_vec_t disabled_items; if(isItemInTrash()) { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); + addTrashContextMenuOptions(items, disabled_items); } else { @@ -3299,18 +3303,12 @@ void LLSoundBridge::openSoundPreview(void* which) void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { lldebugs << "LLSoundBridge::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; + menuentry_vec_t items; + menuentry_vec_t disabled_items; if(isItemInTrash()) { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); + addTrashContextMenuOptions(items, disabled_items); } else { @@ -3347,19 +3345,13 @@ LLUIImagePtr LLLandmarkBridge::getIcon() const void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - std::vector items; - std::vector disabled_items; + menuentry_vec_t items; + menuentry_vec_t disabled_items; lldebugs << "LLLandmarkBridge::buildContextMenu()" << llendl; if(isItemInTrash()) { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); + addTrashContextMenuOptions(items, disabled_items); } else { @@ -3573,18 +3565,12 @@ void LLCallingCardBridge::openItem() void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { lldebugs << "LLCallingCardBridge::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; + menuentry_vec_t items; + menuentry_vec_t disabled_items; if(isItemInTrash()) { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); + addTrashContextMenuOptions(items, disabled_items); } else { @@ -3839,17 +3825,11 @@ BOOL LLGestureBridge::removeItem() void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { lldebugs << "LLGestureBridge::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; + menuentry_vec_t items; + menuentry_vec_t disabled_items; if(isItemInTrash()) { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); + addTrashContextMenuOptions(items, disabled_items); } else { @@ -3901,19 +3881,13 @@ LLUIImagePtr LLAnimationBridge::getIcon() const void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - std::vector items; - std::vector disabled_items; + menuentry_vec_t items; + menuentry_vec_t disabled_items; lldebugs << "LLAnimationBridge::buildContextMenu()" << llendl; if(isItemInTrash()) { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); + addTrashContextMenuOptions(items, disabled_items); } else { @@ -4182,17 +4156,11 @@ static LLNotificationFunctorRegistration confirm_replace_attachment_rez_reg("Rep void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - std::vector items; - std::vector disabled_items; + menuentry_vec_t items; + menuentry_vec_t disabled_items; if(isItemInTrash()) { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); + addTrashContextMenuOptions(items, disabled_items); } else { @@ -4598,17 +4566,11 @@ void LLWearableBridge::openItem() void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { lldebugs << "LLWearableBridge::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; + menuentry_vec_t items; + menuentry_vec_t disabled_items; if(isItemInTrash()) { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); + addTrashContextMenuOptions(items, disabled_items); } else { // FWIW, it looks like SUPPRESS_OPEN_ITEM is not set anywhere @@ -5302,21 +5264,15 @@ void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { // *TODO: Translate lldebugs << "LLLink::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; + menuentry_vec_t items; + menuentry_vec_t disabled_items; items.push_back(std::string("Find Original")); disabled_items.push_back(std::string("Find Original")); if(isItemInTrash()) { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); + addTrashContextMenuOptions(items, disabled_items); } else { @@ -5356,18 +5312,12 @@ void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { // *TODO: Translate lldebugs << "LLLink::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; + menuentry_vec_t items; + menuentry_vec_t disabled_items; - if(isItemInTrash()) + if (isItemInTrash()) { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); + addTrashContextMenuOptions(items, disabled_items); } else { diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 6e256edc05..daa6dbeeba 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -107,13 +107,15 @@ struct LLAttachmentRezAction S32 mAttachPt; }; +typedef std::vector menuentry_vec_t; + const std::string safe_inv_type_lookup(LLInventoryType::EType inv_type); void hide_context_entries(LLMenuGL& menu, - const std::vector &entries_to_show, - const std::vector &disabled_entries); + const menuentry_vec_t &entries_to_show, + const menuentry_vec_t &disabled_entries); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInvFVBridge (& it's derived classes) +// Class LLInvFVBridge (& its derived classes) // // Short for Inventory-Folder-View-Bridge. This is an // implementation class to be able to view inventory items. @@ -172,9 +174,11 @@ public: virtual BOOL isClipboardPasteableAsLink() const; virtual void pasteFromClipboard() {} virtual void pasteLinkFromClipboard() {} - void getClipboardEntries(bool show_asset_id, std::vector &items, - std::vector &disabled_items, U32 flags); + void getClipboardEntries(bool show_asset_id, menuentry_vec_t &items, + menuentry_vec_t &disabled_items, U32 flags); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + virtual void addTrashContextMenuOptions(menuentry_vec_t &items, + menuentry_vec_t &disabled_items); virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const; virtual BOOL dragOrDrop(MASK mask, BOOL drop, EDragAndDropType cargo_type, @@ -361,8 +365,8 @@ private: BOOL mCallingCards; BOOL mWearables; LLMenuGL* mMenu; - std::vector mItems; - std::vector mDisabledItems; + menuentry_vec_t mItems; + menuentry_vec_t mDisabledItems; }; // DEPRECATED @@ -816,7 +820,7 @@ void teleport_via_landmark(const LLUUID& asset_id); // Utility function to hide all entries except those in the list void hide_context_entries(LLMenuGL& menu, - const std::vector &entries_to_show, - const std::vector &disabled_entries); + const menuentry_vec_t &entries_to_show, + const menuentry_vec_t &disabled_entries); #endif // LL_LLINVENTORYBRIDGE_H diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index 1993af6730..2874151df5 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -369,6 +369,14 @@ + + + - - - Date: Thu, 4 Feb 2010 16:44:06 -0500 Subject: Change "Teleport History Location" subheader to "Teleport History". Adjusted color and style on this and other side-panel subheaders to be consistent. --- indra/newview/skins/default/xui/en/panel_landmark_info.xml | 2 +- indra/newview/skins/default/xui/en/panel_place_profile.xml | 4 ++-- indra/newview/skins/default/xui/en/panel_profile_view.xml | 2 +- indra/newview/skins/default/xui/en/sidepanel_appearance.xml | 4 ++-- indra/newview/skins/default/xui/en/sidepanel_item_info.xml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/indra/newview/skins/default/xui/en/panel_landmark_info.xml b/indra/newview/skins/default/xui/en/panel_landmark_info.xml index 396699ad6c..d1b22a34bb 100644 --- a/indra/newview/skins/default/xui/en/panel_landmark_info.xml +++ b/indra/newview/skins/default/xui/en/panel_landmark_info.xml @@ -71,7 +71,7 @@ layout="topleft" left_pad="10" name="title" - text_color="white" + text_color="LtGray" top="0" use_ellipses="true" value="Place Profile" diff --git a/indra/newview/skins/default/xui/en/panel_place_profile.xml b/indra/newview/skins/default/xui/en/panel_place_profile.xml index 7ac771de27..94c9b2de01 100644 --- a/indra/newview/skins/default/xui/en/panel_place_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_place_profile.xml @@ -29,7 +29,7 @@ value="Place Profile" /> + value="Teleport History" /> @@ -156,7 +156,7 @@ layout="topleft" left_pad="10" name="title" - text_color="white" + text_color="LtGray" top="0" use_ellipses="true" value="Place Profile" diff --git a/indra/newview/skins/default/xui/en/panel_profile_view.xml b/indra/newview/skins/default/xui/en/panel_profile_view.xml index f5396951ca..607de65c5c 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_view.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_view.xml @@ -35,7 +35,7 @@ layout="topleft" left_pad="10" name="user_name" - text_color="white" + text_color="LtGray" top="0" value="(Loading...)" use_ellipses="true" diff --git a/indra/newview/skins/default/xui/en/sidepanel_appearance.xml b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml index fab1f11273..bde45a9487 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_appearance.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml @@ -46,10 +46,10 @@ width="333"> top="0" width="30" /> Date: Thu, 4 Feb 2010 17:21:21 -0500 Subject: EXT-4990 : "Remove Link" and "Delete" are both active for links in the InventoryFloater For links, removed "Delete", since having both "Remove Link" and "Delete" is redundant. --- indra/newview/llinventorybridge.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index cdc3650366..c1259aa89a 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -582,12 +582,16 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, items.push_back(std::string("Paste Separator")); + // "Remove link" and "Delete" are the same operation. if (obj && obj->getIsLinkType() && !get_is_item_worn(mUUID)) { items.push_back(std::string("Remove Link")); } + else + { + items.push_back(std::string("Delete")); + } - items.push_back(std::string("Delete")); if (!isItemRemovable()) { disabled_items.push_back(std::string("Delete")); -- cgit v1.2.3 From a3781e07df303542f458dae5649ab24cde1117d8 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Thu, 4 Feb 2010 14:53:33 -0800 Subject: This file should have gone in with a previous changeset (https://hg.lindenlab.com/viewer/viewer-2-0/changeset/dddb40b50424/) --- indra/newview/llfloatertools.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 241497aeaf..4edd09b02c 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -1321,7 +1321,7 @@ bool LLFloaterTools::deleteMediaConfirm(const LLSD& notification, const LLSD& re switch( option ) { case 0: // "Yes" - LLSelectMgr::getInstance()->selectionSetMedia( 0 ); + LLSelectMgr::getInstance()->selectionSetMedia( 0, LLSD() ); if(LLFloaterReg::instanceVisible("media_settings")) { LLFloaterReg::hideInstance("media_settings"); -- cgit v1.2.3 From 14d77a36d4392cd51a0887d957905ce4c532ba38 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 4 Feb 2010 18:38:47 -0500 Subject: EXT-4993 : Deleting an item from the COF in Inventory Floater keeps it worn EXT-4997 : Centralize right-click menu options for delete/remove link EXT-4998 : Automatically reject double separators from right click menu Disabled/hid delete button from COF right-click menu, also means that trash icon is disabled. Added generalized function to remove consecutive separators from right-click menu. Made a minor cosmetic change to have all code duplication for adding "delete" menu item instead call a common function. --- indra/newview/llappearancemgr.cpp | 6 +++ indra/newview/llinventorybridge.cpp | 77 ++++++++++++++++++++++++------------- indra/newview/llinventorybridge.h | 10 ++++- 3 files changed, 64 insertions(+), 29 deletions(-) diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 0fe236c056..326fc41c1e 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1353,6 +1353,11 @@ BOOL LLAppearanceManager::getIsInCOF(const LLUUID& obj_id) const BOOL LLAppearanceManager::getIsProtectedCOFItem(const LLUUID& obj_id) const { if (!getIsInCOF(obj_id)) return FALSE; + + // For now, don't allow direct deletion from the COF. Instead, force users + // to choose "Detach" or "Take Off". + return TRUE; + /* const LLInventoryObject *obj = gInventory.getObject(obj_id); if (!obj) return FALSE; @@ -1363,4 +1368,5 @@ BOOL LLAppearanceManager::getIsProtectedCOFItem(const LLUUID& obj_id) const if (obj->getActualType() == LLAssetType::AT_LINK_FOLDER) return TRUE; return FALSE; + */ } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index c1259aa89a..f6089f3533 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -181,10 +181,14 @@ BOOL LLInvFVBridge::isItemRemovable() const { return FALSE; } + + // Can't delete an item that's in the library. if(!model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID())) { return FALSE; } + + // Disable delete from COF folder; have users explicitly choose "detach/take off". if (LLAppearanceManager::instance().getIsProtectedCOFItem(mUUID)) { return FALSE; @@ -466,6 +470,8 @@ void hide_context_entries(LLMenuGL& menu, { const LLView::child_list_t *list = menu.getChildList(); + BOOL is_previous_entry_separator = FALSE; + LLView::child_list_t::const_iterator itor; for (itor = list->begin(); itor != list->end(); ++itor) { @@ -488,6 +494,17 @@ void hide_context_entries(LLMenuGL& menu, found = true; } } + + // Don't allow multiple separators in a row (e.g. such as if there are no items + // between two separators). + if (found) + { + const BOOL is_entry_separator = (dynamic_cast(*itor) != NULL); + if (is_entry_separator && is_previous_entry_separator) + found = false; + is_previous_entry_separator = is_entry_separator; + } + if (!found) { (*itor)->setVisible(FALSE); @@ -582,20 +599,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, items.push_back(std::string("Paste Separator")); - // "Remove link" and "Delete" are the same operation. - if (obj && obj->getIsLinkType() && !get_is_item_worn(mUUID)) - { - items.push_back(std::string("Remove Link")); - } - else - { - items.push_back(std::string("Delete")); - } - - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Delete")); - } + addDeleteContextMenuOptions(items, disabled_items); // If multiple items are selected, disable properties (if it exists). if ((flags & FIRST_SELECTED_ITEM) == 0) @@ -643,6 +647,32 @@ void LLInvFVBridge::addTrashContextMenuOptions(menuentry_vec_t &items, items.push_back(std::string("Restore Item")); } +void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items, + menuentry_vec_t &disabled_items) +{ + // Don't allow delete as a direct option from COF folder. + if (isCOFFolder()) + { + return; + } + + const LLInventoryObject *obj = getInventoryObject(); + + // "Remove link" and "Delete" are the same operation. + if (obj && obj->getIsLinkType() && !get_is_item_worn(mUUID)) + { + items.push_back(std::string("Remove Link")); + } + else + { + items.push_back(std::string("Delete")); + } + + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Delete")); + } +} // *TODO: remove this BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const @@ -2477,7 +2507,7 @@ void LLFolderBridge::folderOptionsMenu() if (is_sidepanel) { mItems.push_back("Rename"); - mItems.push_back("Delete"); + addDeleteContextMenuOptions(mItems, disabled_items); } // Only enable calling-card related options for non-system folders. @@ -2647,11 +2677,11 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) else { // Want some but not all of the items from getClipboardEntries for outfits. - if (cat && cat->getPreferredType()==LLFolderType::FT_OUTFIT) + if (cat && (cat->getPreferredType() == LLFolderType::FT_OUTFIT)) { mItems.push_back(std::string("Rename")); - mItems.push_back(std::string("Delete")); + addDeleteContextMenuOptions(mItems, mDisabledItems); // EXT-4030: disallow deletion of currently worn outfit const LLViewerInventoryItem *base_outfit_link = LLAppearanceManager::instance().getBaseOutfitLink(); if (base_outfit_link && (cat == base_outfit_link->getLinkedCategory())) @@ -4190,6 +4220,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if( get_is_item_worn( mUUID ) ) { + items.push_back(std::string("Attach Separator")); items.push_back(std::string("Detach From Yourself")); } else if (!isItemInTrash() && !isLinkedObjectInTrash() && !isLinkedObjectMissing()) @@ -5281,11 +5312,7 @@ void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) else { items.push_back(std::string("Properties")); - items.push_back(std::string("Delete")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Delete")); - } + addDeleteContextMenuOptions(items, disabled_items); } hide_context_entries(menu, items, disabled_items); } @@ -5326,11 +5353,7 @@ void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) else { items.push_back(std::string("Find Original")); - items.push_back(std::string("Delete")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Delete")); - } + addDeleteContextMenuOptions(items, disabled_items); } hide_context_entries(menu, items, disabled_items); } diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index daa6dbeeba..32504091cb 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -177,8 +177,6 @@ public: void getClipboardEntries(bool show_asset_id, menuentry_vec_t &items, menuentry_vec_t &disabled_items, U32 flags); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); - virtual void addTrashContextMenuOptions(menuentry_vec_t &items, - menuentry_vec_t &disabled_items); virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const; virtual BOOL dragOrDrop(MASK mask, BOOL drop, EDragAndDropType cargo_type, @@ -191,6 +189,14 @@ public: // Allow context menus to be customized for side panel. bool isInOutfitsSidePanel() const; + //-------------------------------------------------------------------- + // Convenience functions for adding various common menu options. + //-------------------------------------------------------------------- +protected: + virtual void addTrashContextMenuOptions(menuentry_vec_t &items, + menuentry_vec_t &disabled_items); + virtual void addDeleteContextMenuOptions(menuentry_vec_t &items, + menuentry_vec_t &disabled_items); protected: LLInvFVBridge(LLInventoryPanel* inventory, const LLUUID& uuid); -- cgit v1.2.3 From 195b13beff0ea476ed47a08f6a44b85dc151eec8 Mon Sep 17 00:00:00 2001 From: Eli Linden Date: Thu, 4 Feb 2010 16:00:56 -0800 Subject: EXT-2181 DA Danish translation for set6 --- .../skins/default/xui/da/floater_about_land.xml | 368 ++++++++++----------- .../default/xui/da/floater_animation_preview.xml | 231 +++++++++---- .../default/xui/da/floater_avatar_textures.xml | 52 +-- .../skins/default/xui/da/floater_beacons.xml | 26 +- .../skins/default/xui/da/floater_build_options.xml | 17 +- .../skins/default/xui/da/floater_buy_contents.xml | 8 +- .../skins/default/xui/da/floater_buy_currency.xml | 82 +++-- .../skins/default/xui/da/floater_buy_land.xml | 24 +- .../skins/default/xui/da/floater_choose_group.xml | 6 +- .../skins/default/xui/da/floater_customize.xml | 88 ++++- .../default/xui/da/floater_device_settings.xml | 4 +- .../skins/default/xui/da/floater_env_settings.xml | 20 +- .../default/xui/da/floater_hardware_settings.xml | 26 +- .../skins/default/xui/da/floater_help_browser.xml | 8 + indra/newview/skins/default/xui/da/floater_im.xml | 4 +- .../skins/default/xui/da/floater_im_container.xml | 2 + .../skins/default/xui/da/floater_image_preview.xml | 28 +- .../skins/default/xui/da/floater_incoming_call.xml | 21 ++ .../skins/default/xui/da/floater_inspect.xml | 13 +- .../skins/default/xui/da/floater_inventory.xml | 59 +--- .../xui/da/floater_inventory_item_properties.xml | 92 +++--- .../skins/default/xui/da/floater_joystick.xml | 8 +- .../skins/default/xui/da/floater_lagmeter.xml | 215 ++++++------ .../skins/default/xui/da/floater_lsl_guide.xml | 10 +- .../default/xui/da/floater_media_settings.xml | 6 + .../skins/default/xui/da/floater_nearby_chat.xml | 2 + .../skins/default/xui/da/floater_openobject.xml | 8 +- .../skins/default/xui/da/floater_outgoing_call.xml | 28 ++ indra/newview/skins/default/xui/da/floater_pay.xml | 32 +- .../skins/default/xui/da/floater_pay_object.xml | 33 +- .../skins/default/xui/da/floater_preview_event.xml | 8 +- .../default/xui/da/floater_preview_gesture.xml | 53 +-- .../xui/da/floater_preview_gesture_info.xml | 2 + .../xui/da/floater_preview_gesture_shortcut.xml | 15 + .../xui/da/floater_preview_gesture_steps.xml | 2 + .../default/xui/da/floater_preview_notecard.xml | 20 +- .../default/xui/da/floater_preview_texture.xml | 39 ++- .../default/xui/da/floater_script_debug_panel.xml | 2 + .../default/xui/da/floater_script_preview.xml | 7 +- .../skins/default/xui/da/floater_script_search.xml | 10 +- .../skins/default/xui/da/floater_sell_land.xml | 123 +++---- .../default/xui/da/floater_settings_debug.xml | 20 +- .../skins/default/xui/da/floater_snapshot.xml | 68 ++-- .../skins/default/xui/da/floater_sys_well.xml | 9 + .../skins/default/xui/da/floater_telehub.xml | 15 +- .../skins/default/xui/da/floater_top_objects.xml | 34 +- indra/newview/skins/default/xui/da/floater_tos.xml | 11 +- .../newview/skins/default/xui/da/floater_water.xml | 64 ++-- .../default/xui/da/floater_whitelist_entry.xml | 9 + .../skins/default/xui/da/inspect_object.xml | 34 ++ .../skins/default/xui/da/mime_types_linux.xml | 217 ++++++++++++ .../default/xui/da/panel_active_object_row.xml | 9 + .../default/xui/da/panel_adhoc_control_panel.xml | 8 + .../skins/default/xui/da/panel_bottomtray.xml | 23 ++ .../skins/default/xui/da/panel_edit_alpha.xml | 10 + .../skins/default/xui/da/panel_edit_eyes.xml | 9 + .../skins/default/xui/da/panel_edit_gloves.xml | 10 + .../skins/default/xui/da/panel_edit_jacket.xml | 11 + .../skins/default/xui/da/panel_edit_pants.xml | 10 + .../skins/default/xui/da/panel_edit_pick.xml | 28 ++ .../skins/default/xui/da/panel_edit_shoes.xml | 10 + .../skins/default/xui/da/panel_edit_skin.xml | 14 + .../skins/default/xui/da/panel_edit_socks.xml | 10 + .../skins/default/xui/da/panel_edit_underpants.xml | 10 + .../skins/default/xui/da/panel_edit_undershirt.xml | 10 + .../skins/default/xui/da/panel_edit_wearable.xml | 101 ++++++ .../newview/skins/default/xui/da/panel_friends.xml | 36 +- .../default/xui/da/panel_group_control_panel.xml | 9 + .../skins/default/xui/da/panel_group_general.xml | 77 ++--- .../default/xui/da/panel_group_info_sidetray.xml | 36 ++ .../skins/default/xui/da/panel_group_invite.xml | 37 +-- .../default/xui/da/panel_group_land_money.xml | 39 ++- .../skins/default/xui/da/panel_group_notices.xml | 51 ++- indra/newview/skins/default/xui/da/panel_me.xml | 7 + .../xui/da/panel_media_settings_general.xml | 32 ++ .../xui/da/panel_media_settings_security.xml | 12 + .../skins/default/xui/da/panel_my_profile.xml | 37 +++ .../skins/default/xui/da/panel_nearby_chat.xml | 9 + .../skins/default/xui/da/panel_nearby_chat_bar.xml | 11 + .../skins/default/xui/da/panel_pick_info.xml | 16 + .../skins/default/xui/da/panel_place_profile.xml | 103 ++++++ .../default/xui/da/panel_preferences_chat.xml | 4 + .../default/xui/da/panel_preferences_general.xml | 107 +++--- .../default/xui/da/panel_preferences_graphics1.xml | 213 +++++------- .../default/xui/da/panel_prim_media_controls.xml | 28 ++ .../skins/default/xui/da/panel_profile_view.xml | 16 + .../skins/default/xui/da/panel_region_estate.xml | 64 ++-- .../default/xui/da/panel_side_tray_tab_caption.xml | 5 + .../skins/default/xui/da/panel_status_bar.xml | 61 ++-- .../newview/skins/default/xui/da/role_actions.xml | 245 ++++---------- .../skins/default/xui/da/sidepanel_appearance.xml | 11 + .../skins/default/xui/da/sidepanel_inventory.xml | 11 + 92 files changed, 2358 insertions(+), 1475 deletions(-) create mode 100644 indra/newview/skins/default/xui/da/floater_help_browser.xml create mode 100644 indra/newview/skins/default/xui/da/floater_im_container.xml create mode 100644 indra/newview/skins/default/xui/da/floater_incoming_call.xml create mode 100644 indra/newview/skins/default/xui/da/floater_media_settings.xml create mode 100644 indra/newview/skins/default/xui/da/floater_nearby_chat.xml create mode 100644 indra/newview/skins/default/xui/da/floater_outgoing_call.xml create mode 100644 indra/newview/skins/default/xui/da/floater_preview_gesture_info.xml create mode 100644 indra/newview/skins/default/xui/da/floater_preview_gesture_shortcut.xml create mode 100644 indra/newview/skins/default/xui/da/floater_preview_gesture_steps.xml create mode 100644 indra/newview/skins/default/xui/da/floater_script_debug_panel.xml create mode 100644 indra/newview/skins/default/xui/da/floater_sys_well.xml create mode 100644 indra/newview/skins/default/xui/da/floater_whitelist_entry.xml create mode 100644 indra/newview/skins/default/xui/da/inspect_object.xml create mode 100644 indra/newview/skins/default/xui/da/mime_types_linux.xml create mode 100644 indra/newview/skins/default/xui/da/panel_active_object_row.xml create mode 100644 indra/newview/skins/default/xui/da/panel_adhoc_control_panel.xml create mode 100644 indra/newview/skins/default/xui/da/panel_bottomtray.xml create mode 100644 indra/newview/skins/default/xui/da/panel_edit_alpha.xml create mode 100644 indra/newview/skins/default/xui/da/panel_edit_eyes.xml create mode 100644 indra/newview/skins/default/xui/da/panel_edit_gloves.xml create mode 100644 indra/newview/skins/default/xui/da/panel_edit_jacket.xml create mode 100644 indra/newview/skins/default/xui/da/panel_edit_pants.xml create mode 100644 indra/newview/skins/default/xui/da/panel_edit_pick.xml create mode 100644 indra/newview/skins/default/xui/da/panel_edit_shoes.xml create mode 100644 indra/newview/skins/default/xui/da/panel_edit_skin.xml create mode 100644 indra/newview/skins/default/xui/da/panel_edit_socks.xml create mode 100644 indra/newview/skins/default/xui/da/panel_edit_underpants.xml create mode 100644 indra/newview/skins/default/xui/da/panel_edit_undershirt.xml create mode 100644 indra/newview/skins/default/xui/da/panel_edit_wearable.xml create mode 100644 indra/newview/skins/default/xui/da/panel_group_control_panel.xml create mode 100644 indra/newview/skins/default/xui/da/panel_group_info_sidetray.xml create mode 100644 indra/newview/skins/default/xui/da/panel_me.xml create mode 100644 indra/newview/skins/default/xui/da/panel_media_settings_general.xml create mode 100644 indra/newview/skins/default/xui/da/panel_media_settings_security.xml create mode 100644 indra/newview/skins/default/xui/da/panel_my_profile.xml create mode 100644 indra/newview/skins/default/xui/da/panel_nearby_chat.xml create mode 100644 indra/newview/skins/default/xui/da/panel_nearby_chat_bar.xml create mode 100644 indra/newview/skins/default/xui/da/panel_pick_info.xml create mode 100644 indra/newview/skins/default/xui/da/panel_place_profile.xml create mode 100644 indra/newview/skins/default/xui/da/panel_prim_media_controls.xml create mode 100644 indra/newview/skins/default/xui/da/panel_profile_view.xml create mode 100644 indra/newview/skins/default/xui/da/panel_side_tray_tab_caption.xml create mode 100644 indra/newview/skins/default/xui/da/sidepanel_appearance.xml create mode 100644 indra/newview/skins/default/xui/da/sidepanel_inventory.xml diff --git a/indra/newview/skins/default/xui/da/floater_about_land.xml b/indra/newview/skins/default/xui/da/floater_about_land.xml index cb5d618dde..b4af427538 100644 --- a/indra/newview/skins/default/xui/da/floater_about_land.xml +++ b/indra/newview/skins/default/xui/da/floater_about_land.xml @@ -1,7 +1,59 @@ + + [MINUTES] minutter + + + minut + + + [SECONDS] sekunder + + + mangler + - + + + Kun nye brugere + + + Alle + + + Størrelse + + + [AREA] m² + + + Auktion nr: [ID] + + + Du skal godkende dit køb for at kunne æmdre på dette land. + + + (Gruppe ejet) + + + Profil... + + + Info... + + + (offentlig) + + + (ingen) + + + (Salg i gang) + + + Pacel ikke valgt. +Gå til 'Verden' > 'Om land' eller vælg en anden parcel for at se detaljer. + Navn: @@ -26,7 +78,6 @@ Leyla Linden - + - + + + + + + + + + + + + + + + + Parcel Audio + + + + + + + + - + - - - - + + - + - Nearby Media - - - + + - Show: - - + - - - - - - + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + left="10"/> + + + + -- cgit v1.2.3 From 1513643e62a88531888f330e57aa1eb623061729 Mon Sep 17 00:00:00 2001 From: richard Date: Tue, 16 Feb 2010 15:45:17 -0800 Subject: EXT-5471 - Tons of spam in log about Invalid param "name" reviewed by Rick --- indra/llui/llui.cpp | 10 ++++++++-- indra/llui/llui.h | 4 ++-- indra/llui/lluiimage.h | 1 + indra/llxuixml/llinitparam.cpp | 28 ++++----------------------- indra/llxuixml/llinitparam.h | 43 +++++++++++++++++++----------------------- 5 files changed, 34 insertions(+), 52 deletions(-) diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 76f07373b4..caf04339c2 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -1894,7 +1894,9 @@ namespace LLInitParam blue("blue"), alpha("alpha"), control("") - {} + { + setBlockFromValue(); + } void TypedParam::setValueFromBlock() const { @@ -1939,6 +1941,7 @@ namespace LLInitParam size("size"), style("style") { + setBlockFromValue(); addSynonym(name, ""); } @@ -1979,7 +1982,9 @@ namespace LLInitParam bottom("bottom"), width("width"), height("height") - {} + { + setBlockFromValue(); + } void TypedParam::setValueFromBlock() const { @@ -2064,6 +2069,7 @@ namespace LLInitParam x("x"), y("y") { + setBlockFromValue(); } void TypedParam::setValueFromBlock() const diff --git a/indra/llui/llui.h b/indra/llui/llui.h index 5840e76f5c..af8d4ea03b 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -426,8 +426,8 @@ namespace LLInitParam { typedef BlockValue super_t; public: - Mandatory name; - Optional size, + Optional name, + size, style; TypedParam(BlockDescriptor& descriptor, const char* name, const LLFontGL* const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count); diff --git a/indra/llui/lluiimage.h b/indra/llui/lluiimage.h index bdfc44262d..4ea0738026 100644 --- a/indra/llui/lluiimage.h +++ b/indra/llui/lluiimage.h @@ -109,6 +109,7 @@ namespace LLInitParam TypedParam(BlockDescriptor& descriptor, const char* name, super_t::value_assignment_t value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count) : super_t(descriptor, name, value, func, min_count, max_count) { + setBlockFromValue(); } void setValueFromBlock() const; diff --git a/indra/llxuixml/llinitparam.cpp b/indra/llxuixml/llinitparam.cpp index fb0a04dc58..2ead5a4a57 100644 --- a/indra/llxuixml/llinitparam.cpp +++ b/indra/llxuixml/llinitparam.cpp @@ -137,7 +137,7 @@ namespace LLInitParam } - bool BaseBlock::validateBlock(bool silent) const + bool BaseBlock::validateBlock(bool emit_errors) const { const BlockDescriptor& block_data = getBlockDescriptor(); for (BlockDescriptor::param_validation_list_t::const_iterator it = block_data.mValidationList.begin(); it != block_data.mValidationList.end(); ++it) @@ -145,7 +145,7 @@ namespace LLInitParam const Param* param = getParamFromHandle(it->first); if (!it->second(param)) { - if (!silent) + if (emit_errors) { llwarns << "Invalid param \"" << getParamName(block_data, param) << "\"" << llendl; } @@ -458,7 +458,7 @@ namespace LLInitParam // take all provided params from other and apply to self // NOTE: this requires that "other" is of the same derived type as this - bool BaseBlock::overwriteFromImpl(BlockDescriptor& block_data, const BaseBlock& other) + bool BaseBlock::merge(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { bool param_changed = false; BlockDescriptor::all_params_list_t::const_iterator end_it = block_data.mAllParams.end(); @@ -471,27 +471,7 @@ namespace LLInitParam if (merge_func) { Param* paramp = getParamFromHandle(it->mParamHandle); - param_changed |= merge_func(*paramp, *other_paramp, true); - } - } - return param_changed; - } - - // take all provided params that are not already provided, and apply to self - bool BaseBlock::fillFromImpl(BlockDescriptor& block_data, const BaseBlock& other) - { - bool param_changed = false; - BlockDescriptor::all_params_list_t::const_iterator end_it = block_data.mAllParams.end(); - for (BlockDescriptor::all_params_list_t::const_iterator it = block_data.mAllParams.begin(); - it != end_it; - ++it) - { - const Param* other_paramp = other.getParamFromHandle(it->mParamHandle); - ParamDescriptor::merge_func_t merge_func = it->mMergeFunc; - if (merge_func) - { - Param* paramp = getParamFromHandle(it->mParamHandle); - param_changed |= merge_func(*paramp, *other_paramp, false); + param_changed |= merge_func(*paramp, *other_paramp, overwrite); } } return param_changed; diff --git a/indra/llxuixml/llinitparam.h b/indra/llxuixml/llinitparam.h index d264cea3b2..c9c1d4af90 100644 --- a/indra/llxuixml/llinitparam.h +++ b/indra/llxuixml/llinitparam.h @@ -407,7 +407,7 @@ namespace LLInitParam class BaseBlock { public: - // "Multiple" constraint types + // "Multiple" constraint types, put here in root class to avoid ambiguity during use struct AnyAmount { static U32 minCount() { return 0; } @@ -452,7 +452,7 @@ namespace LLInitParam bool submitValue(const Parser::name_stack_t& name_stack, Parser& p, bool silent=false); param_handle_t getHandleFromParam(const Param* param) const; - bool validateBlock(bool silent = false) const; + bool validateBlock(bool emit_errors = true) const; Param* getParamFromHandle(const param_handle_t param_handle) { @@ -500,10 +500,7 @@ namespace LLInitParam // take all provided params from other and apply to self - bool overwriteFromImpl(BlockDescriptor& block_data, const BaseBlock& other); - - // take all provided params that are not already provided, and apply to self - bool fillFromImpl(BlockDescriptor& block_data, const BaseBlock& other); + bool merge(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite); // can be updated in getters mutable S32 mChangeVersion; @@ -805,7 +802,7 @@ namespace LLInitParam if (Param::getProvided() && mData.mValidatedVersion < T::getLastChangeVersion()) { // a sub-block is "provided" when it has been filled in enough to be valid - mData.mValidated = T::validateBlock(true); + mData.mValidated = T::validateBlock(false); mData.mValidatedVersion = T::getLastChangeVersion(); } return Param::getProvided() && mData.mValidated; @@ -1236,7 +1233,7 @@ namespace LLInitParam it != mValues.end(); ++it) { - if(it->validateBlock(true)) count++; + if(it->validateBlock(false)) count++; } return count; } @@ -1286,7 +1283,7 @@ namespace LLInitParam bool overwriteFrom(const self_t& other) { mCurChoice = other.mCurChoice; - return BaseBlock::overwriteFromImpl(blockDescriptor(), other); + return BaseBlock::merge(blockDescriptor(), other, true); } // take all provided params that are not already provided, and apply to self @@ -1413,13 +1410,13 @@ namespace LLInitParam // take all provided params from other and apply to self bool overwriteFrom(const self_t& other) { - return BaseBlock::overwriteFromImpl(blockDescriptor(), other); + return BaseBlock::merge(blockDescriptor(), other, true); } // take all provided params that are not already provided, and apply to self bool fillFrom(const self_t& other) { - return BaseBlock::fillFromImpl(blockDescriptor(), other); + return BaseBlock::merge(blockDescriptor(), other, false); } protected: Block() @@ -1710,7 +1707,7 @@ namespace LLInitParam // if cached value is stale, regenerate from params if (Param::getProvided() && mData.mLastParamVersion < BaseBlock::getLastChangeVersion()) { - if (block_t::validateBlock(true)) + if (block_t::validateBlock(false)) { static_cast(this)->setValueFromBlock(); // clear stale keyword associated with old value @@ -1769,7 +1766,7 @@ namespace LLInitParam if (Param::getProvided() && (mData.mLastParamVersion < BaseBlock::getLastChangeVersion())) { // go ahead and issue warnings at this point if any param is invalid - if(block_t::validateBlock(false)) + if(block_t::validateBlock(true)) { static_cast(this)->setValueFromBlock(); mData.clearKey(); @@ -1797,25 +1794,23 @@ namespace LLInitParam private: static bool mergeWith(Param& dst, const Param& src, bool overwrite) { - const self_t& src_param = static_cast(src); + const self_t& src_typed_param = static_cast(src); self_t& dst_typed_param = static_cast(dst); - if (src_param.isProvided() + if (src_typed_param.isProvided() && (overwrite || !dst_typed_param.isProvided())) { // assign individual parameters - if (overwrite) - { - dst_typed_param.BaseBlock::overwriteFromImpl(block_t::blockDescriptor(), src_param); - } - else - { - dst_typed_param.BaseBlock::fillFromImpl(block_t::blockDescriptor(), src_param); - } + dst_typed_param.BaseBlock::merge(block_t::blockDescriptor(), src_typed_param, overwrite); + // then copy actual value - dst_typed_param.mData.mValue = src_param.get(); + dst_typed_param.mData.mValue = src_typed_param.get(); dst_typed_param.mData.clearKey(); dst_typed_param.setProvided(true); + + // Propagate value back to block params since the value was updated during this merge. + // This will result in mData.mValue and the block params being in sync. + static_cast(dst_typed_param).setBlockFromValue(); return true; } return false; -- cgit v1.2.3 From 69032d8d9d660de5b3c97589b7cc55dac70b153c Mon Sep 17 00:00:00 2001 From: richard Date: Tue, 16 Feb 2010 19:14:55 -0800 Subject: EXT-5071 - Script Editor slows down FPS when editing scripts with 500+ lines reviewed by Monroe --- indra/llui/lltexteditor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index ce5f1bd082..7d230f7d42 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -2524,9 +2524,9 @@ void LLTextEditor::loadKeywords(const std::string& filename, void LLTextEditor::updateSegments() { - LLFastTimer ft(FTM_SYNTAX_HIGHLIGHTING); - if (mKeywords.isLoaded()) + if (mReflowIndex < S32_MAX && mKeywords.isLoaded()) { + LLFastTimer ft(FTM_SYNTAX_HIGHLIGHTING); // HACK: No non-ascii keywords for now segment_vec_t segment_list; mKeywords.findSegments(&segment_list, getWText(), mDefaultColor.get(), *this); -- cgit v1.2.3 From 6518cbdfa578c13cfc96191fef737045fa5d9919 Mon Sep 17 00:00:00 2001 From: Eli Linden Date: Wed, 17 Feb 2010 11:44:51 +0800 Subject: DEV-43688 Cycle3 massive linguistic changes for DE by Simone for better UI, post truncation fix --- indra/newview/skins/default/xui/de/floater_pay.xml | 4 ++-- indra/newview/skins/default/xui/de/floater_pay_object.xml | 2 +- indra/newview/skins/default/xui/de/floater_preferences.xml | 4 ++-- indra/newview/skins/default/xui/de/floater_preview_animation.xml | 4 ++-- indra/newview/skins/default/xui/de/floater_preview_sound.xml | 4 ++-- indra/newview/skins/default/xui/de/floater_report_abuse.xml | 2 +- indra/newview/skins/default/xui/de/floater_sell_land.xml | 8 ++++---- indra/newview/skins/default/xui/de/floater_snapshot.xml | 6 +++--- indra/newview/skins/default/xui/de/inspect_object.xml | 2 +- indra/newview/skins/default/xui/de/menu_attachment_other.xml | 2 +- indra/newview/skins/default/xui/de/menu_avatar_other.xml | 2 +- indra/newview/skins/default/xui/de/menu_inspect_avatar_gear.xml | 2 +- indra/newview/skins/default/xui/de/menu_inspect_object_gear.xml | 2 +- indra/newview/skins/default/xui/de/menu_inventory.xml | 6 +++--- indra/newview/skins/default/xui/de/menu_object.xml | 2 +- indra/newview/skins/default/xui/de/menu_participant_list.xml | 2 +- indra/newview/skins/default/xui/de/menu_people_groups.xml | 2 +- indra/newview/skins/default/xui/de/menu_people_nearby.xml | 2 +- .../skins/default/xui/de/menu_people_nearby_multiselect.xml | 2 +- .../newview/skins/default/xui/de/menu_people_nearby_view_sort.xml | 4 ++-- .../newview/skins/default/xui/de/menu_people_recent_view_sort.xml | 2 +- indra/newview/skins/default/xui/de/menu_profile_overflow.xml | 2 +- indra/newview/skins/default/xui/de/menu_viewer.xml | 6 +++--- indra/newview/skins/default/xui/de/notifications.xml | 8 ++++---- indra/newview/skins/default/xui/de/panel_classified_info.xml | 2 +- indra/newview/skins/default/xui/de/panel_edit_classified.xml | 2 +- indra/newview/skins/default/xui/de/panel_edit_pick.xml | 2 +- indra/newview/skins/default/xui/de/panel_friends.xml | 2 +- indra/newview/skins/default/xui/de/panel_group_notify.xml | 2 +- indra/newview/skins/default/xui/de/panel_main_inventory.xml | 2 +- indra/newview/skins/default/xui/de/panel_navigation_bar.xml | 2 +- indra/newview/skins/default/xui/de/panel_preferences_alerts.xml | 4 ++-- indra/newview/skins/default/xui/de/panel_preferences_general.xml | 4 ++-- indra/newview/skins/default/xui/de/panel_preferences_privacy.xml | 4 ++-- indra/newview/skins/default/xui/de/sidepanel_task_info.xml | 2 +- 35 files changed, 55 insertions(+), 55 deletions(-) diff --git a/indra/newview/skins/default/xui/de/floater_pay.xml b/indra/newview/skins/default/xui/de/floater_pay.xml index 6eb1d9472d..fb89eeb600 100644 --- a/indra/newview/skins/default/xui/de/floater_pay.xml +++ b/indra/newview/skins/default/xui/de/floater_pay.xml @@ -7,7 +7,7 @@ Einwohner bezahlen - Zahlen: + Bezahlen: @@ -20,6 +20,6 @@ Oder Betrag auswählen: -