1// Copyright (c) 2011 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. 4 5#include "chrome/browser/notifications/balloon_host.h" 6#include "chrome/browser/extensions/extension_process_manager.h" 7#include "chrome/browser/extensions/extension_service.h" 8#include "chrome/browser/notifications/balloon.h" 9#include "chrome/browser/notifications/notification.h" 10#include "chrome/browser/profiles/profile.h" 11#include "chrome/browser/renderer_preferences_util.h" 12#include "chrome/browser/ui/browser_list.h" 13#include "chrome/browser/ui/webui/chrome_web_ui_factory.h" 14#include "chrome/common/render_messages.h" 15#include "chrome/common/url_constants.h" 16#include "content/browser/renderer_host/browser_render_process_host.h" 17#include "content/browser/renderer_host/render_view_host.h" 18#include "content/browser/site_instance.h" 19#include "content/common/bindings_policy.h" 20#include "content/common/notification_service.h" 21#include "content/common/notification_source.h" 22#include "content/common/notification_type.h" 23#include "content/common/renderer_preferences.h" 24#include "content/common/view_messages.h" 25#include "webkit/glue/webpreferences.h" 26 27BalloonHost::BalloonHost(Balloon* balloon) 28 : render_view_host_(NULL), 29 balloon_(balloon), 30 initialized_(false), 31 should_notify_on_disconnect_(false), 32 enable_web_ui_(false) { 33 DCHECK(balloon_); 34 35 // If the notification is for an extension URL, make sure to use the extension 36 // process to render it, so that it can communicate with other views in the 37 // extension. 38 const GURL& balloon_url = balloon_->notification().content_url(); 39 if (balloon_url.SchemeIs(chrome::kExtensionScheme)) { 40 site_instance_ = 41 balloon_->profile()->GetExtensionProcessManager()->GetSiteInstanceForURL( 42 balloon_url); 43 } else { 44 site_instance_ = SiteInstance::CreateSiteInstance(balloon_->profile()); 45 } 46} 47 48void BalloonHost::Shutdown() { 49 NotifyDisconnect(); 50 if (render_view_host_) { 51 render_view_host_->Shutdown(); 52 render_view_host_ = NULL; 53 } 54} 55 56Browser* BalloonHost::GetBrowser() { 57 // Notifications aren't associated with a particular browser. 58 return NULL; 59} 60 61gfx::NativeView BalloonHost::GetNativeViewOfHost() { 62 // TODO(aa): Should this return the native view of the BalloonView*? 63 return NULL; 64} 65 66TabContents* BalloonHost::associated_tab_contents() const { return NULL; } 67 68const string16& BalloonHost::GetSource() const { 69 return balloon_->notification().display_source(); 70} 71 72WebPreferences BalloonHost::GetWebkitPrefs() { 73 WebPreferences web_prefs = 74 RenderViewHostDelegateHelper::GetWebkitPrefs(GetProfile(), 75 enable_web_ui_); 76 web_prefs.allow_scripts_to_close_windows = true; 77 return web_prefs; 78} 79 80SiteInstance* BalloonHost::GetSiteInstance() const { 81 return site_instance_.get(); 82} 83 84Profile* BalloonHost::GetProfile() const { 85 return balloon_->profile(); 86} 87 88const GURL& BalloonHost::GetURL() const { 89 return balloon_->notification().content_url(); 90} 91 92void BalloonHost::Close(RenderViewHost* render_view_host) { 93 balloon_->CloseByScript(); 94 NotifyDisconnect(); 95} 96 97void BalloonHost::RenderViewCreated(RenderViewHost* render_view_host) { 98 render_view_host->Send(new ViewMsg_DisableScrollbarsForSmallWindows( 99 render_view_host->routing_id(), balloon_->min_scrollbar_size())); 100 render_view_host->WasResized(); 101#if !defined(OS_MACOSX) 102 // TODO(levin): Make all of the code that went in originally with this change 103 // to be cross-platform. See http://crbug.com/64720 104 render_view_host->EnablePreferredSizeChangedMode( 105 kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow); 106#endif 107} 108 109void BalloonHost::RenderViewReady(RenderViewHost* render_view_host) { 110 should_notify_on_disconnect_ = true; 111 NotificationService::current()->Notify( 112 NotificationType::NOTIFY_BALLOON_CONNECTED, 113 Source<BalloonHost>(this), NotificationService::NoDetails()); 114} 115 116void BalloonHost::RenderViewGone(RenderViewHost* render_view_host, 117 base::TerminationStatus status, 118 int error_code) { 119 Close(render_view_host); 120} 121 122int BalloonHost::GetBrowserWindowID() const { 123 return extension_misc::kUnknownWindowId; 124} 125 126ViewType::Type BalloonHost::GetRenderViewType() const { 127 return ViewType::NOTIFICATION; 128} 129 130RenderViewHostDelegate::View* BalloonHost::GetViewDelegate() { 131 return this; 132} 133 134void BalloonHost::ProcessWebUIMessage( 135 const ExtensionHostMsg_DomMessage_Params& params) { 136 if (extension_function_dispatcher_.get()) { 137 extension_function_dispatcher_->HandleRequest(params); 138 } 139} 140 141// RenderViewHostDelegate::View methods implemented to allow links to 142// open pages in new tabs. 143void BalloonHost::CreateNewWindow( 144 int route_id, 145 const ViewHostMsg_CreateWindow_Params& params) { 146 delegate_view_helper_.CreateNewWindow( 147 route_id, 148 balloon_->profile(), 149 site_instance_.get(), 150 ChromeWebUIFactory::GetInstance()->GetWebUIType(balloon_->profile(), 151 balloon_->notification().content_url()), 152 this, 153 params.window_container_type, 154 params.frame_name); 155} 156 157void BalloonHost::ShowCreatedWindow(int route_id, 158 WindowOpenDisposition disposition, 159 const gfx::Rect& initial_pos, 160 bool user_gesture) { 161 // Don't allow pop-ups from notifications. 162 if (disposition == NEW_POPUP) 163 return; 164 165 TabContents* contents = delegate_view_helper_.GetCreatedWindow(route_id); 166 if (!contents) 167 return; 168 Browser* browser = BrowserList::GetLastActiveWithProfile(balloon_->profile()); 169 if (!browser) 170 return; 171 172 browser->AddTabContents(contents, disposition, initial_pos, user_gesture); 173} 174 175bool BalloonHost::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, 176 bool* is_keyboard_shortcut) { 177 return false; 178} 179 180void BalloonHost::UpdatePreferredSize(const gfx::Size& new_size) { 181 balloon_->SetContentPreferredSize(new_size); 182} 183 184void BalloonHost::HandleMouseDown() { 185 balloon_->OnClick(); 186} 187 188RendererPreferences BalloonHost::GetRendererPrefs(Profile* profile) const { 189 RendererPreferences preferences; 190 renderer_preferences_util::UpdateFromSystemSettings(&preferences, profile); 191 return preferences; 192} 193 194void BalloonHost::Init() { 195 DCHECK(!render_view_host_) << "BalloonViewHost already initialized."; 196 RenderViewHost* rvh = new RenderViewHost( 197 site_instance_.get(), this, MSG_ROUTING_NONE, NULL); 198 if (GetProfile()->GetExtensionService()) { 199 extension_function_dispatcher_.reset( 200 ExtensionFunctionDispatcher::Create( 201 rvh, this, balloon_->notification().content_url())); 202 } 203 if (extension_function_dispatcher_.get()) { 204 rvh->AllowBindings(BindingsPolicy::EXTENSION); 205 rvh->set_is_extension_process(true); 206 const Extension* installed_app = 207 GetProfile()->GetExtensionService()->GetInstalledApp( 208 balloon_->notification().content_url()); 209 static_cast<BrowserRenderProcessHost*>(rvh->process())->set_installed_app( 210 installed_app); 211 } else if (enable_web_ui_) { 212 rvh->AllowBindings(BindingsPolicy::WEB_UI); 213 } 214 215 // Do platform-specific initialization. 216 render_view_host_ = rvh; 217 InitRenderWidgetHostView(); 218 DCHECK(render_widget_host_view()); 219 220 rvh->set_view(render_widget_host_view()); 221 rvh->CreateRenderView(string16()); 222#if defined(OS_MACOSX) 223 registrar_.Add(this, NotificationType::RENDER_WIDGET_HOST_DID_PAINT, 224 Source<RenderWidgetHost>(render_view_host_)); 225#endif 226 rvh->NavigateToURL(balloon_->notification().content_url()); 227 228 initialized_ = true; 229} 230 231void BalloonHost::EnableWebUI() { 232 DCHECK(render_view_host_ == NULL) << 233 "EnableWebUI has to be called before a renderer is created."; 234 enable_web_ui_ = true; 235} 236 237void BalloonHost::UpdateInspectorSetting(const std::string& key, 238 const std::string& value) { 239 RenderViewHostDelegateHelper::UpdateInspectorSetting( 240 GetProfile(), key, value); 241} 242 243void BalloonHost::ClearInspectorSettings() { 244 RenderViewHostDelegateHelper::ClearInspectorSettings(GetProfile()); 245} 246 247void BalloonHost::Observe(NotificationType type, 248 const NotificationSource& source, 249 const NotificationDetails& details) { 250 if (type == NotificationType::RENDER_WIDGET_HOST_DID_PAINT) { 251 registrar_.RemoveAll(); 252 render_view_host_->EnablePreferredSizeChangedMode( 253 kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow); 254 } 255} 256 257BalloonHost::~BalloonHost() { 258 DCHECK(!render_view_host_); 259} 260 261void BalloonHost::NotifyDisconnect() { 262 if (!should_notify_on_disconnect_) 263 return; 264 265 should_notify_on_disconnect_ = false; 266 NotificationService::current()->Notify( 267 NotificationType::NOTIFY_BALLOON_DISCONNECTED, 268 Source<BalloonHost>(this), NotificationService::NoDetails()); 269} 270