| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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/tab_contents/tab_contents_controller.h" | 5 #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/memory/scoped_nsobject.h" | 9 #include "base/memory/scoped_nsobject.h" |
| 10 #include "content/browser/renderer_host/render_view_host.h" | 10 #include "content/browser/renderer_host/render_view_host.h" |
| 11 #include "content/browser/renderer_host/render_widget_host_view.h" | 11 #include "content/browser/renderer_host/render_widget_host_view.h" |
| 12 #include "content/public/browser/navigation_controller.h" | |
| 13 #include "content/public/browser/notification_observer.h" | |
| 14 #include "content/public/browser/notification_registrar.h" | |
| 15 #include "content/public/browser/notification_details.h" | |
| 16 #include "content/public/browser/notification_source.h" | |
| 17 #include "content/public/browser/notification_types.h" | |
| 18 #include "content/public/browser/web_contents.h" | 12 #include "content/public/browser/web_contents.h" |
| 19 | 13 |
| 20 using content::NavigationController; | |
| 21 using content::WebContents; | 14 using content::WebContents; |
| 22 | 15 |
| 23 @interface TabContentsController(Private) | |
| 24 // Forwards frame update to |delegate_| (ResizeNotificationView calls it). | |
| 25 - (void)tabContentsViewFrameWillChange:(NSRect)frameRect; | |
| 26 // Notification from WebContents (forwarded by TabContentsNotificationBridge). | |
| 27 - (void)tabContentsRenderViewHostChanged:(RenderViewHost*)oldHost | |
| 28 newHost:(RenderViewHost*)newHost; | |
| 29 @end | |
| 30 | |
| 31 | |
| 32 // A supporting C++ bridge object to register for TabContents notifications. | |
| 33 | |
| 34 class TabContentsNotificationBridge : public content::NotificationObserver { | |
| 35 public: | |
| 36 explicit TabContentsNotificationBridge(TabContentsController* controller); | |
| 37 | |
| 38 // Overriden from content::NotificationObserver. | |
| 39 virtual void Observe(int type, | |
| 40 const content::NotificationSource& source, | |
| 41 const content::NotificationDetails& details); | |
| 42 // Register for |contents|'s notifications, remove all prior registrations. | |
| 43 void ChangeWebContents(WebContents* contents); | |
| 44 private: | |
| 45 content::NotificationRegistrar registrar_; | |
| 46 TabContentsController* controller_; // weak, owns us | |
| 47 }; | |
| 48 | |
| 49 TabContentsNotificationBridge::TabContentsNotificationBridge( | |
| 50 TabContentsController* controller) | |
| 51 : controller_(controller) { | |
| 52 } | |
| 53 | |
| 54 void TabContentsNotificationBridge::Observe( | |
| 55 int type, | |
| 56 const content::NotificationSource& source, | |
| 57 const content::NotificationDetails& details) { | |
| 58 if (type == content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED) { | |
| 59 std::pair<RenderViewHost*, RenderViewHost*>* switched_details = | |
| 60 content::Details<std::pair<RenderViewHost*, RenderViewHost*> >( | |
| 61 details).ptr(); | |
| 62 [controller_ tabContentsRenderViewHostChanged:switched_details->first | |
| 63 newHost:switched_details->second]; | |
| 64 } else { | |
| 65 NOTREACHED(); | |
| 66 } | |
| 67 } | |
| 68 | |
| 69 void TabContentsNotificationBridge::ChangeWebContents(WebContents* contents) { | |
| 70 registrar_.RemoveAll(); | |
| 71 if (contents) { | |
| 72 registrar_.Add( | |
| 73 this, | |
| 74 content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, | |
| 75 content::Source<NavigationController>(&contents->GetController())); | |
| 76 } | |
| 77 } | |
| 78 | |
| 79 | |
| 80 // A custom view that notifies |controller| that view's frame is changing. | |
| 81 | |
| 82 @interface ResizeNotificationView : NSView { | |
| 83 TabContentsController* controller_; | |
| 84 } | |
| 85 - (id)initWithController:(TabContentsController*)controller; | |
| 86 @end | |
| 87 | |
| 88 @implementation ResizeNotificationView | |
| 89 | |
| 90 - (id)initWithController:(TabContentsController*)controller { | |
| 91 if ((self = [super initWithFrame:NSZeroRect])) { | |
| 92 controller_ = controller; | |
| 93 } | |
| 94 return self; | |
| 95 } | |
| 96 | |
| 97 - (void)setFrame:(NSRect)frameRect { | |
| 98 [controller_ tabContentsViewFrameWillChange:frameRect]; | |
| 99 [super setFrame:frameRect]; | |
| 100 } | |
| 101 | |
| 102 @end | |
| 103 | |
| 104 | 16 |
| 105 @implementation TabContentsController | 17 @implementation TabContentsController |
| 106 @synthesize webContents = contents_; | 18 @synthesize webContents = contents_; |
| 107 | 19 |
| 108 - (id)initWithContents:(WebContents*)contents | 20 - (id)initWithContents:(WebContents*)contents { |
| 109 delegate:(id<TabContentsControllerDelegate>)delegate { | |
| 110 if ((self = [super initWithNibName:nil bundle:nil])) { | 21 if ((self = [super initWithNibName:nil bundle:nil])) { |
| 111 contents_ = contents; | 22 contents_ = contents; |
| 112 delegate_ = delegate; | |
| 113 tabContentsBridge_.reset(new TabContentsNotificationBridge(self)); | |
| 114 tabContentsBridge_->ChangeWebContents(contents); | |
| 115 } | 23 } |
| 116 return self; | 24 return self; |
| 117 } | 25 } |
| 118 | 26 |
| 119 - (void)dealloc { | 27 - (void)dealloc { |
| 120 // make sure our contents have been removed from the window | 28 // make sure our contents have been removed from the window |
| 121 [[self view] removeFromSuperview]; | 29 [[self view] removeFromSuperview]; |
| 122 [super dealloc]; | 30 [super dealloc]; |
| 123 } | 31 } |
| 124 | 32 |
| 125 - (void)loadView { | 33 - (void)loadView { |
| 126 scoped_nsobject<ResizeNotificationView> view( | 34 scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]); |
| 127 [[ResizeNotificationView alloc] initWithController:self]); | |
| 128 [view setAutoresizingMask:NSViewHeightSizable|NSViewWidthSizable]; | 35 [view setAutoresizingMask:NSViewHeightSizable|NSViewWidthSizable]; |
| 129 [self setView:view]; | 36 [self setView:view]; |
| 130 } | 37 } |
| 131 | 38 |
| 132 - (void)ensureContentsSizeDoesNotChange { | 39 - (void)ensureContentsSizeDoesNotChange { |
| 133 if (contents_) { | 40 NSView* contentsContainer = [self view]; |
| 134 NSView* contentsContainer = [self view]; | 41 NSArray* subviews = [contentsContainer subviews]; |
| 135 NSArray* subviews = [contentsContainer subviews]; | 42 if ([subviews count] > 0) |
| 136 if ([subviews count] > 0) | 43 [contents_->GetNativeView() setAutoresizingMask:NSViewNotSizable]; |
| 137 [contents_->GetNativeView() setAutoresizingMask:NSViewNotSizable]; | |
| 138 } | |
| 139 } | 44 } |
| 140 | 45 |
| 141 // Call when the tab view is properly sized and the render widget host view | 46 // Call when the tab view is properly sized and the render widget host view |
| 142 // should be put into the view hierarchy. | 47 // should be put into the view hierarchy. |
| 143 - (void)ensureContentsVisible { | 48 - (void)ensureContentsVisible { |
| 144 if (!contents_) | 49 if (!contents_) |
| 145 return; | 50 return; |
| 146 NSView* contentsContainer = [self view]; | 51 NSView* contentsContainer = [self view]; |
| 147 NSArray* subviews = [contentsContainer subviews]; | 52 NSArray* subviews = [contentsContainer subviews]; |
| 148 NSView* contentsNativeView = contents_->GetNativeView(); | 53 NSView* contentsNativeView = contents_->GetNativeView(); |
| 149 | 54 [contentsNativeView setFrame:[contentsContainer frame]]; |
| 150 NSRect contentsNativeViewFrame = [contentsContainer frame]; | |
| 151 contentsNativeViewFrame.origin = NSZeroPoint; | |
| 152 | |
| 153 [delegate_ tabContentsViewFrameWillChange:self | |
| 154 frameRect:contentsNativeViewFrame]; | |
| 155 | |
| 156 // Native view is resized to the actual size before it becomes visible | |
| 157 // to avoid flickering. | |
| 158 [contentsNativeView setFrame:contentsNativeViewFrame]; | |
| 159 if ([subviews count] == 0) { | 55 if ([subviews count] == 0) { |
| 160 [contentsContainer addSubview:contentsNativeView]; | 56 [contentsContainer addSubview:contentsNativeView]; |
| 161 } else if ([subviews objectAtIndex:0] != contentsNativeView) { | 57 } else if ([subviews objectAtIndex:0] != contentsNativeView) { |
| 162 [contentsContainer replaceSubview:[subviews objectAtIndex:0] | 58 [contentsContainer replaceSubview:[subviews objectAtIndex:0] |
| 163 with:contentsNativeView]; | 59 with:contentsNativeView]; |
| 164 } | 60 } |
| 165 // Restore autoresizing properties possibly stripped by | |
| 166 // ensureContentsSizeDoesNotChange call. | |
| 167 [contentsNativeView setAutoresizingMask:NSViewWidthSizable| | 61 [contentsNativeView setAutoresizingMask:NSViewWidthSizable| |
| 168 NSViewHeightSizable]; | 62 NSViewHeightSizable]; |
| 169 } | 63 } |
| 170 | 64 |
| 171 - (void)changeWebContents:(WebContents*)newContents { | 65 - (void)changeWebContents:(WebContents*)newContents { |
| 172 contents_ = newContents; | 66 contents_ = newContents; |
| 173 tabContentsBridge_->ChangeWebContents(contents_); | |
| 174 } | 67 } |
| 175 | 68 |
| 176 - (void)tabContentsViewFrameWillChange:(NSRect)frameRect { | 69 // Returns YES if the tab represented by this controller is the front-most. |
| 177 [delegate_ tabContentsViewFrameWillChange:self frameRect:frameRect]; | 70 - (BOOL)isCurrentTab { |
| 178 } | 71 // We're the current tab if we're in the view hierarchy, otherwise some other |
| 179 | 72 // tab is. |
| 180 - (void)tabContentsRenderViewHostChanged:(RenderViewHost*)oldHost | 73 return [[self view] superview] ? YES : NO; |
| 181 newHost:(RenderViewHost*)newHost { | |
| 182 if (oldHost && newHost && oldHost->view() && newHost->view()) { | |
| 183 newHost->view()->set_reserved_contents_rect( | |
| 184 oldHost->view()->reserved_contents_rect()); | |
| 185 } else { | |
| 186 [delegate_ tabContentsViewFrameWillChange:self | |
| 187 frameRect:[[self view] frame]]; | |
| 188 } | |
| 189 } | 74 } |
| 190 | 75 |
| 191 - (void)willBecomeUnselectedTab { | 76 - (void)willBecomeUnselectedTab { |
| 192 // The RWHV is ripped out of the view hierarchy on tab switches, so it never | 77 // The RWHV is ripped out of the view hierarchy on tab switches, so it never |
| 193 // formally resigns first responder status. Handle this by explicitly sending | 78 // formally resigns first responder status. Handle this by explicitly sending |
| 194 // a Blur() message to the renderer, but only if the RWHV currently has focus. | 79 // a Blur() message to the renderer, but only if the RWHV currently has focus. |
| 195 RenderViewHost* rvh = [self webContents]->GetRenderViewHost(); | 80 RenderViewHost* rvh = [self webContents]->GetRenderViewHost(); |
| 196 if (rvh && rvh->view() && rvh->view()->HasFocus()) | 81 if (rvh && rvh->view() && rvh->view()->HasFocus()) |
| 197 rvh->Blur(); | 82 rvh->Blur(); |
| 198 } | 83 } |
| 199 | 84 |
| 200 - (void)willBecomeSelectedTab { | 85 - (void)willBecomeSelectedTab { |
| 201 // Do not explicitly call Focus() here, as the RWHV may not actually have | 86 // Do not explicitly call Focus() here, as the RWHV may not actually have |
| 202 // focus (for example, if the omnibox has focus instead). The TabContents | 87 // focus (for example, if the omnibox has focus instead). The TabContents |
| 203 // logic will restore focus to the appropriate view. | 88 // logic will restore focus to the appropriate view. |
| 204 } | 89 } |
| 205 | 90 |
| 206 - (void)tabDidChange:(WebContents*)updatedContents { | 91 - (void)tabDidChange:(WebContents*)updatedContents { |
| 207 // Calling setContentView: here removes any first responder status | 92 // Calling setContentView: here removes any first responder status |
| 208 // the view may have, so avoid changing the view hierarchy unless | 93 // the view may have, so avoid changing the view hierarchy unless |
| 209 // the view is different. | 94 // the view is different. |
| 210 if ([self webContents] != updatedContents) { | 95 if ([self webContents] != updatedContents) { |
| 211 [self changeWebContents:updatedContents]; | 96 contents_ = updatedContents; |
| 212 if ([self webContents]) | 97 [self ensureContentsVisible]; |
| 213 [self ensureContentsVisible]; | |
| 214 } | 98 } |
| 215 } | 99 } |
| 216 | 100 |
| 217 @end | 101 @end |
| OLD | NEW |