summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/cocoa/tab_contents_controller.mm
diff options
context:
space:
mode:
authorKristian Monsen <kristianm@google.com>2011-05-11 20:53:37 +0100
committerKristian Monsen <kristianm@google.com>2011-05-16 13:54:48 +0100
commit21d179b334e59e9a3bfcaed4c4430bef1bc5759d (patch)
tree64e2bb6da27af6a5c93ca34f6051584aafbfcb9e /chrome/browser/ui/cocoa/tab_contents_controller.mm
parent0c63f00edd6ed0482fd5cbcea937ca088baf7858 (diff)
downloadexternal_chromium-21d179b334e59e9a3bfcaed4c4430bef1bc5759d.zip
external_chromium-21d179b334e59e9a3bfcaed4c4430bef1bc5759d.tar.gz
external_chromium-21d179b334e59e9a3bfcaed4c4430bef1bc5759d.tar.bz2
Merge Chromium at 10.0.621.0: Initial merge by git.
Change-Id: I070cc91c608dfa4a968a5a54c173260765ac8097
Diffstat (limited to 'chrome/browser/ui/cocoa/tab_contents_controller.mm')
-rw-r--r--chrome/browser/ui/cocoa/tab_contents_controller.mm212
1 files changed, 212 insertions, 0 deletions
diff --git a/chrome/browser/ui/cocoa/tab_contents_controller.mm b/chrome/browser/ui/cocoa/tab_contents_controller.mm
new file mode 100644
index 0000000..c7b5cf8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_contents_controller.mm
@@ -0,0 +1,212 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "chrome/browser/ui/cocoa/tab_contents_controller.h"
+
+#include "base/mac_util.h"
+#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"
+
+
+@interface TabContentsController(Private)
+// Forwards frame update to |delegate_| (ResizeNotificationView 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(TabContentsController* 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 ChangeTabContents(TabContents* contents);
+ private:
+ NotificationRegistrar registrar_;
+ TabContentsController* controller_; // weak, owns us
+};
+
+TabContentsNotificationBridge::TabContentsNotificationBridge(
+ TabContentsController* 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::ChangeTabContents(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 ResizeNotificationView : NSView {
+ TabContentsController* controller_;
+}
+- (id)initWithController:(TabContentsController*)controller;
+@end
+
+@implementation ResizeNotificationView
+
+- (id)initWithController:(TabContentsController*)controller {
+ if ((self = [super initWithFrame:NSZeroRect])) {
+ controller_ = controller;
+ }
+ return self;
+}
+
+- (void)setFrame:(NSRect)frameRect {
+ [controller_ tabContentsViewFrameWillChange:frameRect];
+ [super setFrame:frameRect];
+}
+
+@end
+
+
+@implementation TabContentsController
+@synthesize tabContents = contents_;
+
+- (id)initWithContents:(TabContents*)contents
+ delegate:(id<TabContentsControllerDelegate>)delegate {
+ if ((self = [super initWithNibName:nil bundle:nil])) {
+ contents_ = contents;
+ delegate_ = delegate;
+ tabContentsBridge_.reset(new TabContentsNotificationBridge(self));
+ tabContentsBridge_->ChangeTabContents(contents);
+ }
+ return self;
+}
+
+- (void)dealloc {
+ // make sure our contents have been removed from the window
+ [[self view] removeFromSuperview];
+ [super dealloc];
+}
+
+- (void)loadView {
+ scoped_nsobject<ResizeNotificationView> view(
+ [[ResizeNotificationView alloc] initWithController:self]);
+ [view setAutoresizingMask:NSViewHeightSizable|NSViewWidthSizable];
+ [self setView:view];
+}
+
+- (void)ensureContentsSizeDoesNotChange {
+ 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();
+
+ 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];
+}
+
+- (void)changeTabContents:(TabContents*)newContents {
+ contents_ = newContents;
+ tabContentsBridge_->ChangeTabContents(contents_);
+}
+
+- (void)tabContentsViewFrameWillChange:(NSRect)frameRect {
+ [delegate_ tabContentsViewFrameWillChange:self frameRect:frameRect];
+}
+
+- (void)tabContentsRenderViewHostChanged:(RenderViewHost*)oldHost
+ newHost:(RenderViewHost*)newHost {
+ if (oldHost && newHost && oldHost->view() && newHost->view()) {
+ newHost->view()->set_reserved_contents_rect(
+ oldHost->view()->reserved_contents_rect());
+ } else {
+ [delegate_ tabContentsViewFrameWillChange:self
+ frameRect:[[self view] frame]];
+ }
+}
+
+- (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 = [self tabContents]->render_view_host();
+ if (rvh && rvh->view() && rvh->view()->HasFocus())
+ rvh->Blur();
+}
+
+- (void)willBecomeSelectedTab {
+ // Do not explicitly call Focus() here, as the RWHV may not actually have
+ // focus (for example, if the omnibox has focus instead). The TabContents
+ // logic will restore focus to the appropriate view.
+}
+
+- (void)tabDidChange:(TabContents*)updatedContents {
+ // Calling setContentView: here removes any first responder status
+ // the view may have, so avoid changing the view hierarchy unless
+ // the view is different.
+ if ([self tabContents] != updatedContents) {
+ [self changeTabContents:updatedContents];
+ if ([self tabContents])
+ [self ensureContentsVisible];
+ }
+}
+
+@end