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