diff options
author | Loren Shih <seraph@lindenlab.com> | 2011-03-21 10:38:39 -0400 |
---|---|---|
committer | Loren Shih <seraph@lindenlab.com> | 2011-03-21 10:38:39 -0400 |
commit | be553242ef706e33260f3f9e62d02f4720f00473 (patch) | |
tree | 553a150a63cd8105f8860780ef7d02f12a69eb23 | |
parent | 9c1c791b29cb5087ebff142d4ad7a55b65be0ad0 (diff) | |
parent | df63c6931e81c034887611711095e3134b9a7318 (diff) |
Automated merge up from viewer-development into mesh-development
32 files changed, 1408 insertions, 1363 deletions
@@ -81,3 +81,6 @@ b53a0576eec80614d7767ed72b40ed67aeff27c9 2.5.2-release f1827b441e05bf37c68e2c15ebc6d09e9b03f527 2.6.0-start f1827b441e05bf37c68e2c15ebc6d09e9b03f527 2.6.0-start 4e9eec6a347f89b2b3f295beb72f1cf7837dff66 2.6.0-start +9283d6d1d7eb71dfe4c330e7c9144857e7356bde 2.6.0-beta1 +9283d6d1d7eb71dfe4c330e7c9144857e7356bde DRTVWR-40_2.6.0-beta1 +c5bdef3aaa2744626aef3c217ce29e1900d357b3 2.6.1-start diff --git a/BuildParams b/BuildParams index c87f5a6034..7011875626 100755 --- a/BuildParams +++ b/BuildParams @@ -53,6 +53,7 @@ viewer-pre-beta.login_channel = "Second Life Beta Viewer" viewer-pre-beta.build_debug_release_separately = true viewer-pre-beta.build_viewer_update_version_manager = true + # ======================================== # Viewer Release # ======================================== @@ -68,14 +69,6 @@ viewer-pre-release.build_debug_release_separately = true viewer-pre-release.build_viewer_update_version_manager = true #viewer-pre-release.release-viewer.jira = DRTVWR-13 -# ======================================== -# aimee -# ======================================== - -viewer-development-import.build_debug_release_separately = true -viewer-development-fixes.build_debug_release_separately = true -viewer-development-tweaks.build_debug_release_separately = true - # ======================================= # brad # ======================================== @@ -189,55 +182,11 @@ media.build_viewer_update_version_manager = false # oz # ================ -oz_viewer-review1_coverity.coverity_product = viewer - -oz_viewer-review1.build_Linux = true -oz_viewer-review1_debug.build_Linux = false -oz_viewer-review1_coverity.build_Linux = false - -oz_viewer-review1.build_Darwin = true -oz_viewer-review1_debug.build_Darwin = false -oz_viewer-review1_coverity.build_Darwin = false - -oz_viewer-review1.build_CYGWIN = true -oz_viewer-review1.build_CYGWIN_Debug = false -oz_viewer-review1.build_CYGWIN_RelWithDebInfo = false -oz_viewer-review1.build_CYGWIN_Release = true -oz_viewer-review1_debug.build_CYGWIN_Debug = true -oz_viewer-review1_debug.build_CYGWIN_RelWithDebInfo = true -oz_viewer-review1_debug.build_CYGWIN_Release = false -oz_viewer-review1_coverity.build_coverity = true -oz_viewer-review1_coverity.build_CYGWIN_Debug = false -oz_viewer-review1_coverity.build_CYGWIN_RelWithDebInfo = false -oz_viewer-review1_coverity.build_CYGWIN_Release = false - -oz_viewer-review2_coverity.coverity_product = viewer - -oz_viewer-review2.build_Linux = true -oz_viewer-review2_debug.build_Linux = false -oz_viewer-review2_coverity.build_Linux = false - -oz_viewer-review2.build_Darwin = true -oz_viewer-review2_debug.build_Darwin = false -oz_viewer-review2_coverity.build_Darwin = false - -oz_viewer-review2.build_CYGWIN = true -oz_viewer-review2.build_CYGWIN_Debug = false -oz_viewer-review2.build_CYGWIN_RelWithDebInfo = false -oz_viewer-review2.build_CYGWIN_Release = true -oz_viewer-review2_debug.build_CYGWIN_Debug = true -oz_viewer-review2_debug.build_CYGWIN_RelWithDebInfo = true -oz_viewer-review2_debug.build_CYGWIN_Release = false -oz_viewer-review2_coverity.build_coverity = true -oz_viewer-review2_coverity.build_CYGWIN_Debug = false -oz_viewer-review2_coverity.build_CYGWIN_RelWithDebInfo = false -oz_viewer-review2_coverity.build_CYGWIN_Release = false - -# ======================================== -# tofu -# ======================================== - -tofu_viewer-development-staging.email = tofu.linden@lindenlab.com +oz-viewer-devreview.build_debug_release_separately = true +oz_viewer-poreview.build_debug_release_separately = true +oz-project-1.build_debug_release_separately = true +oz-project-2.build_debug_release_separately = true +oz-project-3.build_debug_release_separately = true # ======================================== # enus diff --git a/doc/contributions.txt b/doc/contributions.txt index 337a3da6b8..3b1abcebed 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -413,6 +413,7 @@ Jonathan Yap STORM-975
STORM-990
STORM-1020
+ STORM-1064
Kage Pixel
VWR-11
Ken March
diff --git a/indra/llcommon/llprocesslauncher.cpp b/indra/llcommon/llprocesslauncher.cpp index d46188104f..10950181fd 100644 --- a/indra/llcommon/llprocesslauncher.cpp +++ b/indra/llcommon/llprocesslauncher.cpp @@ -103,10 +103,30 @@ int LLProcessLauncher::launch(void) char *args2 = new char[args.size() + 1]; strcpy(args2, args.c_str()); - if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, mWorkingDir.c_str(), &sinfo, &pinfo ) ) + const char * working_directory = 0; + if(!mWorkingDir.empty()) working_directory = mWorkingDir.c_str(); + if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, working_directory, &sinfo, &pinfo ) ) { - // TODO: do better than returning the OS-specific error code on failure... result = GetLastError(); + + LPTSTR error_str = 0; + if( + FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + result, + 0, + (LPTSTR)&error_str, + 0, + NULL) + != 0) + { + char message[256]; + wcstombs(message, error_str, 256); + message[255] = 0; + llwarns << "CreateProcessA failed: " << message << llendl; + LocalFree(error_str); + } + if(result == 0) { // Make absolutely certain we return a non-zero value on failure. diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index 117d96ffa6..d22c879243 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -29,7 +29,7 @@ const S32 LL_VERSION_MAJOR = 2; const S32 LL_VERSION_MINOR = 6; -const S32 LL_VERSION_PATCH = 1; +const S32 LL_VERSION_PATCH = 2; const S32 LL_VERSION_BUILD = 0; const char * const LL_CHANNEL = "Second Life Developer"; diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 35e0d9d890..d19e33ea55 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -2869,7 +2869,7 @@ void LLFloater::initFromParams(const LLFloater::Params& p) // close callback if (p.close_callback.isProvided()) { - mCloseSignal.connect(initCommitCallback(p.close_callback)); + setCloseCallback(initCommitCallback(p.close_callback)); } } @@ -2879,6 +2879,11 @@ boost::signals2::connection LLFloater::setMinimizeCallback( const commit_signal_ return mMinimizeSignal->connect(cb); } +boost::signals2::connection LLFloater::setCloseCallback( const commit_signal_t::slot_type& cb ) +{ + return mCloseSignal.connect(cb); +} + LLFastTimer::DeclareTimer POST_BUILD("Floater Post Build"); bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node) diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 0e83b80c89..5b7b020881 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -144,6 +144,7 @@ public: bool buildFromFile(const std::string &filename, LLXMLNodePtr output_node = NULL); boost::signals2::connection setMinimizeCallback( const commit_signal_t::slot_type& cb ); + boost::signals2::connection setCloseCallback( const commit_signal_t::slot_type& cb ); void initFromParams(const LLFloater::Params& p); bool initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node = NULL); diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 32d7be377a..f0374de98f 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -1936,9 +1936,15 @@ bool LLMenuGL::scrollItems(EScrollingDirection direction) { item_list_t::reverse_iterator first_visible_item_iter = mItems.rend(); + // Need to scroll through number of actual existing items in menu. + // Otherwise viewer will hang for a time needed to scroll U32_MAX + // times in std::advance(). STORM-659. + size_t nitems = mItems.size(); + U32 scrollable_items = nitems < mMaxScrollableItems ? nitems : mMaxScrollableItems; + // Advance by mMaxScrollableItems back from the end of the list // to make the last item visible. - std::advance(first_visible_item_iter, mMaxScrollableItems); + std::advance(first_visible_item_iter, scrollable_items); mFirstVisibleItem = *first_visible_item_iter; break; } diff --git a/indra/media_plugins/winmmshim/CMakeLists.txt b/indra/media_plugins/winmmshim/CMakeLists.txt index 3e3a988310..bf74f81809 100644 --- a/indra/media_plugins/winmmshim/CMakeLists.txt +++ b/indra/media_plugins/winmmshim/CMakeLists.txt @@ -3,12 +3,12 @@ project(winmm_shim) ### winmm_shim -# *HACK - override msvcrt implementation (intialized on 00-Common) to be
-# statically linked for winmm.dll this relies on vc taking the last flag on
-# the command line
-set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
-set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MT")
-set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
+# *HACK - override msvcrt implementation (intialized on 00-Common) to be +# statically linked for winmm.dll this relies on vc taking the last flag on +# the command line +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MT") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") set(winmm_shim_SOURCE_FILES forwarding_api.cpp diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 92a3a0299a..e27397ab1a 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3270,7 +3270,7 @@ <key>FirstRunThisInstall</key> <map> <key>Comment</key> - <string>Specifies that you have not run the viewer since you installed the latest update</string> + <string>Specifies that you have not run the viewer since you performed a clean install</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -3278,7 +3278,18 @@ <key>Value</key> <integer>1</integer> </map> - <key>FirstSelectedDisabledPopups</key> + <key>FirstLoginThisInstall</key> + <map> + <key>Comment</key> + <string>Specifies that you have not logged in with the viewer since you performed a clean install</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstSelectedDisabledPopups</key> <map> <key>Comment</key> <string>Return false if there is not disabled popup selected in the list of floater preferences popups</string> diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 85447842e6..1184c8e76c 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2216,6 +2216,7 @@ bool LLAppViewer::initConfiguration() if (gSavedSettings.getBOOL("FirstRunThisInstall")) { gSavedSettings.setString("SessionSettingsFile", "settings_minimal.xml"); + gSavedSettings.setBOOL("FirstRunThisInstall", FALSE); } if (clp.hasOption("sessionsettings")) diff --git a/indra/newview/llfloatermap.cpp b/indra/newview/llfloatermap.cpp index 45d1cc2b53..641e64247b 100644 --- a/indra/newview/llfloatermap.cpp +++ b/indra/newview/llfloatermap.cpp @@ -42,7 +42,6 @@ #include "llviewercamera.h" #include "lldraghandle.h" #include "lltextbox.h" -#include "llviewermenu.h" #include "llfloaterworldmap.h" #include "llagent.h" @@ -63,7 +62,6 @@ const S32 MAP_PADDING_BOTTOM = 0; LLFloaterMap::LLFloaterMap(const LLSD& key) : LLFloater(key), - mPopupMenu(NULL), mTextBoxEast(NULL), mTextBoxNorth(NULL), mTextBoxWest(NULL), @@ -102,17 +100,6 @@ BOOL LLFloaterMap::postBuild() mTextBoxSouthWest = getChild<LLTextBox> ("floater_map_southwest"); mTextBoxNorthWest = getChild<LLTextBox> ("floater_map_northwest"); - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; - - registrar.add("Minimap.Zoom", boost::bind(&LLFloaterMap::handleZoom, this, _2)); - registrar.add("Minimap.Tracker", boost::bind(&LLFloaterMap::handleStopTracking, this, _2)); - - mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_mini_map.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - if (mPopupMenu && !LLTracker::isTracking(0)) - { - mPopupMenu->setItemEnabled ("Stop Tracking", false); - } - stretchMiniMap(getRect().getWidth() - MAP_PADDING_LEFT - MAP_PADDING_RIGHT ,getRect().getHeight() - MAP_PADDING_TOP - MAP_PADDING_BOTTOM); @@ -163,17 +150,6 @@ BOOL LLFloaterMap::handleDoubleClick(S32 x, S32 y, MASK mask) return TRUE; } -BOOL LLFloaterMap::handleRightMouseDown(S32 x, S32 y, MASK mask) -{ - if (mPopupMenu) - { - mPopupMenu->buildDrawLabels(); - mPopupMenu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, mPopupMenu, x, y); - } - return TRUE; -} - void LLFloaterMap::setDirectionPos( LLTextBox* text_box, F32 rotation ) { // Rotation is in radians. @@ -244,11 +220,6 @@ void LLFloaterMap::draw() getDragHandle()->setMouseOpaque(TRUE); } - if (LLTracker::isTracking(0)) - { - mPopupMenu->setItemEnabled ("Stop Tracking", true); - } - LLFloater::draw(); } @@ -315,14 +286,6 @@ void LLFloaterMap::handleZoom(const LLSD& userdata) } } -void LLFloaterMap::handleStopTracking (const LLSD& userdata) -{ - if (mPopupMenu) - { - mPopupMenu->setItemEnabled ("Stop Tracking", false); - LLTracker::stopTracking ((void*)LLTracker::isTracking(NULL)); - } -} void LLFloaterMap::setMinimized(BOOL b) { LLFloater::setMinimized(b); diff --git a/indra/newview/llfloatermap.h b/indra/newview/llfloatermap.h index 4cbb48fb3e..5cf66a594b 100644 --- a/indra/newview/llfloatermap.h +++ b/indra/newview/llfloatermap.h @@ -29,7 +29,6 @@ #include "llfloater.h" -class LLMenuGL; class LLNetMap; class LLTextBox; @@ -44,7 +43,6 @@ public: /*virtual*/ BOOL postBuild(); /*virtual*/ BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); - /*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); /*virtual*/ void draw(); /*virtual*/ void onFocusLost(); @@ -54,14 +52,11 @@ public: private: void handleZoom(const LLSD& userdata); - void handleStopTracking (const LLSD& userdata); void setDirectionPos( LLTextBox* text_box, F32 rotation ); void updateMinorDirections(); void stretchMiniMap(S32 width,S32 height); - LLMenuGL* mPopupMenu; - LLTextBox* mTextBoxEast; LLTextBox* mTextBoxNorth; LLTextBox* mTextBoxWest; diff --git a/indra/newview/llhudeffectblob.cpp b/indra/newview/llhudeffectblob.cpp index 26e8251899..d8687eed8d 100644 --- a/indra/newview/llhudeffectblob.cpp +++ b/indra/newview/llhudeffectblob.cpp @@ -30,13 +30,14 @@ #include "llagent.h" #include "llviewercamera.h" -#include "llrendersphere.h" +#include "llui.h" LLHUDEffectBlob::LLHUDEffectBlob(const U8 type) : LLHUDEffect(type), mPixelSize(10) { mTimer.start(); + mImage = LLUI::getUIImage("Camera_Drag_Dot"); } LLHUDEffectBlob::~LLHUDEffectBlob() @@ -58,18 +59,29 @@ void LLHUDEffectBlob::render() LLViewerCamera::instance().getPixelVectors(pos_agent, pixel_up, pixel_right); LLGLSPipelineAlpha gls_pipeline_alpha; - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(0)->bind(mImage->getImage()); LLColor4U color = mColor; color.mV[VALPHA] = (U8)clamp_rescale(time, 0.f, mDuration, 255.f, 0.f); - glColor4ubv(color.mV); + gGL.color4ubv(color.mV); - glPushMatrix(); - glTranslatef(pos_agent.mV[0], pos_agent.mV[1], pos_agent.mV[2]); - F32 scale = pixel_up.magVec() * (F32)mPixelSize; - glScalef(scale, scale, scale); - gSphere.render(0); - glPopMatrix(); + { gGL.pushMatrix(); + gGL.translatef(pos_agent.mV[0], pos_agent.mV[1], pos_agent.mV[2]); + LLVector3 u_scale = pixel_right * (F32)mPixelSize; + LLVector3 v_scale = pixel_up * (F32)mPixelSize; + + { gGL.begin(LLRender::QUADS); + gGL.texCoord2f(0.f, 1.f); + gGL.vertex3fv((v_scale - u_scale).mV); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex3fv((-v_scale - u_scale).mV); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex3fv((-v_scale + u_scale).mV); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex3fv((v_scale + u_scale).mV); + } gGL.end(); + + } gGL.popMatrix(); } void LLHUDEffectBlob::renderForTimer() diff --git a/indra/newview/llhudeffectblob.h b/indra/newview/llhudeffectblob.h index 5b0703cdaa..f4c1691108 100644 --- a/indra/newview/llhudeffectblob.h +++ b/indra/newview/llhudeffectblob.h @@ -28,6 +28,7 @@ #define LL_LLHUDEFFECTBLOB_H #include "llhudeffect.h" +#include "lluiimage.h" class LLHUDEffectBlob : public LLHUDEffect { @@ -45,6 +46,7 @@ protected: private: S32 mPixelSize; LLFrameTimer mTimer; + LLPointer<LLUIImage> mImage; }; #endif // LL_LLHUDEFFECTBLOB_H diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp index 836ae9a0cf..162e465fef 100644 --- a/indra/newview/llnearbychatbar.cpp +++ b/indra/newview/llnearbychatbar.cpp @@ -157,6 +157,16 @@ BOOL LLGestureComboList::handleKeyHere(KEY key, MASK mask) return handled; } +void LLGestureComboList::draw() +{ + LLUICtrl::draw(); + + if(mButton->getToggleState()) + { + showList(); + } +} + void LLGestureComboList::showList() { LLRect rect = mList->getRect(); @@ -180,6 +190,7 @@ void LLGestureComboList::showList() // Show the list and push the button down mButton->setToggleState(TRUE); mList->setVisible(TRUE); + sendChildToFront(mList); LLUI::addPopup(mList); } diff --git a/indra/newview/llnearbychatbar.h b/indra/newview/llnearbychatbar.h index 033d1dd5a2..96ab45071b 100644 --- a/indra/newview/llnearbychatbar.h +++ b/indra/newview/llnearbychatbar.h @@ -72,6 +72,8 @@ public: virtual void hideList(); virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual void draw(); + S32 getCurrentIndex() const; void onItemSelected(const LLSD& data); void sortByName(bool ascending = true); diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index e29078c545..981b4dbee3 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -112,10 +112,6 @@ BOOL LLNetMap::postBuild() registrar.add("Minimap.Tracker", boost::bind(&LLNetMap::handleStopTracking, this, _2)); mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_mini_map.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - if (mPopupMenu && !LLTracker::isTracking(0)) - { - mPopupMenu->setItemEnabled ("Stop Tracking", false); - } return TRUE; } @@ -510,13 +506,6 @@ void LLNetMap::draw() gGL.popUIMatrix(); LLUICtrl::draw(); - - if (LLTracker::isTracking(0)) - { - mPopupMenu->setItemEnabled ("Stop Tracking", true); - } - - } void LLNetMap::reshape(S32 width, S32 height, BOOL called_from_parent) @@ -886,6 +875,7 @@ BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask) { mPopupMenu->buildDrawLabels(); mPopupMenu->updateParent(LLMenuGL::sMenuContainer); + mPopupMenu->setItemEnabled("Stop Tracking", LLTracker::isTracking(0)); LLMenuGL::showPopup(this, mPopupMenu, x, y); } return TRUE; diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index b472698a49..903cf4780d 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -1,1183 +1,1183 @@ -/**
- * @file llpanellogin.cpp
- * @brief Login dialog and logo display
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llpanellogin.h"
-
-#include "indra_constants.h" // for key and mask constants
-#include "llfloaterreg.h"
-#include "llfontgl.h"
-#include "llmd5.h"
-#include "llsecondlifeurls.h"
-#include "v4color.h"
-
-#include "llappviewer.h"
-#include "llbutton.h"
-#include "llcheckboxctrl.h"
-#include "llcommandhandler.h" // for secondlife:///app/login/
-#include "llcombobox.h"
-#include "llcurl.h"
-#include "llviewercontrol.h"
-#include "llfloaterpreference.h"
-#include "llfocusmgr.h"
-#include "lllineeditor.h"
-#include "llnotificationsutil.h"
-#include "llsecapi.h"
-#include "llstartup.h"
-#include "lltextbox.h"
-#include "llui.h"
-#include "lluiconstants.h"
-#include "llslurl.h"
-#include "llversioninfo.h"
-#include "llviewerhelp.h"
-#include "llviewertexturelist.h"
-#include "llviewermenu.h" // for handle_preferences()
-#include "llviewernetwork.h"
-#include "llviewerwindow.h" // to link into child list
-#include "lluictrlfactory.h"
-#include "llhttpclient.h"
-#include "llweb.h"
-#include "llmediactrl.h"
-#include "llrootview.h"
-
-#include "llfloatertos.h"
-#include "lltrans.h"
-#include "llglheaders.h"
-#include "llpanelloginlistener.h"
-
-#if LL_WINDOWS
-#pragma warning(disable: 4355) // 'this' used in initializer list
-#endif // LL_WINDOWS
-
-#include "llsdserialize.h"
-
-const S32 BLACK_BORDER_HEIGHT = 160;
-const S32 MAX_PASSWORD = 16;
-
-LLPanelLogin *LLPanelLogin::sInstance = NULL;
-BOOL LLPanelLogin::sCapslockDidNotification = FALSE;
-
-
-class LLLoginRefreshHandler : public LLCommandHandler
-{
-public:
- // don't allow from external browsers
- LLLoginRefreshHandler() : LLCommandHandler("login_refresh", UNTRUSTED_BLOCK) { }
- bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)
- {
- if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP)
- {
- LLPanelLogin::loadLoginPage();
- }
- return true;
- }
-};
-
-LLLoginRefreshHandler gLoginRefreshHandler;
-
-
-// helper class that trys to download a URL from a web site and calls a method
-// on parent class indicating if the web server is working or not
-class LLIamHereLogin : public LLHTTPClient::Responder
-{
- private:
- LLIamHereLogin( LLPanelLogin* parent ) :
- mParent( parent )
- {}
-
- LLPanelLogin* mParent;
-
- public:
- static boost::intrusive_ptr< LLIamHereLogin > build( LLPanelLogin* parent )
- {
- return boost::intrusive_ptr< LLIamHereLogin >( new LLIamHereLogin( parent ) );
- };
-
- virtual void setParent( LLPanelLogin* parentIn )
- {
- mParent = parentIn;
- };
-
- // We don't actually expect LLSD back, so need to override completedRaw
- virtual void completedRaw(U32 status, const std::string& reason,
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- completed(status, reason, LLSD()); // will call result() or error()
- }
-
- virtual void result( const LLSD& content )
- {
- if ( mParent )
- mParent->setSiteIsAlive( true );
- };
-
- virtual void error( U32 status, const std::string& reason )
- {
- if ( mParent )
- mParent->setSiteIsAlive( false );
- };
-};
-
-// this is global and not a class member to keep crud out of the header file
-namespace {
- boost::intrusive_ptr< LLIamHereLogin > gResponsePtr = 0;
-};
-
-
-//---------------------------------------------------------------------------
-// Public methods
-//---------------------------------------------------------------------------
-LLPanelLogin::LLPanelLogin(const LLRect &rect,
- BOOL show_server,
- void (*callback)(S32 option, void* user_data),
- void *cb_data)
-: LLPanel(),
- mLogoImage(),
- mCallback(callback),
- mCallbackData(cb_data),
- mHtmlAvailable( TRUE ),
- mListener(new LLPanelLoginListener(this))
-{
- setBackgroundVisible(FALSE);
- setBackgroundOpaque(TRUE);
-
- // instance management
- if (LLPanelLogin::sInstance)
- {
- llwarns << "Duplicate instance of login view deleted" << llendl;
- // Don't leave bad pointer in gFocusMgr
- gFocusMgr.setDefaultKeyboardFocus(NULL);
-
- delete LLPanelLogin::sInstance;
- }
-
- mPasswordModified = FALSE;
- LLPanelLogin::sInstance = this;
-
- LLView* login_holder = gViewerWindow->getLoginPanelHolder();
- if (login_holder)
- {
- login_holder->addChild(this);
- }
-
- // Logo
- mLogoImage = LLUI::getUIImage("startup_logo");
-
- buildFromFile( "panel_login.xml");
-
- // Legacy login web page is hidden under the menu bar.
- // Adjust reg-in-client web browser widget to not be hidden.
- if (gSavedSettings.getBOOL("RegInClient"))
- {
- reshape(rect.getWidth(), rect.getHeight() - MENU_BAR_HEIGHT);
- }
- else
- {
- reshape(rect.getWidth(), rect.getHeight());
- }
-
- getChild<LLLineEditor>("password_edit")->setKeystrokeCallback(onPassKey, this);
-
- // change z sort of clickable text to be behind buttons
- //sendChildToBack(getChildView("channel_text"));
- sendChildToBack(getChildView("forgot_password_text"));
-
- if(LLStartUp::getStartSLURL().getType() != LLSLURL::LOCATION)
- {
- LLSLURL slurl(gSavedSettings.getString("LoginLocation"));
- LLStartUp::setStartSLURL(slurl);
- }
- updateLocationCombo(false);
-
- gSavedSettings.getControl("SessionSettingsFile")->getSignal()->connect(boost::bind(&onModeChange));
-
- LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");
- server_choice_combo->setCommitCallback(onSelectServer, NULL);
- server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1));
- updateServerCombo();
-
- childSetAction("connect_btn", onClickConnect, this);
-
- getChild<LLPanel>("login")->setDefaultBtn("connect_btn");
-
- std::string channel = LLVersionInfo::getChannel();
- std::string version = llformat("%s (%d)",
- LLVersionInfo::getShortVersion().c_str(),
- LLVersionInfo::getBuild());
- //LLTextBox* channel_text = getChild<LLTextBox>("channel_text");
- //channel_text->setTextArg("[CHANNEL]", channel); // though not displayed
- //channel_text->setTextArg("[VERSION]", version);
- //channel_text->setClickedCallback(onClickVersion, this);
-
- LLTextBox* forgot_password_text = getChild<LLTextBox>("forgot_password_text");
- forgot_password_text->setClickedCallback(onClickForgotPassword, NULL);
-
- LLTextBox* create_new_account_text = getChild<LLTextBox>("create_new_account_text");
- create_new_account_text->setClickedCallback(onClickNewAccount, NULL);
-
- LLTextBox* need_help_text = getChild<LLTextBox>("login_help");
- need_help_text->setClickedCallback(onClickHelp, NULL);
-
- // get the web browser control
- LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
- web_browser->addObserver(this);
-
- // Clear the browser's cache to avoid any potential for the cache messing up the login screen.
- web_browser->clearCache();
-
- reshapeBrowser();
-
- // kick off a request to grab the url manually
- gResponsePtr = LLIamHereLogin::build( this );
-
- LLHTTPClient::head( LLGridManager::getInstance()->getLoginPage(), gResponsePtr );
-
- // Show last logged in user favorites in "Start at" combo.
- addUsersWithFavoritesToUsername();
- getChild<LLComboBox>("username_combo")->setTextChangedCallback(boost::bind(&LLPanelLogin::addFavoritesToStartLocation, this));
-
- updateLocationCombo(false);
-
-}
-
-void LLPanelLogin::addUsersWithFavoritesToUsername()
-{
- LLComboBox* combo = getChild<LLComboBox>("username_combo");
- if (!combo) return;
- std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml");
- LLSD fav_llsd;
- llifstream file;
- file.open(filename);
- if (!file.is_open()) return;
- LLSDSerialize::fromXML(fav_llsd, file);
- for (LLSD::map_const_iterator iter = fav_llsd.beginMap();
- iter != fav_llsd.endMap(); ++iter)
- {
- combo->add(iter->first);
- }
-}
-
-void LLPanelLogin::addFavoritesToStartLocation()
-{
- LLComboBox* combo = getChild<LLComboBox>("start_location_combo");
- if (!combo) return;
- int num_items = combo->getItemCount();
- for (int i = num_items - 1; i > 2; i--)
- {
- combo->remove(i);
- }
- std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml");
- LLSD fav_llsd;
- llifstream file;
- file.open(filename);
- if (!file.is_open()) return;
- LLSDSerialize::fromXML(fav_llsd, file);
- for (LLSD::map_const_iterator iter = fav_llsd.beginMap();
- iter != fav_llsd.endMap(); ++iter)
- {
- if(iter->first != getChild<LLComboBox>("username_combo")->getSimple()) continue;
- combo->addSeparator();
- LLSD user_llsd = iter->second;
- for (LLSD::array_const_iterator iter1 = user_llsd.beginArray();
- iter1 != user_llsd.endArray(); ++iter1)
- {
- std::string label = (*iter1)["name"].asString();
- std::string value = (*iter1)["slurl"].asString();
- if(label != "" && value != "")
- {
- combo->add(label, value);
- }
- }
- break;
- }
-}
-
-// force the size to be correct (XML doesn't seem to be sufficient to do this)
-// (with some padding so the other login screen doesn't show through)
-void LLPanelLogin::reshapeBrowser()
-{
- LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
- LLRect rect = gViewerWindow->getWindowRectScaled();
- LLRect html_rect;
- html_rect.setCenterAndSize(
- rect.getCenterX() - 2, rect.getCenterY() + 40,
- rect.getWidth() + 6, rect.getHeight() - 78 );
- web_browser->setRect( html_rect );
- web_browser->reshape( html_rect.getWidth(), html_rect.getHeight(), TRUE );
- reshape( rect.getWidth(), rect.getHeight(), 1 );
-}
-
-void LLPanelLogin::setSiteIsAlive( bool alive )
-{
- LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
- // if the contents of the site was retrieved
- if ( alive )
- {
- if ( web_browser )
- {
- loadLoginPage();
-
- // mark as available
- mHtmlAvailable = TRUE;
- }
- }
- else
- // the site is not available (missing page, server down, other badness)
- {
- if ( web_browser )
- {
- // hide browser control (revealing default one)
- web_browser->setVisible( FALSE );
-
- // mark as unavailable
- mHtmlAvailable = FALSE;
- }
- }
-}
-
-
-LLPanelLogin::~LLPanelLogin()
-{
- LLPanelLogin::sInstance = NULL;
-
- // tell the responder we're not here anymore
- if ( gResponsePtr )
- gResponsePtr->setParent( 0 );
-
- //// We know we're done with the image, so be rid of it.
- //gTextureList.deleteImage( mLogoImage );
-
- // Controls having keyboard focus by default
- // must reset it on destroy. (EXT-2748)
- gFocusMgr.setDefaultKeyboardFocus(NULL);
-}
-
-// virtual
-void LLPanelLogin::draw()
-{
- glPushMatrix();
- {
- F32 image_aspect = 1.333333f;
- F32 view_aspect = (F32)getRect().getWidth() / (F32)getRect().getHeight();
- // stretch image to maintain aspect ratio
- if (image_aspect > view_aspect)
- {
- glTranslatef(-0.5f * (image_aspect / view_aspect - 1.f) * getRect().getWidth(), 0.f, 0.f);
- glScalef(image_aspect / view_aspect, 1.f, 1.f);
- }
-
- S32 width = getRect().getWidth();
- S32 height = getRect().getHeight();
-
- if ( mHtmlAvailable )
- {
- if (getChild<LLView>("login_widgets")->getVisible())
- {
- // draw a background box in black
- gl_rect_2d( 0, height - 264, width, 264, LLColor4::black );
- // draw the bottom part of the background image
- // just the blue background to the native client UI
- mLogoImage->draw(0, -264, width + 8, mLogoImage->getHeight());
- }
- }
- else
- {
- // the HTML login page is not available so default to the original screen
- S32 offscreen_part = height / 3;
- mLogoImage->draw(0, -offscreen_part, width, height+offscreen_part);
- };
- }
- glPopMatrix();
-
- LLPanel::draw();
-}
-
-// virtual
-BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask)
-{
- if ( KEY_F1 == key )
- {
- LLViewerHelp* vhelp = LLViewerHelp::getInstance();
- vhelp->showTopic(vhelp->f1HelpTopic());
- return TRUE;
- }
-
- return LLPanel::handleKeyHere(key, mask);
-}
-
-// virtual
-void LLPanelLogin::setFocus(BOOL b)
-{
- if(b != hasFocus())
- {
- if(b)
- {
- LLPanelLogin::giveFocus();
- }
- else
- {
- LLPanel::setFocus(b);
- }
- }
-}
-
-// static
-void LLPanelLogin::giveFocus()
-{
- if( sInstance )
- {
- // Grab focus and move cursor to first blank input field
- std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
- std::string pass = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString();
-
- BOOL have_username = !username.empty();
- BOOL have_pass = !pass.empty();
-
- LLLineEditor* edit = NULL;
- LLComboBox* combo = NULL;
- if (have_username && !have_pass)
- {
- // User saved his name but not his password. Move
- // focus to password field.
- edit = sInstance->getChild<LLLineEditor>("password_edit");
- }
- else
- {
- // User doesn't have a name, so start there.
- combo = sInstance->getChild<LLComboBox>("username_combo");
- }
-
- if (edit)
- {
- edit->setFocus(TRUE);
- edit->selectAll();
- }
- else if (combo)
- {
- combo->setFocus(TRUE);
- }
- }
-}
-
-// static
-void LLPanelLogin::showLoginWidgets()
-{
- // *NOTE: Mani - This may or may not be obselete code.
- // It seems to be part of the defunct? reg-in-client project.
- sInstance->getChildView("login_widgets")->setVisible( true);
- LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
- sInstance->reshapeBrowser();
- // *TODO: Append all the usual login parameters, like first_login=Y etc.
- std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage();
- web_browser->navigateTo( splash_screen_url, "text/html" );
- LLUICtrl* username_combo = sInstance->getChild<LLUICtrl>("username_combo");
- username_combo->setFocus(TRUE);
-}
-
-// static
-void LLPanelLogin::show(const LLRect &rect,
- BOOL show_server,
- void (*callback)(S32 option, void* user_data),
- void* callback_data)
-{
- new LLPanelLogin(rect, show_server, callback, callback_data);
-
- if( !gFocusMgr.getKeyboardFocus() )
- {
- // Grab focus and move cursor to first enabled control
- sInstance->setFocus(TRUE);
- }
-
- // Make sure that focus always goes here (and use the latest sInstance that was just created)
- gFocusMgr.setDefaultKeyboardFocus(sInstance);
-}
-
-// static
-void LLPanelLogin::setFields(LLPointer<LLCredential> credential,
- BOOL remember)
-{
- if (!sInstance)
- {
- llwarns << "Attempted fillFields with no login view shown" << llendl;
- return;
- }
- LL_INFOS("Credentials") << "Setting login fields to " << *credential << LL_ENDL;
-
- LLSD identifier = credential->getIdentifier();
- if((std::string)identifier["type"] == "agent")
- {
- std::string firstname = identifier["first_name"].asString();
- std::string lastname = identifier["last_name"].asString();
- std::string login_id = firstname;
- if (!lastname.empty() && lastname != "Resident")
- {
- // support traditional First Last name SLURLs
- login_id += " ";
- login_id += lastname;
- }
- sInstance->getChild<LLComboBox>("username_combo")->setLabel(login_id);
- }
- else if((std::string)identifier["type"] == "account")
- {
- sInstance->getChild<LLComboBox>("username_combo")->setLabel((std::string)identifier["account_name"]);
- }
- else
- {
- sInstance->getChild<LLComboBox>("username_combo")->setLabel(std::string());
- }
- sInstance->addFavoritesToStartLocation();
- // if the password exists in the credential, set the password field with
- // a filler to get some stars
- LLSD authenticator = credential->getAuthenticator();
- LL_INFOS("Credentials") << "Setting authenticator field " << authenticator["type"].asString() << LL_ENDL;
- if(authenticator.isMap() &&
- authenticator.has("secret") &&
- (authenticator["secret"].asString().size() > 0))
- {
-
- // This is a MD5 hex digest of a password.
- // We don't actually use the password input field,
- // fill it with MAX_PASSWORD characters so we get a
- // nice row of asterixes.
- const std::string filler("123456789!123456");
- sInstance->getChild<LLUICtrl>("password_edit")->setValue(std::string("123456789!123456"));
- }
- else
- {
- sInstance->getChild<LLUICtrl>("password_edit")->setValue(std::string());
- }
- sInstance->getChild<LLUICtrl>("remember_check")->setValue(remember);
-}
-
-
-// static
-void LLPanelLogin::getFields(LLPointer<LLCredential>& credential,
- BOOL& remember)
-{
- if (!sInstance)
- {
- llwarns << "Attempted getFields with no login view shown" << llendl;
- return;
- }
-
- // load the credential so we can pass back the stored password or hash if the user did
- // not modify the password field.
-
- credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
-
- LLSD identifier = LLSD::emptyMap();
- LLSD authenticator = LLSD::emptyMap();
-
- if(credential.notNull())
- {
- authenticator = credential->getAuthenticator();
- }
-
- std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
- LLStringUtil::trim(username);
- std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString();
-
- LL_INFOS2("Credentials", "Authentication") << "retrieving username:" << username << LL_ENDL;
- // determine if the username is a first/last form or not.
- size_t separator_index = username.find_first_of(' ');
- if (separator_index == username.npos
- && !LLGridManager::getInstance()->isSystemGrid())
- {
- LL_INFOS2("Credentials", "Authentication") << "account: " << username << LL_ENDL;
- // single username, so this is a 'clear' identifier
- identifier["type"] = CRED_IDENTIFIER_TYPE_ACCOUNT;
- identifier["account_name"] = username;
-
- if (LLPanelLogin::sInstance->mPasswordModified)
- {
- authenticator = LLSD::emptyMap();
- // password is plaintext
- authenticator["type"] = CRED_AUTHENTICATOR_TYPE_CLEAR;
- authenticator["secret"] = password;
- }
- }
- else
- {
- // Be lenient in terms of what separators we allow for two-word names
- // and allow legacy users to login with firstname.lastname
- separator_index = username.find_first_of(" ._");
- std::string first = username.substr(0, separator_index);
- std::string last;
- if (separator_index != username.npos)
- {
- last = username.substr(separator_index+1, username.npos);
- LLStringUtil::trim(last);
- }
- else
- {
- // ...on Linden grids, single username users as considered to have
- // last name "Resident"
- // *TODO: Make login.cgi support "account_name" like above
- last = "Resident";
- }
-
- if (last.find_first_of(' ') == last.npos)
- {
- LL_INFOS2("Credentials", "Authentication") << "agent: " << username << LL_ENDL;
- // traditional firstname / lastname
- identifier["type"] = CRED_IDENTIFIER_TYPE_AGENT;
- identifier["first_name"] = first;
- identifier["last_name"] = last;
-
- if (LLPanelLogin::sInstance->mPasswordModified)
- {
- authenticator = LLSD::emptyMap();
- authenticator["type"] = CRED_AUTHENTICATOR_TYPE_HASH;
- authenticator["algorithm"] = "md5";
- LLMD5 pass((const U8 *)password.c_str());
- char md5pass[33]; /* Flawfinder: ignore */
- pass.hex_digest(md5pass);
- authenticator["secret"] = md5pass;
- }
- }
- }
- credential = gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), identifier, authenticator);
- remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue();
-}
-
-// static
-BOOL LLPanelLogin::isGridComboDirty()
-{
- BOOL user_picked = FALSE;
- if (!sInstance)
- {
- llwarns << "Attempted getServer with no login view shown" << llendl;
- }
- else
- {
- LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
- user_picked = combo->isDirty();
- }
- return user_picked;
-}
-
-// static
-BOOL LLPanelLogin::areCredentialFieldsDirty()
-{
- if (!sInstance)
- {
- llwarns << "Attempted getServer with no login view shown" << llendl;
- }
- else
- {
- std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
- LLStringUtil::trim(username);
- std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString();
- LLComboBox* combo = sInstance->getChild<LLComboBox>("username_combo");
- if(combo && combo->isDirty())
- {
- return true;
- }
- LLLineEditor* ctrl = sInstance->getChild<LLLineEditor>("password_edit");
- if(ctrl && ctrl->isDirty())
- {
- return true;
- }
- }
- return false;
-}
-
-
-// static
-void LLPanelLogin::updateLocationCombo( bool force_visible )
-{
- if (!sInstance)
- {
- return;
- }
-
- LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
-
- switch(LLStartUp::getStartSLURL().getType())
- {
- case LLSLURL::LOCATION:
- {
-
- combo->setCurrentByIndex( 2 );
- combo->setTextEntry(LLStartUp::getStartSLURL().getLocationString());
- break;
- }
- case LLSLURL::HOME_LOCATION:
- combo->setCurrentByIndex(1);
- break;
- default:
- combo->setCurrentByIndex(0);
- break;
- }
-
- BOOL show_start = TRUE;
-
- if ( ! force_visible )
- show_start = gSavedSettings.getBOOL("ShowStartLocation");
-
- sInstance->getChildView("start_location_combo")->setVisible( show_start);
- sInstance->getChildView("start_location_text")->setVisible( show_start);
-
- BOOL show_server = gSavedSettings.getBOOL("ForceShowGrid");
- sInstance->getChildView("server_combo_text")->setVisible( show_server);
- sInstance->getChildView("server_combo")->setVisible( show_server);
-}
-
-// static
-void LLPanelLogin::updateStartSLURL()
-{
- if (!sInstance) return;
-
- LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
- S32 index = combo->getCurrentIndex();
-
- switch (index)
- {
- case 0:
- {
- LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST));
- break;
- }
- case 1:
- {
- LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME));
- break;
- }
- default:
- {
- LLSLURL slurl = LLSLURL(combo->getValue().asString());
- if(slurl.getType() == LLSLURL::LOCATION)
- {
- // we've changed the grid, so update the grid selection
- LLStartUp::setStartSLURL(slurl);
- }
- break;
- }
- }
-}
-
-
-void LLPanelLogin::setLocation(const LLSLURL& slurl)
-{
- LLStartUp::setStartSLURL(slurl);
- updateServer();
-}
-
-// static
-void LLPanelLogin::closePanel()
-{
- if (sInstance)
- {
- LLPanelLogin::sInstance->getParent()->removeChild( LLPanelLogin::sInstance );
-
- delete sInstance;
- sInstance = NULL;
- }
-}
-
-// static
-void LLPanelLogin::setAlwaysRefresh(bool refresh)
-{
- if (LLStartUp::getStartupState() >= STATE_LOGIN_CLEANUP) return;
-
- LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
-
- if (web_browser)
- {
- web_browser->setAlwaysRefresh(refresh);
- }
-}
-
-
-
-void LLPanelLogin::loadLoginPage()
-{
- if (!sInstance) return;
-
- std::ostringstream oStr;
-
- std::string login_page = LLGridManager::getInstance()->getLoginPage();
-
- oStr << login_page;
-
- // Use the right delimeter depending on how LLURI parses the URL
- LLURI login_page_uri = LLURI(login_page);
-
- std::string first_query_delimiter = "&";
- if (login_page_uri.queryMap().size() == 0)
- {
- first_query_delimiter = "?";
- }
-
- // Language
- std::string language = LLUI::getLanguage();
- oStr << first_query_delimiter<<"lang=" << language;
-
- // First Login?
- if (gSavedSettings.getBOOL("FirstLoginThisInstall"))
- {
- oStr << "&firstlogin=TRUE";
- }
-
- // Channel and Version
- std::string version = llformat("%s (%d)",
- LLVersionInfo::getShortVersion().c_str(),
- LLVersionInfo::getBuild());
-
- char* curl_channel = curl_escape(LLVersionInfo::getChannel().c_str(), 0);
- char* curl_version = curl_escape(version.c_str(), 0);
-
- oStr << "&channel=" << curl_channel;
- oStr << "&version=" << curl_version;
-
- curl_free(curl_channel);
- curl_free(curl_version);
-
- // Grid
- char* curl_grid = curl_escape(LLGridManager::getInstance()->getGridLabel().c_str(), 0);
- oStr << "&grid=" << curl_grid;
- curl_free(curl_grid);
-
- // add OS info
- char * os_info = curl_escape(LLAppViewer::instance()->getOSInfo().getOSStringSimple().c_str(), 0);
- oStr << "&os=" << os_info;
- curl_free(os_info);
-
-
- gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid());
- gLoginMenuBarView->setBackgroundColor(gMenuBarView->getBackgroundColor());
-
- LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
-
- // navigate to the "real" page
- if (gSavedSettings.getBOOL("RegInClient"))
- {
- web_browser->setFocus(TRUE);
- login_page = sInstance->getString("reg_in_client_url");
- web_browser->navigateTo(login_page, "text/html");
- }
- else
- {
- web_browser->navigateTo( oStr.str(), "text/html" );
- }
-}
-
-void LLPanelLogin::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event)
-{
- if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
- {
- LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
- if (web_browser)
- {
- // *HACK HACK HACK HACK!
- /* Stuff a Tab key into the browser now so that the first field will
- ** get the focus! The embedded javascript on the page that properly
- ** sets the initial focus in a real web browser is not working inside
- ** the viewer, so this is an UGLY HACK WORKAROUND for now.
- */
- // Commented out as it's not reliable
- //web_browser->handleKey(KEY_TAB, MASK_NONE, false);
- }
- }
-}
-
-//---------------------------------------------------------------------------
-// Protected methods
-//---------------------------------------------------------------------------
-
-// static
-void LLPanelLogin::onClickConnect(void *)
-{
- if (sInstance && sInstance->mCallback)
- {
- // tell the responder we're not here anymore
- if ( gResponsePtr )
- gResponsePtr->setParent( 0 );
-
- // JC - Make sure the fields all get committed.
- sInstance->setFocus(FALSE);
-
- LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
- LLSD combo_val = combo->getSelectedValue();
- if (combo_val.isUndefined())
- {
- combo_val = combo->getValue();
- }
- if(combo_val.isUndefined())
- {
- LLNotificationsUtil::add("StartRegionEmpty");
- return;
- }
- try
- {
- LLGridManager::getInstance()->setGridChoice(combo_val.asString());
- }
- catch (LLInvalidGridName ex)
- {
- LLSD args;
- args["GRID"] = combo_val.asString();
- LLNotificationsUtil::add("InvalidGrid", args);
- return;
- }
- updateStartSLURL();
- std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
-
-
- if(username.empty())
- {
- // user must type in something into the username field
- LLNotificationsUtil::add("MustHaveAccountToLogIn");
- }
- else
- {
- LLPointer<LLCredential> cred;
- BOOL remember;
- getFields(cred, remember);
- std::string identifier_type;
- cred->identifierType(identifier_type);
- LLSD allowed_credential_types;
- LLGridManager::getInstance()->getLoginIdentifierTypes(allowed_credential_types);
-
- // check the typed in credential type against the credential types expected by the server.
- for(LLSD::array_iterator i = allowed_credential_types.beginArray();
- i != allowed_credential_types.endArray();
- i++)
- {
-
- if(i->asString() == identifier_type)
- {
- // yay correct credential type
- sInstance->mCallback(0, sInstance->mCallbackData);
- return;
- }
- }
-
- // Right now, maingrid is the only thing that is picky about
- // credential format, as it doesn't yet allow account (single username)
- // format creds. - Rox. James, we wanna fix the message when we change
- // this.
- LLNotificationsUtil::add("InvalidCredentialFormat");
- }
- }
-}
-
-/*
-// static
-bool LLPanelLogin::newAccountAlertCallback(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (0 == option)
- {
- llinfos << "Going to account creation URL" << llendl;
- LLWeb::loadURLExternal( LLNotifications::instance().getGlobalString("CREATE_ACCOUNT_URL"));
- }
- else
- {
- sInstance->setFocus(TRUE);
- }
- return false;
-}
-*/
-
-// static
-void LLPanelLogin::onClickNewAccount(void*)
-{
- LLWeb::loadURLExternal(sInstance->getString("create_account_url"));
-}
-
-
-// static
-void LLPanelLogin::onClickVersion(void*)
-{
- LLFloaterReg::showInstance("sl_about");
-}
-
-//static
-void LLPanelLogin::onClickForgotPassword(void*)
-{
- if (sInstance )
- {
- LLWeb::loadURLExternal(sInstance->getString( "forgot_password_url" ));
- }
-}
-
-//static
-void LLPanelLogin::onClickHelp(void*)
-{
- if (sInstance)
- {
- LLViewerHelp* vhelp = LLViewerHelp::getInstance();
- vhelp->showTopic(vhelp->preLoginTopic());
- }
-}
-
-// static
-void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data)
-{
- LLPanelLogin *This = (LLPanelLogin *) user_data;
- This->mPasswordModified = TRUE;
- if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == FALSE)
- {
-// *TODO: use another way to notify user about enabled caps lock, see EXT-6858
- sCapslockDidNotification = TRUE;
- }
-}
-
-
-void LLPanelLogin::updateServer()
-{
- try
- {
-
- updateServerCombo();
- // if they've selected another grid, we should load the credentials
- // for that grid and set them to the UI.
- if(sInstance && !sInstance->areCredentialFieldsDirty())
- {
- LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
- bool remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue();
- sInstance->setFields(credential, remember);
- }
- // grid changed so show new splash screen (possibly)
- loadLoginPage();
- updateLocationCombo(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION);
- }
- catch (LLInvalidGridName ex)
- {
- // do nothing
- }
-}
-
-void LLPanelLogin::updateServerCombo()
-{
- if (!sInstance)
- {
- return;
- }
- // We add all of the possible values, sorted, and then add a bar and the current value at the top
- LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");
- server_choice_combo->removeall();
-
- std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(!gSavedSettings.getBOOL("ShowBetaGrids"));
-
- for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin();
- grid_choice != known_grids.end();
- grid_choice++)
- {
- if (!grid_choice->first.empty())
- {
- server_choice_combo->add(grid_choice->second, grid_choice->first);
- }
- }
- server_choice_combo->sortByName();
-
- server_choice_combo->addSeparator(ADD_TOP);
-
- server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(),
- LLGridManager::getInstance()->getGrid(), ADD_TOP);
-
- server_choice_combo->selectFirstItem();
-}
-
-// static
-void LLPanelLogin::onSelectServer(LLUICtrl*, void*)
-{
- // *NOTE: The paramters for this method are ignored.
- // LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe, void*)
- // calls this method.
- LL_INFOS("AppInit") << "onSelectServer" << LL_ENDL;
- // The user twiddled with the grid choice ui.
- // apply the selection to the grid setting.
- LLPointer<LLCredential> credential;
-
- LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
- LLSD combo_val = combo->getSelectedValue();
- if (combo_val.isUndefined())
- {
- combo_val = combo->getValue();
- }
-
- combo = sInstance->getChild<LLComboBox>("start_location_combo");
- combo->setCurrentByIndex(1);
- LLStartUp::setStartSLURL(LLSLURL(gSavedSettings.getString("LoginLocation")));
- LLGridManager::getInstance()->setGridChoice(combo_val.asString());
- // This new selection will override preset uris
- // from the command line.
- updateServer();
- updateLocationCombo(false);
- updateLoginPanelLinks();
-}
-
-void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe)
-{
- if (!sInstance)
- {
- return;
- }
-
- LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
- if(fe == combo)
- {
- onSelectServer(combo, NULL);
- }
-}
-
-void LLPanelLogin::updateLoginPanelLinks()
-{
- LLSD grid_data;
- LLGridManager::getInstance()->getGridInfo(grid_data);
- bool system_grid = grid_data.has(GRID_IS_SYSTEM_GRID_VALUE);
-
- // need to call through sInstance, as it's called from onSelectServer, which
- // is static.
- sInstance->getChildView("create_new_account_text")->setVisible( system_grid);
- sInstance->getChildView("forgot_password_text")->setVisible( system_grid);
-}
-
-//static
-void LLPanelLogin::onModeChange()
-{
- LLNotificationsUtil::add("ModeChange", LLSD(), LLSD(), boost::bind(&onModeChangeConfirm, _1, _2));
-}
-
-//static
-void LLPanelLogin::onModeChangeConfirm(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- switch (option)
- {
- case 0:
- LLAppViewer::instance()->requestQuit();
- break;
- case 1:
- // do nothing
- break;
- default:
- break;
- }
-}
+/** + * @file llpanellogin.cpp + * @brief Login dialog and logo display + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanellogin.h" + +#include "indra_constants.h" // for key and mask constants +#include "llfloaterreg.h" +#include "llfontgl.h" +#include "llmd5.h" +#include "llsecondlifeurls.h" +#include "v4color.h" + +#include "llappviewer.h" +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "llcommandhandler.h" // for secondlife:///app/login/ +#include "llcombobox.h" +#include "llcurl.h" +#include "llviewercontrol.h" +#include "llfloaterpreference.h" +#include "llfocusmgr.h" +#include "lllineeditor.h" +#include "llnotificationsutil.h" +#include "llsecapi.h" +#include "llstartup.h" +#include "lltextbox.h" +#include "llui.h" +#include "lluiconstants.h" +#include "llslurl.h" +#include "llversioninfo.h" +#include "llviewerhelp.h" +#include "llviewertexturelist.h" +#include "llviewermenu.h" // for handle_preferences() +#include "llviewernetwork.h" +#include "llviewerwindow.h" // to link into child list +#include "lluictrlfactory.h" +#include "llhttpclient.h" +#include "llweb.h" +#include "llmediactrl.h" +#include "llrootview.h" + +#include "llfloatertos.h" +#include "lltrans.h" +#include "llglheaders.h" +#include "llpanelloginlistener.h" + +#if LL_WINDOWS +#pragma warning(disable: 4355) // 'this' used in initializer list +#endif // LL_WINDOWS + +#include "llsdserialize.h" + +const S32 BLACK_BORDER_HEIGHT = 160; +const S32 MAX_PASSWORD = 16; + +LLPanelLogin *LLPanelLogin::sInstance = NULL; +BOOL LLPanelLogin::sCapslockDidNotification = FALSE; + + +class LLLoginRefreshHandler : public LLCommandHandler +{ +public: + // don't allow from external browsers + LLLoginRefreshHandler() : LLCommandHandler("login_refresh", UNTRUSTED_BLOCK) { } + bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) + { + if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) + { + LLPanelLogin::loadLoginPage(); + } + return true; + } +}; + +LLLoginRefreshHandler gLoginRefreshHandler; + + +// helper class that trys to download a URL from a web site and calls a method +// on parent class indicating if the web server is working or not +class LLIamHereLogin : public LLHTTPClient::Responder +{ + private: + LLIamHereLogin( LLPanelLogin* parent ) : + mParent( parent ) + {} + + LLPanelLogin* mParent; + + public: + static boost::intrusive_ptr< LLIamHereLogin > build( LLPanelLogin* parent ) + { + return boost::intrusive_ptr< LLIamHereLogin >( new LLIamHereLogin( parent ) ); + }; + + virtual void setParent( LLPanelLogin* parentIn ) + { + mParent = parentIn; + }; + + // We don't actually expect LLSD back, so need to override completedRaw + virtual void completedRaw(U32 status, const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + completed(status, reason, LLSD()); // will call result() or error() + } + + virtual void result( const LLSD& content ) + { + if ( mParent ) + mParent->setSiteIsAlive( true ); + }; + + virtual void error( U32 status, const std::string& reason ) + { + if ( mParent ) + mParent->setSiteIsAlive( false ); + }; +}; + +// this is global and not a class member to keep crud out of the header file +namespace { + boost::intrusive_ptr< LLIamHereLogin > gResponsePtr = 0; +}; + + +//--------------------------------------------------------------------------- +// Public methods +//--------------------------------------------------------------------------- +LLPanelLogin::LLPanelLogin(const LLRect &rect, + BOOL show_server, + void (*callback)(S32 option, void* user_data), + void *cb_data) +: LLPanel(), + mLogoImage(), + mCallback(callback), + mCallbackData(cb_data), + mHtmlAvailable( TRUE ), + mListener(new LLPanelLoginListener(this)) +{ + setBackgroundVisible(FALSE); + setBackgroundOpaque(TRUE); + + // instance management + if (LLPanelLogin::sInstance) + { + llwarns << "Duplicate instance of login view deleted" << llendl; + // Don't leave bad pointer in gFocusMgr + gFocusMgr.setDefaultKeyboardFocus(NULL); + + delete LLPanelLogin::sInstance; + } + + mPasswordModified = FALSE; + LLPanelLogin::sInstance = this; + + LLView* login_holder = gViewerWindow->getLoginPanelHolder(); + if (login_holder) + { + login_holder->addChild(this); + } + + // Logo + mLogoImage = LLUI::getUIImage("startup_logo"); + + buildFromFile( "panel_login.xml"); + + // Legacy login web page is hidden under the menu bar. + // Adjust reg-in-client web browser widget to not be hidden. + if (gSavedSettings.getBOOL("RegInClient")) + { + reshape(rect.getWidth(), rect.getHeight() - MENU_BAR_HEIGHT); + } + else + { + reshape(rect.getWidth(), rect.getHeight()); + } + + getChild<LLLineEditor>("password_edit")->setKeystrokeCallback(onPassKey, this); + + // change z sort of clickable text to be behind buttons + //sendChildToBack(getChildView("channel_text")); + sendChildToBack(getChildView("forgot_password_text")); + + if(LLStartUp::getStartSLURL().getType() != LLSLURL::LOCATION) + { + LLSLURL slurl(gSavedSettings.getString("LoginLocation")); + LLStartUp::setStartSLURL(slurl); + } + updateLocationCombo(false); + + gSavedSettings.getControl("SessionSettingsFile")->getSignal()->connect(boost::bind(&onModeChange)); + + LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo"); + server_choice_combo->setCommitCallback(onSelectServer, NULL); + server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1)); + updateServerCombo(); + + childSetAction("connect_btn", onClickConnect, this); + + getChild<LLPanel>("login")->setDefaultBtn("connect_btn"); + + std::string channel = LLVersionInfo::getChannel(); + std::string version = llformat("%s (%d)", + LLVersionInfo::getShortVersion().c_str(), + LLVersionInfo::getBuild()); + //LLTextBox* channel_text = getChild<LLTextBox>("channel_text"); + //channel_text->setTextArg("[CHANNEL]", channel); // though not displayed + //channel_text->setTextArg("[VERSION]", version); + //channel_text->setClickedCallback(onClickVersion, this); + + LLTextBox* forgot_password_text = getChild<LLTextBox>("forgot_password_text"); + forgot_password_text->setClickedCallback(onClickForgotPassword, NULL); + + LLTextBox* create_new_account_text = getChild<LLTextBox>("create_new_account_text"); + create_new_account_text->setClickedCallback(onClickNewAccount, NULL); + + LLTextBox* need_help_text = getChild<LLTextBox>("login_help"); + need_help_text->setClickedCallback(onClickHelp, NULL); + + // get the web browser control + LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html"); + web_browser->addObserver(this); + + // Clear the browser's cache to avoid any potential for the cache messing up the login screen. + web_browser->clearCache(); + + reshapeBrowser(); + + // kick off a request to grab the url manually + gResponsePtr = LLIamHereLogin::build( this ); + + LLHTTPClient::head( LLGridManager::getInstance()->getLoginPage(), gResponsePtr ); + + // Show last logged in user favorites in "Start at" combo. + addUsersWithFavoritesToUsername(); + getChild<LLComboBox>("username_combo")->setTextChangedCallback(boost::bind(&LLPanelLogin::addFavoritesToStartLocation, this)); + + updateLocationCombo(false); + +} + +void LLPanelLogin::addUsersWithFavoritesToUsername() +{ + LLComboBox* combo = getChild<LLComboBox>("username_combo"); + if (!combo) return; + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml"); + LLSD fav_llsd; + llifstream file; + file.open(filename); + if (!file.is_open()) return; + LLSDSerialize::fromXML(fav_llsd, file); + for (LLSD::map_const_iterator iter = fav_llsd.beginMap(); + iter != fav_llsd.endMap(); ++iter) + { + combo->add(iter->first); + } +} + +void LLPanelLogin::addFavoritesToStartLocation() +{ + LLComboBox* combo = getChild<LLComboBox>("start_location_combo"); + if (!combo) return; + int num_items = combo->getItemCount(); + for (int i = num_items - 1; i > 2; i--) + { + combo->remove(i); + } + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml"); + LLSD fav_llsd; + llifstream file; + file.open(filename); + if (!file.is_open()) return; + LLSDSerialize::fromXML(fav_llsd, file); + for (LLSD::map_const_iterator iter = fav_llsd.beginMap(); + iter != fav_llsd.endMap(); ++iter) + { + if(iter->first != getChild<LLComboBox>("username_combo")->getSimple()) continue; + combo->addSeparator(); + LLSD user_llsd = iter->second; + for (LLSD::array_const_iterator iter1 = user_llsd.beginArray(); + iter1 != user_llsd.endArray(); ++iter1) + { + std::string label = (*iter1)["name"].asString(); + std::string value = (*iter1)["slurl"].asString(); + if(label != "" && value != "") + { + combo->add(label, value); + } + } + break; + } +} + +// force the size to be correct (XML doesn't seem to be sufficient to do this) +// (with some padding so the other login screen doesn't show through) +void LLPanelLogin::reshapeBrowser() +{ + LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html"); + LLRect rect = gViewerWindow->getWindowRectScaled(); + LLRect html_rect; + html_rect.setCenterAndSize( + rect.getCenterX() - 2, rect.getCenterY() + 40, + rect.getWidth() + 6, rect.getHeight() - 78 ); + web_browser->setRect( html_rect ); + web_browser->reshape( html_rect.getWidth(), html_rect.getHeight(), TRUE ); + reshape( rect.getWidth(), rect.getHeight(), 1 ); +} + +void LLPanelLogin::setSiteIsAlive( bool alive ) +{ + LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html"); + // if the contents of the site was retrieved + if ( alive ) + { + if ( web_browser ) + { + loadLoginPage(); + + // mark as available + mHtmlAvailable = TRUE; + } + } + else + // the site is not available (missing page, server down, other badness) + { + if ( web_browser ) + { + // hide browser control (revealing default one) + web_browser->setVisible( FALSE ); + + // mark as unavailable + mHtmlAvailable = FALSE; + } + } +} + + +LLPanelLogin::~LLPanelLogin() +{ + LLPanelLogin::sInstance = NULL; + + // tell the responder we're not here anymore + if ( gResponsePtr ) + gResponsePtr->setParent( 0 ); + + //// We know we're done with the image, so be rid of it. + //gTextureList.deleteImage( mLogoImage ); + + // Controls having keyboard focus by default + // must reset it on destroy. (EXT-2748) + gFocusMgr.setDefaultKeyboardFocus(NULL); +} + +// virtual +void LLPanelLogin::draw() +{ + glPushMatrix(); + { + F32 image_aspect = 1.333333f; + F32 view_aspect = (F32)getRect().getWidth() / (F32)getRect().getHeight(); + // stretch image to maintain aspect ratio + if (image_aspect > view_aspect) + { + glTranslatef(-0.5f * (image_aspect / view_aspect - 1.f) * getRect().getWidth(), 0.f, 0.f); + glScalef(image_aspect / view_aspect, 1.f, 1.f); + } + + S32 width = getRect().getWidth(); + S32 height = getRect().getHeight(); + + if ( mHtmlAvailable ) + { + if (getChild<LLView>("login_widgets")->getVisible()) + { + // draw a background box in black + gl_rect_2d( 0, height - 264, width, 264, LLColor4::black ); + // draw the bottom part of the background image + // just the blue background to the native client UI + mLogoImage->draw(0, -264, width + 8, mLogoImage->getHeight()); + } + } + else + { + // the HTML login page is not available so default to the original screen + S32 offscreen_part = height / 3; + mLogoImage->draw(0, -offscreen_part, width, height+offscreen_part); + }; + } + glPopMatrix(); + + LLPanel::draw(); +} + +// virtual +BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask) +{ + if ( KEY_F1 == key ) + { + LLViewerHelp* vhelp = LLViewerHelp::getInstance(); + vhelp->showTopic(vhelp->f1HelpTopic()); + return TRUE; + } + + return LLPanel::handleKeyHere(key, mask); +} + +// virtual +void LLPanelLogin::setFocus(BOOL b) +{ + if(b != hasFocus()) + { + if(b) + { + LLPanelLogin::giveFocus(); + } + else + { + LLPanel::setFocus(b); + } + } +} + +// static +void LLPanelLogin::giveFocus() +{ + if( sInstance ) + { + // Grab focus and move cursor to first blank input field + std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString(); + std::string pass = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString(); + + BOOL have_username = !username.empty(); + BOOL have_pass = !pass.empty(); + + LLLineEditor* edit = NULL; + LLComboBox* combo = NULL; + if (have_username && !have_pass) + { + // User saved his name but not his password. Move + // focus to password field. + edit = sInstance->getChild<LLLineEditor>("password_edit"); + } + else + { + // User doesn't have a name, so start there. + combo = sInstance->getChild<LLComboBox>("username_combo"); + } + + if (edit) + { + edit->setFocus(TRUE); + edit->selectAll(); + } + else if (combo) + { + combo->setFocus(TRUE); + } + } +} + +// static +void LLPanelLogin::showLoginWidgets() +{ + // *NOTE: Mani - This may or may not be obselete code. + // It seems to be part of the defunct? reg-in-client project. + sInstance->getChildView("login_widgets")->setVisible( true); + LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); + sInstance->reshapeBrowser(); + // *TODO: Append all the usual login parameters, like first_login=Y etc. + std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage(); + web_browser->navigateTo( splash_screen_url, "text/html" ); + LLUICtrl* username_combo = sInstance->getChild<LLUICtrl>("username_combo"); + username_combo->setFocus(TRUE); +} + +// static +void LLPanelLogin::show(const LLRect &rect, + BOOL show_server, + void (*callback)(S32 option, void* user_data), + void* callback_data) +{ + new LLPanelLogin(rect, show_server, callback, callback_data); + + if( !gFocusMgr.getKeyboardFocus() ) + { + // Grab focus and move cursor to first enabled control + sInstance->setFocus(TRUE); + } + + // Make sure that focus always goes here (and use the latest sInstance that was just created) + gFocusMgr.setDefaultKeyboardFocus(sInstance); +} + +// static +void LLPanelLogin::setFields(LLPointer<LLCredential> credential, + BOOL remember) +{ + if (!sInstance) + { + llwarns << "Attempted fillFields with no login view shown" << llendl; + return; + } + LL_INFOS("Credentials") << "Setting login fields to " << *credential << LL_ENDL; + + LLSD identifier = credential->getIdentifier(); + if((std::string)identifier["type"] == "agent") + { + std::string firstname = identifier["first_name"].asString(); + std::string lastname = identifier["last_name"].asString(); + std::string login_id = firstname; + if (!lastname.empty() && lastname != "Resident") + { + // support traditional First Last name SLURLs + login_id += " "; + login_id += lastname; + } + sInstance->getChild<LLComboBox>("username_combo")->setLabel(login_id); + } + else if((std::string)identifier["type"] == "account") + { + sInstance->getChild<LLComboBox>("username_combo")->setLabel((std::string)identifier["account_name"]); + } + else + { + sInstance->getChild<LLComboBox>("username_combo")->setLabel(std::string()); + } + sInstance->addFavoritesToStartLocation(); + // if the password exists in the credential, set the password field with + // a filler to get some stars + LLSD authenticator = credential->getAuthenticator(); + LL_INFOS("Credentials") << "Setting authenticator field " << authenticator["type"].asString() << LL_ENDL; + if(authenticator.isMap() && + authenticator.has("secret") && + (authenticator["secret"].asString().size() > 0)) + { + + // This is a MD5 hex digest of a password. + // We don't actually use the password input field, + // fill it with MAX_PASSWORD characters so we get a + // nice row of asterixes. + const std::string filler("123456789!123456"); + sInstance->getChild<LLUICtrl>("password_edit")->setValue(std::string("123456789!123456")); + } + else + { + sInstance->getChild<LLUICtrl>("password_edit")->setValue(std::string()); + } + sInstance->getChild<LLUICtrl>("remember_check")->setValue(remember); +} + + +// static +void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, + BOOL& remember) +{ + if (!sInstance) + { + llwarns << "Attempted getFields with no login view shown" << llendl; + return; + } + + // load the credential so we can pass back the stored password or hash if the user did + // not modify the password field. + + credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + + LLSD identifier = LLSD::emptyMap(); + LLSD authenticator = LLSD::emptyMap(); + + if(credential.notNull()) + { + authenticator = credential->getAuthenticator(); + } + + std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString(); + LLStringUtil::trim(username); + std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString(); + + LL_INFOS2("Credentials", "Authentication") << "retrieving username:" << username << LL_ENDL; + // determine if the username is a first/last form or not. + size_t separator_index = username.find_first_of(' '); + if (separator_index == username.npos + && !LLGridManager::getInstance()->isSystemGrid()) + { + LL_INFOS2("Credentials", "Authentication") << "account: " << username << LL_ENDL; + // single username, so this is a 'clear' identifier + identifier["type"] = CRED_IDENTIFIER_TYPE_ACCOUNT; + identifier["account_name"] = username; + + if (LLPanelLogin::sInstance->mPasswordModified) + { + authenticator = LLSD::emptyMap(); + // password is plaintext + authenticator["type"] = CRED_AUTHENTICATOR_TYPE_CLEAR; + authenticator["secret"] = password; + } + } + else + { + // Be lenient in terms of what separators we allow for two-word names + // and allow legacy users to login with firstname.lastname + separator_index = username.find_first_of(" ._"); + std::string first = username.substr(0, separator_index); + std::string last; + if (separator_index != username.npos) + { + last = username.substr(separator_index+1, username.npos); + LLStringUtil::trim(last); + } + else + { + // ...on Linden grids, single username users as considered to have + // last name "Resident" + // *TODO: Make login.cgi support "account_name" like above + last = "Resident"; + } + + if (last.find_first_of(' ') == last.npos) + { + LL_INFOS2("Credentials", "Authentication") << "agent: " << username << LL_ENDL; + // traditional firstname / lastname + identifier["type"] = CRED_IDENTIFIER_TYPE_AGENT; + identifier["first_name"] = first; + identifier["last_name"] = last; + + if (LLPanelLogin::sInstance->mPasswordModified) + { + authenticator = LLSD::emptyMap(); + authenticator["type"] = CRED_AUTHENTICATOR_TYPE_HASH; + authenticator["algorithm"] = "md5"; + LLMD5 pass((const U8 *)password.c_str()); + char md5pass[33]; /* Flawfinder: ignore */ + pass.hex_digest(md5pass); + authenticator["secret"] = md5pass; + } + } + } + credential = gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), identifier, authenticator); + remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); +} + +// static +BOOL LLPanelLogin::isGridComboDirty() +{ + BOOL user_picked = FALSE; + if (!sInstance) + { + llwarns << "Attempted getServer with no login view shown" << llendl; + } + else + { + LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo"); + user_picked = combo->isDirty(); + } + return user_picked; +} + +// static +BOOL LLPanelLogin::areCredentialFieldsDirty() +{ + if (!sInstance) + { + llwarns << "Attempted getServer with no login view shown" << llendl; + } + else + { + std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString(); + LLStringUtil::trim(username); + std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString(); + LLComboBox* combo = sInstance->getChild<LLComboBox>("username_combo"); + if(combo && combo->isDirty()) + { + return true; + } + LLLineEditor* ctrl = sInstance->getChild<LLLineEditor>("password_edit"); + if(ctrl && ctrl->isDirty()) + { + return true; + } + } + return false; +} + + +// static +void LLPanelLogin::updateLocationCombo( bool force_visible ) +{ + if (!sInstance) + { + return; + } + + LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo"); + + switch(LLStartUp::getStartSLURL().getType()) + { + case LLSLURL::LOCATION: + { + + combo->setCurrentByIndex( 2 ); + combo->setTextEntry(LLStartUp::getStartSLURL().getLocationString()); + break; + } + case LLSLURL::HOME_LOCATION: + combo->setCurrentByIndex(1); + break; + default: + combo->setCurrentByIndex(0); + break; + } + + BOOL show_start = TRUE; + + if ( ! force_visible ) + show_start = gSavedSettings.getBOOL("ShowStartLocation"); + + sInstance->getChildView("start_location_combo")->setVisible( show_start); + sInstance->getChildView("start_location_text")->setVisible( show_start); + + BOOL show_server = gSavedSettings.getBOOL("ForceShowGrid"); + sInstance->getChildView("server_combo_text")->setVisible( show_server); + sInstance->getChildView("server_combo")->setVisible( show_server); +} + +// static +void LLPanelLogin::updateStartSLURL() +{ + if (!sInstance) return; + + LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo"); + S32 index = combo->getCurrentIndex(); + + switch (index) + { + case 0: + { + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST)); + break; + } + case 1: + { + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); + break; + } + default: + { + LLSLURL slurl = LLSLURL(combo->getValue().asString()); + if(slurl.getType() == LLSLURL::LOCATION) + { + // we've changed the grid, so update the grid selection + LLStartUp::setStartSLURL(slurl); + } + break; + } + } +} + + +void LLPanelLogin::setLocation(const LLSLURL& slurl) +{ + LLStartUp::setStartSLURL(slurl); + updateServer(); +} + +// static +void LLPanelLogin::closePanel() +{ + if (sInstance) + { + LLPanelLogin::sInstance->getParent()->removeChild( LLPanelLogin::sInstance ); + + delete sInstance; + sInstance = NULL; + } +} + +// static +void LLPanelLogin::setAlwaysRefresh(bool refresh) +{ + if (LLStartUp::getStartupState() >= STATE_LOGIN_CLEANUP) return; + + LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); + + if (web_browser) + { + web_browser->setAlwaysRefresh(refresh); + } +} + + + +void LLPanelLogin::loadLoginPage() +{ + if (!sInstance) return; + + std::ostringstream oStr; + + std::string login_page = LLGridManager::getInstance()->getLoginPage(); + + oStr << login_page; + + // Use the right delimeter depending on how LLURI parses the URL + LLURI login_page_uri = LLURI(login_page); + + std::string first_query_delimiter = "&"; + if (login_page_uri.queryMap().size() == 0) + { + first_query_delimiter = "?"; + } + + // Language + std::string language = LLUI::getLanguage(); + oStr << first_query_delimiter<<"lang=" << language; + + // First Login? + if (gSavedSettings.getBOOL("FirstLoginThisInstall")) + { + oStr << "&firstlogin=TRUE"; + } + + // Channel and Version + std::string version = llformat("%s (%d)", + LLVersionInfo::getShortVersion().c_str(), + LLVersionInfo::getBuild()); + + char* curl_channel = curl_escape(LLVersionInfo::getChannel().c_str(), 0); + char* curl_version = curl_escape(version.c_str(), 0); + + oStr << "&channel=" << curl_channel; + oStr << "&version=" << curl_version; + + curl_free(curl_channel); + curl_free(curl_version); + + // Grid + char* curl_grid = curl_escape(LLGridManager::getInstance()->getGridLabel().c_str(), 0); + oStr << "&grid=" << curl_grid; + curl_free(curl_grid); + + // add OS info + char * os_info = curl_escape(LLAppViewer::instance()->getOSInfo().getOSStringSimple().c_str(), 0); + oStr << "&os=" << os_info; + curl_free(os_info); + + + gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid()); + gLoginMenuBarView->setBackgroundColor(gMenuBarView->getBackgroundColor()); + + LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); + + // navigate to the "real" page + if (gSavedSettings.getBOOL("RegInClient")) + { + web_browser->setFocus(TRUE); + login_page = sInstance->getString("reg_in_client_url"); + web_browser->navigateTo(login_page, "text/html"); + } + else + { + web_browser->navigateTo( oStr.str(), "text/html" ); + } +} + +void LLPanelLogin::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event) +{ + if(event == MEDIA_EVENT_NAVIGATE_COMPLETE) + { + LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); + if (web_browser) + { + // *HACK HACK HACK HACK! + /* Stuff a Tab key into the browser now so that the first field will + ** get the focus! The embedded javascript on the page that properly + ** sets the initial focus in a real web browser is not working inside + ** the viewer, so this is an UGLY HACK WORKAROUND for now. + */ + // Commented out as it's not reliable + //web_browser->handleKey(KEY_TAB, MASK_NONE, false); + } + } +} + +//--------------------------------------------------------------------------- +// Protected methods +//--------------------------------------------------------------------------- + +// static +void LLPanelLogin::onClickConnect(void *) +{ + if (sInstance && sInstance->mCallback) + { + // tell the responder we're not here anymore + if ( gResponsePtr ) + gResponsePtr->setParent( 0 ); + + // JC - Make sure the fields all get committed. + sInstance->setFocus(FALSE); + + LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo"); + LLSD combo_val = combo->getSelectedValue(); + if (combo_val.isUndefined()) + { + combo_val = combo->getValue(); + } + if(combo_val.isUndefined()) + { + LLNotificationsUtil::add("StartRegionEmpty"); + return; + } + try + { + LLGridManager::getInstance()->setGridChoice(combo_val.asString()); + } + catch (LLInvalidGridName ex) + { + LLSD args; + args["GRID"] = combo_val.asString(); + LLNotificationsUtil::add("InvalidGrid", args); + return; + } + updateStartSLURL(); + std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString(); + + + if(username.empty()) + { + // user must type in something into the username field + LLNotificationsUtil::add("MustHaveAccountToLogIn"); + } + else + { + LLPointer<LLCredential> cred; + BOOL remember; + getFields(cred, remember); + std::string identifier_type; + cred->identifierType(identifier_type); + LLSD allowed_credential_types; + LLGridManager::getInstance()->getLoginIdentifierTypes(allowed_credential_types); + + // check the typed in credential type against the credential types expected by the server. + for(LLSD::array_iterator i = allowed_credential_types.beginArray(); + i != allowed_credential_types.endArray(); + i++) + { + + if(i->asString() == identifier_type) + { + // yay correct credential type + sInstance->mCallback(0, sInstance->mCallbackData); + return; + } + } + + // Right now, maingrid is the only thing that is picky about + // credential format, as it doesn't yet allow account (single username) + // format creds. - Rox. James, we wanna fix the message when we change + // this. + LLNotificationsUtil::add("InvalidCredentialFormat"); + } + } +} + +/* +// static +bool LLPanelLogin::newAccountAlertCallback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + llinfos << "Going to account creation URL" << llendl; + LLWeb::loadURLExternal( LLNotifications::instance().getGlobalString("CREATE_ACCOUNT_URL")); + } + else + { + sInstance->setFocus(TRUE); + } + return false; +} +*/ + +// static +void LLPanelLogin::onClickNewAccount(void*) +{ + LLWeb::loadURLExternal(sInstance->getString("create_account_url")); +} + + +// static +void LLPanelLogin::onClickVersion(void*) +{ + LLFloaterReg::showInstance("sl_about"); +} + +//static +void LLPanelLogin::onClickForgotPassword(void*) +{ + if (sInstance ) + { + LLWeb::loadURLExternal(sInstance->getString( "forgot_password_url" )); + } +} + +//static +void LLPanelLogin::onClickHelp(void*) +{ + if (sInstance) + { + LLViewerHelp* vhelp = LLViewerHelp::getInstance(); + vhelp->showTopic(vhelp->preLoginTopic()); + } +} + +// static +void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data) +{ + LLPanelLogin *This = (LLPanelLogin *) user_data; + This->mPasswordModified = TRUE; + if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == FALSE) + { +// *TODO: use another way to notify user about enabled caps lock, see EXT-6858 + sCapslockDidNotification = TRUE; + } +} + + +void LLPanelLogin::updateServer() +{ + try + { + + updateServerCombo(); + // if they've selected another grid, we should load the credentials + // for that grid and set them to the UI. + if(sInstance && !sInstance->areCredentialFieldsDirty()) + { + LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + bool remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); + sInstance->setFields(credential, remember); + } + // grid changed so show new splash screen (possibly) + loadLoginPage(); + updateLocationCombo(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION); + } + catch (LLInvalidGridName ex) + { + // do nothing + } +} + +void LLPanelLogin::updateServerCombo() +{ + if (!sInstance) + { + return; + } + // We add all of the possible values, sorted, and then add a bar and the current value at the top + LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo"); + server_choice_combo->removeall(); + + std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(!gSavedSettings.getBOOL("ShowBetaGrids")); + + for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin(); + grid_choice != known_grids.end(); + grid_choice++) + { + if (!grid_choice->first.empty()) + { + server_choice_combo->add(grid_choice->second, grid_choice->first); + } + } + server_choice_combo->sortByName(); + + server_choice_combo->addSeparator(ADD_TOP); + + server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(), + LLGridManager::getInstance()->getGrid(), ADD_TOP); + + server_choice_combo->selectFirstItem(); +} + +// static +void LLPanelLogin::onSelectServer(LLUICtrl*, void*) +{ + // *NOTE: The paramters for this method are ignored. + // LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe, void*) + // calls this method. + LL_INFOS("AppInit") << "onSelectServer" << LL_ENDL; + // The user twiddled with the grid choice ui. + // apply the selection to the grid setting. + LLPointer<LLCredential> credential; + + LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo"); + LLSD combo_val = combo->getSelectedValue(); + if (combo_val.isUndefined()) + { + combo_val = combo->getValue(); + } + + combo = sInstance->getChild<LLComboBox>("start_location_combo"); + combo->setCurrentByIndex(1); + LLStartUp::setStartSLURL(LLSLURL(gSavedSettings.getString("LoginLocation"))); + LLGridManager::getInstance()->setGridChoice(combo_val.asString()); + // This new selection will override preset uris + // from the command line. + updateServer(); + updateLocationCombo(false); + updateLoginPanelLinks(); +} + +void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe) +{ + if (!sInstance) + { + return; + } + + LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo"); + if(fe == combo) + { + onSelectServer(combo, NULL); + } +} + +void LLPanelLogin::updateLoginPanelLinks() +{ + LLSD grid_data; + LLGridManager::getInstance()->getGridInfo(grid_data); + bool system_grid = grid_data.has(GRID_IS_SYSTEM_GRID_VALUE); + + // need to call through sInstance, as it's called from onSelectServer, which + // is static. + sInstance->getChildView("create_new_account_text")->setVisible( system_grid); + sInstance->getChildView("forgot_password_text")->setVisible( system_grid); +} + +//static +void LLPanelLogin::onModeChange() +{ + LLNotificationsUtil::add("ModeChange", LLSD(), LLSD(), boost::bind(&onModeChangeConfirm, _1, _2)); +} + +//static +void LLPanelLogin::onModeChangeConfirm(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch (option) + { + case 0: + LLAppViewer::instance()->requestQuit(); + break; + case 1: + // do nothing + break; + default: + break; + } +} diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index 8aaa7f0e13..a9bb01ac70 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -96,6 +96,7 @@ bool LLSideTray::instanceCreated () class LLSideTrayTab: public LLPanel { + LOG_CLASS(LLSideTrayTab); friend class LLUICtrlFactory; friend class LLSideTray; public: @@ -122,6 +123,8 @@ protected: void undock(LLFloater* floater_tab); LLSideTray* getSideTray(); + + void onFloaterClose(LLSD::Boolean app_quitting); public: virtual ~LLSideTrayTab(); @@ -140,6 +143,8 @@ public: void onOpen (const LLSD& key); void toggleTabDocked(); + void setDocked(bool dock); + bool isDocked() const; BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); @@ -151,6 +156,7 @@ private: std::string mDescription; LLView* mMainPanel; + boost::signals2::connection mFloaterCloseConn; }; LLSideTrayTab::LLSideTrayTab(const Params& p) @@ -271,6 +277,35 @@ void LLSideTrayTab::toggleTabDocked() LLFloaterReg::toggleInstance("side_bar_tab", tab_name); } +// Same as toggleTabDocked() apart from making sure that we do exactly what we want. +void LLSideTrayTab::setDocked(bool dock) +{ + if (isDocked() == dock) + { + llwarns << "Tab " << getName() << " is already " << (dock ? "docked" : "undocked") << llendl; + return; + } + + toggleTabDocked(); +} + +bool LLSideTrayTab::isDocked() const +{ + return dynamic_cast<LLSideTray*>(getParent()) != NULL; +} + +void LLSideTrayTab::onFloaterClose(LLSD::Boolean app_quitting) +{ + // If user presses Ctrl-Shift-W, handle that gracefully by docking all + // undocked tabs before their floaters get destroyed (STORM-1016). + + // Don't dock on quit for the current dock state to be correctly saved. + if (app_quitting) return; + + lldebugs << "Forcibly docking tab " << getName() << llendl; + setDocked(true); +} + BOOL LLSideTrayTab::handleScrollWheel(S32 x, S32 y, S32 clicks) { // Let children handle the event @@ -294,6 +329,7 @@ void LLSideTrayTab::dock(LLFloater* floater_tab) return; } + mFloaterCloseConn.disconnect(); setRect(side_tray->getLocalRect()); reshape(getRect().getWidth(), getRect().getHeight()); @@ -342,6 +378,7 @@ void LLSideTrayTab::undock(LLFloater* floater_tab) } floater_tab->addChild(this); + mFloaterCloseConn = floater_tab->setCloseCallback(boost::bind(&LLSideTrayTab::onFloaterClose, this, _2)); floater_tab->setTitle(mTabTitle); floater_tab->setName(getName()); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 86087ba0a1..87b33980d6 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -749,8 +749,6 @@ bool idle_startup() } LLPanelLogin::giveFocus(); - gSavedSettings.setBOOL("FirstRunThisInstall", FALSE); - LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input } else diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 582f50ba37..9549f180df 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -83,7 +83,7 @@ LLToolPie::LLToolPie() mMouseOutsideSlop( false ), mMouseSteerX(-1), mMouseSteerY(-1), - mAbortClickToWalk(false), + mBlockClickToWalk(false), mClickAction(0), mClickActionBuyEnabled( gSavedSettings.getBOOL("ClickActionBuyEnabled") ), mClickActionPayEnabled( gSavedSettings.getBOOL("ClickActionPayEnabled") ) @@ -303,7 +303,7 @@ BOOL LLToolPie::handleLeftClickPick() if (gFocusMgr.getKeyboardFocus()) { // don't click to walk on attempt to give focus to world - mAbortClickToWalk = true; + mBlockClickToWalk = true; gFocusMgr.setKeyboardFocus(NULL); } @@ -625,7 +625,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) // let media have first pass at click if (handleMediaMouseUp() || LLViewerMediaFocus::getInstance()->getFocus()) { - mAbortClickToWalk = true; + mBlockClickToWalk = true; } stopCameraSteering(); mMouseButtonDown = false; @@ -633,7 +633,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) if (click_action == CLICK_ACTION_NONE // not doing 1-click action && gSavedSettings.getBOOL("ClickToWalk") // click to walk enabled && !gAgent.getFlying() // don't auto-navigate while flying until that works - && !mAbortClickToWalk // another behavior hasn't cancelled click to walk + && !mBlockClickToWalk // another behavior hasn't cancelled click to walk && !mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick && (mPick.mPickType == LLPickInfo::PICK_LAND // we clicked on land || mPick.mObjectID.notNull())) // or on an object @@ -658,11 +658,11 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE); mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal); mAutoPilotDestination->setPixelSize(5); - mAutoPilotDestination->setColor(LLColor4U(50, 50, 200)); + mAutoPilotDestination->setColor(LLColor4U(170, 210, 190)); mAutoPilotDestination->setDuration(3.f); handle_go_to(); - mAbortClickToWalk = false; + mBlockClickToWalk = false; return TRUE; } @@ -675,7 +675,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) LLToolMgr::getInstance()->clearTransientTool(); gAgentCamera.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on - mAbortClickToWalk = false; + mBlockClickToWalk = false; return LLTool::handleMouseUp(x, y, mask); } @@ -1298,7 +1298,8 @@ void LLToolPie::VisitHomePage(const LLPickInfo& info) void LLToolPie::handleSelect() { - mAbortClickToWalk = true; + // tool is reselected when app gets focus, etc. + mBlockClickToWalk = true; } void LLToolPie::handleDeselect() @@ -1738,7 +1739,7 @@ bool intersect_ray_with_sphere( const LLVector3& ray_pt, const LLVector3& ray_di void LLToolPie::startCameraSteering() { mMouseOutsideSlop = true; - mAbortClickToWalk = true; + mBlockClickToWalk = true; if (gAgentCamera.getFocusOnAvatar()) { @@ -1777,7 +1778,7 @@ void LLToolPie::startCameraSteering() if (mMouseSteerGrabPoint) { mMouseSteerGrabPoint->markDead(); } mMouseSteerGrabPoint = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE); mMouseSteerGrabPoint->setPositionGlobal(mSteerPick.mPosGlobal); - mMouseSteerGrabPoint->setColor(LLColor4U(50, 50, 200)); + mMouseSteerGrabPoint->setColor(LLColor4U(170, 210, 190)); mMouseSteerGrabPoint->setPixelSize(5); mMouseSteerGrabPoint->setDuration(2.f); } diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index 22e77a3159..22359a6db8 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -66,6 +66,7 @@ public: LLViewerObject* getClickActionObject() { return mClickActionObject; } LLObjectSelection* getLeftClickSelection() { return (LLObjectSelection*)mLeftClickSelection; } void resetSelection(); + void blockClickToWalk() { mBlockClickToWalk = true; } static void selectionPropertiesReceived(); @@ -105,7 +106,7 @@ private: LLPointer<LLHUDEffectBlob> mAutoPilotDestination; LLPointer<LLHUDEffectBlob> mMouseSteerGrabPoint; bool mClockwise; - bool mAbortClickToWalk; + bool mBlockClickToWalk; LLUUID mMediaMouseCaptureID; LLPickInfo mPick; LLPickInfo mHoverPick; diff --git a/indra/newview/lltracker.h b/indra/newview/lltracker.h index c0c154abe8..8e916af315 100644 --- a/indra/newview/lltracker.h +++ b/indra/newview/lltracker.h @@ -75,7 +75,7 @@ public: // these are static so that they can be used a callbacks static ETrackingStatus getTrackingStatus() { return instance()->mTrackingStatus; } static ETrackingLocationType getTrackedLocationType() { return instance()->mTrackingLocationType; } - static BOOL isTracking(void*) { return (BOOL) instance()->mTrackingStatus; } + static BOOL isTracking(void*) { return instance()->mTrackingStatus != TRACKING_NOTHING; } static void stopTracking(void*); static void clearFocus(); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 26b6ffa19e..f5b0857425 100755 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -845,37 +845,50 @@ class LLAdvancedCheckFeature : public view_listener_t void toggle_destination_and_avatar_picker(const LLSD& show) { S32 panel_idx = show.isDefined() ? show.asInteger() : -1; - LLView* container = gViewerWindow->getRootView()->getChildView("avatar_picker_and_destination_guide_container"); + LLView* container = gViewerWindow->getRootView()->findChildView("avatar_picker_and_destination_guide_container"); + if (!container) return; + LLMediaCtrl* destinations = container->findChild<LLMediaCtrl>("destination_guide_contents"); LLMediaCtrl* avatar_picker = container->findChild<LLMediaCtrl>("avatar_picker_contents"); + if (!destinations || !avatar_picker) return; + LLButton* avatar_btn = gViewerWindow->getRootView()->getChildView("bottom_tray")->getChild<LLButton>("avatar_btn"); LLButton* destination_btn = gViewerWindow->getRootView()->getChildView("bottom_tray")->getChild<LLButton>("destination_btn"); switch(panel_idx) { case 0: - container->setVisible(true); - destinations->setVisible(true); - avatar_picker->setVisible(false); - LLFirstUse::notUsingDestinationGuide(false); - avatar_btn->setToggleState(false); - destination_btn->setToggleState(true); + if (!destinations->getVisible()) + { + container->setVisible(true); + destinations->setVisible(true); + avatar_picker->setVisible(false); + LLFirstUse::notUsingDestinationGuide(false); + avatar_btn->setToggleState(false); + destination_btn->setToggleState(true); + return; + } break; case 1: - container->setVisible(true); - destinations->setVisible(false); - avatar_picker->setVisible(true); - avatar_btn->setToggleState(true); - destination_btn->setToggleState(false); + if (!avatar_picker->getVisible()) + { + container->setVisible(true); + destinations->setVisible(false); + avatar_picker->setVisible(true); + avatar_btn->setToggleState(true); + destination_btn->setToggleState(false); + return; + } break; default: - container->setVisible(false); - destinations->setVisible(false); - avatar_picker->setVisible(false); - avatar_btn->setToggleState(false); - destination_btn->setToggleState(false); break; } + + container->setVisible(false); + destinations->setVisible(false); + avatar_picker->setVisible(false); + avatar_btn->setToggleState(false); + destination_btn->setToggleState(false); }; @@ -7166,7 +7179,13 @@ LLViewerMenuHolderGL::LLViewerMenuHolderGL(const LLViewerMenuHolderGL::Params& p BOOL LLViewerMenuHolderGL::hideMenus() { - BOOL handled = LLMenuHolderGL::hideMenus(); + BOOL handled = FALSE; + + if (LLMenuHolderGL::hideMenus()) + { + LLToolPie::instance().blockClickToWalk(); + handled = TRUE; + } // drop pie menu selection mParcelSelection = NULL; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index f1acd34e11..39ef56d156 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1930,6 +1930,11 @@ void LLViewerWindow::initWorldUI() avatar_picker->navigateTo(gSavedSettings.getString("AvatarPickerURL"), "text/html"); } + if (gSavedSettings.getBOOL("FirstLoginThisInstall")) + { + toggle_destination_and_avatar_picker(0); + gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE); + } } // Destroy the UI diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 87d8e54a89..bfcf130e33 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -696,4 +696,5 @@ with the same filename but different name <texture name="Yellow_Gradient" file_name="windows/yellow_gradient.png"/> <texture name="Popup_Caution" file_name="icons/pop_up_caution.png"/> + <texture name="Camera_Drag_Dot" file_name="world/CameraDragDot.png"/> </textures> diff --git a/indra/newview/skins/default/textures/world/CameraDragDot.png b/indra/newview/skins/default/textures/world/CameraDragDot.png Binary files differnew file mode 100644 index 0000000000..57698e1956 --- /dev/null +++ b/indra/newview/skins/default/textures/world/CameraDragDot.png diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 8655a6bf97..ea40a08c95 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -261,6 +261,17 @@ function="Floater.Toggle" parameter="world_map" /> </menu_item_check> + <menu_item_check + label="Search" + name="Search" + shortcut="control|F"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="search" /> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="search" /> + </menu_item_check> <menu_item_call label="Snapshot" name="Take Snapshot" diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index 43431ea7c1..1a00416b2a 100644 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -76,7 +76,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M follows="all" height="383" layout="topleft" - left="5" + left="3" name="tabs" tab_group="1" tab_min_width="70" @@ -84,7 +84,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M tab_position="top" top_pad="10" halign="center" - width="317"> + width="319"> <panel background_opaque="true" background_visible="true" @@ -106,20 +106,20 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M left="3" mouse_opaque="false" name="Net Map" - width="307" + width="305" height="140" - top="0"/> + top="5"/> <avatar_list allow_select="true" follows="top|left|bottom|right" - height="216" + height="211" ignore_online_status="true" layout="topleft" left="3" multi_select="true" name="avatar_list" top="145" - width="307" /> + width="306" /> <panel background_visible="true" follows="left|right|bottom" @@ -165,7 +165,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M layout="topleft" left_pad="1" name="dummy_icon" - width="241" + width="243" /> </panel> </panel> @@ -251,7 +251,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M top_pad="1" left="0" name="bottom_panel" - width="305"> + width="308"> <layout_panel auto_resize="false" height="25" @@ -300,7 +300,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M layout="topleft" name="dummy_panel" user_resize="false" - width="212"> + width="210"> <icon follows="bottom|left|right" height="25" @@ -309,7 +309,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M left="0" top="0" name="dummy_icon" - width="211" /> + width="210" /> </layout_panel> <layout_panel auto_resize="false" @@ -471,7 +471,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M layout="topleft" left_pad="1" name="dummy_icon" - width="209" + width="212" /> </panel> </panel> @@ -506,7 +506,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M height="27" label="bottom_panel" layout="topleft" - left="0" + left="3" name="bottom_panel" top_pad="0" width="313"> @@ -544,7 +544,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M layout="topleft" left_pad="1" name="dummy_icon" - width="241" + width="244" /> </panel> </panel> diff --git a/indra/newview/skins/default/xui/es/panel_landmark_info.xml b/indra/newview/skins/default/xui/es/panel_landmark_info.xml index 49a9f84cfe..1a0ac3ba79 100644 --- a/indra/newview/skins/default/xui/es/panel_landmark_info.xml +++ b/indra/newview/skins/default/xui/es/panel_landmark_info.xml @@ -19,7 +19,7 @@ [wkday,datetime,local][day,datetime,local] [mth,datetime,local] [year,datetime,local][hour,datetime,local]:[min,datetime,local]:[second,datetime,local] </string> <button name="back_btn" tool_tip="Atrás"/> - <text name="title" value="Añadir el perfil"/> + <text name="title" value="Perfil del lugar"/> <scroll_container name="place_scroll"> <panel name="scrolling_panel"> <text name="maturity_value" value="desconocido"/> diff --git a/indra/newview/skins/default/xui/es/panel_place_profile.xml b/indra/newview/skins/default/xui/es/panel_place_profile.xml index 524ba2253b..3c363859a4 100644 --- a/indra/newview/skins/default/xui/es/panel_place_profile.xml +++ b/indra/newview/skins/default/xui/es/panel_place_profile.xml @@ -5,7 +5,7 @@ <string name="anyone" value="Cualquiera"/> <string name="available" value="disponible"/> <string name="allocated" value="asignados"/> - <string name="title_place" value="Añadir el perfil"/> + <string name="title_place" value="Perfil del lugar"/> <string name="title_teleport_history" value="Historial de teleportes"/> <string name="not_available" value="(No disp.)"/> <string name="unknown" value="(desconocido)"/> @@ -42,7 +42,7 @@ [wkday,datetime,local][day,datetime,local] [mth,datetime,local] [year,datetime,local][hour,datetime,local]:[min,datetime,local]:[second,datetime,local] </string> <button name="back_btn" tool_tip="Atrás"/> - <text name="title" value="Añadir el perfil"/> + <text name="title" value="Perfil del lugar"/> <scroll_container name="place_scroll"> <panel name="scrolling_panel"> <text name="owner_label" value="Propietario:"/> |