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 27 BalloonHost::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 48 void BalloonHost::Shutdown() { 49 NotifyDisconnect(); 50 if (render_view_host_) { 51 render_view_host_->Shutdown(); 52 render_view_host_ = NULL; 53 } 54 } 55 56 Browser* BalloonHost::GetBrowser() { 57 // Notifications aren't associated with a particular browser. 58 return NULL; 59 } 60 61 gfx::NativeView BalloonHost::GetNativeViewOfHost() { 62 // TODO(aa): Should this return the native view of the BalloonView*? 63 return NULL; 64 } 65 66 TabContents* BalloonHost::associated_tab_contents() const { return NULL; } 67 68 const string16& BalloonHost::GetSource() const { 69 return balloon_->notification().display_source(); 70 } 71 72 WebPreferences 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 80 SiteInstance* BalloonHost::GetSiteInstance() const { 81 return site_instance_.get(); 82 } 83 84 Profile* BalloonHost::GetProfile() const { 85 return balloon_->profile(); 86 } 87 88 const GURL& BalloonHost::GetURL() const { 89 return balloon_->notification().content_url(); 90 } 91 92 void BalloonHost::Close(RenderViewHost* render_view_host) { 93 balloon_->CloseByScript(); 94 NotifyDisconnect(); 95 } 96 97 void 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 109 void 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 116 void BalloonHost::RenderViewGone(RenderViewHost* render_view_host, 117 base::TerminationStatus status, 118 int error_code) { 119 Close(render_view_host); 120 } 121 122 int BalloonHost::GetBrowserWindowID() const { 123 return extension_misc::kUnknownWindowId; 124 } 125 126 ViewType::Type BalloonHost::GetRenderViewType() const { 127 return ViewType::NOTIFICATION; 128 } 129 130 RenderViewHostDelegate::View* BalloonHost::GetViewDelegate() { 131 return this; 132 } 133 134 void 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. 143 void 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 157 void 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 175 bool BalloonHost::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, 176 bool* is_keyboard_shortcut) { 177 return false; 178 } 179 180 void BalloonHost::UpdatePreferredSize(const gfx::Size& new_size) { 181 balloon_->SetContentPreferredSize(new_size); 182 } 183 184 void BalloonHost::HandleMouseDown() { 185 balloon_->OnClick(); 186 } 187 188 RendererPreferences BalloonHost::GetRendererPrefs(Profile* profile) const { 189 RendererPreferences preferences; 190 renderer_preferences_util::UpdateFromSystemSettings(&preferences, profile); 191 return preferences; 192 } 193 194 void 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 231 void 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 237 void BalloonHost::UpdateInspectorSetting(const std::string& key, 238 const std::string& value) { 239 RenderViewHostDelegateHelper::UpdateInspectorSetting( 240 GetProfile(), key, value); 241 } 242 243 void BalloonHost::ClearInspectorSettings() { 244 RenderViewHostDelegateHelper::ClearInspectorSettings(GetProfile()); 245 } 246 247 void 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 257 BalloonHost::~BalloonHost() { 258 DCHECK(!render_view_host_); 259 } 260 261 void 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