Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h" | 5 #import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/callback.h" | 9 #include "base/callback.h" |
| 10 #include "chrome/browser/chrome_notification_types.h" | 10 #include "chrome/browser/chrome_notification_types.h" |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 39 | 39 |
| 40 // Given a value and a rage, clamp the value into the range. | 40 // Given a value and a rage, clamp the value into the range. |
| 41 CGFloat Clamp(CGFloat value, CGFloat min, CGFloat max) { | 41 CGFloat Clamp(CGFloat value, CGFloat min, CGFloat max) { |
| 42 return std::max(min, std::min(max, value)); | 42 return std::max(min, std::min(max, value)); |
| 43 } | 43 } |
| 44 | 44 |
| 45 } // namespace | 45 } // namespace |
| 46 | 46 |
| 47 @interface ExtensionPopupController (Private) | 47 @interface ExtensionPopupController (Private) |
| 48 // Callers should be using the public static method for initialization. | 48 // Callers should be using the public static method for initialization. |
| 49 // NOTE: This takes ownership of |host|. | 49 - (id)initWithParentWindow:(NSWindow*)parentWindow |
| 50 - (id)initWithHost:(extensions::ExtensionViewHost*)host | 50 anchoredAt:(NSPoint)anchoredAt |
| 51 parentWindow:(NSWindow*)parentWindow | 51 arrowLocation:(info_bubble::BubbleArrowLocation)arrowLocation |
| 52 anchoredAt:(NSPoint)anchoredAt | 52 devMode:(BOOL)devMode; |
| 53 arrowLocation:(info_bubble::BubbleArrowLocation)arrowLocation | 53 |
| 54 devMode:(BOOL)devMode; | 54 // Set the ExtensionViewHost, taking ownership. |
| 55 - (void)setExtensionViewHost:(scoped_ptr<extensions::ExtensionViewHost>)host; | |
| 55 | 56 |
| 56 // Called when the extension's hosted NSView has been resized. | 57 // Called when the extension's hosted NSView has been resized. |
| 57 - (void)extensionViewFrameChanged; | 58 - (void)extensionViewFrameChanged; |
| 58 | 59 |
| 59 // Called when the extension's size changes. | 60 // Called when the extension's size changes. |
| 60 - (void)onSizeChanged:(NSSize)newSize; | 61 - (void)onSizeChanged:(NSSize)newSize; |
| 61 | 62 |
| 62 // Called when the extension view is shown. | 63 // Called when the extension view is shown. |
| 63 - (void)onViewDidShow; | 64 - (void)onViewDidShow; |
| 64 | 65 |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 143 // know what it is for notifications, but our ExtensionViewHost may not be | 144 // know what it is for notifications, but our ExtensionViewHost may not be |
| 144 // valid. | 145 // valid. |
| 145 WebContents* web_contents_; | 146 WebContents* web_contents_; |
| 146 base::Callback<void(content::DevToolsAgentHost*, bool)> devtools_callback_; | 147 base::Callback<void(content::DevToolsAgentHost*, bool)> devtools_callback_; |
| 147 }; | 148 }; |
| 148 | 149 |
| 149 @implementation ExtensionPopupController | 150 @implementation ExtensionPopupController |
| 150 | 151 |
| 151 @synthesize extensionId = extensionId_; | 152 @synthesize extensionId = extensionId_; |
| 152 | 153 |
| 153 - (id)initWithHost:(extensions::ExtensionViewHost*)host | 154 - (id)initWithParentWindow:(NSWindow*)parentWindow |
| 154 parentWindow:(NSWindow*)parentWindow | 155 anchoredAt:(NSPoint)anchoredAt |
| 155 anchoredAt:(NSPoint)anchoredAt | 156 arrowLocation:(info_bubble::BubbleArrowLocation)arrowLocation |
| 156 arrowLocation:(info_bubble::BubbleArrowLocation)arrowLocation | 157 devMode:(BOOL)devMode { |
| 157 devMode:(BOOL)devMode { | |
| 158 base::scoped_nsobject<InfoBubbleWindow> window([[InfoBubbleWindow alloc] | 158 base::scoped_nsobject<InfoBubbleWindow> window([[InfoBubbleWindow alloc] |
| 159 initWithContentRect:ui::kWindowSizeDeterminedLater | 159 initWithContentRect:ui::kWindowSizeDeterminedLater |
| 160 styleMask:NSBorderlessWindowMask | 160 styleMask:NSBorderlessWindowMask |
| 161 backing:NSBackingStoreBuffered | 161 backing:NSBackingStoreBuffered |
| 162 defer:YES]); | 162 defer:YES]); |
| 163 if (!window.get()) | 163 if (!window.get()) |
| 164 return nil; | 164 return nil; |
| 165 | 165 |
| 166 anchoredAt = [parentWindow convertBaseToScreen:anchoredAt]; | 166 anchoredAt = [parentWindow convertBaseToScreen:anchoredAt]; |
| 167 if ((self = [super initWithWindow:window | 167 if ((self = [super initWithWindow:window |
| 168 parentWindow:parentWindow | 168 parentWindow:parentWindow |
| 169 anchoredAt:anchoredAt])) { | 169 anchoredAt:anchoredAt])) { |
| 170 host_.reset(host); | |
| 171 extensionId_ = host_->extension_id(); | |
| 172 beingInspected_ = devMode; | 170 beingInspected_ = devMode; |
| 173 ignoreWindowDidResignKey_ = NO; | 171 ignoreWindowDidResignKey_ = NO; |
| 174 | 172 [[self bubble] setArrowLocation:arrowLocation]; |
| 175 InfoBubbleView* view = self.bubble; | |
| 176 [view setArrowLocation:arrowLocation]; | |
| 177 | |
| 178 extensionView_ = host->view()->GetNativeView(); | |
| 179 container_.reset(new ExtensionPopupContainer(self)); | |
| 180 static_cast<ExtensionViewMac*>(host->view()) | |
| 181 ->set_container(container_.get()); | |
| 182 | |
| 183 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; | |
| 184 [center addObserver:self | |
| 185 selector:@selector(extensionViewFrameChanged) | |
| 186 name:NSViewFrameDidChangeNotification | |
| 187 object:extensionView_]; | |
| 188 | |
| 189 [view addSubview:extensionView_]; | |
| 190 | |
| 191 notificationBridge_.reset(new DevtoolsNotificationBridge(self)); | |
| 192 registrar_.reset(new content::NotificationRegistrar); | |
| 193 if (beingInspected_) { | |
| 194 // Listen for the extension to finish loading so the dev tools can be | |
| 195 // opened. | |
| 196 registrar_->Add(notificationBridge_.get(), | |
| 197 extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, | |
| 198 content::Source<BrowserContext>(host->browser_context())); | |
| 199 } | |
| 200 } | 173 } |
| 201 return self; | 174 return self; |
| 202 } | 175 } |
| 203 | 176 |
| 204 - (void)dealloc { | 177 - (void)dealloc { |
| 205 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 178 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 206 [super dealloc]; | 179 [super dealloc]; |
| 207 } | 180 } |
| 208 | 181 |
| 209 - (void)showDevTools { | 182 - (void)showDevTools { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 278 devMode:(BOOL)devMode { | 251 devMode:(BOOL)devMode { |
| 279 DCHECK([NSThread isMainThread]); | 252 DCHECK([NSThread isMainThread]); |
| 280 DCHECK(browser); | 253 DCHECK(browser); |
| 281 if (!browser) | 254 if (!browser) |
| 282 return nil; | 255 return nil; |
| 283 | 256 |
| 284 // If we click the browser/page action again, we should close the popup. | 257 // If we click the browser/page action again, we should close the popup. |
| 285 // Make Mac behavior the same with Windows and others. | 258 // Make Mac behavior the same with Windows and others. |
| 286 if (gPopup) { | 259 if (gPopup) { |
| 287 std::string extension_id = url.host(); | 260 std::string extension_id = url.host(); |
| 288 extensions::ExtensionViewHost* host = [gPopup extensionViewHost]; | 261 std::string old_extension_id = [gPopup extensionViewHost]->extension_id(); |
| 289 if (extension_id == host->extension_id()) { | 262 [gPopup close]; |
| 290 [gPopup close]; | 263 DCHECK(!gPopup); |
|
tapted
2015/02/19 07:38:17
tl;dr - I had to remove the DCHECK
So this turned
| |
| 264 if (extension_id == old_extension_id) | |
| 291 return nil; | 265 return nil; |
| 292 } | |
| 293 } | 266 } |
| 294 | 267 |
| 295 extensions::ExtensionViewHost* host = | 268 // Create the popup first. This establishes an initially hidden NSWindow so |
| 296 extensions::ExtensionViewHostFactory::CreatePopupHost(url, browser); | 269 // that the renderer is able to gather correct screen metrics for the initial |
| 270 // paint. | |
| 271 gPopup = [[ExtensionPopupController alloc] | |
| 272 initWithParentWindow:browser->window()->GetNativeWindow() | |
| 273 anchoredAt:anchoredAt | |
| 274 arrowLocation:arrowLocation | |
| 275 devMode:devMode]; | |
| 276 | |
| 277 scoped_ptr<extensions::ExtensionViewHost> host( | |
| 278 extensions::ExtensionViewHostFactory::CreatePopupHost(url, browser)); | |
| 297 DCHECK(host); | 279 DCHECK(host); |
| 298 if (!host) | 280 [gPopup setExtensionViewHost:host.Pass()]; |
| 299 return nil; | |
| 300 | |
| 301 [gPopup close]; | |
| 302 | |
| 303 // Takes ownership of |host|. Also will autorelease itself when the popup is | |
| 304 // closed, so no need to do that here. | |
| 305 gPopup = [[ExtensionPopupController alloc] | |
| 306 initWithHost:host | |
| 307 parentWindow:browser->window()->GetNativeWindow() | |
| 308 anchoredAt:anchoredAt | |
| 309 arrowLocation:arrowLocation | |
| 310 devMode:devMode]; | |
| 311 return gPopup; | 281 return gPopup; |
| 312 } | 282 } |
| 313 | 283 |
| 314 + (ExtensionPopupController*)popup { | 284 + (ExtensionPopupController*)popup { |
| 315 return gPopup; | 285 return gPopup; |
| 316 } | 286 } |
| 317 | 287 |
| 288 - (void)setExtensionViewHost:(scoped_ptr<extensions::ExtensionViewHost>)host { | |
| 289 DCHECK(!host_); | |
| 290 DCHECK(host); | |
| 291 host_.swap(host); | |
| 292 | |
| 293 extensionId_ = host_->extension_id(); | |
| 294 container_.reset(new ExtensionPopupContainer(self)); | |
| 295 ExtensionViewMac* hostView = static_cast<ExtensionViewMac*>(host_->view()); | |
| 296 hostView->set_container(container_.get()); | |
| 297 hostView->CreateWidgetHostViewIn([self bubble]); | |
| 298 | |
| 299 extensionView_ = hostView->GetNativeView(); | |
| 300 | |
| 301 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; | |
| 302 [center addObserver:self | |
| 303 selector:@selector(extensionViewFrameChanged) | |
| 304 name:NSViewFrameDidChangeNotification | |
| 305 object:extensionView_]; | |
| 306 | |
| 307 notificationBridge_.reset(new DevtoolsNotificationBridge(self)); | |
| 308 registrar_.reset(new content::NotificationRegistrar); | |
| 309 if (beingInspected_) { | |
| 310 // Listen for the extension to finish loading so the dev tools can be | |
| 311 // opened. | |
| 312 registrar_->Add(notificationBridge_.get(), | |
| 313 extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, | |
| 314 content::Source<BrowserContext>(host_->browser_context())); | |
| 315 } | |
| 316 } | |
| 317 | |
| 318 - (void)extensionViewFrameChanged { | 318 - (void)extensionViewFrameChanged { |
| 319 // If there are no changes in the width or height of the frame, then ignore. | 319 // If there are no changes in the width or height of the frame, then ignore. |
| 320 if (NSEqualSizes([extensionView_ frame].size, extensionFrame_.size)) | 320 if (NSEqualSizes([extensionView_ frame].size, extensionFrame_.size)) |
| 321 return; | 321 return; |
| 322 | 322 |
| 323 extensionFrame_ = [extensionView_ frame]; | 323 extensionFrame_ = [extensionView_ frame]; |
| 324 // Constrain the size of the view. | 324 // Constrain the size of the view. |
| 325 [extensionView_ setFrameSize:NSMakeSize( | 325 [extensionView_ setFrameSize:NSMakeSize( |
| 326 Clamp(NSWidth(extensionFrame_), | 326 Clamp(NSWidth(extensionFrame_), |
| 327 ExtensionViewMac::kMinWidth, | 327 ExtensionViewMac::kMinWidth, |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 375 // the notification is fired (and consequently the view contents have loaded). | 375 // the notification is fired (and consequently the view contents have loaded). |
| 376 if (![window isVisible]) { | 376 if (![window isVisible]) { |
| 377 [self showWindow:self]; | 377 [self showWindow:self]; |
| 378 } | 378 } |
| 379 } | 379 } |
| 380 | 380 |
| 381 - (void)onSizeChanged:(NSSize)newSize { | 381 - (void)onSizeChanged:(NSSize)newSize { |
| 382 // When we update the size, the window will become visible. Stay hidden until | 382 // When we update the size, the window will become visible. Stay hidden until |
| 383 // the host is loaded. | 383 // the host is loaded. |
| 384 pendingSize_ = newSize; | 384 pendingSize_ = newSize; |
| 385 if (!host_->did_stop_loading()) | 385 if (!host_ || !host_->did_stop_loading()) |
| 386 return; | 386 return; |
| 387 | 387 |
| 388 // No need to use CA here, our caller calls us repeatedly to animate the | 388 // No need to use CA here, our caller calls us repeatedly to animate the |
| 389 // resizing. | 389 // resizing. |
| 390 NSRect frame = [extensionView_ frame]; | 390 NSRect frame = [extensionView_ frame]; |
| 391 frame.size = newSize; | 391 frame.size = newSize; |
| 392 | 392 |
| 393 // |new_size| is in pixels. Convert to view units. | 393 // |new_size| is in pixels. Convert to view units. |
| 394 frame.size = [extensionView_ convertSize:frame.size fromView:nil]; | 394 frame.size = [extensionView_ convertSize:frame.size fromView:nil]; |
| 395 | 395 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 433 return minSize; | 433 return minSize; |
| 434 } | 434 } |
| 435 | 435 |
| 436 // Private (TestingAPI) | 436 // Private (TestingAPI) |
| 437 + (NSSize)maxPopupSize { | 437 + (NSSize)maxPopupSize { |
| 438 NSSize maxSize = {ExtensionViewMac::kMaxWidth, ExtensionViewMac::kMaxHeight}; | 438 NSSize maxSize = {ExtensionViewMac::kMaxWidth, ExtensionViewMac::kMaxHeight}; |
| 439 return maxSize; | 439 return maxSize; |
| 440 } | 440 } |
| 441 | 441 |
| 442 @end | 442 @end |
| OLD | NEW |