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]; // Starts the animation to fade out the popup. |
290 [gPopup close]; | 263 if (extension_id == old_extension_id) |
291 return nil; | 264 return nil; |
292 } | |
293 } | 265 } |
294 | 266 |
295 extensions::ExtensionViewHost* host = | 267 // Create the popup first. This establishes an initially hidden NSWindow so |
296 extensions::ExtensionViewHostFactory::CreatePopupHost(url, browser); | 268 // that the renderer is able to gather correct screen metrics for the initial |
| 269 // paint. |
| 270 gPopup = [[ExtensionPopupController alloc] |
| 271 initWithParentWindow:browser->window()->GetNativeWindow() |
| 272 anchoredAt:anchoredAt |
| 273 arrowLocation:arrowLocation |
| 274 devMode:devMode]; |
| 275 |
| 276 scoped_ptr<extensions::ExtensionViewHost> host( |
| 277 extensions::ExtensionViewHostFactory::CreatePopupHost(url, browser)); |
297 DCHECK(host); | 278 DCHECK(host); |
298 if (!host) | 279 [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; | 280 return gPopup; |
312 } | 281 } |
313 | 282 |
314 + (ExtensionPopupController*)popup { | 283 + (ExtensionPopupController*)popup { |
315 return gPopup; | 284 return gPopup; |
316 } | 285 } |
317 | 286 |
| 287 - (void)setExtensionViewHost:(scoped_ptr<extensions::ExtensionViewHost>)host { |
| 288 DCHECK(!host_); |
| 289 DCHECK(host); |
| 290 host_.swap(host); |
| 291 |
| 292 extensionId_ = host_->extension_id(); |
| 293 container_.reset(new ExtensionPopupContainer(self)); |
| 294 ExtensionViewMac* hostView = static_cast<ExtensionViewMac*>(host_->view()); |
| 295 hostView->set_container(container_.get()); |
| 296 hostView->CreateWidgetHostViewIn([self bubble]); |
| 297 |
| 298 extensionView_ = hostView->GetNativeView(); |
| 299 |
| 300 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; |
| 301 [center addObserver:self |
| 302 selector:@selector(extensionViewFrameChanged) |
| 303 name:NSViewFrameDidChangeNotification |
| 304 object:extensionView_]; |
| 305 |
| 306 notificationBridge_.reset(new DevtoolsNotificationBridge(self)); |
| 307 registrar_.reset(new content::NotificationRegistrar); |
| 308 if (beingInspected_) { |
| 309 // Listen for the extension to finish loading so the dev tools can be |
| 310 // opened. |
| 311 registrar_->Add(notificationBridge_.get(), |
| 312 extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, |
| 313 content::Source<BrowserContext>(host_->browser_context())); |
| 314 } |
| 315 } |
| 316 |
318 - (void)extensionViewFrameChanged { | 317 - (void)extensionViewFrameChanged { |
319 // If there are no changes in the width or height of the frame, then ignore. | 318 // If there are no changes in the width or height of the frame, then ignore. |
320 if (NSEqualSizes([extensionView_ frame].size, extensionFrame_.size)) | 319 if (NSEqualSizes([extensionView_ frame].size, extensionFrame_.size)) |
321 return; | 320 return; |
322 | 321 |
323 extensionFrame_ = [extensionView_ frame]; | 322 extensionFrame_ = [extensionView_ frame]; |
324 // Constrain the size of the view. | 323 // Constrain the size of the view. |
325 [extensionView_ setFrameSize:NSMakeSize( | 324 [extensionView_ setFrameSize:NSMakeSize( |
326 Clamp(NSWidth(extensionFrame_), | 325 Clamp(NSWidth(extensionFrame_), |
327 ExtensionViewMac::kMinWidth, | 326 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). | 374 // the notification is fired (and consequently the view contents have loaded). |
376 if (![window isVisible]) { | 375 if (![window isVisible]) { |
377 [self showWindow:self]; | 376 [self showWindow:self]; |
378 } | 377 } |
379 } | 378 } |
380 | 379 |
381 - (void)onSizeChanged:(NSSize)newSize { | 380 - (void)onSizeChanged:(NSSize)newSize { |
382 // When we update the size, the window will become visible. Stay hidden until | 381 // When we update the size, the window will become visible. Stay hidden until |
383 // the host is loaded. | 382 // the host is loaded. |
384 pendingSize_ = newSize; | 383 pendingSize_ = newSize; |
385 if (!host_->did_stop_loading()) | 384 if (!host_ || !host_->did_stop_loading()) |
386 return; | 385 return; |
387 | 386 |
388 // No need to use CA here, our caller calls us repeatedly to animate the | 387 // No need to use CA here, our caller calls us repeatedly to animate the |
389 // resizing. | 388 // resizing. |
390 NSRect frame = [extensionView_ frame]; | 389 NSRect frame = [extensionView_ frame]; |
391 frame.size = newSize; | 390 frame.size = newSize; |
392 | 391 |
393 // |new_size| is in pixels. Convert to view units. | 392 // |new_size| is in pixels. Convert to view units. |
394 frame.size = [extensionView_ convertSize:frame.size fromView:nil]; | 393 frame.size = [extensionView_ convertSize:frame.size fromView:nil]; |
395 | 394 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 return minSize; | 432 return minSize; |
434 } | 433 } |
435 | 434 |
436 // Private (TestingAPI) | 435 // Private (TestingAPI) |
437 + (NSSize)maxPopupSize { | 436 + (NSSize)maxPopupSize { |
438 NSSize maxSize = {ExtensionViewMac::kMaxWidth, ExtensionViewMac::kMaxHeight}; | 437 NSSize maxSize = {ExtensionViewMac::kMaxWidth, ExtensionViewMac::kMaxHeight}; |
439 return maxSize; | 438 return maxSize; |
440 } | 439 } |
441 | 440 |
442 @end | 441 @end |
OLD | NEW |