Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / ui / views / extensions / extension_popup.cc
blob6df648a2eb57e76a3928f3772214dfbb05f7c843
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/ui/browser.h"
12 #include "chrome/browser/ui/tabs/tab_strip_model.h"
13 #include "content/public/browser/devtools_agent_host.h"
14 #include "content/public/browser/notification_details.h"
15 #include "content/public/browser/notification_source.h"
16 #include "content/public/browser/render_view_host.h"
17 #include "content/public/browser/web_contents.h"
18 #include "ui/gfx/geometry/insets.h"
19 #include "ui/views/layout/fill_layout.h"
20 #include "ui/views/widget/widget.h"
22 namespace {
24 ExtensionViewViews* GetExtensionView(extensions::ExtensionViewHost* host) {
25 return static_cast<ExtensionViewViews*>(host->view());
28 } // namespace
30 // The minimum/maximum dimensions of the popup.
31 // The minimum is just a little larger than the size of the button itself.
32 // The maximum is an arbitrary number that should be smaller than most screens.
33 const int ExtensionPopup::kMinWidth = 25;
34 const int ExtensionPopup::kMinHeight = 25;
35 const int ExtensionPopup::kMaxWidth = 800;
36 const int ExtensionPopup::kMaxHeight = 600;
38 #if !defined(USE_AURA)
39 // static
40 ExtensionPopup* ExtensionPopup::Create(extensions::ExtensionViewHost* host,
41 views::View* anchor_view,
42 views::BubbleBorder::Arrow arrow,
43 ShowAction show_action) {
44 auto popup = new ExtensionPopup(host, anchor_view, arrow, show_action);
45 views::BubbleDelegateView::CreateBubble(popup);
46 return popup;
48 #endif
50 ExtensionPopup::ExtensionPopup(extensions::ExtensionViewHost* host,
51 views::View* anchor_view,
52 views::BubbleBorder::Arrow arrow,
53 ShowAction show_action)
54 : BubbleDelegateView(anchor_view, arrow),
55 host_(host),
56 devtools_callback_(base::Bind(
57 &ExtensionPopup::OnDevToolsStateChanged, base::Unretained(this))),
58 widget_initialized_(false) {
59 inspect_with_devtools_ = show_action == SHOW_AND_INSPECT;
60 // Adjust the margin so that contents fit better.
61 const int margin = views::BubbleBorder::GetCornerRadius() / 2;
62 set_margins(gfx::Insets(margin, margin, margin, margin));
63 SetLayoutManager(new views::FillLayout());
64 AddChildView(GetExtensionView(host));
65 GetExtensionView(host)->set_container(this);
66 // ExtensionPopup closes itself on very specific de-activation conditions.
67 set_close_on_deactivate(false);
70 // Listen for the containing view calling window.close();
71 registrar_.Add(
72 this,
73 extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
74 content::Source<content::BrowserContext>(host->browser_context()));
75 content::DevToolsAgentHost::AddAgentStateCallback(devtools_callback_);
77 GetExtensionView(host)->GetBrowser()->tab_strip_model()->AddObserver(this);
79 // If the host had somehow finished loading, then we'd miss the notification
80 // and not show. This seems to happen in single-process mode.
81 if (host_->has_loaded_once()) {
82 ShowBubble();
83 } else {
84 // Wait to show the popup until the contained host finishes loading.
85 registrar_.Add(this,
86 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
87 content::Source<content::WebContents>(
88 host_->host_contents()));
92 ExtensionPopup::~ExtensionPopup() {
93 content::DevToolsAgentHost::RemoveAgentStateCallback(devtools_callback_);
95 GetExtensionView(
96 host_.get())->GetBrowser()->tab_strip_model()->RemoveObserver(this);
99 void ExtensionPopup::Observe(int type,
100 const content::NotificationSource& source,
101 const content::NotificationDetails& details) {
102 switch (type) {
103 case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME:
104 DCHECK_EQ(host()->host_contents(),
105 content::Source<content::WebContents>(source).ptr());
106 // Show when the content finishes loading and its width is computed.
107 ShowBubble();
108 break;
109 case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE:
110 // If we aren't the host of the popup, then disregard the notification.
111 if (content::Details<extensions::ExtensionHost>(host()) == details)
112 GetWidget()->Close();
113 break;
114 default:
115 NOTREACHED() << L"Received unexpected notification";
119 void ExtensionPopup::OnDevToolsStateChanged(
120 content::DevToolsAgentHost* agent_host,
121 bool attached) {
122 // First check that the devtools are being opened on this popup.
123 if (host()->host_contents() != agent_host->GetWebContents())
124 return;
126 if (attached) {
127 // Set inspect_with_devtools_ so the popup will be kept open while
128 // the devtools are open.
129 inspect_with_devtools_ = true;
130 } else {
131 // Widget::Close posts a task, which should give the devtools window a
132 // chance to finish detaching from the inspected RenderViewHost.
133 GetWidget()->Close();
137 void ExtensionPopup::OnExtensionSizeChanged(ExtensionViewViews* view) {
138 SizeToContents();
141 gfx::Size ExtensionPopup::GetPreferredSize() const {
142 // Constrain the size to popup min/max.
143 gfx::Size sz = views::View::GetPreferredSize();
144 sz.set_width(std::max(kMinWidth, std::min(kMaxWidth, sz.width())));
145 sz.set_height(std::max(kMinHeight, std::min(kMaxHeight, sz.height())));
146 return sz;
149 void ExtensionPopup::ViewHierarchyChanged(
150 const ViewHierarchyChangedDetails& details) {
151 // TODO(msw): Find any remaining crashes related to http://crbug.com/327776
152 // No view hierarchy changes are expected if the widget no longer exists.
153 widget_initialized_ |= details.child == this && details.is_add && GetWidget();
154 CHECK(GetWidget() || !widget_initialized_);
157 void ExtensionPopup::OnWidgetActivationChanged(views::Widget* widget,
158 bool active) {
159 if (active && widget == anchor_widget())
160 OnAnchorWindowActivation();
163 void ExtensionPopup::ActiveTabChanged(content::WebContents* old_contents,
164 content::WebContents* new_contents,
165 int index,
166 int reason) {
167 GetWidget()->Close();
170 void ExtensionPopup::OnAnchorWindowActivation() {
171 // TODO(msw): Find any remaining crashes related to http://crbug.com/327776
172 // No calls are expected if the widget isn't initialized or no longer exists.
173 CHECK(widget_initialized_);
174 CHECK(GetWidget());
176 if (!inspect_with_devtools_)
177 GetWidget()->Close();
180 // static
181 ExtensionPopup* ExtensionPopup::ShowPopup(
182 scoped_ptr<extensions::ExtensionViewHost> host,
183 views::View* anchor_view,
184 views::BubbleBorder::Arrow arrow,
185 ShowAction show_action) {
186 return ExtensionPopup::Create(
187 host.release(), anchor_view, arrow, show_action);
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());