Chromium Code Reviews| Index: chrome/browser/cocoa/tab_contents_controller.mm |
| =================================================================== |
| --- chrome/browser/cocoa/tab_contents_controller.mm (revision 64775) |
| +++ chrome/browser/cocoa/tab_contents_controller.mm (working copy) |
| @@ -8,15 +8,106 @@ |
| #include "base/scoped_nsobject.h" |
| #include "chrome/browser/renderer_host/render_view_host.h" |
| #include "chrome/browser/renderer_host/render_widget_host_view.h" |
| +#include "chrome/browser/tab_contents/navigation_controller.h" |
| #include "chrome/browser/tab_contents/tab_contents.h" |
| +#include "chrome/common/notification_details.h" |
| +#include "chrome/common/notification_observer.h" |
| +#include "chrome/common/notification_registrar.h" |
| +#include "chrome/common/notification_source.h" |
| +#include "chrome/common/notification_type.h" |
| -@implementation TabContentsController |
| +@interface TabContentsViewController(Private) |
| +// Forwards frame update to |delegate_| (TabContentsControllerView calls it). |
| +- (void)tabContentsViewFrameWillChange:(NSRect)frameRect; |
| +// Notification from TabContents (forwarded by TabContentsNotificationBridge). |
| +- (void)tabContentsRenderViewHostChanged:(RenderViewHost*)oldHost |
| + newHost:(RenderViewHost*)newHost; |
| +@end |
| + |
| + |
| +// A supporting C++ bridge object to register for TabContents notifications. |
| + |
| +class TabContentsNotificationBridge : public NotificationObserver { |
| + public: |
| + explicit TabContentsNotificationBridge(TabContentsViewController* controller); |
| + |
| + // Overriden from NotificationObserver. |
| + virtual void Observe(NotificationType type, |
| + const NotificationSource& source, |
| + const NotificationDetails& details); |
| + // Register for |contents|'s notifications, remove all prior registrations. |
| + void ObserveNotifications(TabContents* contents); |
| + private: |
| + NotificationRegistrar registrar_; |
| + TabContentsViewController* controller_; // weak, owns us |
| +}; |
| + |
| +TabContentsNotificationBridge::TabContentsNotificationBridge( |
| + TabContentsViewController* controller) |
| + : controller_(controller) { |
| +} |
| + |
| +void TabContentsNotificationBridge::Observe( |
| + NotificationType type, |
| + const NotificationSource& source, |
| + const NotificationDetails& details) { |
| + if (type == NotificationType::RENDER_VIEW_HOST_CHANGED) { |
| + RenderViewHostSwitchedDetails* switched_details = |
| + Details<RenderViewHostSwitchedDetails>(details).ptr(); |
| + [controller_ tabContentsRenderViewHostChanged:switched_details->old_host |
| + newHost:switched_details->new_host]; |
| + } else { |
| + NOTREACHED(); |
| + } |
| +} |
| + |
| +void TabContentsNotificationBridge::ObserveNotifications( |
| + TabContents* contents) { |
| + registrar_.RemoveAll(); |
| + if (contents) { |
| + registrar_.Add(this, |
| + NotificationType::RENDER_VIEW_HOST_CHANGED, |
| + Source<NavigationController>(&contents->controller())); |
| + } |
| +} |
| + |
| + |
| +// A custom view that notifies |controller| that view's frame is changing. |
| + |
| +@interface TabContentsControllerView : NSView { |
| + TabContentsViewController* controller_; |
| +} |
| +- (id)initWithController:(TabContentsViewController*)controller; |
| +@end |
| + |
| +@implementation TabContentsControllerView |
| + |
| +- (id)initWithController:(TabContentsViewController*)controller { |
| + if ((self = [super initWithFrame:NSZeroRect])) { |
| + controller_ = controller; |
| + } |
| + return self; |
| +} |
| + |
| +- (void)setFrame:(NSRect)frameRect { |
| + [controller_ tabContentsViewFrameWillChange:frameRect]; |
| + [super setFrame:frameRect]; |
| +} |
| + |
| +@end |
| + |
| + |
| +@implementation TabContentsViewController |
| @synthesize tabContents = contents_; |
| -- (id)initWithContents:(TabContents*)contents { |
| +- (id)initWithContents:(TabContents*)contents |
| + delegate:(id<TabContentsViewControllerDelegate>)delegate { |
| if ((self = [super initWithNibName:nil bundle:nil])) { |
| contents_ = contents; |
| + delegate_ = delegate; |
| + tabContentsBridge_.reset(new TabContentsNotificationBridge(self)); |
| + tabContentsBridge_->ObserveNotifications(contents); |
| } |
| return self; |
| } |
| @@ -28,47 +119,81 @@ |
| } |
| - (void)loadView { |
| - scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]); |
| + scoped_nsobject<TabContentsControllerView> view( |
| + [[TabContentsControllerView alloc] initWithController:self]); |
| [view setAutoresizingMask:NSViewHeightSizable|NSViewWidthSizable]; |
| [self setView:view]; |
| } |
| - (void)ensureContentsSizeDoesNotChange { |
| - NSView* contentsContainer = [self view]; |
| - NSArray* subviews = [contentsContainer subviews]; |
| - if ([subviews count] > 0) |
| - [contents_->GetNativeView() setAutoresizingMask:NSViewNotSizable]; |
| + if (contents_) { |
| + NSView* contentsContainer = [self view]; |
| + NSArray* subviews = [contentsContainer subviews]; |
| + if ([subviews count] > 0) |
| + [contents_->GetNativeView() setAutoresizingMask:NSViewNotSizable]; |
| + } |
| } |
| // Call when the tab view is properly sized and the render widget host view |
| // should be put into the view hierarchy. |
| - (void)ensureContentsVisible { |
| + if (!contents_) |
| + return; |
| NSView* contentsContainer = [self view]; |
| NSArray* subviews = [contentsContainer subviews]; |
| NSView* contentsNativeView = contents_->GetNativeView(); |
| - [contentsNativeView setFrame:[contentsContainer frame]]; |
| + |
| + NSRect contentsNativeViewFrame = [contentsContainer frame]; |
| + contentsNativeViewFrame.origin = NSZeroPoint; |
| + |
| + [delegate_ tabContentsViewFrameWillChange:self |
| + frameRect:contentsNativeViewFrame]; |
| + |
| + // Native view is resized to the actual size before it becomes visible |
| + // to avoid flickering. |
| + [contentsNativeView setFrame:contentsNativeViewFrame]; |
| if ([subviews count] == 0) { |
| [contentsContainer addSubview:contentsNativeView]; |
| } else if ([subviews objectAtIndex:0] != contentsNativeView) { |
| [contentsContainer replaceSubview:[subviews objectAtIndex:0] |
| with:contentsNativeView]; |
| } |
| + // Restore autoresizing properties possibly stripped by |
| + // ensureContentsSizeDoesNotChange call. |
| [contentsNativeView setAutoresizingMask:NSViewWidthSizable| |
| NSViewHeightSizable]; |
| } |
| -// Returns YES if the tab represented by this controller is the front-most. |
| -- (BOOL)isCurrentTab { |
| - // We're the current tab if we're in the view hierarchy, otherwise some other |
| - // tab is. |
| - return [[self view] superview] ? YES : NO; |
| +- (void)changeTabContents:(TabContents*)newContents { |
| + contents_ = newContents; |
| + tabContentsBridge_->ObserveNotifications(contents_); |
| } |
| +- (void)tabContentsViewFrameWillChange:(NSRect)frameRect { |
| + [delegate_ tabContentsViewFrameWillChange:self frameRect:frameRect]; |
| +} |
| + |
| +- (void)tabContentsRenderViewHostChanged:(RenderViewHost*)oldHost |
| + newHost:(RenderViewHost*)newHost { |
| + if (oldHost && newHost && oldHost->view() && newHost->view()) { |
|
rohitrao (ping after 24h)
2010/11/12 18:45:19
You're going to have this same basic code copy/pas
Aleksey Shlyapnikov
2010/11/13 01:37:11
I tried to move this part into RenderViewHostManag
|
| + newHost->view()->set_reserved_contents_rect( |
| + oldHost->view()->reserved_contents_rect()); |
| + } else { |
| + [delegate_ tabContentsViewFrameWillChange:self |
| + frameRect:[[self view] frame]]; |
|
rohitrao (ping after 24h)
2010/11/12 18:45:19
How important is this fallback case? When does it
Aleksey Shlyapnikov
2010/11/13 01:37:11
One or both of the hosts can be NULL when we're tr
|
| + } |
| +} |
| + |
| +@end |
| + |
| + |
| +@implementation TabContentsController |
| + |
| - (void)willBecomeUnselectedTab { |
| // The RWHV is ripped out of the view hierarchy on tab switches, so it never |
| // formally resigns first responder status. Handle this by explicitly sending |
| // a Blur() message to the renderer, but only if the RWHV currently has focus. |
| - RenderViewHost* rvh = contents_->render_view_host(); |
| + RenderViewHost* rvh = [self tabContents]->render_view_host(); |
| if (rvh && rvh->view() && rvh->view()->HasFocus()) |
| rvh->Blur(); |
| } |
| @@ -83,9 +208,10 @@ |
| // Calling setContentView: here removes any first responder status |
| // the view may have, so avoid changing the view hierarchy unless |
| // the view is different. |
| - if (contents_ != updatedContents) { |
| - contents_ = updatedContents; |
| - [self ensureContentsVisible]; |
| + if ([self tabContents] != updatedContents) { |
| + [self changeTabContents:updatedContents]; |
| + if ([self tabContents]) |
| + [self ensureContentsVisible]; |
| } |
| } |