Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / ui / views / extensions / extension_popup.cc
blob1467f24de70ee9fd4999d46cd5dfa44f68e4eb1d
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/extensions/extension_popup.h"
7 #include "base/bind.h"
8 #include "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/devtools/devtools_window.h"
10 #include "chrome/browser/extensions/extension_view_host.h"
11 #include "chrome/browser/extensions/extension_view_host_factory.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/tabs/tab_strip_model.h"
14 #include "content/public/browser/devtools_agent_host.h"
15 #include "content/public/browser/notification_details.h"
16 #include "content/public/browser/notification_source.h"
17 #include "content/public/browser/render_view_host.h"
18 #include "content/public/browser/web_contents.h"
19 #include "ui/gfx/geometry/insets.h"
20 #include "ui/views/layout/fill_layout.h"
21 #include "ui/views/widget/widget.h"
23 namespace {
25 ExtensionViewViews* GetExtensionView(extensions::ExtensionViewHost* host) {
26 return static_cast<ExtensionViewViews*>(host->view());
29 } // namespace
31 // The minimum/maximum dimensions of the popup.
32 // The minimum is just a little larger than the size of the button itself.
33 // The maximum is an arbitrary number that should be smaller than most screens.
34 const int ExtensionPopup::kMinWidth = 25;
35 const int ExtensionPopup::kMinHeight = 25;
36 const int ExtensionPopup::kMaxWidth = 800;
37 const int ExtensionPopup::kMaxHeight = 600;
39 #if !defined(USE_AURA)
40 // static
41 ExtensionPopup* ExtensionPopup::Create(extensions::ExtensionViewHost* host,
42 views::View* anchor_view,
43 views::BubbleBorder::Arrow arrow,
44 ShowAction show_action) {
45 auto popup = new ExtensionPopup(host, anchor_view, arrow, show_action);
46 views::BubbleDelegateView::CreateBubble(popup);
47 return popup;
49 #endif
51 ExtensionPopup::ExtensionPopup(extensions::ExtensionViewHost* host,
52 views::View* anchor_view,
53 views::BubbleBorder::Arrow arrow,
54 ShowAction show_action)
55 : BubbleDelegateView(anchor_view, arrow),
56 host_(host),
57 devtools_callback_(base::Bind(
58 &ExtensionPopup::OnDevToolsStateChanged, base::Unretained(this))),
59 widget_initialized_(false) {
60 inspect_with_devtools_ = show_action == SHOW_AND_INSPECT;
61 // Adjust the margin so that contents fit better.
62 const int margin = views::BubbleBorder::GetCornerRadius() / 2;
63 set_margins(gfx::Insets(margin, margin, margin, margin));
64 SetLayoutManager(new views::FillLayout());
65 AddChildView(GetExtensionView(host));
66 GetExtensionView(host)->set_container(this);
67 // ExtensionPopup closes itself on very specific de-activation conditions.
68 set_close_on_deactivate(false);
70 // Wait to show the popup until the contained host finishes loading.
71 registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
72 content::Source<content::WebContents>(host->host_contents()));
74 // Listen for the containing view calling window.close();
75 registrar_.Add(
76 this,
77 extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
78 content::Source<content::BrowserContext>(host->browser_context()));
79 content::DevToolsAgentHost::AddAgentStateCallback(devtools_callback_);
81 GetExtensionView(host)->GetBrowser()->tab_strip_model()->AddObserver(this);
84 ExtensionPopup::~ExtensionPopup() {
85 content::DevToolsAgentHost::RemoveAgentStateCallback(devtools_callback_);
87 GetExtensionView(
88 host_.get())->GetBrowser()->tab_strip_model()->RemoveObserver(this);
91 void ExtensionPopup::Observe(int type,
92 const content::NotificationSource& source,
93 const content::NotificationDetails& details) {
94 switch (type) {
95 case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME:
96 DCHECK_EQ(host()->host_contents(),
97 content::Source<content::WebContents>(source).ptr());
98 // Show when the content finishes loading and its width is computed.
99 ShowBubble();
100 break;
101 case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE:
102 // If we aren't the host of the popup, then disregard the notification.
103 if (content::Details<extensions::ExtensionHost>(host()) == details)
104 GetWidget()->Close();
105 break;
106 default:
107 NOTREACHED() << L"Received unexpected notification";
111 void ExtensionPopup::OnDevToolsStateChanged(
112 content::DevToolsAgentHost* agent_host,
113 bool attached) {
114 // First check that the devtools are being opened on this popup.
115 if (host()->host_contents() != agent_host->GetWebContents())
116 return;
118 if (attached) {
119 // Set inspect_with_devtools_ so the popup will be kept open while
120 // the devtools are open.
121 inspect_with_devtools_ = true;
122 } else {
123 // Widget::Close posts a task, which should give the devtools window a
124 // chance to finish detaching from the inspected RenderViewHost.
125 GetWidget()->Close();
129 void ExtensionPopup::OnExtensionSizeChanged(ExtensionViewViews* view) {
130 SizeToContents();
133 gfx::Size ExtensionPopup::GetPreferredSize() const {
134 // Constrain the size to popup min/max.
135 gfx::Size sz = views::View::GetPreferredSize();
136 sz.set_width(std::max(kMinWidth, std::min(kMaxWidth, sz.width())));
137 sz.set_height(std::max(kMinHeight, std::min(kMaxHeight, sz.height())));
138 return sz;
141 void ExtensionPopup::ViewHierarchyChanged(
142 const ViewHierarchyChangedDetails& details) {
143 // TODO(msw): Find any remaining crashes related to http://crbug.com/327776
144 // No view hierarchy changes are expected if the widget no longer exists.
145 widget_initialized_ |= details.child == this && details.is_add && GetWidget();
146 CHECK(GetWidget() || !widget_initialized_);
149 void ExtensionPopup::OnWidgetActivationChanged(views::Widget* widget,
150 bool active) {
151 if (active && widget == anchor_widget())
152 OnAnchorWindowActivation();
155 void ExtensionPopup::ActiveTabChanged(content::WebContents* old_contents,
156 content::WebContents* new_contents,
157 int index,
158 int reason) {
159 GetWidget()->Close();
162 void ExtensionPopup::OnAnchorWindowActivation() {
163 // TODO(msw): Find any remaining crashes related to http://crbug.com/327776
164 // No calls are expected if the widget isn't initialized or no longer exists.
165 CHECK(widget_initialized_);
166 CHECK(GetWidget());
168 if (!inspect_with_devtools_)
169 GetWidget()->Close();
172 // static
173 ExtensionPopup* ExtensionPopup::ShowPopup(const GURL& url,
174 Browser* browser,
175 views::View* anchor_view,
176 views::BubbleBorder::Arrow arrow,
177 ShowAction show_action) {
178 extensions::ExtensionViewHost* host =
179 extensions::ExtensionViewHostFactory::CreatePopupHost(url, browser);
180 auto popup = ExtensionPopup::Create(host, anchor_view, arrow, show_action);
182 // If the host had somehow finished loading, then we'd miss the notification
183 // and not show. This seems to happen in single-process mode.
184 if (host->has_loaded_once())
185 popup->ShowBubble();
187 return popup;
190 void ExtensionPopup::ShowBubble() {
191 GetWidget()->Show();
193 // Focus on the host contents when the bubble is first shown.
194 host()->host_contents()->Focus();
196 if (inspect_with_devtools_) {
197 DevToolsWindow::OpenDevToolsWindow(host()->host_contents(),
198 DevToolsToggleAction::ShowConsole());