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