This source file includes following definitions.
- IsOwnerOf
- devtools_callback_
- Observe
- OnDevToolsStateChanged
- OnExtensionSizeChanged
- GetPreferredSize
- OnWidgetDestroying
- OnWidgetActivationChanged
- OnWindowActivated
- ActiveTabChanged
- ShowPopup
- ShowBubble
#include "chrome/browser/ui/views/extensions/extension_popup.h"
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/extensions/extension_view_host.h"
#include "chrome/browser/extensions/extension_view_host_factory.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/host_desktop.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_manager.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "ui/gfx/insets.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/widget/widget.h"
#if defined(USE_AURA)
#include "ui/aura/window.h"
#include "ui/wm/core/window_animations.h"
#include "ui/wm/core/window_util.h"
#include "ui/wm/public/activation_client.h"
#endif
#if defined(OS_WIN)
#include "ui/views/win/hwnd_util.h"
#endif
using content::BrowserContext;
using content::RenderViewHost;
using content::WebContents;
namespace {
bool IsOwnerOf(gfx::NativeView child, gfx::NativeView possible_owner) {
if (!child)
return false;
#if defined(OS_WIN)
if (::GetWindow(views::HWNDForNativeView(child), GW_OWNER) ==
views::HWNDForNativeView(possible_owner))
return true;
#endif
return false;
}
}
const int ExtensionPopup::kMinWidth = 25;
const int ExtensionPopup::kMinHeight = 25;
const int ExtensionPopup::kMaxWidth = 800;
const int ExtensionPopup::kMaxHeight = 600;
ExtensionPopup::ExtensionPopup(extensions::ExtensionViewHost* host,
views::View* anchor_view,
views::BubbleBorder::Arrow arrow,
ShowAction show_action)
: BubbleDelegateView(anchor_view, arrow),
host_(host),
devtools_callback_(base::Bind(
&ExtensionPopup::OnDevToolsStateChanged, base::Unretained(this))) {
inspect_with_devtools_ = show_action == SHOW_AND_INSPECT;
const int margin = views::BubbleBorder::GetCornerRadius() / 2;
set_margins(gfx::Insets(margin, margin, margin, margin));
SetLayoutManager(new views::FillLayout());
AddChildView(host->view());
host->view()->set_container(this);
set_close_on_deactivate(false);
set_move_with_anchor(true);
registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
content::Source<WebContents>(host->host_contents()));
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
content::Source<BrowserContext>(host->browser_context()));
content::DevToolsManager::GetInstance()->AddAgentStateCallback(
devtools_callback_);
host_->view()->browser()->tab_strip_model()->AddObserver(this);
}
ExtensionPopup::~ExtensionPopup() {
content::DevToolsManager::GetInstance()->RemoveAgentStateCallback(
devtools_callback_);
host_->view()->browser()->tab_strip_model()->RemoveObserver(this);
}
void ExtensionPopup::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME:
DCHECK(content::Source<WebContents>(host()->host_contents()) == source);
ShowBubble();
break;
case chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE:
if (content::Details<extensions::ExtensionHost>(host()) == details)
GetWidget()->Close();
break;
default:
NOTREACHED() << L"Received unexpected notification";
}
}
void ExtensionPopup::OnDevToolsStateChanged(
content::DevToolsAgentHost* agent_host, bool attached) {
if (host()->render_view_host() != agent_host->GetRenderViewHost())
return;
if (attached) {
inspect_with_devtools_ = true;
} else {
GetWidget()->Close();
}
}
void ExtensionPopup::OnExtensionSizeChanged(ExtensionViewViews* view) {
SizeToContents();
}
gfx::Size ExtensionPopup::GetPreferredSize() {
gfx::Size sz = views::View::GetPreferredSize();
sz.set_width(std::max(kMinWidth, std::min(kMaxWidth, sz.width())));
sz.set_height(std::max(kMinHeight, std::min(kMaxHeight, sz.height())));
return sz;
}
void ExtensionPopup::OnWidgetDestroying(views::Widget* widget) {
BubbleDelegateView::OnWidgetDestroying(widget);
#if defined(USE_AURA)
aura::Window* bubble_window = GetWidget()->GetNativeWindow();
aura::client::ActivationClient* activation_client =
aura::client::GetActivationClient(bubble_window->GetRootWindow());
activation_client->RemoveObserver(this);
#endif
}
void ExtensionPopup::OnWidgetActivationChanged(views::Widget* widget,
bool active) {
views::Widget* this_widget = GetWidget();
CHECK(!close_on_deactivate());
CHECK(this_widget);
CHECK(widget);
gfx::NativeView activated_view = widget->GetNativeView();
gfx::NativeView this_view = this_widget->GetNativeView();
if (active && !inspect_with_devtools_ && activated_view != this_view &&
!IsOwnerOf(activated_view, this_view))
this_widget->Close();
}
#if defined(USE_AURA)
void ExtensionPopup::OnWindowActivated(aura::Window* gained_active,
aura::Window* lost_active) {
aura::Window* this_window = GetWidget()->GetNativeWindow();
aura::Window* anchor_window = anchor_widget()->GetNativeWindow();
chrome::HostDesktopType host_desktop_type =
chrome::GetHostDesktopTypeForNativeWindow(this_window);
if (!inspect_with_devtools_ && anchor_window == gained_active &&
host_desktop_type != chrome::HOST_DESKTOP_TYPE_ASH &&
this_window->GetRootWindow() == anchor_window->GetRootWindow() &&
wm::GetTransientParent(gained_active) != this_window)
GetWidget()->Close();
}
#endif
void ExtensionPopup::ActiveTabChanged(content::WebContents* old_contents,
content::WebContents* new_contents,
int index,
int reason) {
GetWidget()->Close();
}
ExtensionPopup* ExtensionPopup::ShowPopup(const GURL& url,
Browser* browser,
views::View* anchor_view,
views::BubbleBorder::Arrow arrow,
ShowAction show_action) {
extensions::ExtensionViewHost* host =
extensions::ExtensionViewHostFactory::CreatePopupHost(url, browser);
ExtensionPopup* popup = new ExtensionPopup(host, anchor_view, arrow,
show_action);
views::BubbleDelegateView::CreateBubble(popup);
#if defined(USE_AURA)
gfx::NativeView native_view = popup->GetWidget()->GetNativeView();
wm::SetWindowVisibilityAnimationType(
native_view,
wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
wm::SetWindowVisibilityAnimationVerticalPosition(
native_view,
-3.0f);
#endif
if (host->did_stop_loading())
popup->ShowBubble();
#if defined(USE_AURA)
aura::Window* bubble_window = popup->GetWidget()->GetNativeWindow();
aura::client::ActivationClient* activation_client =
aura::client::GetActivationClient(bubble_window->GetRootWindow());
activation_client->AddObserver(popup);
#endif
return popup;
}
void ExtensionPopup::ShowBubble() {
GetWidget()->Show();
host()->host_contents()->GetView()->Focus();
if (inspect_with_devtools_) {
DevToolsWindow::OpenDevToolsWindow(host()->render_view_host(),
DevToolsToggleAction::ShowConsole());
}
}