summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-19 18:05:56 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-19 18:05:56 +0000
commit8b8e7c9bce4198a4ee2865d9dfce6e8baa173ad3 (patch)
tree938304b8e1be417c1b9c73d7463dacbc1da79843 /chrome/browser
parentf2c4ee3627e6039fd42bd7c0c93e902b72653449 (diff)
downloadchromium_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')
-rw-r--r--chrome/browser/browser.cc3
-rw-r--r--chrome/browser/browser.h4
-rw-r--r--chrome/browser/browser_process.h2
-rw-r--r--chrome/browser/browser_process_impl.cc15
-rw-r--r--chrome/browser/browser_process_impl.h5
-rw-r--r--chrome/browser/browser_window.h3
-rw-r--r--chrome/browser/dom_ui/dom_ui.cc11
-rw-r--r--chrome/browser/dom_ui/dom_ui.h9
-rw-r--r--chrome/browser/extensions/extension_dom_ui.cc13
-rw-r--r--chrome/browser/extensions/extension_dom_ui.h7
-rw-r--r--chrome/browser/extensions/extension_function.h6
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc33
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.h4
-rw-r--r--chrome/browser/extensions/extension_host.cc10
-rw-r--r--chrome/browser/extensions/extension_host.h6
-rw-r--r--chrome/browser/extensions/extension_sidebar_api.cc270
-rw-r--r--chrome/browser/extensions/extension_sidebar_api.h117
-rw-r--r--chrome/browser/extensions/extension_sidebar_apitest.cc19
-rw-r--r--chrome/browser/gtk/view_id_util_browsertest.cc4
-rw-r--r--chrome/browser/notifications/balloon_host.cc10
-rw-r--r--chrome/browser/notifications/balloon_host.h6
-rw-r--r--chrome/browser/renderer_host/render_view_host.cc34
-rw-r--r--chrome/browser/renderer_host/render_view_host.h6
-rw-r--r--chrome/browser/renderer_host/render_view_host_delegate.h8
-rw-r--r--chrome/browser/sidebar/sidebar_container.cc73
-rw-r--r--chrome/browser/sidebar/sidebar_container.h141
-rw-r--r--chrome/browser/sidebar/sidebar_manager.cc323
-rw-r--r--chrome/browser/sidebar/sidebar_manager.h156
-rw-r--r--chrome/browser/sidebar/sidebar_test.cc177
-rw-r--r--chrome/browser/tab_contents/background_contents.cc9
-rw-r--r--chrome/browser/tab_contents/background_contents.h6
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc13
-rw-r--r--chrome/browser/tab_contents/tab_contents.h7
-rw-r--r--chrome/browser/view_ids.h6
-rw-r--r--chrome/browser/views/dropdown_bar_host.cc2
-rw-r--r--chrome/browser/views/find_bar_host.cc5
-rw-r--r--chrome/browser/views/frame/browser_view.cc155
-rw-r--r--chrome/browser/views/frame/browser_view.h52
-rw-r--r--chrome/browser/views/frame/browser_view_layout.cc13
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(&params.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(&params.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, &params.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;