// Copyright (c) 2011 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/notifications/balloon_host.h" #include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/notifications/balloon.h" #include "chrome/browser/notifications/notification.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_preferences_util.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/webui/chrome_web_ui_factory.h" #include "chrome/common/render_messages.h" #include "chrome/common/url_constants.h" #include "content/browser/renderer_host/browser_render_process_host.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/browser/site_instance.h" #include "content/common/bindings_policy.h" #include "content/common/notification_service.h" #include "content/common/notification_source.h" #include "content/common/notification_type.h" #include "content/common/renderer_preferences.h" #include "content/common/view_messages.h" #include "webkit/glue/webpreferences.h" BalloonHost::BalloonHost(Balloon* balloon) : render_view_host_(NULL), balloon_(balloon), initialized_(false), should_notify_on_disconnect_(false), enable_web_ui_(false) { DCHECK(balloon_); // If the notification is for an extension URL, make sure to use the extension // process to render it, so that it can communicate with other views in the // extension. const GURL& balloon_url = balloon_->notification().content_url(); if (balloon_url.SchemeIs(chrome::kExtensionScheme)) { site_instance_ = balloon_->profile()->GetExtensionProcessManager()->GetSiteInstanceForURL( balloon_url); } else { site_instance_ = SiteInstance::CreateSiteInstance(balloon_->profile()); } } void BalloonHost::Shutdown() { NotifyDisconnect(); if (render_view_host_) { render_view_host_->Shutdown(); render_view_host_ = NULL; } } Browser* BalloonHost::GetBrowser() { // Notifications aren't associated with a particular browser. return NULL; } gfx::NativeView BalloonHost::GetNativeViewOfHost() { // TODO(aa): Should this return the native view of the BalloonView*? return NULL; } TabContents* BalloonHost::associated_tab_contents() const { return NULL; } const string16& BalloonHost::GetSource() const { return balloon_->notification().display_source(); } WebPreferences BalloonHost::GetWebkitPrefs() { WebPreferences web_prefs = RenderViewHostDelegateHelper::GetWebkitPrefs(GetProfile(), enable_web_ui_); web_prefs.allow_scripts_to_close_windows = true; return web_prefs; } SiteInstance* BalloonHost::GetSiteInstance() const { return site_instance_.get(); } Profile* BalloonHost::GetProfile() const { return balloon_->profile(); } const GURL& BalloonHost::GetURL() const { return balloon_->notification().content_url(); } void BalloonHost::Close(RenderViewHost* render_view_host) { balloon_->CloseByScript(); NotifyDisconnect(); } void BalloonHost::RenderViewCreated(RenderViewHost* render_view_host) { render_view_host->Send(new ViewMsg_DisableScrollbarsForSmallWindows( render_view_host->routing_id(), balloon_->min_scrollbar_size())); render_view_host->WasResized(); #if !defined(OS_MACOSX) // TODO(levin): Make all of the code that went in originally with this change // to be cross-platform. See http://crbug.com/64720 render_view_host->EnablePreferredSizeChangedMode( kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow); #endif } void BalloonHost::RenderViewReady(RenderViewHost* render_view_host) { should_notify_on_disconnect_ = true; NotificationService::current()->Notify( NotificationType::NOTIFY_BALLOON_CONNECTED, Source<BalloonHost>(this), NotificationService::NoDetails()); } void BalloonHost::RenderViewGone(RenderViewHost* render_view_host, base::TerminationStatus status, int error_code) { Close(render_view_host); } int BalloonHost::GetBrowserWindowID() const { return extension_misc::kUnknownWindowId; } ViewType::Type BalloonHost::GetRenderViewType() const { return ViewType::NOTIFICATION; } RenderViewHostDelegate::View* BalloonHost::GetViewDelegate() { return this; } void BalloonHost::ProcessWebUIMessage( const ExtensionHostMsg_DomMessage_Params& params) { if (extension_function_dispatcher_.get()) { extension_function_dispatcher_->HandleRequest(params); } } // RenderViewHostDelegate::View methods implemented to allow links to // open pages in new tabs. void BalloonHost::CreateNewWindow( int route_id, const ViewHostMsg_CreateWindow_Params& params) { delegate_view_helper_.CreateNewWindow( route_id, balloon_->profile(), site_instance_.get(), ChromeWebUIFactory::GetInstance()->GetWebUIType(balloon_->profile(), balloon_->notification().content_url()), this, params.window_container_type, params.frame_name); } void BalloonHost::ShowCreatedWindow(int route_id, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture) { // Don't allow pop-ups from notifications. if (disposition == NEW_POPUP) return; TabContents* contents = delegate_view_helper_.GetCreatedWindow(route_id); if (!contents) return; Browser* browser = BrowserList::GetLastActiveWithProfile(balloon_->profile()); if (!browser) return; browser->AddTabContents(contents, disposition, initial_pos, user_gesture); } bool BalloonHost::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, bool* is_keyboard_shortcut) { return false; } void BalloonHost::UpdatePreferredSize(const gfx::Size& new_size) { balloon_->SetContentPreferredSize(new_size); } void BalloonHost::HandleMouseDown() { balloon_->OnClick(); } RendererPreferences BalloonHost::GetRendererPrefs(Profile* profile) const { RendererPreferences preferences; renderer_preferences_util::UpdateFromSystemSettings(&preferences, profile); return preferences; } void BalloonHost::Init() { DCHECK(!render_view_host_) << "BalloonViewHost already initialized."; RenderViewHost* rvh = new RenderViewHost( site_instance_.get(), this, MSG_ROUTING_NONE, NULL); if (GetProfile()->GetExtensionService()) { extension_function_dispatcher_.reset( ExtensionFunctionDispatcher::Create( rvh, this, balloon_->notification().content_url())); } if (extension_function_dispatcher_.get()) { rvh->AllowBindings(BindingsPolicy::EXTENSION); rvh->set_is_extension_process(true); const Extension* installed_app = GetProfile()->GetExtensionService()->GetInstalledApp( balloon_->notification().content_url()); static_cast<BrowserRenderProcessHost*>(rvh->process())->set_installed_app( installed_app); } else if (enable_web_ui_) { rvh->AllowBindings(BindingsPolicy::WEB_UI); } // Do platform-specific initialization. render_view_host_ = rvh; InitRenderWidgetHostView(); DCHECK(render_widget_host_view()); rvh->set_view(render_widget_host_view()); rvh->CreateRenderView(string16()); #if defined(OS_MACOSX) registrar_.Add(this, NotificationType::RENDER_WIDGET_HOST_DID_PAINT, Source<RenderWidgetHost>(render_view_host_)); #endif rvh->NavigateToURL(balloon_->notification().content_url()); initialized_ = true; } void BalloonHost::EnableWebUI() { DCHECK(render_view_host_ == NULL) << "EnableWebUI has to be called before a renderer is created."; enable_web_ui_ = true; } void BalloonHost::UpdateInspectorSetting(const std::string& key, const std::string& value) { RenderViewHostDelegateHelper::UpdateInspectorSetting( GetProfile(), key, value); } void BalloonHost::ClearInspectorSettings() { RenderViewHostDelegateHelper::ClearInspectorSettings(GetProfile()); } void BalloonHost::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { if (type == NotificationType::RENDER_WIDGET_HOST_DID_PAINT) { registrar_.RemoveAll(); render_view_host_->EnablePreferredSizeChangedMode( kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow); } } BalloonHost::~BalloonHost() { DCHECK(!render_view_host_); } void BalloonHost::NotifyDisconnect() { if (!should_notify_on_disconnect_) return; should_notify_on_disconnect_ = false; NotificationService::current()->Notify( NotificationType::NOTIFY_BALLOON_DISCONNECTED, Source<BalloonHost>(this), NotificationService::NoDetails()); }