diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-19 18:05:56 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-19 18:05:56 +0000 |
commit | 8b8e7c9bce4198a4ee2865d9dfce6e8baa173ad3 (patch) | |
tree | 938304b8e1be417c1b9c73d7463dacbc1da79843 /chrome/browser | |
parent | f2c4ee3627e6039fd42bd7c0c93e902b72653449 (diff) | |
download | chromium_src-8b8e7c9bce4198a4ee2865d9dfce6e8baa173ad3.zip chromium_src-8b8e7c9bce4198a4ee2865d9dfce6e8baa173ad3.tar.gz chromium_src-8b8e7c9bce4198a4ee2865d9dfce6e8baa173ad3.tar.bz2 |
Initial version of chrome.experimental.sidebar extension API.
BUG=51084
TEST=Run interactive_ui_tests and browser_tests.
New:
- sidebar Extension API (design doc: https://docs.google.com/a/google.com/Doc?docid=0AV4Qg3xyZ8RQZGZtbWIydDJfNWc0eHJtbmRm&hl=en);
- Sidebar panel in Chrome browser view;
Original review=http://codereview.chromium.org/2836040/show
Patch by alekseys@google.com
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@56716 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
39 files changed, 1599 insertions, 144 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 6cad802..e07d701 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -1163,7 +1163,7 @@ bool Browser::SupportsWindowFeatureImpl(WindowFeature feature, window_->IsFullscreen(); #endif - unsigned int features = FEATURE_INFOBAR; + unsigned int features = FEATURE_INFOBAR | FEATURE_SIDEBAR; #if !defined(OS_CHROMEOS) // Chrome OS opens a FileBrowse pop up instead of using download shelf. @@ -1922,6 +1922,7 @@ void Browser::RegisterPrefs(PrefService* prefs) { prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0); prefs->RegisterIntegerPref(prefs::kDevToolsSplitLocation, -1); prefs->RegisterDictionaryPref(prefs::kPreferencesWindowPlacement); + prefs->RegisterIntegerPref(prefs::kExtensionSidebarWidth, -1); } // static diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index 17d7955..12def80 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -8,6 +8,7 @@ #include <map> #include <set> +#include <string> #include <vector> #include "base/basictypes.h" @@ -86,7 +87,8 @@ class Browser : public TabStripModelDelegate, FEATURE_LOCATIONBAR = 8, FEATURE_BOOKMARKBAR = 16, FEATURE_INFOBAR = 32, - FEATURE_DOWNLOADSHELF = 64 + FEATURE_SIDEBAR = 64, + FEATURE_DOWNLOADSHELF = 128 }; // Maximized state on creation. diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h index a853c74..0eeb08d 100644 --- a/chrome/browser/browser_process.h +++ b/chrome/browser/browser_process.h @@ -29,6 +29,7 @@ class NotificationUIManager; class PrefService; class ProfileManager; class ResourceDispatcherHost; +class SidebarManager; class TabCloseableStateWatcher; class ThumbnailGenerator; @@ -63,6 +64,7 @@ class BrowserProcess { virtual ProfileManager* profile_manager() = 0; virtual PrefService* local_state() = 0; virtual DevToolsManager* devtools_manager() = 0; + virtual SidebarManager* sidebar_manager() = 0; virtual Clipboard* clipboard() = 0; // Returns the manager for desktop notifications. diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index f314388..ff43685 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc @@ -43,6 +43,7 @@ #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/resource_dispatcher_host.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" +#include "chrome/browser/sidebar/sidebar_manager.h" #include "chrome/browser/tab_closeable_state_watcher.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" @@ -85,6 +86,7 @@ BrowserProcessImpl::BrowserProcessImpl(const CommandLine& command_line) created_icon_manager_(false), created_debugger_wrapper_(false), created_devtools_manager_(false), + created_sidebar_manager_(false), created_notification_ui_manager_(false), module_ref_count_(0), did_start_(false), @@ -346,6 +348,13 @@ DevToolsManager* BrowserProcessImpl::devtools_manager() { return devtools_manager_.get(); } +SidebarManager* BrowserProcessImpl::sidebar_manager() { + DCHECK(CalledOnValidThread()); + if (!created_sidebar_manager_) + CreateSidebarManager(); + return sidebar_manager_.get(); +} + Clipboard* BrowserProcessImpl::clipboard() { DCHECK(CalledOnValidThread()); return clipboard_.get(); @@ -617,6 +626,12 @@ void BrowserProcessImpl::CreateDevToolsManager() { devtools_manager_ = new DevToolsManager(); } +void BrowserProcessImpl::CreateSidebarManager() { + DCHECK(sidebar_manager_.get() == NULL); + created_sidebar_manager_ = true; + sidebar_manager_ = new SidebarManager(); +} + void BrowserProcessImpl::CreateGoogleURLTracker() { DCHECK(google_url_tracker_.get() == NULL); scoped_ptr<GoogleURLTracker> google_url_tracker(new GoogleURLTracker); diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h index 9118ff6..0ae2de6 100644 --- a/chrome/browser/browser_process_impl.h +++ b/chrome/browser/browser_process_impl.h @@ -49,6 +49,7 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe { virtual ProfileManager* profile_manager(); virtual PrefService* local_state(); virtual DevToolsManager* devtools_manager(); + virtual SidebarManager* sidebar_manager(); virtual Clipboard* clipboard(); virtual NotificationUIManager* notification_ui_manager(); virtual IconManager* icon_manager(); @@ -100,6 +101,7 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe { void CreateIconManager(); void CreateDebuggerWrapper(int port, bool useHttp); void CreateDevToolsManager(); + void CreateSidebarManager(); void CreateGoogleURLTracker(); void CreateIntranetRedirectDetector(); void CreateNotificationUIManager(); @@ -150,6 +152,9 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe { bool created_devtools_manager_; scoped_refptr<DevToolsManager> devtools_manager_; + bool created_sidebar_manager_; + scoped_refptr<SidebarManager> sidebar_manager_; + scoped_ptr<Clipboard> clipboard_; // Manager for desktop notification UI. diff --git a/chrome/browser/browser_window.h b/chrome/browser/browser_window.h index 6554713..98cd042 100644 --- a/chrome/browser/browser_window.h +++ b/chrome/browser/browser_window.h @@ -349,6 +349,9 @@ class BrowserWindowTesting { // Returns the TabContentsContainer. virtual views::View* GetTabContentsContainerView() const = 0; + // Returns the TabContentsContainer. + virtual views::View* GetSidebarContainerView() const = 0; + // Returns the ToolbarView. virtual ToolbarView* GetToolbarView() const = 0; #endif diff --git a/chrome/browser/dom_ui/dom_ui.cc b/chrome/browser/dom_ui/dom_ui.cc index 118e262..a5b965a 100644 --- a/chrome/browser/dom_ui/dom_ui.cc +++ b/chrome/browser/dom_ui/dom_ui.cc @@ -16,6 +16,7 @@ #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_contents_view.h" #include "chrome/common/bindings_policy.h" +#include "chrome/common/render_messages.h" namespace { @@ -53,19 +54,15 @@ DOMUI::~DOMUI() { // DOMUI, public: ------------------------------------------------------------- -void DOMUI::ProcessDOMUIMessage(const std::string& message, - const ListValue* content, - const GURL& source_url, - int request_id, - bool has_callback) { +void DOMUI::ProcessDOMUIMessage(const ViewHostMsg_DomMessage_Params& params) { // Look up the callback for this message. MessageCallbackMap::const_iterator callback = - message_callbacks_.find(message); + message_callbacks_.find(params.name); if (callback == message_callbacks_.end()) return; // Forward this message and content on. - callback->second->Run(content); + callback->second->Run(¶ms.arguments); } void DOMUI::CallJavascriptFunction(const std::wstring& function_name) { diff --git a/chrome/browser/dom_ui/dom_ui.h b/chrome/browser/dom_ui/dom_ui.h index 66c5455..d805921 100644 --- a/chrome/browser/dom_ui/dom_ui.h +++ b/chrome/browser/dom_ui/dom_ui.h @@ -20,9 +20,10 @@ class GURL; class ListValue; class Profile; class RenderViewHost; -class Value; class TabContents; class ThemeProvider; +class Value; +struct ViewHostMsg_DomMessage_Params; // A DOMUI sets up the datasources and message handlers for a given HTML-based // UI. It is contained by a DOMUIManager. @@ -42,11 +43,7 @@ class DOMUI { virtual void RenderViewReused(RenderViewHost* render_view_host) {} // Called from TabContents. - virtual void ProcessDOMUIMessage(const std::string& message, - const ListValue* content, - const GURL& source_url, - int request_id, - bool has_callback); + virtual void ProcessDOMUIMessage(const ViewHostMsg_DomMessage_Params& params); // Used by DOMMessageHandlers. typedef Callback1<const Value*>::Type MessageCallback; diff --git a/chrome/browser/extensions/extension_dom_ui.cc b/chrome/browser/extensions/extension_dom_ui.cc index dd9d169..598e43b 100644 --- a/chrome/browser/extensions/extension_dom_ui.cc +++ b/chrome/browser/extensions/extension_dom_ui.cc @@ -162,16 +162,9 @@ void ExtensionDOMUI::RenderViewReused(RenderViewHost* render_view_host) { ResetExtensionBookmarkManagerEventRouter(); } -void ExtensionDOMUI::ProcessDOMUIMessage(const std::string& message, - const ListValue* content, - const GURL& source_url, - int request_id, - bool has_callback) { - extension_function_dispatcher_->HandleRequest(message, - content, - source_url, - request_id, - has_callback); +void ExtensionDOMUI::ProcessDOMUIMessage( + const ViewHostMsg_DomMessage_Params& params) { + extension_function_dispatcher_->HandleRequest(params); } Browser* ExtensionDOMUI::GetBrowser() const { diff --git a/chrome/browser/extensions/extension_dom_ui.h b/chrome/browser/extensions/extension_dom_ui.h index e0698e7..d5f146d 100644 --- a/chrome/browser/extensions/extension_dom_ui.h +++ b/chrome/browser/extensions/extension_dom_ui.h @@ -20,6 +20,7 @@ class PrefService; class Profile; class RenderViewHost; class TabContents; +struct ViewHostMsg_DomMessage_Params; // This class implements DOMUI for extensions and allows extensions to put UI in // the main tab contents area. @@ -38,11 +39,7 @@ class ExtensionDOMUI // DOMUI virtual void RenderViewCreated(RenderViewHost* render_view_host); virtual void RenderViewReused(RenderViewHost* render_view_host); - virtual void ProcessDOMUIMessage(const std::string& message, - const ListValue* content, - const GURL& source_url, - int request_id, - bool has_callback); + virtual void ProcessDOMUIMessage(const ViewHostMsg_DomMessage_Params& params); // ExtensionFunctionDispatcher::Delegate virtual Browser* GetBrowser() const; diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h index 44fde69..51f25fe 100644 --- a/chrome/browser/extensions/extension_function.h +++ b/chrome/browser/extensions/extension_function.h @@ -90,6 +90,9 @@ class ExtensionFunction : public base::RefCountedThreadSafe<ExtensionFunction> { void set_include_incognito(bool include) { include_incognito_ = include; } bool include_incognito() { return include_incognito_; } + void set_user_gesture(bool user_gesture) { user_gesture_ = user_gesture; } + bool user_gesture() const { return user_gesture_; } + // Execute the API. Clients should call set_raw_args() and // set_request_id() before calling this method. Derived classes should be // ready to return raw_result() and error() before returning from this @@ -149,6 +152,9 @@ class ExtensionFunction : public base::RefCountedThreadSafe<ExtensionFunction> { // True if this callback should include information from incognito contexts. bool include_incognito_; + // True if the call was made in response of user gesture. + bool user_gesture_; + DISALLOW_COPY_AND_ASSIGN(ExtensionFunction); }; diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index cb9e126..a2b16ee 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -39,6 +39,7 @@ #include "chrome/browser/extensions/extension_processes_api.h" #include "chrome/browser/extensions/extension_proxy_api.h" #include "chrome/browser/extensions/extension_rlz_module.h" +#include "chrome/browser/extensions/extension_sidebar_api.h" #include "chrome/browser/extensions/extension_tabs_module.h" #include "chrome/browser/extensions/extension_test_api.h" #if defined(OS_CHROMEOS) @@ -249,6 +250,17 @@ void FactoryRegistry::ResetFunctions() { // Proxies. RegisterFunction<UseCustomProxySettingsFunction>(); + + // Sidebar. + RegisterFunction<CollapseSidebarFunction>(); + RegisterFunction<ExpandSidebarFunction>(); + RegisterFunction<GetStateSidebarFunction>(); + RegisterFunction<HideSidebarFunction>(); + RegisterFunction<NavigateSidebarFunction>(); + RegisterFunction<SetBadgeTextSidebarFunction>(); + RegisterFunction<SetIconSidebarFunction>(); + RegisterFunction<SetTitleSidebarFunction>(); + RegisterFunction<ShowSidebarFunction>(); } void FactoryRegistry::GetAllNames(std::vector<std::string>* names) { @@ -400,20 +412,18 @@ Browser* ExtensionFunctionDispatcher::GetCurrentBrowser( return browser; } -void ExtensionFunctionDispatcher::HandleRequest(const std::string& name, - const ListValue* args, - const GURL& source_url, - int request_id, - bool has_callback) { +void ExtensionFunctionDispatcher::HandleRequest( + const ViewHostMsg_DomMessage_Params& params) { scoped_refptr<ExtensionFunction> function( - FactoryRegistry::instance()->NewFunction(name)); + FactoryRegistry::instance()->NewFunction(params.name)); function->set_dispatcher_peer(peer_); function->set_profile(profile_); function->set_extension_id(extension_id()); - function->SetArgs(args); - function->set_source_url(source_url); - function->set_request_id(request_id); - function->set_has_callback(has_callback); + function->SetArgs(¶ms.arguments); + function->set_source_url(params.source_url); + function->set_request_id(params.request_id); + function->set_has_callback(params.has_callback); + function->set_user_gesture(params.user_gesture); ExtensionsService* service = profile()->GetExtensionsService(); DCHECK(service); Extension* extension = service->GetExtensionById(extension_id(), false); @@ -421,7 +431,8 @@ void ExtensionFunctionDispatcher::HandleRequest(const std::string& name, function->set_include_incognito(service->IsIncognitoEnabled(extension)); ExtensionsQuotaService* quota = service->quota_service(); - if (quota->Assess(extension_id(), function, args, base::TimeTicks::Now())) { + if (quota->Assess(extension_id(), function, ¶ms.arguments, + base::TimeTicks::Now())) { // See crbug.com/39178. ExternalProtocolHandler::PermitLaunchUrl(); diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h index e089e29..9bddecf 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.h +++ b/chrome/browser/extensions/extension_function_dispatcher.h @@ -20,6 +20,7 @@ class ListValue; class Profile; class RenderViewHost; class TabContents; +struct ViewHostMsg_DomMessage_Params; // A factory function for creating new ExtensionFunction instances. typedef ExtensionFunction* (*ExtensionFunctionFactory)(); @@ -92,8 +93,7 @@ class ExtensionFunctionDispatcher { Delegate* delegate() { return delegate_; } // Handle a request to execute an extension function. - void HandleRequest(const std::string& name, const ListValue* args, - const GURL& source_url, int request_id, bool has_callback); + void HandleRequest(const ViewHostMsg_DomMessage_Params& params); // Send a response to a function. void SendResponse(ExtensionFunction* api, bool success); diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index 7e78619..0b3cc5a 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -493,14 +493,10 @@ WebPreferences ExtensionHost::GetWebkitPrefs() { return webkit_prefs; } -void ExtensionHost::ProcessDOMUIMessage(const std::string& message, - const ListValue* content, - const GURL& source_url, - int request_id, - bool has_callback) { +void ExtensionHost::ProcessDOMUIMessage( + const ViewHostMsg_DomMessage_Params& params) { if (extension_function_dispatcher_.get()) { - extension_function_dispatcher_->HandleRequest( - message, content, source_url, request_id, has_callback); + extension_function_dispatcher_->HandleRequest(params); } } diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h index e8fd600..c473e87 100644 --- a/chrome/browser/extensions/extension_host.h +++ b/chrome/browser/extensions/extension_host.h @@ -125,11 +125,7 @@ class ExtensionHost : public RenderViewHostDelegate, RenderViewHost* render_view_host); virtual WebPreferences GetWebkitPrefs(); - virtual void ProcessDOMUIMessage(const std::string& message, - const ListValue* content, - const GURL& source_url, - int request_id, - bool has_callback); + virtual void ProcessDOMUIMessage(const ViewHostMsg_DomMessage_Params& params); virtual void RunJavaScriptMessage(const std::wstring& message, const std::wstring& default_prompt, const GURL& frame_url, diff --git a/chrome/browser/extensions/extension_sidebar_api.cc b/chrome/browser/extensions/extension_sidebar_api.cc new file mode 100644 index 0000000..9453ac7 --- /dev/null +++ b/chrome/browser/extensions/extension_sidebar_api.cc @@ -0,0 +1,270 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/extension_sidebar_api.h" + +#include "base/json/json_writer.h" +#include "base/string_number_conversions.h" +#include "base/string_util.h" +#include "base/string16.h" +#include "base/values.h" +#include "chrome/browser/extensions/extension_message_service.h" +#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_tabs_module.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/sidebar/sidebar_container.h" +#include "chrome/browser/sidebar/sidebar_manager.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_constants.h" +#include "chrome/common/extensions/extension_error_utils.h" +#include "chrome/common/render_messages.h" +#include "chrome/common/url_constants.h" +#include "ipc/ipc_message_utils.h" +#include "third_party/skia/include/core/SkBitmap.h" + +namespace { +// Errors. +const char kNoTabError[] = "No tab with id: *."; +const char kInvalidUrlError[] = "Invalid url: \"*\"."; +const char kNoCurrentWindowError[] = "No current browser window was found"; +const char kNoDefaultTabError[] = "No default tab was found"; +const char kInvalidExpandContextError[] = + "Sidebar can be expanded only in response to an explicit user gesture"; +// Keys. +const char kBadgeTextKey[] = "text"; +const char kImageDataKey[] = "imageData"; +const char kStateKey[] = "state"; +const char kTabIdKey[] = "tabId"; +const char kTitleKey[] = "title"; +const char kUrlKey[] = "url"; +// Events. +const char kOnStateChanged[] = "experimental.sidebar.onStateChanged"; +} // namespace + +namespace extension_sidebar_constants { +// Sidebar states. +const char kActiveState[] = "active"; +const char kHiddenState[] = "hidden"; +const char kShownState[] = "shown"; +} + +static GURL ResolvePossiblyRelativeURL(const std::string& url_string, + Extension* extension) { + GURL url = GURL(url_string); + if (!url.is_valid()) + url = extension->GetResourceURL(url_string); + + return url; +} + +static bool CanUseHost(Extension* extension, + const GURL& url, + std::string* error) { + if (extension->HasHostPermission(url)) + return true; + + if (error) { + *error = ExtensionErrorUtils::FormatErrorMessage( + extension_manifest_errors::kCannotAccessPage, url.spec()); + } + + return false; +} + + +// static +void ExtensionSidebarEventRouter::OnStateChanged( + Profile* profile, int tab_id, const std::string& content_id, + const std::string& state) { + DictionaryValue* details = new DictionaryValue; + details->Set(kTabIdKey, Value::CreateIntegerValue(tab_id)); + details->Set(kStateKey, Value::CreateStringValue(state)); + + ListValue args; + args.Set(0, details); + std::string json_args; + base::JSONWriter::Write(&args, false, &json_args); + + const std::string& extension_id(content_id); + profile->GetExtensionMessageService()->DispatchEventToExtension( + extension_id, kOnStateChanged, json_args, + profile->IsOffTheRecord(), GURL()); +} + + +bool SidebarFunction::RunImpl() { + if (!args_.get()) + return false; + + DictionaryValue* details = NULL; + DictionaryValue default_details; + if (args_->empty()) { + details = &default_details; + } else { + EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details)); + } + + int tab_id; + TabContents* tab_contents = NULL; + if (details->HasKey(kTabIdKey)) { + EXTENSION_FUNCTION_VALIDATE(details->GetInteger(kTabIdKey, &tab_id)); + if (!ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(), + NULL, NULL, &tab_contents, NULL)) { + error_ = ExtensionErrorUtils::FormatErrorMessage( + kNoTabError, base::IntToString(tab_id)); + return false; + } + } else { + Browser* browser = GetCurrentBrowser(); + if (!browser) { + error_ = kNoCurrentWindowError; + return false; + } + if (!ExtensionTabUtil::GetDefaultTab(browser, &tab_contents, &tab_id)) { + error_ = kNoDefaultTabError; + return false; + } + } + if (!tab_contents) + return false; + + std::string content_id(GetExtension()->id()); + return RunImpl(tab_contents, content_id, *details); +} + + +bool CollapseSidebarFunction::RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details) { + SidebarManager::GetInstance()->CollapseSidebar(tab, content_id); + return true; +} + +bool ExpandSidebarFunction::RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details) { + // TODO(alekseys): enable this check back when WebKit's user gesture flag + // reporting for extension calls is fixed. + // if (!user_gesture()) { + // error_ = kInvalidExpandContextError; + // return false; + // } + SidebarManager::GetInstance()->ExpandSidebar(tab, content_id); + return true; +} + +bool GetStateSidebarFunction::RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details) { + SidebarManager* manager = SidebarManager::GetInstance(); + + const char* result = extension_sidebar_constants::kHiddenState; + if (manager->GetSidebarTabContents(tab, content_id)) { + bool is_active = false; + // Sidebar is considered active only if tab is selected, sidebar UI + // is expanded and this extension's content is displayed on it. + SidebarContainer* active_sidebar = + manager->GetActiveSidebarContainerFor(tab); + // Check if sidebar UI is expanded and this extension's content + // is displayed on it. + if (active_sidebar && active_sidebar->content_id() == content_id) { + if (!details.HasKey(kTabIdKey)) { + is_active = NULL != GetCurrentBrowser(); + } else { + int tab_id; + EXTENSION_FUNCTION_VALIDATE(details.GetInteger(kTabIdKey, &tab_id)); + + // Check if this tab is selected. + Browser* browser = GetCurrentBrowser(); + TabContents* contents = NULL; + int default_tab_id = -1; + if (browser && + ExtensionTabUtil::GetDefaultTab(browser, &contents, + &default_tab_id)) { + is_active = default_tab_id == tab_id; + } + } + } + + result = is_active ? extension_sidebar_constants::kActiveState : + extension_sidebar_constants::kShownState; + } + + result_.reset(Value::CreateStringValue(result)); + return true; +} + +bool HideSidebarFunction::RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details) { + SidebarManager::GetInstance()->HideSidebar(tab, content_id); + return true; +} + +bool NavigateSidebarFunction::RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details) { + std::string url_string; + EXTENSION_FUNCTION_VALIDATE(details.GetString(kUrlKey, &url_string)); + GURL url = ResolvePossiblyRelativeURL(url_string, GetExtension()); + if (!url.is_valid()) { + error_ = ExtensionErrorUtils::FormatErrorMessage(kInvalidUrlError, + url_string); + return false; + } + if (!url.SchemeIs(chrome::kExtensionScheme) && + !CanUseHost(GetExtension(), url, &error_)) { + return false; + } + // Disallow requests outside of the requesting extension view's extension. + if (url.SchemeIs(chrome::kExtensionScheme)) { + std::string extension_id(url.host()); + if (extension_id != GetExtension()->id()) + return false; + } + + SidebarManager::GetInstance()->NavigateSidebar(tab, content_id, GURL(url)); + return true; +} + +bool SetBadgeTextSidebarFunction::RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details) { + string16 badge_text; + EXTENSION_FUNCTION_VALIDATE(details.GetString(kBadgeTextKey, &badge_text)); + SidebarManager::GetInstance()->SetSidebarBadgeText( + tab, content_id, badge_text); + return true; +} + +bool SetIconSidebarFunction::RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details) { + BinaryValue* binary; + EXTENSION_FUNCTION_VALIDATE(details.GetBinary(kImageDataKey, &binary)); + IPC::Message bitmap_pickle(binary->GetBuffer(), binary->GetSize()); + void* iter = NULL; + scoped_ptr<SkBitmap> bitmap(new SkBitmap); + EXTENSION_FUNCTION_VALIDATE( + IPC::ReadParam(&bitmap_pickle, &iter, bitmap.get())); + SidebarManager::GetInstance()->SetSidebarIcon(tab, content_id, *bitmap); + return true; +} + +bool SetTitleSidebarFunction::RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details) { + string16 title; + EXTENSION_FUNCTION_VALIDATE(details.GetString(kTitleKey, &title)); + SidebarManager::GetInstance()->SetSidebarTitle(tab, content_id, title); + return true; +} + +bool ShowSidebarFunction::RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details) { + SidebarManager::GetInstance()->ShowSidebar(tab, content_id); + return true; +} diff --git a/chrome/browser/extensions/extension_sidebar_api.h b/chrome/browser/extensions/extension_sidebar_api.h new file mode 100644 index 0000000..e4ab780 --- /dev/null +++ b/chrome/browser/extensions/extension_sidebar_api.h @@ -0,0 +1,117 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_SIDEBAR_API_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_SIDEBAR_API_H_ + +#include <string> +#include "chrome/browser/extensions/extension_function.h" + +class DictionaryValue; +class Profile; +class RenderViewHost; +class TabContents; + +namespace extension_sidebar_constants { +extern const char kActiveState[]; +extern const char kHiddenState[]; +extern const char kShownState[]; +} // namespace extension_sidebar_constants + +// Event router class for events related to the sidebar API. +class ExtensionSidebarEventRouter { + public: + // Sidebar state changed. + static void OnStateChanged( + Profile* profile, int tab_id, const std::string& content_id, + const std::string& state); + + private: + DISALLOW_COPY_AND_ASSIGN(ExtensionSidebarEventRouter); +}; + +// Base class for sidebar function APIs. +class SidebarFunction : public SyncExtensionFunction { + public: + virtual bool RunImpl(); + private: + virtual bool RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details) = 0; +}; + +class CollapseSidebarFunction : public SidebarFunction { + private: + virtual bool RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details); + DECLARE_EXTENSION_FUNCTION_NAME("experimental.sidebar.collapse"); +}; + +class ExpandSidebarFunction : public SidebarFunction { + private: + virtual bool RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details); + DECLARE_EXTENSION_FUNCTION_NAME("experimental.sidebar.expand"); +}; + +class GetStateSidebarFunction : public SidebarFunction { + private: + virtual bool RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details); + DECLARE_EXTENSION_FUNCTION_NAME("experimental.sidebar.getState"); +}; + +class HideSidebarFunction : public SidebarFunction { + private: + virtual bool RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details); + DECLARE_EXTENSION_FUNCTION_NAME("experimental.sidebar.hide"); +}; + +class NavigateSidebarFunction : public SidebarFunction { + private: + virtual bool RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details); + DECLARE_EXTENSION_FUNCTION_NAME("experimental.sidebar.navigate"); +}; + +class SetBadgeTextSidebarFunction : public SidebarFunction { + private: + virtual bool RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details); + DECLARE_EXTENSION_FUNCTION_NAME("experimental.sidebar.setBadgeText"); +}; + +class SetIconSidebarFunction : public SidebarFunction { + private: + virtual bool RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details); + DECLARE_EXTENSION_FUNCTION_NAME("experimental.sidebar.setIcon"); +}; + +class SetTitleSidebarFunction : public SidebarFunction { + private: + virtual bool RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details); + DECLARE_EXTENSION_FUNCTION_NAME("experimental.sidebar.setTitle"); +}; + +class ShowSidebarFunction : public SidebarFunction { + private: + virtual bool RunImpl(TabContents* tab, + const std::string& content_id, + const DictionaryValue& details); + DECLARE_EXTENSION_FUNCTION_NAME("experimental.sidebar.show"); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_SIDEBAR_API_H_ + diff --git a/chrome/browser/extensions/extension_sidebar_apitest.cc b/chrome/browser/extensions/extension_sidebar_apitest.cc new file mode 100644 index 0000000..9d33fa0 --- /dev/null +++ b/chrome/browser/extensions/extension_sidebar_apitest.cc @@ -0,0 +1,19 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/command_line.h" +#include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/common/chrome_switches.h" + +class SidebarApiTest : public ExtensionApiTest { + public: + void SetUpCommandLine(CommandLine* command_line) { + ExtensionApiTest::SetUpCommandLine(command_line); + command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis); + } +}; + +IN_PROC_BROWSER_TEST_F(SidebarApiTest, Sidebar) { + ASSERT_TRUE(RunExtensionTest("sidebar")) << message_; +} diff --git a/chrome/browser/gtk/view_id_util_browsertest.cc b/chrome/browser/gtk/view_id_util_browsertest.cc index b80fb02..be4f38c 100644 --- a/chrome/browser/gtk/view_id_util_browsertest.cc +++ b/chrome/browser/gtk/view_id_util_browsertest.cc @@ -38,7 +38,9 @@ IN_PROC_BROWSER_TEST_F(ViewIDTest, Basic) { i == VIEW_ID_INFO_BAR_CONTAINER || i == VIEW_ID_DOWNLOAD_SHELF || i == VIEW_ID_BOOKMARK_BAR_ELEMENT || - i == VIEW_ID_TAB) { + i == VIEW_ID_TAB || + i == VIEW_ID_SIDE_BAR_CONTAINER || + i == VIEW_ID_SIDE_BAR_SPLIT) { continue; } diff --git a/chrome/browser/notifications/balloon_host.cc b/chrome/browser/notifications/balloon_host.cc index 621fa7e..85022dc 100644 --- a/chrome/browser/notifications/balloon_host.cc +++ b/chrome/browser/notifications/balloon_host.cc @@ -76,14 +76,10 @@ void BalloonHost::RenderViewGone(RenderViewHost* render_view_host) { Close(render_view_host); } -void BalloonHost::ProcessDOMUIMessage(const std::string& message, - const ListValue* content, - const GURL& source_url, - int request_id, - bool has_callback) { +void BalloonHost::ProcessDOMUIMessage( + const ViewHostMsg_DomMessage_Params& params) { if (extension_function_dispatcher_.get()) { - extension_function_dispatcher_->HandleRequest( - message, content, source_url, request_id, has_callback); + extension_function_dispatcher_->HandleRequest(params); } } diff --git a/chrome/browser/notifications/balloon_host.h b/chrome/browser/notifications/balloon_host.h index 45d5c2d..77e52ee 100644 --- a/chrome/browser/notifications/balloon_host.h +++ b/chrome/browser/notifications/balloon_host.h @@ -74,11 +74,7 @@ class BalloonHost : public RenderViewHostDelegate, virtual RenderViewHostDelegate::View* GetViewDelegate() { return this; } - virtual void ProcessDOMUIMessage(const std::string& message, - const ListValue* content, - const GURL& source_url, - int request_id, - bool has_callback); + virtual void ProcessDOMUIMessage(const ViewHostMsg_DomMessage_Params& params); // RenderViewHostDelegate::View methods. Only the ones for opening new // windows are currently implemented. diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 9f1ea87..0ba65d6 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -1279,11 +1279,6 @@ void RenderViewHost::OnMsgDOMUISend( return; } - // DOMUI doesn't use these values yet. - // TODO(aa): When DOMUI is ported to ExtensionFunctionDispatcher, send real - // values here. - const int kRequestId = -1; - const bool kHasCallback = false; scoped_ptr<Value> value; if (!content.empty()) { value.reset(base::JSONReader::Read(content, false)); @@ -1295,11 +1290,18 @@ void RenderViewHost::OnMsgDOMUISend( } } - delegate_->ProcessDOMUIMessage(message, - static_cast<const ListValue*>(value.get()), - source_url, - kRequestId, - kHasCallback); + ViewHostMsg_DomMessage_Params params; + params.name = message; + if (value.get()) + params.arguments.Swap(static_cast<ListValue*>(value.get())); + params.source_url = source_url; + // DOMUI doesn't use these values yet. + // TODO(aa): When DOMUI is ported to ExtensionFunctionDispatcher, send real + // values here. + params.request_id = -1; + params.has_callback = false; + params.user_gesture = false; + delegate_->ProcessDOMUIMessage(params); } void RenderViewHost::OnMsgForwardMessageToExternalHost( @@ -1904,21 +1906,17 @@ void RenderViewHost::OnRequestNotificationPermission( } } -void RenderViewHost::OnExtensionRequest(const std::string& name, - const ListValue& args, - const GURL& source_url, - int request_id, - bool has_callback) { +void RenderViewHost::OnExtensionRequest( + const ViewHostMsg_DomMessage_Params& params) { if (!ChildProcessSecurityPolicy::GetInstance()-> HasExtensionBindings(process()->id())) { // This can happen if someone uses window.open() to open an extension URL // from a non-extension context. - BlockExtensionRequest(request_id); + BlockExtensionRequest(params.request_id); return; } - delegate_->ProcessDOMUIMessage(name, &args, source_url, request_id, - has_callback); + delegate_->ProcessDOMUIMessage(params); } void RenderViewHost::SendExtensionResponse(int request_id, bool success, diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index a6d99be..58b8388 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -36,6 +36,7 @@ struct ContextMenuParams; struct MediaPlayerAction; struct ThumbnailScore; struct ViewHostMsg_DidPrintPage_Params; +struct ViewHostMsg_DomMessage_Params; struct ViewHostMsg_RunFileChooser_Params; struct ViewHostMsg_ShowNotification_Params; struct ViewMsg_Navigate_Params; @@ -636,10 +637,7 @@ class RenderViewHost : public RenderWidgetHost { void OnCancelDesktopNotification(int notification_id); void OnRequestNotificationPermission(const GURL& origin, int callback_id); - void OnExtensionRequest(const std::string& name, const ListValue& args, - const GURL& source_url, - int request_id, - bool has_callback); + void OnExtensionRequest(const ViewHostMsg_DomMessage_Params& params); void OnExtensionPostMessage(int port_id, const std::string& message); void OnAccessibilityFocusChange(int acc_obj_id); void OnAccessibilityObjectStateChange(int acc_obj_id); diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h index 328826f..51e5029 100644 --- a/chrome/browser/renderer_host/render_view_host_delegate.h +++ b/chrome/browser/renderer_host/render_view_host_delegate.h @@ -45,6 +45,7 @@ class SSLAddCertHandler; class TabContents; struct ThumbnailScore; struct ViewHostMsg_DidPrintPage_Params; +struct ViewHostMsg_DomMessage_Params; struct ViewHostMsg_FrameNavigate_Params; struct ViewHostMsg_GetSearchProviderInstallState_Params; struct ViewHostMsg_RunFileChooser_Params; @@ -716,11 +717,8 @@ class RenderViewHostDelegate { // A message was sent from HTML-based UI. // By default we ignore such messages. - virtual void ProcessDOMUIMessage(const std::string& message, - const ListValue* content, - const GURL& source_url, - int request_id, - bool has_callback) {} + virtual void ProcessDOMUIMessage( + const ViewHostMsg_DomMessage_Params& params) {} // A message for external host. By default we ignore such messages. // |receiver| can be a receiving script and |message| is any diff --git a/chrome/browser/sidebar/sidebar_container.cc b/chrome/browser/sidebar/sidebar_container.cc new file mode 100644 index 0000000..4c73110 --- /dev/null +++ b/chrome/browser/sidebar/sidebar_container.cc @@ -0,0 +1,73 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sidebar/sidebar_container.h" + +#include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/browser/tab_contents/navigation_controller.h" +#include "chrome/browser/tab_contents/navigation_entry.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tab_contents/tab_contents_view.h" +#include "chrome/common/bindings_policy.h" +#include "googleurl/src/gurl.h" +#include "third_party/skia/include/core/SkBitmap.h" + +SidebarContainer::SidebarContainer(TabContents* tab, + const std::string& content_id, + Delegate* delegate) + : tab_(tab), + content_id_(content_id), + delegate_(delegate), + icon_(new SkBitmap) { + // Create TabContents for sidebar. + sidebar_contents_.reset( + new TabContents(tab->profile(), NULL, MSG_ROUTING_NONE, NULL)); + sidebar_contents_->render_view_host()->set_is_extension_process(true); + sidebar_contents_->render_view_host()->AllowBindings( + BindingsPolicy::EXTENSION); + sidebar_contents_->set_delegate(this); +} + +SidebarContainer::~SidebarContainer() { +} + +void SidebarContainer::SidebarClosing() { + delegate_->UpdateSidebar(this); +} + +int SidebarContainer::GetTabId() const { + return tab_->controller().session_id().id(); +} + +void SidebarContainer::Show() { + delegate_->UpdateSidebar(this); +} + +void SidebarContainer::Expand() { + delegate_->UpdateSidebar(this); + sidebar_contents_->view()->SetInitialFocus(); +} + +void SidebarContainer::Collapse() { + delegate_->UpdateSidebar(this); +} + +void SidebarContainer::Navigate(const GURL& url) { + DCHECK(sidebar_contents_.get()); + // TODO(alekseys): add a progress UI. + sidebar_contents_->controller().LoadURL( + url, GURL(), PageTransition::START_PAGE); +} + +void SidebarContainer::SetBadgeText(const string16& badge_text) { + badge_text_ = badge_text; +} + +void SidebarContainer::SetIcon(const SkBitmap& bitmap) { + *icon_ = bitmap; +} + +void SidebarContainer::SetTitle(const string16& title) { + title_ = title; +} diff --git a/chrome/browser/sidebar/sidebar_container.h b/chrome/browser/sidebar/sidebar_container.h new file mode 100644 index 0000000..152331d --- /dev/null +++ b/chrome/browser/sidebar/sidebar_container.h @@ -0,0 +1,141 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SIDEBAR_SIDEBAR_CONTAINER_H_ +#define CHROME_BROWSER_SIDEBAR_SIDEBAR_CONTAINER_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "base/string16.h" +#include "chrome/browser/tab_contents/tab_contents_delegate.h" + +class BrowserWindow; +class Profile; +class RenderViewHost; +class SkBitmap; +class TabContents; + +/////////////////////////////////////////////////////////////////////////////// +// SidebarContainer +// +// Stores one particular sidebar state: sidebar's content, its content id, +// tab it is linked to, mini tab icon, title etc. +// +class SidebarContainer + : public TabContentsDelegate { + public: + // Interface to implement to listen for sidebar update notification. + class Delegate { + public: + Delegate() {} + virtual ~Delegate() {} + virtual void UpdateSidebar(SidebarContainer* host) = 0; + private: + DISALLOW_COPY_AND_ASSIGN(Delegate); + }; + + SidebarContainer(TabContents* tab, const std::string& content_id, + Delegate* delegate); + virtual ~SidebarContainer(); + + // Called right before destroying this sidebar. + // Does all the necessary cleanup. + void SidebarClosing(); + + // Returns id of the tab this sidebar is linked to. + int GetTabId() const; + + // Returns sidebar's content id. + const std::string& content_id() const { return content_id_; } + + // Returns TabContents sidebar is linked to. + TabContents* tab_contents() const { return tab_; } + + // Returns sidebar's TabContents. + TabContents* sidebar_contents() const { return sidebar_contents_.get(); } + + // Accessor for the badge text. + const string16& badge_text() const { return badge_text_; } + + // Accessor for the icon. + const SkBitmap& icon() const { return *icon_; } + + // Accessor for the title. + const string16& title() const { return title_; } + + // Functions supporting chrome.experimental.sidebar API. + + // Notifies hosting window that this sidebar was expanded. + void Show(); + + // Notifies hosting window that this sidebar was expanded. + void Expand(); + + // Notifies hosting window that this sidebar was collapsed. + void Collapse(); + + // Navigates sidebar contents to the |url|. + void Navigate(const GURL& url); + + // Changes sidebar's badge text. + void SetBadgeText(const string16& badge_text); + + // Changes sidebar's icon. + void SetIcon(const SkBitmap& bitmap); + + // Changes sidebar's title. + void SetTitle(const string16& title); + + private: + // Overridden from TabContentsDelegate. + virtual void OpenURLFromTab(TabContents* source, + const GURL& url, + const GURL& referrer, + WindowOpenDisposition disposition, + PageTransition::Type transition) {} + virtual void NavigationStateChanged(const TabContents* source, + unsigned changed_flags) {} + virtual void AddNewContents(TabContents* source, + TabContents* new_contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture) {} + virtual void ActivateContents(TabContents* contents) {} + virtual void LoadingStateChanged(TabContents* source) {} + virtual void CloseContents(TabContents* source) {} + virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {} + virtual bool IsPopup(TabContents* source) { return false; } + virtual void URLStarredChanged(TabContents* source, bool starred) {} + virtual void UpdateTargetURL(TabContents* source, const GURL& url) {} + virtual void ToolbarSizeChanged(TabContents* source, bool is_animating) {} + + // Contents of the tab this sidebar is linked to. + TabContents* tab_; + + // Sidebar's content id. There might be more than one sidebar liked to each + // particular tab and they are identified by their unique content id. + const std::string content_id_; + + // Sidebar update notification listener. + Delegate* delegate_; + + // Sidebar contents. + scoped_ptr<TabContents> sidebar_contents_; + + // Badge text displayed on the sidebar's mini tab. + string16 badge_text_; + + // Icon displayed on the sidebar's mini tab. + scoped_ptr<SkBitmap> icon_; + + // Sidebar's title, displayed as a tooltip for sidebar's mini tab. + string16 title_; + + DISALLOW_COPY_AND_ASSIGN(SidebarContainer); +}; + +#endif // CHROME_BROWSER_SIDEBAR_SIDEBAR_CONTAINER_H_ + diff --git a/chrome/browser/sidebar/sidebar_manager.cc b/chrome/browser/sidebar/sidebar_manager.cc new file mode 100644 index 0000000..5ec9e12 --- /dev/null +++ b/chrome/browser/sidebar/sidebar_manager.cc @@ -0,0 +1,323 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sidebar/sidebar_manager.h" + +#include <vector> + +#include "base/command_line.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/extensions/extension_sidebar_api.h" +#include "chrome/browser/pref_service.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/sidebar/sidebar_container.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/pref_names.h" +#include "googleurl/src/gurl.h" + +// static +SidebarManager* SidebarManager::GetInstance() { + return g_browser_process->sidebar_manager(); +} + +// static +bool SidebarManager::IsSidebarAllowed() { + return CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableExperimentalExtensionApis); +} + +SidebarManager::SidebarManager() { +} + +SidebarContainer* SidebarManager::GetActiveSidebarContainerFor( + TabContents* tab) { + TabToSidebarHostMap::iterator it = tab_to_sidebar_host_.find(tab); + if (it == tab_to_sidebar_host_.end()) + return NULL; + if (it->second.active_content_id.empty()) + return NULL; + ContentIdToSidebarHostMap::iterator host_it = + it->second.content_id_to_sidebar_host.find(it->second.active_content_id); + DCHECK(host_it != it->second.content_id_to_sidebar_host.end()); + return host_it->second; +} + +SidebarContainer* SidebarManager::GetSidebarContainerFor( + TabContents* tab, const std::string& content_id) { + DCHECK(!content_id.empty()); + TabToSidebarHostMap::iterator it = tab_to_sidebar_host_.find(tab); + if (it == tab_to_sidebar_host_.end()) + return NULL; + ContentIdToSidebarHostMap::iterator host_it = + it->second.content_id_to_sidebar_host.find(content_id); + if (host_it == it->second.content_id_to_sidebar_host.end()) + return NULL; + return host_it->second; +} + +TabContents* SidebarManager::GetSidebarTabContents( + TabContents* tab, const std::string& content_id) { + DCHECK(!content_id.empty()); + SidebarContainer* sidebar_host = GetSidebarContainerFor(tab, content_id); + if (!sidebar_host) + return NULL; + return sidebar_host->sidebar_contents(); +} + +void SidebarManager::NotifyStateChanges( + TabContents* was_active_sidebar_contents, + TabContents* active_sidebar_contents) { + if (was_active_sidebar_contents == active_sidebar_contents) + return; + + SidebarContainer* was_active_host = + was_active_sidebar_contents == NULL ? NULL : + FindSidebarContainerFor(was_active_sidebar_contents); + SidebarContainer* active_host = + active_sidebar_contents == NULL ? NULL : + FindSidebarContainerFor(active_sidebar_contents); + + if (was_active_host != NULL) { + ExtensionSidebarEventRouter::OnStateChanged( + was_active_sidebar_contents->profile(), + was_active_host->GetTabId(), was_active_host->content_id(), + extension_sidebar_constants::kShownState); + } + + if (active_host != NULL) { + ExtensionSidebarEventRouter::OnStateChanged( + active_sidebar_contents->profile(), + active_host->GetTabId(), active_host->content_id(), + extension_sidebar_constants::kActiveState); + } +} + +void SidebarManager::ShowSidebar(TabContents* tab, + const std::string& content_id) { + DCHECK(!content_id.empty()); + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + if (!host) { + host = new SidebarContainer(tab, content_id, this); + RegisterSidebarContainerFor(tab, host); + } + + host->Show(); + + ExtensionSidebarEventRouter::OnStateChanged( + tab->profile(), host->GetTabId(), content_id, + extension_sidebar_constants::kShownState); +} + +void SidebarManager::ExpandSidebar(TabContents* tab, + const std::string& content_id) { + DCHECK(!content_id.empty()); + TabToSidebarHostMap::iterator it = tab_to_sidebar_host_.find(tab); + if (it == tab_to_sidebar_host_.end()) + return; + // If it's already active, bail out. + if (it->second.active_content_id == content_id) + return; + + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + DCHECK(host); + if (!host) + return; + it->second.active_content_id = content_id; + + host->Expand(); +} + +void SidebarManager::CollapseSidebar(TabContents* tab, + const std::string& content_id) { + DCHECK(!content_id.empty()); + TabToSidebarHostMap::iterator it = tab_to_sidebar_host_.find(tab); + if (it == tab_to_sidebar_host_.end()) + return; + // If it's not the one active now, bail out. + if (it->second.active_content_id != content_id) + return; + + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + DCHECK(host); + if (!host) + return; + it->second.active_content_id.clear(); + + host->Collapse(); +} + +void SidebarManager::HideSidebar(TabContents* tab, + const std::string& content_id) { + DCHECK(!content_id.empty()); + TabToSidebarHostMap::iterator it = tab_to_sidebar_host_.find(tab); + if (it == tab_to_sidebar_host_.end()) + return; + if (it->second.active_content_id == content_id) + it->second.active_content_id.clear(); + + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + DCHECK(host); + int tab_id = host->GetTabId(); + + UnregisterSidebarContainerFor(tab, content_id); + + ExtensionSidebarEventRouter::OnStateChanged( + tab->profile(), tab_id, content_id, + extension_sidebar_constants::kHiddenState); +} + +void SidebarManager::NavigateSidebar(TabContents* tab, + const std::string& content_id, + const GURL& url) { + DCHECK(!content_id.empty()); + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + if (!host) + return; + + host->Navigate(url); +} + +void SidebarManager::SetSidebarBadgeText( + TabContents* tab, const std::string& content_id, + const string16& badge_text) { + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + if (!host) + return; + host->SetBadgeText(badge_text); +} + +void SidebarManager::SetSidebarIcon( + TabContents* tab, const std::string& content_id, + const SkBitmap& bitmap) { + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + if (!host) + return; + host->SetIcon(bitmap); +} + +void SidebarManager::SetSidebarTitle( + TabContents* tab, const std::string& content_id, + const string16& title) { + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + if (!host) + return; + host->SetTitle(title); +} + +SidebarManager::~SidebarManager() { + DCHECK(tab_to_sidebar_host_.empty()); + DCHECK(sidebar_host_to_tab_.empty()); +} + +void SidebarManager::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type == NotificationType::TAB_CONTENTS_DESTROYED) { + HideAllSidebars(Source<TabContents>(source).ptr()); + } else { + NOTREACHED() << "Got a notification we didn't register for!"; + } +} + +void SidebarManager::UpdateSidebar(SidebarContainer* host) { + NotificationService::current()->Notify( + NotificationType::SIDEBAR_CHANGED, + Source<SidebarManager>(this), + Details<SidebarContainer>(host)); +} + +void SidebarManager::HideAllSidebars(TabContents* tab) { + TabToSidebarHostMap::iterator tab_it = tab_to_sidebar_host_.find(tab); + if (tab_it == tab_to_sidebar_host_.end()) + return; + const ContentIdToSidebarHostMap& hosts = + tab_it->second.content_id_to_sidebar_host; + + std::vector<std::string> content_ids; + for (ContentIdToSidebarHostMap::const_iterator it = hosts.begin(); + it != hosts.end(); ++it) { + content_ids.push_back(it->first); + } + + for (std::vector<std::string>::iterator it = content_ids.begin(); + it != content_ids.end(); ++it) { + HideSidebar(tab, *it); + } +} + +SidebarContainer* SidebarManager::FindSidebarContainerFor( + TabContents* sidebar_contents) { + for (SidebarHostToTabMap::iterator it = sidebar_host_to_tab_.begin(); + it != sidebar_host_to_tab_.end(); + ++it) { + if (sidebar_contents == it->first->sidebar_contents()) + return it->first; + } + return NULL; +} + +void SidebarManager::RegisterSidebarContainerFor( + TabContents* tab, SidebarContainer* sidebar_host) { + DCHECK(!GetSidebarContainerFor(tab, sidebar_host->content_id())); + + // If it's a first sidebar for this tab, register destroy notification. + if (tab_to_sidebar_host_.find(tab) == tab_to_sidebar_host_.end()) { + registrar_.Add(this, + NotificationType::TAB_CONTENTS_DESTROYED, + Source<TabContents>(tab)); + } + + BindSidebarHost(tab, sidebar_host); +} + +void SidebarManager::UnregisterSidebarContainerFor( + TabContents* tab, const std::string& content_id) { + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + DCHECK(host); + if (!host) + return; + + UnbindSidebarHost(tab, host); + + // If there's no more sidebars linked to this tab, unsubscribe. + if (tab_to_sidebar_host_.find(tab) == tab_to_sidebar_host_.end()) { + registrar_.Remove(this, + NotificationType::TAB_CONTENTS_DESTROYED, + Source<TabContents>(tab)); + } + + // Issue tab closing event post unbound. + host->SidebarClosing(); + // Destroy sidebar container. + delete host; +} + +void SidebarManager::BindSidebarHost(TabContents* tab, + SidebarContainer* sidebar_host) { + const std::string& content_id = sidebar_host->content_id(); + + DCHECK(GetSidebarContainerFor(tab, content_id) == NULL); + DCHECK(sidebar_host_to_tab_.find(sidebar_host) == + sidebar_host_to_tab_.end()); + + tab_to_sidebar_host_[tab].content_id_to_sidebar_host[content_id] = + sidebar_host; + sidebar_host_to_tab_[sidebar_host] = tab; +} + +void SidebarManager::UnbindSidebarHost(TabContents* tab, + SidebarContainer* sidebar_host) { + const std::string& content_id = sidebar_host->content_id(); + + DCHECK(GetSidebarContainerFor(tab, content_id) == sidebar_host); + DCHECK(sidebar_host_to_tab_.find(sidebar_host)->second == tab); + DCHECK(tab_to_sidebar_host_[tab].active_content_id != content_id); + + tab_to_sidebar_host_[tab].content_id_to_sidebar_host.erase(content_id); + if (tab_to_sidebar_host_[tab].content_id_to_sidebar_host.empty()) + tab_to_sidebar_host_.erase(tab); + sidebar_host_to_tab_.erase(sidebar_host); +} diff --git a/chrome/browser/sidebar/sidebar_manager.h b/chrome/browser/sidebar/sidebar_manager.h new file mode 100644 index 0000000..4f3231e --- /dev/null +++ b/chrome/browser/sidebar/sidebar_manager.h @@ -0,0 +1,156 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SIDEBAR_SIDEBAR_MANAGER_H_ +#define CHROME_BROWSER_SIDEBAR_SIDEBAR_MANAGER_H_ + +#include <map> +#include <set> +#include <string> + +#include "base/ref_counted.h" +#include "base/string16.h" +#include "chrome/browser/sidebar/sidebar_container.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" + +class GURL; +class PrefService; +class Profile; +class SidebarContainer; +class SkBitmap; +class TabContents; + +/////////////////////////////////////////////////////////////////////////////// +// SidebarManager +// +// This class is a singleton that manages SidebarContainer instances and +// maintains a connection between tabs and sidebars. +// +class SidebarManager : public NotificationObserver, + public base::RefCounted<SidebarManager>, + private SidebarContainer::Delegate { + public: + // Returns s singleton instance. + static SidebarManager* GetInstance(); + + // Returns true if sidebar is allowed to be displayed in the browser. + static bool IsSidebarAllowed(); + + SidebarManager(); + + // Returns SidebarContainer registered for |tab| and active or NULL if + // there is no alive and active SidebarContainer registered for |tab|. + SidebarContainer* GetActiveSidebarContainerFor(TabContents* tab); + + // Returns SidebarContainer registered for |tab| and |content_id| or NULL if + // there is no such SidebarContainer registered. + SidebarContainer* GetSidebarContainerFor(TabContents* tab, + const std::string& content_id); + + // Returns sidebar's TabContents registered for |tab| and |content_id|. + TabContents* GetSidebarTabContents(TabContents* tab, + const std::string& content_id); + + // Sends sidebar state change notification to extensions. + void NotifyStateChanges(TabContents* was_active_sidebar_contents, + TabContents* active_sidebar_contents); + + // Functions supporting chrome.experimental.sidebar API. + + // Shows sidebar identified by |tab| and |content_id| (only sidebar's + // mini tab is visible). + void ShowSidebar(TabContents* tab, const std::string& content_id); + + // Expands sidebar identified by |tab| and |content_id|. + void ExpandSidebar(TabContents* tab, const std::string& content_id); + + // Collapses sidebar identified by |tab| and |content_id| (has no effect + // if sidebar is not expanded). + void CollapseSidebar(TabContents* tab, const std::string& content_id); + + // Hides sidebar identified by |tab| and |content_id| (removes sidebar's + // mini tab). + void HideSidebar(TabContents* tab, const std::string& content_id); + + // Navigates sidebar identified by |tab| and |content_id| to |url|. + void NavigateSidebar(TabContents* tab, const std::string& content_id, + const GURL& url); + + // Changes sidebar's badge text (displayed on the mini tab). + void SetSidebarBadgeText(TabContents* tab, const std::string& content_id, + const string16& badge_text); + + // Changes sidebar's icon (displayed on the mini tab). + void SetSidebarIcon(TabContents* tab, const std::string& content_id, + const SkBitmap& bitmap); + + // Changes sidebar's title (mini tab's tooltip). + void SetSidebarTitle(TabContents* tab, const std::string& content_id, + const string16& title); + + private: + friend class base::RefCounted<SidebarManager>; + + virtual ~SidebarManager(); + + // Overridden from NotificationObserver. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // Overridden from SidebarContainer::Delegate. + virtual void UpdateSidebar(SidebarContainer* host); + + // Hides all sidebars registered for |tab|. + void HideAllSidebars(TabContents* tab); + + // Returns SidebarContainer corresponding to |sidebar_contents|. + SidebarContainer* FindSidebarContainerFor(TabContents* sidebar_contents); + + // Registers new SidebarContainer for |tab|. There must be no + // other SidebarContainers registered for the RenderViewHost at the moment. + void RegisterSidebarContainerFor(TabContents* tab, + SidebarContainer* container); + + // Unregisters SidebarContainer identified by |tab| and |content_id|. + void UnregisterSidebarContainerFor(TabContents* tab, + const std::string& content_id); + + // Records the link between |tab| and |sidebar_host|. + void BindSidebarHost(TabContents* tab, SidebarContainer* sidebar_host); + + // Forgets the link between |tab| and |sidebar_host|. + void UnbindSidebarHost(TabContents* tab, SidebarContainer* sidebar_host); + + NotificationRegistrar registrar_; + + // This map stores sidebars linked to a particular tab. Sidebars are + // identified by their unique content id (string). + typedef std::map<std::string, SidebarContainer*> + ContentIdToSidebarHostMap; + // These two maps are for tracking dependencies between tabs and + // their SidebarContainers. + // + // SidebarManager start listening to SidebarContainers when they are put + // into these maps and removes them when they are closing. + typedef struct { + // Sidebars linked to this tab. + ContentIdToSidebarHostMap content_id_to_sidebar_host; + // Content id of the currently active (expanded and visible) sidebar. + std::string active_content_id; + } SidebarStateForTab; + typedef std::map<TabContents*, SidebarStateForTab> + TabToSidebarHostMap; + TabToSidebarHostMap tab_to_sidebar_host_; + + typedef std::map<SidebarContainer*, TabContents*> + SidebarHostToTabMap; + SidebarHostToTabMap sidebar_host_to_tab_; + + DISALLOW_COPY_AND_ASSIGN(SidebarManager); +}; + +#endif // CHROME_BROWSER_SIDEBAR_SIDEBAR_MANAGER_H_ + diff --git a/chrome/browser/sidebar/sidebar_test.cc b/chrome/browser/sidebar/sidebar_test.cc new file mode 100644 index 0000000..a518587 --- /dev/null +++ b/chrome/browser/sidebar/sidebar_test.cc @@ -0,0 +1,177 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/command_line.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_window.h" +#include "chrome/browser/sidebar/sidebar_manager.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/views/frame/browser_view.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/test/in_process_browser_test.h" +#include "chrome/test/ui_test_utils.h" +#include "net/test/test_server.h" + +namespace { + +const char kSampleContentId[] = "sample_content_id"; +const char kSimplePage[] = "files/sidebar/simple_page.html"; + +class SidebarTest : public InProcessBrowserTest { + public: + SidebarTest() { + CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableExperimentalExtensionApis); + set_show_window(true); + } + + protected: + void ShowSidebarForCurrentTab() { + ShowSidebar(browser()->GetSelectedTabContents()); + } + + void ExpandSidebarForCurrentTab() { + ExpandSidebar(browser()->GetSelectedTabContents()); + } + + void CollapseSidebarForCurrentTab() { + CollapseSidebar(browser()->GetSelectedTabContents()); + } + + void HideSidebarForCurrentTab() { + HideSidebar(browser()->GetSelectedTabContents()); + } + + void NavigateSidebarForCurrentTabTo(const std::string& test_page) { + net::TestServer* server = test_server(); + ASSERT_TRUE(server); + GURL url = server->GetURL(test_page); + + TabContents* tab = browser()->GetSelectedTabContents(); + + SidebarManager* sidebar_manager = SidebarManager::GetInstance(); + + sidebar_manager->NavigateSidebar(tab, kSampleContentId, url); + + SidebarContainer* sidebar_container = + sidebar_manager->GetSidebarContainerFor(tab, kSampleContentId); + + TabContents* client_contents = sidebar_container->sidebar_contents(); + ui_test_utils::WaitForNavigation(&client_contents->controller()); + } + + void ShowSidebar(TabContents* tab) { + SidebarManager* sidebar_manager = SidebarManager::GetInstance(); + sidebar_manager->ShowSidebar(tab, kSampleContentId); + } + + void ExpandSidebar(TabContents* tab) { + SidebarManager* sidebar_manager = SidebarManager::GetInstance(); + sidebar_manager->ExpandSidebar(tab, kSampleContentId); + if (browser()->GetSelectedTabContents() == tab) + EXPECT_GT(browser_view()->GetSidebarWidth(), 0); + } + + void CollapseSidebar(TabContents* tab) { + SidebarManager* sidebar_manager = SidebarManager::GetInstance(); + sidebar_manager->CollapseSidebar(tab, kSampleContentId); + if (browser()->GetSelectedTabContents() == tab) + EXPECT_EQ(0, browser_view()->GetSidebarWidth()); + } + + void HideSidebar(TabContents* tab) { + SidebarManager* sidebar_manager = SidebarManager::GetInstance(); + sidebar_manager->HideSidebar(tab, kSampleContentId); + if (browser()->GetSelectedTabContents() == tab) + EXPECT_EQ(0, browser_view()->GetSidebarWidth()); + } + + TabContents* tab_contents(int i) { + return browser()->GetTabContentsAt(i); + } + + BrowserView* browser_view() const { + return static_cast<BrowserView*>(browser()->window()); + } +}; + +IN_PROC_BROWSER_TEST_F(SidebarTest, OpenClose) { + ShowSidebarForCurrentTab(); + + ExpandSidebarForCurrentTab(); + CollapseSidebarForCurrentTab(); + + ExpandSidebarForCurrentTab(); + CollapseSidebarForCurrentTab(); + + ExpandSidebarForCurrentTab(); + CollapseSidebarForCurrentTab(); + + HideSidebarForCurrentTab(); + + ShowSidebarForCurrentTab(); + + ExpandSidebarForCurrentTab(); + CollapseSidebarForCurrentTab(); + + HideSidebarForCurrentTab(); +} + +IN_PROC_BROWSER_TEST_F(SidebarTest, SwitchingTabs) { + ShowSidebarForCurrentTab(); + ExpandSidebarForCurrentTab(); + + browser()->NewTab(); + + // Make sure sidebar is not visbile for the newly opened tab. + EXPECT_EQ(0, browser_view()->GetSidebarWidth()); + + // Switch back to the first tab. + browser()->SelectNumberedTab(0); + + // Make sure it is visible now. + EXPECT_GT(browser_view()->GetSidebarWidth(), 0); + + HideSidebarForCurrentTab(); +} + +IN_PROC_BROWSER_TEST_F(SidebarTest, SidebarOnInactiveTab) { + ShowSidebarForCurrentTab(); + ExpandSidebarForCurrentTab(); + + browser()->NewTab(); + + // Hide sidebar on inactive (first) tab. + HideSidebar(tab_contents(0)); + + // Switch back to the first tab. + browser()->SelectNumberedTab(0); + + // Make sure sidebar is not visbile anymore. + EXPECT_EQ(0, browser_view()->GetSidebarWidth()); + + // Show sidebar on inactive (second) tab. + ShowSidebar(tab_contents(1)); + ExpandSidebar(tab_contents(1)); + // Make sure sidebar is not visible yet. + EXPECT_EQ(0, browser_view()->GetSidebarWidth()); + + // Switch back to the second tab. + browser()->SelectNumberedTab(1); + // Make sure sidebar is visible now. + EXPECT_GT(browser_view()->GetSidebarWidth(), 0); + + HideSidebarForCurrentTab(); +} + +IN_PROC_BROWSER_TEST_F(SidebarTest, SidebarNavigate) { + ShowSidebarForCurrentTab(); + + NavigateSidebarForCurrentTabTo(kSimplePage); + + HideSidebarForCurrentTab(); +} + +} // namespace + diff --git a/chrome/browser/tab_contents/background_contents.cc b/chrome/browser/tab_contents/background_contents.cc index 0876419..d4a0a19 100644 --- a/chrome/browser/tab_contents/background_contents.cc +++ b/chrome/browser/tab_contents/background_contents.cc @@ -154,14 +154,11 @@ WebPreferences BackgroundContents::GetWebkitPrefs() { false); // is_dom_ui } -void BackgroundContents::ProcessDOMUIMessage(const std::string& message, - const ListValue* content, - const GURL& source_url, - int request_id, - bool has_callback) { +void BackgroundContents::ProcessDOMUIMessage( + const ViewHostMsg_DomMessage_Params& params) { // TODO(rafaelw): It may make sense for extensions to be able to open // BackgroundContents to chrome-extension://<id> pages. Consider implementing. - render_view_host_->BlockExtensionRequest(request_id); + render_view_host_->BlockExtensionRequest(params.request_id); } void BackgroundContents::CreateNewWindow( diff --git a/chrome/browser/tab_contents/background_contents.h b/chrome/browser/tab_contents/background_contents.h index 0fb238f..12d9b02 100644 --- a/chrome/browser/tab_contents/background_contents.h +++ b/chrome/browser/tab_contents/background_contents.h @@ -69,11 +69,7 @@ class BackgroundContents : public RenderViewHostDelegate, virtual void DidNavigate(RenderViewHost* render_view_host, const ViewHostMsg_FrameNavigate_Params& params); virtual WebPreferences GetWebkitPrefs(); - virtual void ProcessDOMUIMessage(const std::string& message, - const ListValue* content, - const GURL& source_url, - int request_id, - bool has_callback); + virtual void ProcessDOMUIMessage(const ViewHostMsg_DomMessage_Params& params); virtual void RunJavaScriptMessage(const std::wstring& message, const std::wstring& default_prompt, const GURL& frame_url, diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index a0ef815..c8e212f 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -2585,20 +2585,15 @@ void TabContents::DomOperationResponse(const std::string& json_string, int automation_id) { } -void TabContents::ProcessDOMUIMessage(const std::string& message, - const ListValue* content, - const GURL& source_url, - int request_id, - bool has_callback) { +void TabContents::ProcessDOMUIMessage( + const ViewHostMsg_DomMessage_Params& params) { if (!render_manager_.dom_ui()) { // This can happen if someone uses window.open() to open an extension URL // from a non-extension context. - render_view_host()->BlockExtensionRequest(request_id); + render_view_host()->BlockExtensionRequest(params.request_id); return; } - render_manager_.dom_ui()->ProcessDOMUIMessage(message, content, source_url, - request_id, - has_callback); + render_manager_.dom_ui()->ProcessDOMUIMessage(params); } void TabContents::ProcessExternalHostMessage(const std::string& message, diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index 49f89e2..41d298a 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -83,6 +83,7 @@ class TabContentsSSLHelper; class TabContentsView; class URLPattern; struct ThumbnailScore; +struct ViewHostMsg_DomMessage_Params; struct ViewHostMsg_FrameNavigate_Params; struct ViewHostMsg_RunFileChooser_Params; struct WebPreferences; @@ -920,11 +921,7 @@ class TabContents : public PageNavigator, WindowOpenDisposition disposition); virtual void DomOperationResponse(const std::string& json_string, int automation_id); - virtual void ProcessDOMUIMessage(const std::string& message, - const ListValue* content, - const GURL& source_url, - int request_id, - bool has_callback); + virtual void ProcessDOMUIMessage(const ViewHostMsg_DomMessage_Params& params); virtual void ProcessExternalHostMessage(const std::string& message, const std::string& origin, const std::string& target); diff --git a/chrome/browser/view_ids.h b/chrome/browser/view_ids.h index f345b3f..c1e02a1 100644 --- a/chrome/browser/view_ids.h +++ b/chrome/browser/view_ids.h @@ -71,6 +71,12 @@ enum ViewID { // The Download shelf. VIEW_ID_DOWNLOAD_SHELF, + // The Sidebar container. + VIEW_ID_SIDE_BAR_CONTAINER, + + // The sidebar split. + VIEW_ID_SIDE_BAR_SPLIT, + // Used in chrome/browser/gtk/view_id_util_browsertests.cc // If you add new ids, make sure the above test passes. VIEW_ID_PREDEFINED_COUNT diff --git a/chrome/browser/views/dropdown_bar_host.cc b/chrome/browser/views/dropdown_bar_host.cc index 4878e15..d01459e 100644 --- a/chrome/browser/views/dropdown_bar_host.cc +++ b/chrome/browser/views/dropdown_bar_host.cc @@ -276,7 +276,7 @@ void DropdownBarHost::UpdateWindowEdges(const gfx::Rect& new_pos) { // TODO(brettw) this constant is evil. This is the amount of room we've added // to the window size, when we set the region, it can change the size. static const int kAddedWidth = 7; - int difference = new_pos.right() - kAddedWidth - widget_bounds.width() - + int difference = new_pos.right() - kAddedWidth - widget_bounds.right() - gfx::scrollbar_size() + 1; if (difference > 0) { Path::Point exclude[4]; diff --git a/chrome/browser/views/find_bar_host.cc b/chrome/browser/views/find_bar_host.cc index 26a0db0..21dcf8b 100644 --- a/chrome/browser/views/find_bar_host.cc +++ b/chrome/browser/views/find_bar_host.cc @@ -227,8 +227,9 @@ gfx::Rect FindBarHost::GetDialogPosition(gfx::Rect avoid_overlapping_rect) { // Place the view in the top right corner of the widget boundaries (top left // for RTL languages). gfx::Rect view_location; - int x = base::i18n::IsRTL() ? - widget_bounds.x() : widget_bounds.width() - prefsize.width(); + int x = widget_bounds.x(); + if (!base::i18n::IsRTL()) + x += widget_bounds.width() - prefsize.width(); int y = widget_bounds.y(); view_location.SetRect(x, y, prefsize.width(), prefsize.height()); diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index 1e32b5c..16dd49a 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -32,6 +32,8 @@ #include "chrome/browser/pref_service.h" #include "chrome/browser/profile.h" #include "chrome/browser/sessions/tab_restore_service.h" +#include "chrome/browser/sidebar/sidebar_container.h" +#include "chrome/browser/sidebar/sidebar_manager.h" #include "chrome/browser/tab_contents/match_preview.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_contents_view.h" @@ -484,6 +486,8 @@ BrowserView::BrowserView(Browser* browser) tabstrip_(NULL), toolbar_(NULL), infobar_container_(NULL), + sidebar_container_(NULL), + sidebar_split_(NULL), contents_container_(NULL), devtools_container_(NULL), preview_container_(NULL), @@ -497,6 +501,10 @@ BrowserView::BrowserView(Browser* browser) #endif { browser_->tabstrip_model()->AddObserver(this); + + registrar_.Add(this, + NotificationType::SIDEBAR_CHANGED, + Source<SidebarManager>(SidebarManager::GetInstance())); } BrowserView::~BrowserView() { @@ -618,6 +626,12 @@ gfx::Rect BrowserView::GetTabStripBounds() const { return frame_->GetBoundsForTabStrip(tabstrip_); } +int BrowserView::GetSidebarWidth() const { + if (!sidebar_container_ || !sidebar_container_->IsVisible()) + return 0; + return sidebar_split_->divider_offset(); +} + bool BrowserView::IsTabStripVisible() const { return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP); } @@ -951,18 +965,24 @@ void BrowserView::RotatePaneFocus(bool forwards) { // focusable children it will be automatically skipped. std::vector<AccessibleToolbarView*> accessible_toolbars; GetAccessibleToolbars(&accessible_toolbars); - // Add NULL, which represents the tab contents getting focus - accessible_toolbars.push_back(NULL); - - // Figure out which toolbar (if any) currently has the focus. - AccessibleToolbarView* current_toolbar = NULL; + int toolbars_count = static_cast<int>(accessible_toolbars.size()); + + std::vector<views::View*> accessible_views( + accessible_toolbars.begin(), accessible_toolbars.end()); + accessible_views.push_back(GetTabContentsContainerView()); + if (sidebar_container_ && sidebar_container_->IsVisible()) + accessible_views.push_back(GetSidebarContainerView()); + if (devtools_container_->IsVisible()) + accessible_views.push_back(devtools_container_->GetFocusView()); + int count = static_cast<int>(accessible_views.size()); + + // Figure out which view (if any) currently has the focus. views::View* focused_view = GetRootView()->GetFocusedView(); int index = -1; - int count = static_cast<int>(accessible_toolbars.size()); if (focused_view) { - for (int i = 0; i < count; i++) { - if (accessible_toolbars[i]->IsParentOf(focused_view)) { - current_toolbar = accessible_toolbars[i]; + for (int i = 0; i < count; ++i) { + if (accessible_views[i] == focused_view || + accessible_views[i]->IsParentOf(focused_view)) { index = i; break; } @@ -971,7 +991,7 @@ void BrowserView::RotatePaneFocus(bool forwards) { // If the focus isn't currently in a toolbar, save the focus so we // can restore it if the user presses Escape. - if (focused_view && !current_toolbar) + if (focused_view && index >= toolbars_count) SaveFocusedView(); // Try to focus the next pane; if SetToolbarFocusAndFocusDefault returns @@ -981,16 +1001,15 @@ void BrowserView::RotatePaneFocus(bool forwards) { if (forwards) index = (index + 1) % count; else - index = ((index - 1) + count + count) % count; - AccessibleToolbarView* next_toolbar = accessible_toolbars[index]; + index = ((index - 1) + count) % count; - if (next_toolbar) { - if (next_toolbar->SetToolbarFocusAndFocusDefault( + if (index < toolbars_count) { + if (accessible_toolbars[index]->SetToolbarFocusAndFocusDefault( last_focused_view_storage_id_)) { break; } } else { - GetTabContentsContainerView()->RequestFocus(); + accessible_views[index]->RequestFocus(); break; } } @@ -1374,6 +1393,12 @@ views::View* BrowserView::GetTabContentsContainerView() const { return contents_container_->GetFocusView(); } +views::View* BrowserView::GetSidebarContainerView() const { + if (!sidebar_container_) + return NULL; + return sidebar_container_->GetFocusView(); +} + ToolbarView* BrowserView::GetToolbarView() const { return toolbar_; } @@ -1411,6 +1436,13 @@ void BrowserView::Observe(NotificationType type, break; } + case NotificationType::SIDEBAR_CHANGED: + if (Details<SidebarContainer>(details)->tab_contents() == + browser_->GetSelectedTabContents()) { + UpdateSidebar(); + } + break; + default: NOTREACHED() << "Got a notification we didn't register for!"; break; @@ -1430,6 +1462,7 @@ void BrowserView::TabDetachedAt(TabContents* contents, int index) { // on the selected TabContents when it is removed. contents_container_->ChangeTabContents(NULL); infobar_container_->ChangeTabContents(NULL); + UpdateSidebarForContents(NULL); UpdateDevToolsForContents(NULL); } } @@ -1843,18 +1876,42 @@ void BrowserView::Init() { contents_container_ = new TabContentsContainer; contents_ = new ContentsContainer(this, contents_container_); + + SkColor bg_color = GetWidget()->GetThemeProvider()-> + GetColor(BrowserThemeProvider::COLOR_TOOLBAR); + + bool sidebar_allowed = SidebarManager::IsSidebarAllowed(); + if (sidebar_allowed) { + sidebar_container_ = new TabContentsContainer; + sidebar_container_->SetID(VIEW_ID_SIDE_BAR_CONTAINER); + sidebar_container_->SetVisible(false); + + sidebar_split_ = new views::SingleSplitView( + contents_, + sidebar_container_, + views::SingleSplitView::HORIZONTAL_SPLIT); + sidebar_split_->SetID(VIEW_ID_SIDE_BAR_SPLIT); + sidebar_split_-> + SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_SIDE_BAR)); + sidebar_split_->set_background( + views::Background::CreateSolidBackground(bg_color)); + } + devtools_container_ = new TabContentsContainer; devtools_container_->SetID(VIEW_ID_DEV_TOOLS_DOCKED); devtools_container_->SetVisible(false); + + views::View* contents_view = contents_; + if (sidebar_allowed) + contents_view = sidebar_split_; + contents_split_ = new views::SingleSplitView( - contents_, + contents_view, devtools_container_, views::SingleSplitView::VERTICAL_SPLIT); contents_split_->SetID(VIEW_ID_CONTENTS_SPLIT); contents_split_-> SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_WEB_CONTENTS)); - SkColor bg_color = GetWidget()->GetThemeProvider()-> - GetColor(BrowserThemeProvider::COLOR_TOOLBAR); contents_split_->set_background( views::Background::CreateSolidBackground(bg_color)); AddChildView(contents_split_); @@ -1953,6 +2010,67 @@ bool BrowserView::MaybeShowInfoBar(TabContents* contents) { return true; } +void BrowserView::UpdateSidebar() { + UpdateSidebarForContents(GetSelectedTabContents()); + Layout(); +} + +void BrowserView::UpdateSidebarForContents(TabContents* tab_contents) { + if (!sidebar_container_) + return; // Happens when sidebar is not allowed. + if (!SidebarManager::GetInstance()) + return; // Happens only in tests. + + TabContents* sidebar_contents = NULL; + if (tab_contents) { + SidebarContainer* client_host = SidebarManager::GetInstance()-> + GetActiveSidebarContainerFor(tab_contents); + if (client_host) + sidebar_contents = client_host->sidebar_contents(); + } + + bool visible = NULL != sidebar_contents && + browser_->SupportsWindowFeature(Browser::FEATURE_SIDEBAR); + + bool should_show = visible && !sidebar_container_->IsVisible(); + bool should_hide = !visible && sidebar_container_->IsVisible(); + + // Update sidebar content. + TabContents* old_contents = sidebar_container_->tab_contents(); + sidebar_container_->ChangeTabContents(sidebar_contents); + SidebarManager::GetInstance()-> + NotifyStateChanges(old_contents, sidebar_contents); + + // Update sidebar UI width. + if (should_show) { + // Restore split offset. + int sidebar_width = g_browser_process->local_state()->GetInteger( + prefs::kExtensionSidebarWidth); + if (sidebar_width < 0) { + // Initial load, set to default value. + sidebar_width = sidebar_split_->width() / 7; + } + // Make sure user can see both panes. + int min_sidebar_width = sidebar_split_->GetMinimumSize().width(); + sidebar_width = std::min(sidebar_split_->width() - min_sidebar_width, + std::max(min_sidebar_width, sidebar_width)); + + sidebar_split_->set_divider_offset( + sidebar_split_->width() - sidebar_width); + + sidebar_container_->SetVisible(true); + sidebar_split_->Layout(); + } else if (should_hide) { + // Store split offset when hiding sidebar only. + g_browser_process->local_state()->SetInteger( + prefs::kExtensionSidebarWidth, + sidebar_split_->width() - sidebar_split_->divider_offset()); + + sidebar_container_->SetVisible(false); + sidebar_split_->Layout(); + } +} + void BrowserView::UpdateDevToolsForContents(TabContents* tab_contents) { TabContents* devtools_contents = DevToolsWindow::GetDevToolsContents(tab_contents); @@ -2343,6 +2461,7 @@ void BrowserView::ProcessTabSelected(TabContents* new_contents, UpdateUIForContents(new_contents); if (change_tab_contents) contents_container_->ChangeTabContents(new_contents); + UpdateSidebarForContents(new_contents); UpdateDevToolsForContents(new_contents); // TODO(beng): This should be called automatically by ChangeTabContents, but I diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h index d94726a..a56bbb3 100644 --- a/chrome/browser/views/frame/browser_view.h +++ b/chrome/browser/views/frame/browser_view.h @@ -144,6 +144,9 @@ class BrowserView : public BrowserBubbleHost, // offset of IDR_THEME_TOOLBAR. gfx::Rect GetTabStripBounds() const; + // Returns the width of the currently displayed sidebar or 0. + int GetSidebarWidth() const; + // Accessor for the TabStrip. BaseTabStrip* tabstrip() const { return tabstrip_; } @@ -316,6 +319,7 @@ class BrowserView : public BrowserBubbleHost, virtual BookmarkBarView* GetBookmarkBarView() const; virtual LocationBarView* GetLocationBarView() const; virtual views::View* GetTabContentsContainerView() const; + virtual views::View* GetSidebarContainerView() const; virtual ToolbarView* GetToolbarView() const; // Overridden from NotificationObserver: @@ -436,6 +440,12 @@ class BrowserView : public BrowserBubbleHost, // |contents| can be NULL. bool MaybeShowInfoBar(TabContents* contents); + // Updates sidebar UI according to the current tab and sidebar state. + void UpdateSidebar(); + // Displays active sidebar linked to the |tab_contents| or hides sidebar UI, + // if there's no such sidebar. + void UpdateSidebarForContents(TabContents* tab_contents); + // Updated devtools window for given contents. void UpdateDevToolsForContents(TabContents* tab_contents); @@ -499,6 +509,42 @@ class BrowserView : public BrowserBubbleHost, // The Browser object we are associated with. scoped_ptr<Browser> browser_; + // BrowserView layout (LTR one is pictured here). + // + // -------------------------------------------------------------------------- + // | | Tabs (1) | + // | |--------------------------------------------------------------| + // | | Navigation buttons, menus and the address bar (toolbar_) | + // | |--------------------------------------------------------------| + // | | All infobars (infobar_container_) | + // | |--------------------------------------------------------------| + // | | Bookmarks (bookmark_bar_view_) | + // | |--------------------------------------------------------------| + // | |Page content (contents_) || | + // | |--------------------------------------|| Sidebar content | + // | || contents_container_ or ||| (sidebar_container_) | + // | || preview_container_ ||| | + // | || |(3) | + // | Tabs (2)|| ||| | + // | || ||| | + // | || ||| | + // | || ||| | + // | |--------------------------------------|| | + // | |==(4)=========================================================| + // | | | + // | | | + // | | Debugger (devtools_container_) | + // | | | + // | | | + // | |--------------------------------------------------------------| + // | | Active downloads (download_shelf_) | + // -------------------------------------------------------------------------- + // + // (1) - tabstrip_, default position + // (2) - tabstrip_, position when side tabs are enabled + // (3) - sidebar_split_ + // (4) - contents_split_ + // Tool/Info bars that we are currently showing. Used for layout. // active_bookmark_bar_ is either NULL, if the bookmark bar isn't showing, // or is bookmark_bar_view_ if the bookmark bar is showing. @@ -519,6 +565,12 @@ class BrowserView : public BrowserBubbleHost, // The InfoBarContainer that contains InfoBars for the current tab. InfoBarContainer* infobar_container_; + // The view that contains sidebar for the current tab. + TabContentsContainer* sidebar_container_; + + // Split view containing the contents container and sidebar container. + views::SingleSplitView* sidebar_split_; + // The view that contains the selected TabContents. TabContentsContainer* contents_container_; diff --git a/chrome/browser/views/frame/browser_view_layout.cc b/chrome/browser/views/frame/browser_view_layout.cc index 7aad8b7..f7d8128 100644 --- a/chrome/browser/views/frame/browser_view_layout.cc +++ b/chrome/browser/views/frame/browser_view_layout.cc @@ -6,6 +6,7 @@ #include "chrome/browser/find_bar.h" #include "chrome/browser/find_bar_controller.h" +#include "chrome/browser/sidebar/sidebar_manager.h" #include "chrome/browser/view_ids.h" #include "chrome/browser/views/bookmark_bar_view.h" #include "chrome/browser/views/download_shelf_view.h" @@ -204,9 +205,15 @@ void BrowserViewLayout::Uninstalled(views::View* host) {} void BrowserViewLayout::ViewAdded(views::View* host, views::View* view) { switch (view->GetID()) { - case VIEW_ID_CONTENTS_SPLIT: - contents_split_ = view; - contents_container_ = contents_split_->GetChildViewAt(0); + case VIEW_ID_CONTENTS_SPLIT: { + contents_split_ = view; + if (SidebarManager::IsSidebarAllowed()) { + views::View* sidebar_split = contents_split_->GetChildViewAt(0); + contents_container_ = sidebar_split->GetChildViewAt(0); + } else { + contents_container_ = contents_split_->GetChildViewAt(0); + } + } break; case VIEW_ID_INFO_BAR_CONTAINER: infobar_container_ = view; |