15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/ui/views/extensions/extension_popup.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/bind.h"
89ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/devtools/devtools_window.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/extensions/extension_view_host.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/extensions/extension_view_host_factory.h"
123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
14c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "content/public/browser/devtools_agent_host.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_details.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h"
1746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "content/public/browser/render_view_host.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/insets.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/layout/fill_layout.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/wm/core/window_animations.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/wm/core/window_util.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/wm/public/activation_client.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionViewViews* GetExtensionView(extensions::ExtensionViewHost* host) {
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return static_cast<ExtensionViewViews*>(host->view());
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// The minimum/maximum dimensions of the popup.
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// The minimum is just a little larger than the size of the button itself.
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The maximum is an arbitrary number that should be smaller than most screens.
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int ExtensionPopup::kMinWidth = 25;
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int ExtensionPopup::kMinHeight = 25;
4046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const int ExtensionPopup::kMaxWidth = 800;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int ExtensionPopup::kMaxHeight = 600;
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)ExtensionPopup::ExtensionPopup(extensions::ExtensionViewHost* host,
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               views::View* anchor_view,
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               views::BubbleBorder::Arrow arrow,
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                               ShowAction show_action)
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : BubbleDelegateView(anchor_view, arrow),
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      host_(host),
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      devtools_callback_(base::Bind(
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          &ExtensionPopup::OnDevToolsStateChanged, base::Unretained(this))),
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      widget_initialized_(false) {
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  inspect_with_devtools_ = show_action == SHOW_AND_INSPECT;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Adjust the margin so that contents fit better.
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int margin = views::BubbleBorder::GetCornerRadius() / 2;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  set_margins(gfx::Insets(margin, margin, margin, margin));
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetLayoutManager(new views::FillLayout());
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddChildView(GetExtensionView(host));
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetExtensionView(host)->set_container(this);
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ExtensionPopup closes itself on very specific de-activation conditions.
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  set_close_on_deactivate(false);
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Wait to show the popup until the contained host finishes loading.
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 content::Source<content::WebContents>(host->host_contents()));
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Listen for the containing view calling window.close();
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registrar_.Add(
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this,
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      content::Source<content::BrowserContext>(host->browser_context()));
7146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  content::DevToolsAgentHost::AddAgentStateCallback(devtools_callback_);
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetExtensionView(host)->GetBrowser()->tab_strip_model()->AddObserver(this);
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciExtensionPopup::~ExtensionPopup() {
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  content::DevToolsAgentHost::RemoveAgentStateCallback(devtools_callback_);
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GetExtensionView(
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      host_.get())->GetBrowser()->tab_strip_model()->RemoveObserver(this);
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ExtensionPopup::Observe(int type,
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                             const content::NotificationSource& source,
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                             const content::NotificationDetails& details) {
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  switch (type) {
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME:
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(host()->host_contents(),
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                content::Source<content::WebContents>(source).ptr());
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Show when the content finishes loading and its width is computed.
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ShowBubble();
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      break;
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE:
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If we aren't the host of the popup, then disregard the notification.
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (content::Details<extensions::ExtensionHost>(host()) == details)
9646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        GetWidget()->Close();
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      break;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << L"Received unexpected notification";
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ExtensionPopup::OnDevToolsStateChanged(
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    content::DevToolsAgentHost* agent_host,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool attached) {
10646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // First check that the devtools are being opened on this popup.
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (host()->host_contents() != agent_host->GetWebContents())
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (attached) {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Set inspect_with_devtools_ so the popup will be kept open while
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the devtools are open.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    inspect_with_devtools_ = true;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Widget::Close posts a task, which should give the devtools window a
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // chance to finish detaching from the inspected RenderViewHost.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetWidget()->Close();
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionPopup::OnExtensionSizeChanged(ExtensionViewViews* view) {
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  SizeToContents();
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
12546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)gfx::Size ExtensionPopup::GetPreferredSize() const {
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Constrain the size to popup min/max.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size sz = views::View::GetPreferredSize();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sz.set_width(std::max(kMinWidth, std::min(kMaxWidth, sz.width())));
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sz.set_height(std::max(kMinHeight, std::min(kMaxHeight, sz.height())));
13046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return sz;
13146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ExtensionPopup::ViewHierarchyChanged(
13446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const ViewHierarchyChangedDetails& details) {
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(msw): Find any remaining crashes related to http://crbug.com/327776
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // No view hierarchy changes are expected if the widget no longer exists.
1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  widget_initialized_ |= details.child == this && details.is_add && GetWidget();
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(GetWidget() || !widget_initialized_);
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ExtensionPopup::OnWidgetDestroying(views::Widget* widget) {
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  BubbleDelegateView::OnWidgetDestroying(widget);
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  aura::Window* bubble_window = GetWidget()->GetNativeWindow();
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  aura::client::ActivationClient* activation_client =
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      aura::client::GetActivationClient(bubble_window->GetRootWindow());
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If the popup was being inspected with devtools and the browser window was
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // closed, then the root window and activation client are already destroyed.
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (activation_client)
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    activation_client->RemoveObserver(this);
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionPopup::OnWidgetActivationChanged(views::Widget* widget,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               bool active) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(msw): Find any remaining crashes related to http://crbug.com/327776
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No calls are expected if the widget isn't initialized or no longer exists.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(widget_initialized_);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(GetWidget());
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Close on anchor window activation (ie. user clicked the browser window).
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!inspect_with_devtools_ && widget && active &&
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      widget->GetNativeWindow() == anchor_widget()->GetNativeWindow())
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetWidget()->Close();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ExtensionPopup::OnWindowActivated(aura::Window* gained_active,
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       aura::Window* lost_active) {
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(msw): Find any remaining crashes related to http://crbug.com/327776
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // No calls are expected if the widget isn't initialized or no longer exists.
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK(widget_initialized_);
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK(GetWidget());
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Close on anchor window activation (ie. user clicked the browser window).
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // DesktopNativeWidgetAura does not trigger the expected browser widget
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // [de]activation events when activating widgets in its own root window.
1754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // This additional check handles those cases. See: http://crbug.com/320889
1764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!inspect_with_devtools_ &&
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gained_active == anchor_widget()->GetNativeWindow())
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetWidget()->Close();
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ExtensionPopup::ActiveTabChanged(content::WebContents* old_contents,
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                      content::WebContents* new_contents,
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                      int index,
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                      int reason) {
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GetWidget()->Close();
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionPopup* ExtensionPopup::ShowPopup(const GURL& url,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          Browser* browser,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          views::View* anchor_view,
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                          views::BubbleBorder::Arrow arrow,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          ShowAction show_action) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extensions::ExtensionViewHost* host =
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extensions::ExtensionViewHostFactory::CreatePopupHost(url, browser);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionPopup* popup = new ExtensionPopup(host, anchor_view, arrow,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      show_action);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::BubbleDelegateView::CreateBubble(popup);
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::NativeView native_view = popup->GetWidget()->GetNativeView();
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wm::SetWindowVisibilityAnimationType(
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      native_view, wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wm::SetWindowVisibilityAnimationVerticalPosition(native_view, -3.0f);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the host had somehow finished loading, then we'd miss the notification
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and not show.  This seems to happen in single-process mode.
207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (host->did_stop_loading())
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup->ShowBubble();
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  aura::Window* bubble_window = popup->GetWidget()->GetNativeWindow();
211  aura::client::ActivationClient* activation_client =
212      aura::client::GetActivationClient(bubble_window->GetRootWindow());
213  activation_client->AddObserver(popup);
214
215  return popup;
216}
217
218void ExtensionPopup::ShowBubble() {
219  GetWidget()->Show();
220
221  // Focus on the host contents when the bubble is first shown.
222  host()->host_contents()->Focus();
223
224  if (inspect_with_devtools_) {
225    DevToolsWindow::OpenDevToolsWindow(host()->host_contents(),
226                                       DevToolsToggleAction::ShowConsole());
227  }
228}
229