diff options
37 files changed, 1325 insertions, 256 deletions
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 69ed0fb09c..de4456aa4e 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -160,7 +160,7 @@ void LLPluginClassMedia::idle(void) mPlugin->idle(); } - if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked())) + if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL)) { // Can't process a size change at this time } @@ -522,7 +522,15 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie } break; } - + +#if LL_DARWIN + if(modifiers & MASK_ALT) + { + // Option-key modified characters should be handled by the unicode input path instead of this one. + result = false; + } +#endif + if(result) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event"); @@ -682,6 +690,20 @@ void LLPluginClassMedia::sendPickFileResponse(const std::string &file) sendMessage(message); } +void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response"); + message.setValueBoolean("ok", ok); + message.setValue("username", username); + message.setValue("password", password); + if(mPlugin->isBlocked()) + { + // If the plugin sent a blocking pick-file request, the response should unblock it. + message.setValueBoolean("blocking_response", true); + } + sendMessage(message); +} + void LLPluginClassMedia::cut() { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut"); @@ -947,6 +969,12 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) { mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST); } + else if(message_name == "auth_request") + { + mAuthURL = message.getValue("url"); + mAuthRealm = message.getValue("realm"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST); + } else { LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; @@ -1019,6 +1047,15 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE); } + else if(message_name == "link_hovered") + { + // Link and text are not currently used -- the tooltip hover text is taken from the "title". + // message.getValue("link"); + mHoverText = message.getValue("title"); + // message.getValue("text"); + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED); + } else { LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; @@ -1192,6 +1229,20 @@ void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid) sendMessage(message); } +void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors"); + message.setValueBoolean("ignore", ignore); + sendMessage(message); +} + +void LLPluginClassMedia::setCertificateFilePath(const std::string& path) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_certificate_file_path"); + message.setValue("path", path); + sendMessage(message); +} + void LLPluginClassMedia::crashPlugin() { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash"); diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 9cb67fe909..fa4dc2b43f 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -85,6 +85,8 @@ public: void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; }; + void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; }; + // Returns true if all of the texture parameters (depth, format, size, and texture size) are set up and consistent. // This will initially be false, and will also be false for some time after setSize while the resize is processed. // Note that if this returns true, it is safe to use all the get() functions above without checking for invalid return values @@ -159,6 +161,8 @@ public: void sendPickFileResponse(const std::string &file); + void sendAuthResponse(bool ok, const std::string &username, const std::string &password); + // Valid after a MEDIA_EVENT_CURSOR_CHANGED event std::string getCursorName() const { return mCursorName; }; @@ -198,6 +202,8 @@ public: void setBrowserUserAgent(const std::string& user_agent); void proxyWindowOpened(const std::string &target, const std::string &uuid); void proxyWindowClosed(const std::string &uuid); + void ignore_ssl_cert_errors(bool ignore); + void setCertificateFilePath(const std::string& path); // This is valid after MEDIA_EVENT_NAVIGATE_BEGIN or MEDIA_EVENT_NAVIGATE_COMPLETE std::string getNavigateURI() const { return mNavigateURI; }; @@ -231,7 +237,14 @@ public: S32 getGeometryY() const { return mGeometryY; }; S32 getGeometryWidth() const { return mGeometryWidth; }; S32 getGeometryHeight() const { return mGeometryHeight; }; + + // These are valid during MEDIA_EVENT_AUTH_REQUEST + std::string getAuthURL() const { return mAuthURL; }; + std::string getAuthRealm() const { return mAuthRealm; }; + // This is valid during MEDIA_EVENT_LINK_HOVERED + std::string getHoverText() const { return mHoverText; }; + std::string getMediaName() const { return mMediaName; }; std::string getMediaDescription() const { return mMediaDescription; }; @@ -369,6 +382,9 @@ protected: S32 mGeometryY; S32 mGeometryWidth; S32 mGeometryHeight; + std::string mAuthURL; + std::string mAuthRealm; + std::string mHoverText; ///////////////////////////////////////// // media_time class diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h index c9efff216c..42e93cc6d7 100644 --- a/indra/llplugin/llpluginclassmediaowner.h +++ b/indra/llplugin/llpluginclassmediaowner.h @@ -59,7 +59,11 @@ public: MEDIA_EVENT_GEOMETRY_CHANGE, // The plugin requested its window geometry be changed (per the javascript window interface) MEDIA_EVENT_PLUGIN_FAILED_LAUNCH, // The plugin failed to launch - MEDIA_EVENT_PLUGIN_FAILED // The plugin died unexpectedly + MEDIA_EVENT_PLUGIN_FAILED, // The plugin died unexpectedly + + MEDIA_EVENT_AUTH_REQUEST, // The plugin wants to display an auth dialog + + MEDIA_EVENT_LINK_HOVERED // Got a "link hovered" event from the plugin } EMediaEvent; diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 940c7e7e18..6c0a2a9a10 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -38,6 +38,12 @@ static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack"); static LLLayoutStack::LayoutStackRegistry::Register<LLLayoutPanel> register_layout_panel("layout_panel"); +void LLLayoutStack::OrientationNames::declareValues() +{ + declare("horizontal", HORIZONTAL); + declare("vertical", VERTICAL); +} + // // LLLayoutPanel // @@ -47,47 +53,47 @@ LLLayoutPanel::LLLayoutPanel(const Params& p) mMaxDim(p.max_dim), mAutoResize(p.auto_resize), mUserResize(p.user_resize), - mCollapsed(FALSE), - mCollapseAmt(0.f), - mVisibleAmt(1.f), // default to fully visible - mResizeBar(NULL) - { + mCollapsed(FALSE), + mCollapseAmt(0.f), + mVisibleAmt(1.f), // default to fully visible + mResizeBar(NULL) +{ // panels initialized as hidden should not start out partially visible if (!getVisible()) - { + { mVisibleAmt = 0.f; - } - } + } +} void LLLayoutPanel::initFromParams(const Params& p) - { +{ LLPanel::initFromParams(p); setFollowsNone(); - } +} LLLayoutPanel::~LLLayoutPanel() - { - // probably not necessary, but... - delete mResizeBar; - mResizeBar = NULL; - } +{ + // probably not necessary, but... + delete mResizeBar; + mResizeBar = NULL; +} F32 LLLayoutPanel::getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation) - { +{ if (orientation == LLLayoutStack::HORIZONTAL) - { - F32 collapse_amt = - clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinDim / (F32)llmax(1, getRect().getWidth())); - return mVisibleAmt * collapse_amt; - } - else + { + F32 collapse_amt = + clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinDim / (F32)llmax(1, getRect().getWidth())); + return mVisibleAmt * collapse_amt; + } + else { F32 collapse_amt = clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinDim / (F32)llmax(1, getRect().getHeight()))); return mVisibleAmt * collapse_amt; - } } +} // // LLLayoutStack @@ -107,7 +113,7 @@ LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p) mMinWidth(0), mMinHeight(0), mPanelSpacing(p.border_size), - mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL), + mOrientation(p.orientation), mAnimate(p.animate), mAnimatedThisFrame(false), mClip(p.clip) diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h index e19ef403ef..9e8539c716 100644 --- a/indra/llui/lllayoutstack.h +++ b/indra/llui/lllayoutstack.h @@ -37,12 +37,24 @@ class LLLayoutPanel; class LLLayoutStack : public LLView, public LLInstanceTracker<LLLayoutStack> { public: + typedef enum e_layout_orientation + { + HORIZONTAL, + VERTICAL + } ELayoutOrientation; + + struct OrientationNames + : public LLInitParam::TypeValuesHelper<ELayoutOrientation, OrientationNames> + { + static void declareValues(); + }; + struct LayoutStackRegistry : public LLChildRegistry<LayoutStackRegistry> {}; struct Params : public LLInitParam::Block<Params, LLView::Params> { - Mandatory<std::string> orientation; + Mandatory<ELayoutOrientation, OrientationNames> orientation; Optional<S32> border_size; Optional<bool> animate, clip; @@ -52,12 +64,6 @@ public: typedef LayoutStackRegistry child_registry_t; - typedef enum e_layout_orientation - { - HORIZONTAL, - VERTICAL - } ELayoutOrientation; - virtual ~LLLayoutStack(); /*virtual*/ void draw(); diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 3eb58e1aec..6ad1a0bac4 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -88,6 +88,7 @@ LLLineEditor::Params::Params() revert_on_esc("revert_on_esc", true), commit_on_focus_lost("commit_on_focus_lost", true), ignore_tab("ignore_tab", true), + is_password("is_password", false), cursor_color("cursor_color"), text_color("text_color"), text_readonly_color("text_readonly_color"), @@ -129,7 +130,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) mBorderThickness( 0 ), mIgnoreArrowKeys( FALSE ), mIgnoreTab( p.ignore_tab ), - mDrawAsterixes( FALSE ), + mDrawAsterixes( p.is_password ), mSelectAllonFocusReceived( p.select_on_focus ), mPassDelete(FALSE), mReadOnly(FALSE), diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index a1aa6b71c6..d9d36b73a3 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -85,7 +85,8 @@ public: Optional<bool> select_on_focus, revert_on_esc, commit_on_focus_lost, - ignore_tab; + ignore_tab, + is_password; // colors Optional<LLUIColor> cursor_color, diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index a3df6a3ced..15edf270bd 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -81,6 +81,7 @@ LLNotificationForm::FormButton::FormButton() LLNotificationForm::FormInput::FormInput() : type("type"), + text("text"), max_length_chars("max_length_chars"), width("width", 0), value("value") @@ -404,7 +405,7 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par it != end_it; ++it) { - mUniqueContext.push_back(it->key); + mUniqueContext.push_back(it->value); } mForm = LLNotificationFormPtr(new LLNotificationForm(p.name, p.form_ref.form)); @@ -719,13 +720,19 @@ bool LLNotification::isEquivalentTo(LLNotificationPtr that) const { const LLSD& these_substitutions = this->getSubstitutions(); const LLSD& those_substitutions = that->getSubstitutions(); + const LLSD& this_payload = this->getPayload(); + const LLSD& that_payload = that->getPayload(); // highlander bit sez there can only be one of these for (std::vector<std::string>::const_iterator it = mTemplatep->mUniqueContext.begin(), end_it = mTemplatep->mUniqueContext.end(); it != end_it; ++it) { - if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString()) + // if templates differ in either substitution strings or payload with the given field name + // then they are considered inequivalent + // use of get() avoids converting the LLSD value to a map as the [] operator would + if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString() + || this_payload.get(*it).asString() != that_payload.get(*it).asString()) { return false; } diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 524cff70e8..a607f52b97 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -195,6 +195,7 @@ public: Mandatory<std::string> type; Optional<S32> width; Optional<S32> max_length_chars; + Optional<std::string> text; Optional<std::string> value; FormInput(); diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h index 6bc0d2aaff..644d5c4d74 100644 --- a/indra/llui/llnotificationtemplate.h +++ b/indra/llui/llnotificationtemplate.h @@ -74,11 +74,13 @@ struct LLNotificationTemplate struct UniquenessContext : public LLInitParam::Block<UniquenessContext> { - Mandatory<std::string> key; + Mandatory<std::string> value; UniquenessContext() - : key("key") - {} + : value("value") + { + addSynonym(value, "key"); + } }; @@ -88,7 +90,7 @@ struct LLNotificationTemplate // this idiom allows // <notification unique="true"> // as well as - // <notification> <unique> <context key=""/> </unique>... + // <notification> <unique> <context></context> </unique>... Optional<bool> dummy_val; public: Multiple<UniquenessContext> contexts; @@ -232,8 +234,8 @@ struct LLNotificationTemplate // (used for things like progress indications, or repeating warnings // like "the grid is going down in N minutes") bool mUnique; - // if we want to be unique only if a certain part of the payload is constant - // specify the field names for the payload. The notification will only be + // if we want to be unique only if a certain part of the payload or substitutions args + // are constant specify the field names for the payload. The notification will only be // combined if all of the fields named in the context are identical in the // new and the old notification; otherwise, the notification will be // duplicated. This is to support suppressing duplicate offers from the same diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index bd1a44a930..19244d2d1f 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -341,7 +341,7 @@ private: url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f); url << "%22%3E%3C/body%3E%3C/html%3E"; - lldebugs << "data url is: " << url.str() << llendl; + //lldebugs << "data url is: " << url.str() << llendl; LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() ); // LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" ); @@ -407,6 +407,8 @@ private: { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin"); message.setValue("uri", event.getEventUri()); + message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK)); + message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD)); sendMessage(message); setStatus(STATUS_LOADING); @@ -569,6 +571,57 @@ private: return blockingPickFile(); } + std::string mAuthUsername; + std::string mAuthPassword; + bool mAuthOK; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password) + { + mAuthOK = false; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request"); + message.setValue("url", in_url); + message.setValue("realm", in_realm); + message.setValueBoolean("blocking_request", true); + + // The "blocking_request" key in the message means this sendMessage call will block until a response is received. + sendMessage(message); + + if(mAuthOK) + { + out_username = mAuthUsername; + out_password = mAuthPassword; + } + + return mAuthOK; + } + + void authResponse(LLPluginMessage &message) + { + mAuthOK = message.getValueBoolean("ok"); + if(mAuthOK) + { + mAuthUsername = message.getValue("username"); + mAuthPassword = message.getValue("password"); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onLinkHovered(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "link_hovered"); + message.setValue("link", event.getEventUri()); + message.setValue("title", event.getStringValue()); + message.setValue("text", event.getStringValue2()); + sendMessage(message); + } + } + LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers) { int result = 0; @@ -1096,6 +1149,10 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) { onPickFileResponse(message_in.getValue("file")); } + if(message_name == "auth_response") + { + authResponse(message_in); + } else { // std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl; @@ -1182,6 +1239,22 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) mUserAgent = message_in.getValue("user_agent"); LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent ); } + else if(message_name == "ignore_ssl_cert_errors") + { +#if LLQTWEBKIT_API_VERSION >= 3 + LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( message_in.getValueBoolean("ignore") ); +#else + llwarns << "Ignoring ignore_ssl_cert_errors message (llqtwebkit version is too old)." << llendl; +#endif + } + else if(message_name == "set_certificate_file_path") + { +#if LLQTWEBKIT_API_VERSION >= 3 + LLQtWebKit::getInstance()->setCAFile( message_in.getValue("path") ); +#else + llwarns << "Ignoring set_certificate_file_path message (llqtwebkit version is too old)." << llendl; +#endif + } else if(message_name == "init_history") { // Initialize browser history diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 679637caf6..aef5cfa51b 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -222,6 +222,7 @@ set(viewer_SOURCE_FILES llfloaterurlentry.cpp llfloatervoiceeffect.cpp llfloaterwater.cpp + llfloaterwebcontent.cpp llfloaterwhitelistentry.cpp llfloaterwindlight.cpp llfloaterwindowsize.cpp @@ -757,6 +758,7 @@ set(viewer_HEADER_FILES llfloaterurlentry.h llfloatervoiceeffect.h llfloaterwater.h + llfloaterwebcontent.h llfloaterwhitelistentry.h llfloaterwindlight.h llfloaterwindowsize.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 7dbb375a20..2158b95f4d 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -674,6 +674,39 @@ <key>Value</key> <string>http://www.secondlife.com</string> </map> + <key>BrowserIgnoreSSLCertErrors</key> + <map> + <key>Comment</key> + <string>FOR TESTING ONLY: Tell the built-in web browser to ignore SSL cert errors.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>BrowserUseDefaultCAFile</key> + <map> + <key>Comment</key> + <string>Tell the built-in web browser to use the CA.pem file shipped with the client.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>BrowserCAFilePath</key> + <map> + <key>Comment</key> + <string>Tell the built-in web browser the path to an alternative CA.pem file (only used if BrowserUseDefaultCAFile is false).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string></string> + </map> <key>BlockAvatarAppearanceMessages</key> <map> <key>Comment</key> @@ -6604,7 +6637,18 @@ <key>MediaBrowserWindowLimit</key> <map> <key>Comment</key> - <string>Maximum number of media brower windows that can be open at once (0 for no limit)</string> + <string>Maximum number of media brower windows that can be open at once in the media browser floater (0 for no limit)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>5</integer> + </map> + <key>WebContentWindowLimit</key> + <map> + <key>Comment</key> + <string>Maximum number of web brower windows that can be open at once in the Web content floater (0 for no limit)</string> <key>Persist</key> <integer>1</integer> <key>Type</key> diff --git a/indra/newview/llbrowsernotification.cpp b/indra/newview/llbrowsernotification.cpp index d6a813d608..633ef4f1ce 100644 --- a/indra/newview/llbrowsernotification.cpp +++ b/indra/newview/llbrowsernotification.cpp @@ -29,8 +29,8 @@ #include "llnotificationhandler.h" #include "llnotifications.h" -#include "llfloaterreg.h" #include "llmediactrl.h" +#include "llviewermedia.h" using namespace LLNotificationsUI; diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 271ee0c4a4..e933770601 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -586,7 +586,7 @@ void LLChatHistory::initFromParams(const LLChatHistory::Params& p) LLLayoutStack::Params layout_p; layout_p.rect = stack_rect; layout_p.follows.flags = FOLLOWS_ALL; - layout_p.orientation = "vertical"; + layout_p.orientation = LLLayoutStack::VERTICAL; layout_p.mouse_opaque = false; LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p, this); diff --git a/indra/newview/llfloaterhelpbrowser.cpp b/indra/newview/llfloaterhelpbrowser.cpp index cec98e9992..a650886d89 100644 --- a/indra/newview/llfloaterhelpbrowser.cpp +++ b/indra/newview/llfloaterhelpbrowser.cpp @@ -132,9 +132,10 @@ void LLFloaterHelpBrowser::onClickOpenWebBrowser(void* user_data) void LLFloaterHelpBrowser::openMedia(const std::string& media_url) { - mBrowser->setHomePageUrl(media_url); - //mBrowser->navigateTo("data:text/html;charset=utf-8,I'd really love to be going to:<br><b>" + media_url + "</b>"); // tofu HACK for debugging =:) - mBrowser->navigateTo(media_url); + // explicitly make the media mime type for this floater since it will + // only ever display one type of content (Web). + mBrowser->setHomePageUrl(media_url, "text/html"); + mBrowser->navigateTo(media_url, "text/html"); setCurrentURL(media_url); } diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index 3ed4aec89a..2041fac8d8 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -200,5 +200,5 @@ void LLFloaterSearch::search(const LLSD &key) url = LLWeb::expandURLSubstitutions(url, subs); // and load the URL in the web view - mBrowser->navigateTo(url); + mBrowser->navigateTo(url, "text/html"); } diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp new file mode 100644 index 0000000000..8e5638f549 --- /dev/null +++ b/indra/newview/llfloaterwebcontent.cpp @@ -0,0 +1,304 @@ +/**
+ * @file llfloaterwebcontent.cpp
+ * @brief floater for displaying web content - e.g. profiles and search (eventually)
+ *
+ * $LicenseInfo:firstyear=2006&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 "llcombobox.h"
+#include "llfloaterreg.h"
+#include "lllayoutstack.h"
+#include "llpluginclassmedia.h"
+#include "llprogressbar.h"
+#include "lltextbox.h"
+#include "llviewercontrol.h"
+#include "llwindow.h"
+
+#include "llfloaterwebcontent.h"
+
+LLFloaterWebContent::LLFloaterWebContent(const LLSD& key)
+ : LLFloater(key)
+{
+ mCommitCallbackRegistrar.add("WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this));
+ mCommitCallbackRegistrar.add("WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this));
+ mCommitCallbackRegistrar.add("WebContent.Reload", boost::bind( &LLFloaterWebContent::onClickReload, this));
+
+ mCommitCallbackRegistrar.add("WebContent.EnterAddress", boost::bind( &LLFloaterWebContent::onEnterAddress, this));
+}
+
+BOOL LLFloaterWebContent::postBuild()
+{
+ // these are used in a bunch of places so cache them
+ mWebBrowser = getChild<LLMediaCtrl>("webbrowser");
+ mAddressCombo = getChild<LLComboBox>("address");
+ mStatusBarText = getChild<LLTextBox>("statusbartext");
+ mStatusBarProgress = getChild<LLProgressBar>("statusbarprogress");
+
+ // observe browser events
+ mWebBrowser->addObserver(this);
+
+ // these button are always enabled
+ getChildView("reload")->setEnabled( true );
+
+ return TRUE;
+}
+
+//static
+void LLFloaterWebContent::create(const std::string &url, const std::string& target, const std::string& uuid)
+{
+ lldebugs << "url = " << url << ", target = " << target << ", uuid = " << uuid << llendl;
+
+ std::string tag = target;
+
+ if(target.empty() || target == "_blank")
+ {
+ if(!uuid.empty())
+ {
+ tag = uuid;
+ }
+ else
+ {
+ // create a unique tag for this instance
+ LLUUID id;
+ id.generate();
+ tag = id.asString();
+ }
+ }
+
+ S32 browser_window_limit = gSavedSettings.getS32("WebContentWindowLimit");
+
+ if(LLFloaterReg::findInstance("web_content", tag) != NULL)
+ {
+ // There's already a web browser for this tag, so we won't be opening a new window.
+ }
+ else if(browser_window_limit != 0)
+ {
+ // showInstance will open a new window. Figure out how many web browsers are already open,
+ // and close the least recently opened one if this will put us over the limit.
+
+ LLFloaterReg::const_instance_list_t &instances = LLFloaterReg::getFloaterList("web_content");
+ lldebugs << "total instance count is " << instances.size() << llendl;
+
+ for(LLFloaterReg::const_instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); iter++)
+ {
+ lldebugs << " " << (*iter)->getKey() << llendl;
+ }
+
+ if(instances.size() >= (size_t)browser_window_limit)
+ {
+ // Destroy the least recently opened instance
+ (*instances.begin())->closeFloater();
+ }
+ }
+
+ LLFloaterWebContent *browser = dynamic_cast<LLFloaterWebContent*> (LLFloaterReg::showInstance("web_content", tag));
+ llassert(browser);
+ if(browser)
+ {
+ browser->mUUID = uuid;
+
+ // tell the browser instance to load the specified URL
+ browser->open_media(url, target);
+ LLViewerMedia::proxyWindowOpened(target, uuid);
+ }
+}
+
+//static
+void LLFloaterWebContent::closeRequest(const std::string &uuid)
+{
+ LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
+ lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
+ for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
+ {
+ LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
+ lldebugs << " " << i->mUUID << llendl;
+ if (i && i->mUUID == uuid)
+ {
+ i->closeFloater(false);
+ return;
+ }
+ }
+}
+
+//static
+void LLFloaterWebContent::geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height)
+{
+ LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
+ lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
+ for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
+ {
+ LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
+ lldebugs << " " << i->mUUID << llendl;
+ if (i && i->mUUID == uuid)
+ {
+ i->geometryChanged(x, y, width, height);
+ return;
+ }
+ }
+}
+
+void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height)
+{
+ // Make sure the layout of the browser control is updated, so this calculation is correct.
+ LLLayoutStack::updateClass();
+
+ // TODO: need to adjust size and constrain position to make sure floaters aren't moved outside the window view, etc.
+ LLCoordWindow window_size;
+ getWindow()->getSize(&window_size);
+
+ // Adjust width and height for the size of the chrome on the web Browser window.
+ width += getRect().getWidth() - mWebBrowser->getRect().getWidth();
+ height += getRect().getHeight() - mWebBrowser->getRect().getHeight();
+
+ LLRect geom;
+ geom.setOriginAndSize(x, window_size.mY - (y + height), width, height);
+
+ lldebugs << "geometry change: " << geom << llendl;
+
+ handleReshape(geom,false);
+}
+
+void LLFloaterWebContent::open_media(const std::string& web_url, const std::string& target)
+{
+ mWebBrowser->setHomePageUrl(web_url);
+ mWebBrowser->setTarget(target);
+ mWebBrowser->navigateTo(web_url);
+ set_current_url(web_url);
+}
+
+//virtual
+void LLFloaterWebContent::onClose(bool app_quitting)
+{
+ LLViewerMedia::proxyWindowClosed(mUUID);
+ destroy();
+}
+
+void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
+{
+ if(event == MEDIA_EVENT_LOCATION_CHANGED)
+ {
+ const std::string url = self->getStatusText();
+
+ if ( url.length() )
+ mStatusBarText->setText( url );
+
+ set_current_url( url );
+ }
+ else if(event == MEDIA_EVENT_NAVIGATE_BEGIN)
+ {
+ // flags are sent with this event
+ getChildView("back")->setEnabled( self->getHistoryBackAvailable() );
+ getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() );
+
+ // manually decide on the state of this button
+ getChildView("reload")->setVisible( false );
+ getChildView("stop")->setVisible( true );
+
+ // turn "on" progress bar now we're loaded
+ mStatusBarProgress->setVisible( true );
+ }
+ else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
+ {
+ // flags are sent with this event
+ getChildView("back")->setEnabled( self->getHistoryBackAvailable() );
+ getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() );
+
+ // manually decide on the state of this button
+ getChildView("reload")->setVisible( true );
+ getChildView("stop")->setVisible( false );
+
+ // turn "off" progress bar now we're loaded
+ mStatusBarProgress->setVisible( false );
+ }
+ else if(event == MEDIA_EVENT_CLOSE_REQUEST)
+ {
+ // The browser instance wants its window closed.
+ closeFloater();
+ }
+ else if(event == MEDIA_EVENT_GEOMETRY_CHANGE)
+ {
+ geometryChanged(self->getGeometryX(), self->getGeometryY(), self->getGeometryWidth(), self->getGeometryHeight());
+ }
+ else if(event == MEDIA_EVENT_STATUS_TEXT_CHANGED )
+ {
+ const std::string text = self->getStatusText();
+ if ( text.length() )
+ mStatusBarText->setText( text );
+ }
+ else if(event == MEDIA_EVENT_PROGRESS_UPDATED )
+ {
+ int percent = (int)self->getProgressPercent();
+ mStatusBarProgress->setPercent( percent );
+ }
+ else if(event == MEDIA_EVENT_NAME_CHANGED )
+ {
+ std::string page_title = self->getMediaName();
+ setTitle( page_title );
+ }
+}
+
+void LLFloaterWebContent::set_current_url(const std::string& url)
+{
+ mCurrentURL = url;
+
+ // redirects will navigate momentarily to about:blank, don't add to history
+ if ( mCurrentURL != "about:blank" )
+ {
+ mAddressCombo->remove( mCurrentURL );
+ mAddressCombo->add( mCurrentURL );
+ mAddressCombo->selectByValue( mCurrentURL );
+ }
+}
+
+void LLFloaterWebContent::onClickForward()
+{
+ mWebBrowser->navigateForward();
+}
+
+void LLFloaterWebContent::onClickBack()
+{
+ mWebBrowser->navigateBack();
+}
+
+void LLFloaterWebContent::onClickReload()
+{
+ mAddressCombo->remove(0);
+
+ if( mWebBrowser->getMediaPlugin() )
+ {
+ bool ignore_cache = true;
+ mWebBrowser->getMediaPlugin()->browse_reload( ignore_cache );
+ };
+}
+
+void LLFloaterWebContent::onClickStop()
+{
+ if( mWebBrowser->getMediaPlugin() )
+ mWebBrowser->getMediaPlugin()->stop();
+}
+
+void LLFloaterWebContent::onEnterAddress()
+{
+ mWebBrowser->navigateTo( mAddressCombo->getValue().asString() );
+}
diff --git a/indra/newview/llfloaterwebcontent.h b/indra/newview/llfloaterwebcontent.h new file mode 100644 index 0000000000..b41da57a6f --- /dev/null +++ b/indra/newview/llfloaterwebcontent.h @@ -0,0 +1,77 @@ +/**
+ * @file llfloaterwebcontent.h
+ * @brief floater for displaying web content - e.g. profiles and search (eventually)
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+#ifndef LL_LLFLOATERWEBCONTENT_H
+#define LL_LLFLOATERWEBCONTENT_H
+
+#include "llfloater.h"
+#include "llmediactrl.h"
+
+class LLMediaCtrl;
+class LLComboBox;
+class LLTextBox;
+class LLProgressBar;
+
+class LLFloaterWebContent :
+ public LLFloater,
+ public LLViewerMediaObserver
+{
+public:
+ LOG_CLASS(LLFloaterWebContent);
+ LLFloaterWebContent(const LLSD& key);
+
+ static void create(const std::string &url, const std::string& target, const std::string& uuid = LLStringUtil::null);
+
+ static void closeRequest(const std::string &uuid);
+ static void geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height);
+ void geometryChanged(S32 x, S32 y, S32 width, S32 height);
+
+ /*virtual*/ BOOL postBuild();
+ /*virtual*/ void onClose(bool app_quitting);
+
+ // inherited from LLViewerMediaObserver
+ /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
+
+ void onClickBack();
+ void onClickForward();
+ void onClickReload();
+ void onClickStop();
+ void onEnterAddress();
+ void onClickGo();
+
+private:
+ void open_media(const std::string& media_url, const std::string& target);
+ void set_current_url(const std::string& url);
+
+ LLMediaCtrl* mWebBrowser;
+ LLComboBox* mAddressCombo;
+ LLTextBox* mStatusBarText;
+ LLProgressBar* mStatusBarProgress;
+ std::string mCurrentURL;
+ std::string mUUID;
+};
+
+#endif // LL_LLFLOATERWEBCONTENT_H
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index e84c9152b1..08d07f9540 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -25,7 +25,7 @@ */ #include "llviewerprecompiledheaders.h" - +#include "lltooltip.h" #include "llmediactrl.h" @@ -54,11 +54,265 @@ #include "llbutton.h" #include "llcheckboxctrl.h" #include "llnotifications.h" +#include "lllineeditor.h" extern BOOL gRestoreGL; static LLDefaultChildRegistry::Register<LLMediaCtrl> r("web_browser"); +class LLWindowShade : public LLView +{ +public: + struct Params : public LLInitParam::Block<Params, LLView::Params> + { + Mandatory<LLNotificationPtr> notification; + Optional<LLUIImage*> bg_image; + + Params() + : bg_image("bg_image") + { + mouse_opaque = false; + } + }; + + void show(); + /*virtual*/ void draw(); + void hide(); + +private: + friend class LLUICtrlFactory; + + LLWindowShade(const Params& p); + void initFromParams(const Params& params); + + void onCloseNotification(); + void onClickNotificationButton(const std::string& name); + void onEnterNotificationText(LLUICtrl* ctrl, const std::string& name); + void onClickIgnore(LLUICtrl* ctrl); + + LLNotificationPtr mNotification; + LLSD mNotificationResponse; +}; + +LLWindowShade::LLWindowShade(const LLWindowShade::Params& params) +: LLView(params), + mNotification(params.notification) +{ +} + +void LLWindowShade::initFromParams(const LLWindowShade::Params& params) +{ + LLView::initFromParams(params); + + LLLayoutStack::Params layout_p; + layout_p.name = "notification_stack"; + layout_p.rect = LLRect(0,getLocalRect().mTop,getLocalRect().mRight, 30); + layout_p.follows.flags = FOLLOWS_ALL; + layout_p.mouse_opaque = false; + layout_p.orientation = LLLayoutStack::VERTICAL; + + LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p); + addChild(stackp); + + LLLayoutPanel::Params panel_p; + panel_p.rect = LLRect(0, 30, 800, 0); + panel_p.min_height = 30; + panel_p.name = "notification_area"; + panel_p.visible = false; + panel_p.user_resize = false; + panel_p.background_visible = true; + panel_p.bg_alpha_image = params.bg_image; + panel_p.auto_resize = false; + LLLayoutPanel* notification_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); + stackp->addChild(notification_panel); + + panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); + panel_p.auto_resize = true; + panel_p.mouse_opaque = false; + LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); + stackp->addChild(dummy_panel); + + layout_p = LLUICtrlFactory::getDefaultParams<LLLayoutStack>(); + layout_p.rect = LLRect(0, 30, 800, 0); + layout_p.follows.flags = FOLLOWS_ALL; + layout_p.orientation = LLLayoutStack::HORIZONTAL; + stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p); + notification_panel->addChild(stackp); + + panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); + panel_p.rect.height = 30; + LLLayoutPanel* panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); + stackp->addChild(panel); + + LLIconCtrl::Params icon_p; + icon_p.name = "notification_icon"; + icon_p.rect = LLRect(5, 23, 21, 8); + panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p)); + + LLTextBox::Params text_p; + text_p.rect = LLRect(31, 20, 430, 0); + text_p.text_color = LLColor4::black; + text_p.font = LLFontGL::getFontSansSerif(); + text_p.font.style = "BOLD"; + text_p.name = "notification_text"; + text_p.use_ellipses = true; + panel->addChild(LLUICtrlFactory::create<LLTextBox>(text_p)); + + panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); + panel_p.auto_resize = false; + panel_p.user_resize = false; + panel_p.name="form_elements"; + panel_p.rect = LLRect(0, 30, 130, 0); + LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); + stackp->addChild(form_elements_panel); + + panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); + panel_p.auto_resize = false; + panel_p.user_resize = false; + panel_p.rect = LLRect(0, 30, 25, 0); + LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); + stackp->addChild(close_panel); + + LLButton::Params button_p; + button_p.name = "close_notification"; + button_p.rect = LLRect(5, 23, 21, 7); + button_p.image_color=LLUIColorTable::instance().getColor("DkGray_66"); + button_p.image_unselected.name="Icon_Close_Foreground"; + button_p.image_selected.name="Icon_Close_Press"; + button_p.click_callback.function = boost::bind(&LLWindowShade::onCloseNotification, this); + + close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p)); + + LLSD payload = mNotification->getPayload(); + + LLNotificationFormPtr formp = mNotification->getForm(); + LLLayoutPanel& notification_area = getChildRef<LLLayoutPanel>("notification_area"); + notification_area.getChild<LLUICtrl>("notification_icon")->setValue(mNotification->getIcon()); + notification_area.getChild<LLUICtrl>("notification_text")->setValue(mNotification->getMessage()); + notification_area.getChild<LLUICtrl>("notification_text")->setToolTip(mNotification->getMessage()); + LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType(); + LLLayoutPanel& form_elements = notification_area.getChildRef<LLLayoutPanel>("form_elements"); + form_elements.deleteAllChildren(); + + const S32 FORM_PADDING_HORIZONTAL = 10; + const S32 FORM_PADDING_VERTICAL = 3; + S32 cur_x = FORM_PADDING_HORIZONTAL; + + if (ignore_type != LLNotificationForm::IGNORE_NO) + { + LLCheckBoxCtrl::Params checkbox_p; + checkbox_p.name = "ignore_check"; + checkbox_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x, FORM_PADDING_VERTICAL); + checkbox_p.label = formp->getIgnoreMessage(); + checkbox_p.label_text.text_color = LLColor4::black; + checkbox_p.commit_callback.function = boost::bind(&LLWindowShade::onClickIgnore, this, _1); + checkbox_p.initial_value = formp->getIgnored(); + + LLCheckBoxCtrl* check = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p); + check->setRect(check->getBoundingRect()); + form_elements.addChild(check); + cur_x = check->getRect().mRight + FORM_PADDING_HORIZONTAL; + } + + for (S32 i = 0; i < formp->getNumElements(); i++) + { + LLSD form_element = formp->getElement(i); + std::string type = form_element["type"].asString(); + if (type == "button") + { + LLButton::Params button_p; + button_p.name = form_element["name"]; + button_p.label = form_element["text"]; + button_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x, FORM_PADDING_VERTICAL); + button_p.click_callback.function = boost::bind(&LLWindowShade::onClickNotificationButton, this, form_element["name"].asString()); + button_p.auto_resize = true; + + LLButton* button = LLUICtrlFactory::create<LLButton>(button_p); + button->autoResize(); + form_elements.addChild(button); + + cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL; + } + else if (type == "text" || type == "password") + { + LLTextBox::Params label_p; + label_p.name = form_element["name"].asString() + "_label"; + label_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x + 120, FORM_PADDING_VERTICAL); + label_p.initial_value = form_element["text"]; + label_p.text_color = LLColor4::black; + LLTextBox* textbox = LLUICtrlFactory::create<LLTextBox>(label_p); + textbox->reshapeToFitText(); + form_elements.addChild(textbox); + cur_x = textbox->getRect().mRight + FORM_PADDING_HORIZONTAL; + + LLLineEditor::Params line_p; + line_p.name = form_element["name"]; + line_p.commit_callback.function = boost::bind(&LLWindowShade::onEnterNotificationText, this, _1, form_element["name"].asString()); + line_p.commit_on_focus_lost = true; + line_p.is_password = type == "password"; + line_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x + 120, FORM_PADDING_VERTICAL); + + LLLineEditor* line_editor = LLUICtrlFactory::create<LLLineEditor>(line_p); + form_elements.addChild(line_editor); + cur_x = line_editor->getRect().mRight + FORM_PADDING_HORIZONTAL; + } + } + + form_elements.reshape(cur_x, form_elements.getRect().getHeight()); +} + +void LLWindowShade::show() +{ + LLLayoutPanel& panel = getChildRef<LLLayoutPanel>("notification_area"); + panel.setVisible(true); +} + +void LLWindowShade::draw() +{ + LLView::draw(); + if (mNotification && !mNotification->isActive()) + { + hide(); + } +} + +void LLWindowShade::hide() +{ + LLLayoutPanel& panel = getChildRef<LLLayoutPanel>("notification_area"); + panel.setVisible(false); +} + +void LLWindowShade::onCloseNotification() +{ + LLNotifications::instance().cancel(mNotification); +} + +void LLWindowShade::onClickIgnore(LLUICtrl* ctrl) +{ + bool check = ctrl->getValue().asBoolean(); + if (mNotification && mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) + { + // question was "show again" so invert value to get "ignore" + check = !check; + } + mNotification->setIgnored(check); +} + +void LLWindowShade::onClickNotificationButton(const std::string& name) +{ + if (!mNotification) return; + + mNotificationResponse[name] = true; + + mNotification->respond(mNotificationResponse); +} + +void LLWindowShade::onEnterNotificationText(LLUICtrl* ctrl, const std::string& name) +{ + mNotificationResponse[name] = ctrl->getValue().asString(); +} + + LLMediaCtrl::Params::Params() : start_url("start_url"), border_visible("border_visible", true), @@ -69,7 +323,6 @@ LLMediaCtrl::Params::Params() texture_height("texture_height", 1024), caret_color("caret_color"), initial_mime_type("initial_mime_type"), - media_id("media_id"), trusted_content("trusted_content", false) { tab_stop(false); @@ -97,7 +350,9 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) : mTextureHeight ( 1024 ), mClearCache(false), mHomePageMimeType(p.initial_mime_type), - mTrusted(p.trusted_content) + mTrusted(p.trusted_content), + mWindowShade(NULL), + mHoverTextChanged(false) { { LLColor4 color = p.caret_color().get(); @@ -126,7 +381,7 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) : setTextureSize(screen_width, screen_height); } - mMediaTextureID.generate(); + mMediaTextureID = getKey(); // We don't need to create the media source up front anymore unless we have a non-empty home URL to navigate to. if(!mHomePageUrl.empty()) @@ -140,8 +395,6 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) : // addChild( mBorder ); } -//////////////////////////////////////////////////////////////////////////////// -// note: this is now a singleton and destruction happens via initClass() now LLMediaCtrl::~LLMediaCtrl() { @@ -181,6 +434,13 @@ BOOL LLMediaCtrl::handleHover( S32 x, S32 y, MASK mask ) mMediaSource->mouseMove(x, y, mask); gViewerWindow->setCursor(mMediaSource->getLastSetCursor()); } + + // TODO: Is this the right way to handle hover text changes driven by the plugin? + if(mHoverTextChanged) + { + mHoverTextChanged = false; + handleToolTip(x, y, mask); + } return TRUE; } @@ -197,6 +457,35 @@ BOOL LLMediaCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks ) } //////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL LLMediaCtrl::handleToolTip(S32 x, S32 y, MASK mask) +{ + std::string hover_text; + + if (mMediaSource && mMediaSource->hasMedia()) + hover_text = mMediaSource->getMediaPlugin()->getHoverText(); + + if(hover_text.empty()) + { + return FALSE; + } + else + { + S32 screen_x, screen_y; + + localPointToScreen(x, y, &screen_x, &screen_y); + LLRect sticky_rect_screen; + sticky_rect_screen.setCenterAndSize(screen_x, screen_y, 20, 20); + + LLToolTipMgr::instance().show(LLToolTip::Params() + .message(hover_text) + .sticky_rect(sticky_rect_screen)); + } + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// // BOOL LLMediaCtrl::handleMouseUp( S32 x, S32 y, MASK mask ) { @@ -345,85 +634,6 @@ void LLMediaCtrl::onFocusLost() // BOOL LLMediaCtrl::postBuild () { - LLLayoutStack::Params layout_p; - layout_p.name = "notification_stack"; - layout_p.rect = LLRect(0,getLocalRect().mTop,getLocalRect().mRight, 30); - layout_p.follows.flags = FOLLOWS_ALL; - layout_p.mouse_opaque = false; - layout_p.orientation = "vertical"; - - LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p); - addChild(stackp); - - LLLayoutPanel::Params panel_p; - panel_p.rect = LLRect(0, 30, 800, 0); - panel_p.min_height = 30; - panel_p.name = "notification_area"; - panel_p.visible = false; - panel_p.user_resize = false; - panel_p.background_visible = true; - panel_p.bg_alpha_image.name = "Yellow_Gradient"; - panel_p.auto_resize = false; - LLLayoutPanel* notification_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); - stackp->addChild(notification_panel); - - panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); - panel_p.auto_resize = true; - panel_p.mouse_opaque = false; - LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); - stackp->addChild(dummy_panel); - - layout_p = LLUICtrlFactory::getDefaultParams<LLLayoutStack>(); - layout_p.rect = LLRect(0, 30, 800, 0); - layout_p.follows.flags = FOLLOWS_ALL; - layout_p.orientation = "horizontal"; - stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p); - notification_panel->addChild(stackp); - - panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); - panel_p.rect.height = 30; - LLLayoutPanel* panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); - stackp->addChild(panel); - - LLIconCtrl::Params icon_p; - icon_p.name = "notification_icon"; - icon_p.rect = LLRect(5, 23, 21, 8); - panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p)); - - LLTextBox::Params text_p; - text_p.rect = LLRect(31, 20, 430, 0); - text_p.text_color = LLColor4::black; - text_p.font = LLFontGL::getFontSansSerif(); - text_p.font.style = "BOLD"; - text_p.name = "notification_text"; - text_p.use_ellipses = true; - panel->addChild(LLUICtrlFactory::create<LLTextBox>(text_p)); - - panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); - panel_p.auto_resize = false; - panel_p.user_resize = false; - panel_p.name="form_elements"; - panel_p.rect = LLRect(0, 30, 130, 0); - LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); - stackp->addChild(form_elements_panel); - - panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); - panel_p.auto_resize = false; - panel_p.user_resize = false; - panel_p.rect = LLRect(0, 30, 25, 0); - LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); - stackp->addChild(close_panel); - - LLButton::Params button_p; - button_p.name = "close_notification"; - button_p.rect = LLRect(5, 23, 21, 7); - button_p.image_color=LLUIColorTable::instance().getColor("DkGray_66"); - button_p.image_unselected.name="Icon_Close_Foreground"; - button_p.image_selected.name="Icon_Close_Press"; - button_p.click_callback.function = boost::bind(&LLMediaCtrl::onCloseNotification, this); - - close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p)); - setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChange, this, _2)); return TRUE; } @@ -432,13 +642,15 @@ BOOL LLMediaCtrl::postBuild () // BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask ) { - if (LLPanel::handleKeyHere(key, mask)) return TRUE; BOOL result = FALSE; if (mMediaSource) { result = mMediaSource->handleKeyHere(key, mask); } + + if ( ! result ) + result = LLPanel::handleKeyHere(key, mask); return result; } @@ -458,7 +670,6 @@ void LLMediaCtrl::handleVisibilityChange ( BOOL new_visibility ) // BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char) { - if (LLPanel::handleUnicodeCharHere(uni_char)) return TRUE; BOOL result = FALSE; if (mMediaSource) @@ -466,6 +677,9 @@ BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char) result = mMediaSource->handleUnicodeCharHere(uni_char); } + if ( ! result ) + result = LLPanel::handleUnicodeCharHere(uni_char); + return result; } @@ -921,11 +1135,6 @@ void LLMediaCtrl::draw() if ( mBorder && mBorder->getVisible() ) mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus( this ) ); - if (mCurNotification && !mCurNotification->isActive()) - { - hideNotification(); - } - LLPanel::draw(); // Restore the previous values @@ -1033,7 +1242,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) LLNotification::Params notify_params; notify_params.name = "PopupAttempt"; - notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", getKey()); + notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", mMediaTextureID); notify_params.functor.function = boost::bind(&LLMediaCtrl::onPopup, this, _1, _2); if (mTrusted) @@ -1088,6 +1297,23 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() << LL_ENDL; } break; + + case MEDIA_EVENT_AUTH_REQUEST: + { + LLNotification::Params auth_request_params; + auth_request_params.name = "AuthRequest"; + auth_request_params.payload = LLSD().with("media_id", mMediaTextureID); + auth_request_params.functor.function = boost::bind(&LLMediaCtrl::onAuthSubmit, this, _1, _2); + LLNotifications::instance().add(auth_request_params); + }; + break; + + case MEDIA_EVENT_LINK_HOVERED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << LL_ENDL; + mHoverTextChanged = true; + }; + break; }; // chain all events to any potential observers of this object. @@ -1112,102 +1338,45 @@ void LLMediaCtrl::onPopup(const LLSD& notification, const LLSD& response) // Make sure the opening instance knows its window open request was denied, so it can clean things up. LLViewerMedia::proxyWindowClosed(notification["payload"]["uuid"]); } - } -void LLMediaCtrl::onCloseNotification() +void LLMediaCtrl::onAuthSubmit(const LLSD& notification, const LLSD& response) { - LLNotifications::instance().cancel(mCurNotification); -} - -void LLMediaCtrl::onClickIgnore(LLUICtrl* ctrl) -{ - bool check = ctrl->getValue().asBoolean(); - if (mCurNotification && mCurNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) + if (response["ok"]) { - // question was "show again" so invert value to get "ignore" - check = !check; + mMediaSource->getMediaPlugin()->sendAuthResponse(true, response["username"], response["password"]); + } + else + { + mMediaSource->getMediaPlugin()->sendAuthResponse(false, "", ""); } - mCurNotification->setIgnored(check); } -void LLMediaCtrl::onClickNotificationButton(const std::string& name) -{ - if (!mCurNotification) return; - - LLSD response = mCurNotification->getResponseTemplate(); - response[name] = true; - - mCurNotification->respond(response); -} void LLMediaCtrl::showNotification(LLNotificationPtr notify) { - mCurNotification = notify; - - // add popup here - LLSD payload = notify->getPayload(); - - LLNotificationFormPtr formp = notify->getForm(); - LLLayoutPanel& panel = getChildRef<LLLayoutPanel>("notification_area"); - panel.setVisible(true); - panel.getChild<LLUICtrl>("notification_icon")->setValue(notify->getIcon()); - panel.getChild<LLUICtrl>("notification_text")->setValue(notify->getMessage()); - panel.getChild<LLUICtrl>("notification_text")->setToolTip(notify->getMessage()); - LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType(); - LLLayoutPanel& form_elements = panel.getChildRef<LLLayoutPanel>("form_elements"); - form_elements.deleteAllChildren(); - - const S32 FORM_PADDING_HORIZONTAL = 10; - const S32 FORM_PADDING_VERTICAL = 3; - S32 cur_x = FORM_PADDING_HORIZONTAL; - - if (ignore_type != LLNotificationForm::IGNORE_NO) - { - LLCheckBoxCtrl::Params checkbox_p; - checkbox_p.name = "ignore_check"; - checkbox_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x, FORM_PADDING_VERTICAL); - checkbox_p.label = formp->getIgnoreMessage(); - checkbox_p.label_text.text_color = LLColor4::black; - checkbox_p.commit_callback.function = boost::bind(&LLMediaCtrl::onClickIgnore, this, _1); - checkbox_p.initial_value = formp->getIgnored(); - - LLCheckBoxCtrl* check = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p); - check->setRect(check->getBoundingRect()); - form_elements.addChild(check); - cur_x = check->getRect().mRight + FORM_PADDING_HORIZONTAL; - } - - for (S32 i = 0; i < formp->getNumElements(); i++) + delete mWindowShade; + + LLWindowShade::Params params; + params.rect = getLocalRect(); + params.follows.flags = FOLLOWS_ALL; + params.notification = notify; + //HACK: don't hardcode this + if (notify->getName() == "PopupAttempt") { - LLSD form_element = formp->getElement(i); - if (form_element["type"].asString() == "button") - { - LLButton::Params button_p; - button_p.name = form_element["name"]; - button_p.label = form_element["text"]; - button_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x, FORM_PADDING_VERTICAL); - button_p.click_callback.function = boost::bind(&LLMediaCtrl::onClickNotificationButton, this, form_element["name"].asString()); - button_p.auto_resize = true; - - LLButton* button = LLUICtrlFactory::create<LLButton>(button_p); - button->autoResize(); - form_elements.addChild(button); - - cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL; - } + params.bg_image.name = "Yellow_Gradient"; } + mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params); - form_elements.reshape(cur_x, form_elements.getRect().getHeight()); - - //LLWeb::loadURL(payload["url"], payload["target"]); + addChild(mWindowShade); + mWindowShade->show(); } void LLMediaCtrl::hideNotification() { - LLLayoutPanel& panel = getChildRef<LLLayoutPanel>("notification_area"); - panel.setVisible(FALSE); - - mCurNotification.reset(); + if (mWindowShade) + { + mWindowShade->hide(); + } } diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 65dfbbff78..0c369840bf 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -61,7 +61,6 @@ public: Optional<LLUIColor> caret_color; Optional<std::string> initial_mime_type; - Optional<std::string> media_id; Params(); }; @@ -89,6 +88,7 @@ public: virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); // navigation void navigateTo( std::string url_in, std::string mime_type = ""); @@ -167,9 +167,7 @@ public: private: void onVisibilityChange ( const LLSD& new_visibility ); void onPopup(const LLSD& notification, const LLSD& response); - void onCloseNotification(); - void onClickNotificationButton(const std::string& name); - void onClickIgnore(LLUICtrl* ctrl); + void onAuthSubmit(const LLSD& notification, const LLSD& response); const S32 mTextureDepthBytes; LLUUID mMediaTextureID; @@ -193,7 +191,8 @@ public: S32 mTextureWidth; S32 mTextureHeight; bool mClearCache; - boost::shared_ptr<class LLNotification> mCurNotification; + class LLWindowShade* mWindowShade; + bool mHoverTextChanged; }; #endif // LL_LLMediaCtrl_H diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index cf567fb208..b755f6ec17 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -211,9 +211,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, //sendChildToBack(getChildView("channel_text")); sendChildToBack(getChildView("forgot_password_text")); - LLLineEditor* edit = getChild<LLLineEditor>("password_edit"); - if (edit) edit->setDrawAsterixes(TRUE); - if(LLStartUp::getStartSLURL().getType() != LLSLURL::LOCATION) { LLSLURL slurl(gSavedSettings.getString("LoginLocation")); diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index f573f25efe..dca1e33e60 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -60,6 +60,7 @@ #include "llfloaterhardwaresettings.h" #include "llfloaterhelpbrowser.h" #include "llfloatermediabrowser.h" +#include "llfloaterwebcontent.h" #include "llfloatermediasettings.h" #include "llfloaterhud.h" #include "llfloaterimagepreview.h" @@ -252,6 +253,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("voice_controls", "floater_voice_controls.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLCallFloater>); LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVoiceEffect>); + LLFloaterReg::add("web_content", "floater_web_content.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWebContent>); LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>); LLFloaterWindowSizeUtil::registerFloater(); LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWorldMap>); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index fae4eb3c05..be4e23728a 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -293,6 +293,7 @@ public: LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL; LLURL LLViewerMedia::sOpenIDURL; std::string LLViewerMedia::sOpenIDCookie; +LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = NULL; static LLViewerMedia::impl_list sViewerMediaImplList; static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap; static LLTimer sMediaCreateTimer; @@ -742,6 +743,9 @@ void LLViewerMedia::updateMedia(void *dummy_arg) // Enable/disable the plugin read thread LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread")); + // HACK: we always try to keep a spare running webkit plugin around to improve launch times. + createSpareBrowserMediaSource(); + sAnyMediaShowing = false; sUpdatedCookies = getCookieStore()->getChangedCookies(); if(!sUpdatedCookies.empty()) @@ -759,6 +763,12 @@ void LLViewerMedia::updateMedia(void *dummy_arg) pimpl->update(); pimpl->calculateInterest(); } + + // Let the spare media source actually launch + if(sSpareBrowserMediaSource) + { + sSpareBrowserMediaSource->idle(); + } // Sort the static instance list using our interest criteria sViewerMediaImplList.sort(priorityComparitor); @@ -1400,6 +1410,29 @@ void LLViewerMedia::proxyWindowClosed(const std::string &uuid) } } +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::createSpareBrowserMediaSource() +{ + if(!sSpareBrowserMediaSource) + { + // If we don't have a spare browser media source, create one. + // The null owner will keep the browser plugin from fully initializing + // (specifically, it keeps LLPluginClassMedia from negotiating a size change, + // which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) + sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource() +{ + LLPluginClassMedia* result = sSpareBrowserMediaSource; + sSpareBrowserMediaSource = NULL; + return result; +}; + bool LLViewerMedia::hasInWorldMedia() { if (sInWorldMediaDisabled) return false; @@ -1636,6 +1669,21 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type) LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target) { std::string plugin_basename = LLMIMETypes::implType(media_type); + LLPluginClassMedia* media_source = NULL; + + // HACK: we always try to keep a spare running webkit plugin around to improve launch times. + if(plugin_basename == "media_plugin_webkit") + { + media_source = LLViewerMedia::getSpareBrowserMediaSource(); + if(media_source) + { + media_source->setOwner(owner); + media_source->setTarget(target); + media_source->setSize(default_width, default_height); + + return media_source; + } + } if(plugin_basename.empty()) { @@ -1673,7 +1721,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ } else { - LLPluginClassMedia* media_source = new LLPluginClassMedia(owner); + media_source = new LLPluginClassMedia(owner); media_source->setSize(default_width, default_height); media_source->setUserDataPath(user_data_path); media_source->setLanguageCode(LLUI::getLanguage()); @@ -1753,6 +1801,22 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) media_source->focus(mHasFocus); media_source->setBackgroundColor(mBackgroundColor); + if(gSavedSettings.getBOOL("BrowserIgnoreSSLCertErrors")) + { + media_source->ignore_ssl_cert_errors(true); + } + + // start by assuming the default CA file will be used + std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "CA.pem" ); + + // default turned off so pick up the user specified path + if( ! gSavedSettings.getBOOL("BrowserUseDefaultCAFile")) + { + ca_path = gSavedSettings.getString("BrowserCAFilePath"); + } + // set the path to the CA.pem file + media_source->setCertificateFilePath( ca_path ); + media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort")); if(mClearCache) @@ -2850,7 +2914,6 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL; std::string url = plugin->getClickURL(); LLURLDispatcher::dispatch(url, NULL, mTrustedBrowser); - } break; case MEDIA_EVENT_CLICK_LINK_HREF: @@ -3003,6 +3066,13 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla plugin->sendPickFileResponse(response); } break; + + case LLViewerMediaObserver::MEDIA_EVENT_AUTH_REQUEST: + { + llinfos << "MEDIA_EVENT_AUTH_REQUEST, url " << plugin->getAuthURL() << ", realm " << plugin->getAuthRealm() << LL_ENDL; + //plugin->sendAuthResponse(false, "", ""); + } + break; case LLViewerMediaObserver::MEDIA_EVENT_CLOSE_REQUEST: { diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 4025a4484f..6f8d12e676 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -155,6 +155,9 @@ public: static void proxyWindowOpened(const std::string &target, const std::string &uuid); static void proxyWindowClosed(const std::string &uuid); + static void createSpareBrowserMediaSource(); + static LLPluginClassMedia* getSpareBrowserMediaSource(); + private: static void setOpenIDCookie(); static void onTeleportFinished(); @@ -162,6 +165,7 @@ private: static LLPluginCookieStore *sCookieStore; static LLURL sOpenIDURL; static std::string sOpenIDCookie; + static LLPluginClassMedia* sSpareBrowserMediaSource; }; // Implementation functions not exported into header file diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 03490034d8..c43a5975fd 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -7165,6 +7165,12 @@ void handle_web_browser_test(const LLSD& param) LLWeb::loadURLInternal(url); } +void handle_web_content_test(const LLSD& param) +{ + std::string url = param.asString(); + LLWeb::loadWebURLInternal(url); +} + void handle_buy_currency_test(void*) { std::string url = @@ -7915,7 +7921,8 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache"); // Advanced > UI - commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); + commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser + commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest"); view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr"); view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 99e869dafc..40f0b43313 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -586,6 +586,18 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() << LL_ENDL; } break; + + case MEDIA_EVENT_AUTH_REQUEST: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_AUTH_REQUEST, url " << self->getAuthURL() << ", realm " << self->getAuthRealm() << LL_ENDL; + } + break; + + case MEDIA_EVENT_LINK_HOVERED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << LL_ENDL; + }; + break; }; } diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index 73a37a6993..91a713be56 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -35,6 +35,7 @@ #include "llagent.h" #include "llappviewer.h" #include "llfloatermediabrowser.h" +#include "llfloaterwebcontent.h" #include "llfloaterreg.h" #include "lllogininstance.h" #include "llparcel.h" @@ -102,6 +103,13 @@ void LLWeb::loadURLInternal(const std::string &url, const std::string& target, c LLFloaterMediaBrowser::create(url, target, uuid); } +// static +// Explicitly open a Web URL using the Web content floater +void LLWeb::loadWebURLInternal(const std::string &url, const std::string& target, const std::string& uuid) +{ + LLFloaterWebContent::create(url, target, uuid); +} + // static void LLWeb::loadURLExternal(const std::string& url, const std::string& uuid) diff --git a/indra/newview/llweb.h b/indra/newview/llweb.h index 2915376583..3fe5a4dcad 100644 --- a/indra/newview/llweb.h +++ b/indra/newview/llweb.h @@ -57,6 +57,10 @@ public: static void loadURLExternal(const std::string& url, const std::string& uuid); static void loadURLExternal(const std::string& url, bool async, const std::string& uuid = LLStringUtil::null); + // Explicitly open a Web URL using the Web content floater vs. the more general media browser + static void loadWebURLInternal(const std::string &url, const std::string& target, const std::string& uuid); + static void loadWebURLInternal(const std::string &url) { loadWebURLInternal(url, LLStringUtil::null, LLStringUtil::null); } + /// Returns escaped url (eg, " " to "%20") - used by all loadURL methods static std::string escapeURL(const std::string& url); /// Expands various strings like [LANG], [VERSION], etc. in a URL diff --git a/indra/newview/skins/default/xui/en/floater_help_browser.xml b/indra/newview/skins/default/xui/en/floater_help_browser.xml index 837923bcf6..02e50ee584 100644 --- a/indra/newview/skins/default/xui/en/floater_help_browser.xml +++ b/indra/newview/skins/default/xui/en/floater_help_browser.xml @@ -36,7 +36,8 @@ user_resize="false" width="620"> <web_browser - trusted_content="true" + trusted_content="true" + initial_mime_type="text/html" bottom="-25" follows="left|right|top|bottom" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/floater_web_content.xml b/indra/newview/skins/default/xui/en/floater_web_content.xml new file mode 100644 index 0000000000..97a7a0e737 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_web_content.xml @@ -0,0 +1,153 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ can_resize="true"
+ height="440"
+ layout="topleft"
+ min_height="140"
+ min_width="467"
+ name="floater_web_content"
+ help_topic="floater_web_content"
+ save_rect="true"
+ auto_tile="true"
+ title="WEB CONTENT"
+ width="820">
+ <layout_stack
+ bottom="440"
+ follows="left|right|top|bottom"
+ layout="topleft"
+ left="5"
+ name="stack1"
+ orientation="vertical"
+ top="20"
+ width="810">
+ <layout_panel
+ auto_resize="false"
+ default_tab_group="1"
+ height="22"
+ layout="topleft"
+ left="0"
+ min_height="20"
+ name="nav_controls"
+ top="400"
+ user_resize="false"
+ width="800">
+ <button
+ image_overlay="Arrow_Left_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ hover_glow_amount="0.15"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="1"
+ name="back"
+ top="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Back" />
+ </button>
+ <button
+ image_overlay="Stop_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ enabled="false"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="27"
+ name="stop"
+ top_delta="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Stop" />
+ </button>
+ <button
+ image_overlay="Refresh_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="27"
+ name="reload"
+ top_delta="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Reload" />
+ </button>
+ <button
+ image_overlay="Arrow_Right_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="51"
+ name="forward"
+ top_delta="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Forward" />
+ </button>
+ <combo_box
+ allow_text_entry="true"
+ follows="left|top|right"
+ tab_group="1"
+ height="22"
+ layout="topleft"
+ left_pad="4"
+ max_chars="1024"
+ name="address"
+ combo_editor.select_on_focus="true"
+ top_delta="0"
+ width="729">
+ <combo_box.commit_callback
+ function="WebContent.EnterAddress" />
+ </combo_box>
+ </layout_panel>
+ <layout_panel
+ height="40"
+ layout="topleft"
+ left_delta="0"
+ name="external_controls"
+ top_delta="0"
+ user_resize="false"
+ width="540">
+ <web_browser
+ bottom="-22"
+ follows="all"
+ layout="topleft"
+ left="0"
+ name="webbrowser"
+ top="0"/>
+ <text
+ type="string"
+ length="100"
+ follows="bottom|left"
+ height="20"
+ layout="topleft"
+ left_delta="0"
+ name="statusbartext"
+ top_pad="5"
+ width="452"/>
+ <progress_bar
+ color_bar="0.3 1.0 0.3 1"
+ follows="bottom|right"
+ height="16"
+ top_delta="-1"
+ left_pad="24"
+ layout="topleft"
+ name="statusbarprogress"
+ width="64"/>
+ </layout_panel>
+ </layout_stack>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml index 4f982cc8e9..2f47d4e201 100644 --- a/indra/newview/skins/default/xui/en/menu_login.xml +++ b/indra/newview/skins/default/xui/en/menu_login.xml @@ -182,6 +182,13 @@ function="Advanced.WebBrowserTest" parameter="http://join.secondlife.com/"/> </menu_item_call> + <menu_item_call + label="Web Content Floater Test" + name="Web Content Floater Test"> + <menu_item_call.on_click + function="Advanced.WebContentTest" + parameter="http://www.google.com"/> + </menu_item_call> <menu_item_separator/> <menu_item_check label="Show Grid Picker" diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 907f68dc06..9ac811971e 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2629,7 +2629,14 @@ function="Advanced.WebBrowserTest" parameter="http://secondlife.com/app/search/slurls.html"/> </menu_item_call> - <menu_item_call + <menu_item_call + label="Web Content Browser Test" + name="Web Content Browser Test"> + <menu_item_call.on_click + function="Advanced.WebContentTest" + parameter="http://secondlife.com/app/search/slurls.html"/> + </menu_item_call> + <menu_item_call label="Dump SelectMgr" name="Dump SelectMgr"> <menu_item_call.on_click diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 60b876d163..39d623b246 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -5009,7 +5009,7 @@ If you want to view streaming media on parcels that support it you should go to type="notify"> No Media Plugin was found to handle the "[MIME_TYPE]" mime type. Media of this type will be unavailable. <unique> - <context key="[MIME_TYPE]"/> + <context>MIME_TYPE</context> </unique> </notification> @@ -5911,7 +5911,7 @@ You may only select up to [MAX_SELECT] items from this list. [NAME] is inviting you to a Voice Chat call. Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller. <unique> - <context key="NAME"/> + <context>NAME</context> </unique> <form name="form"> <button @@ -5960,8 +5960,8 @@ Click Accept to join the call or Decline to decline the invitation. Click Block [NAME] has joined a Voice Chat call with the group [GROUP]. Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller. <unique> - <context key="NAME"/> - <context key="GROUP"/> + <context>NAME</context> + <context>GROUP</context> </unique> <form name="form"> <button @@ -5986,7 +5986,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block [NAME] has joined a voice chat call with a conference chat. Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller. <unique> - <context key="NAME"/> + <context>NAME</context> </unique> <form name="form"> <button @@ -6011,7 +6011,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block [NAME] is inviting you to a conference chat. Click Accept to join the chat or Decline to decline the invitation. Click Block to block this caller. <unique> - <context key="NAME"/> + <context>NAME</context> </unique> <form name="form"> <button @@ -6035,7 +6035,7 @@ Click Accept to join the chat or Decline to decline the invitation. Click Block type="notifytip"> The voice call you are trying to join, [VOICE_CHANNEL_NAME], has reached maximum capacity. Please try again later. <unique> - <context key="VOICE_CHANNEL_NAME"/> + <context>VOICE_CHANNEL_NAME</context> </unique> </notification> @@ -6053,7 +6053,7 @@ We're sorry. This area has reached maximum capacity for voice conversation type="notifytip"> You have been disconnected from [VOICE_CHANNEL_NAME]. You will now be reconnected to Nearby Voice Chat. <unique> - <context key="VOICE_CHANNEL_NAME"/> + <context>VOICE_CHANNEL_NAME</context> </unique> </notification> @@ -6063,7 +6063,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME]. You will now be reconnect type="notifytip"> [VOICE_CHANNEL_NAME] has ended the call. You will now be reconnected to Nearby Voice Chat. <unique> - <context key="VOICE_CHANNEL_NAME"/> + <context>VOICE_CHANNEL_NAME</context> </unique> </notification> @@ -6073,7 +6073,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME]. You will now be reconnect type="notifytip"> [VOICE_CHANNEL_NAME] has declined your call. You will now be reconnected to Nearby Voice Chat. <unique> - <context key="VOICE_CHANNEL_NAME"/> + <context>VOICE_CHANNEL_NAME</context> </unique> </notification> @@ -6083,7 +6083,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME]. You will now be reconnect type="notifytip"> [VOICE_CHANNEL_NAME] is not available to take your call. You will now be reconnected to Nearby Voice Chat. <unique> - <context key="VOICE_CHANNEL_NAME"/> + <context>VOICE_CHANNEL_NAME</context> </unique> </notification> @@ -6093,7 +6093,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME]. You will now be reconnect type="notifytip"> Failed to connect to [VOICE_CHANNEL_NAME], please try again later. You will now be reconnected to Nearby Voice Chat. <unique> - <context key="VOICE_CHANNEL_NAME"/> + <context>VOICE_CHANNEL_NAME</context> </unique> </notification> @@ -6176,7 +6176,7 @@ Cannot enter parcel, you are not on the access list. type="notifytip"> You do not have permission to connect to voice chat for [VOICE_CHANNEL_NAME]. <unique> - <context key="VOICE_CHANNEL_NAME"/> + <context>VOICE_CHANNEL_NAME</context> </unique> </notification> @@ -6186,7 +6186,7 @@ You do not have permission to connect to voice chat for [VOICE_CHANNEL_NAME]. type="notifytip"> An error has occurred while trying to connect to voice chat for [VOICE_CHANNEL_NAME]. Please try again later. <unique> - <context key="VOICE_CHANNEL_NAME"/> + <context>VOICE_CHANNEL_NAME</context> </unique> </notification> @@ -6574,6 +6574,23 @@ Mute everyone? </form> </notification> + <notification + name="AuthRequest" + type="browser"> + Enter user name and password to continue. + <form name="form"> + <input name="username" type="text" text="User Name"/> + <input name="password" type="password" text="Password"/> + <button default="true" + index="0" + name="ok" + text="Submit"/> + <button index="1" + name="cancel" + text="Cancel"/> + </form> + </notification> + <global name="UnsupportedCPU"> - Your CPU speed does not meet the minimum requirements. diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index b181ca3bba..1b6c80b376 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -91,6 +91,7 @@ follows="left|bottom" height="22" max_length_bytes="16" name="password_edit" +is_password="true" select_on_focus="true" top_pad="0" width="135" /> diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp index 873fa23db8..4a2272032b 100644 --- a/indra/test_apps/llplugintest/llmediaplugintest.cpp +++ b/indra/test_apps/llplugintest/llmediaplugintest.cpp @@ -2220,6 +2220,21 @@ void LLMediaPluginTest::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent e << ", height = " << self->getGeometryHeight() << std::endl; break; + + case MEDIA_EVENT_AUTH_REQUEST: + { + //std::cerr << "Media event: MEDIA_EVENT_AUTH_REQUEST, url " << self->getAuthURL() ", realm " << self->getAuthRealm() << std::endl; + + // TODO: display an auth dialog + self->sendAuthResponse(false, "", ""); + } + break; + + case MEDIA_EVENT_LINK_HOVERED: + { + std::cerr << "Media event: MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << std::endl; + }; + break; } } diff --git a/install.xml b/install.xml index 98e983299e..f50088495a 100644 --- a/install.xml +++ b/install.xml @@ -981,9 +981,9 @@ anguage Infrstructure (CLI) international standard</string> <key>darwin</key> <map> <key>md5sum</key> - <string>34d9e4c93678a422cf80521bf0cd7628</string> + <string>c69208572a74df24e910e419fbbbb884</string> <key>url</key> - <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-4.6-darwin-20100914.tar.bz2</uri> + <uri>http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/llqtwebkit-darwin-qt4.7.1-20101201.tar.bz2</uri> </map> <key>linux</key> <map> @@ -995,9 +995,9 @@ anguage Infrstructure (CLI) international standard</string> <key>windows</key> <map> <key>md5sum</key> - <string>4b8412833c00f8cdaba26808f0ddb404</string> + <string>40ee8464da01fde6845b8276dcb4cc0f</string> <key>url</key> - <uri>http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/llqtwebkit-windows-qt4.6-20100916.tar.bz2</uri> + <uri>http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/llqtwebkit-windows-qt4.7.1-20101201.tar.bz2</uri> </map> </map> </map> |