web_contents_view_mac.mm revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#import <Carbon/Carbon.h> 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#import "content/browser/web_contents/web_contents_view_mac.h" 8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <string> 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#import "base/mac/scoped_sending_event.h" 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/message_loop.h" 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#import "base/message_pump_mac.h" 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/browser/renderer_host/popup_menu_helper_mac.h" 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/browser/renderer_host/render_view_host_factory.h" 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/browser/renderer_host/render_view_host_impl.h" 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/browser/renderer_host/render_widget_host_view_mac.h" 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/browser/web_contents/web_contents_impl.h" 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#import "content/browser/web_contents/web_drag_dest_mac.h" 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#import "content/browser/web_contents/web_drag_source_mac.h" 21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/common/view_messages.h" 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/web_contents_delegate.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/web_contents_view_delegate.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "skia/ext/skia_utils_mac.h" 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#import "third_party/mozilla/NSPasteboard+Utils.h" 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/clipboard/custom_data_helper.h" 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#import "ui/base/cocoa/focus_tracker.h" 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/base/dragdrop/cocoa_dnd_util.h" 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/image/image_skia_util_mac.h" 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using WebKit::WebDragOperation; 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using WebKit::WebDragOperationsMask; 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::PopupMenuHelper; 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::RenderViewHostFactory; 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::RenderWidgetHostView; 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::RenderWidgetHostViewMac; 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::WebContents; 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::WebContentsImpl; 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using content::WebContentsViewMac; 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Ensure that the WebKit::WebDragOperation enum values stay in sync with 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// NSDragOperation constants, since the code below static_casts between 'em. 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#define COMPILE_ASSERT_MATCHING_ENUM(name) \ 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) COMPILE_ASSERT(int(NS##name) == int(WebKit::Web##name), enum_mismatch_##name) 45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone); 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy); 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink); 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric); 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate); 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove); 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete); 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery); 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)@interface WebContentsViewCocoa (Private) 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (id)initWithWebContentsViewMac:(WebContentsViewMac*)w; 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (void)registerDragTypes; 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (void)setCurrentDragOperation:(NSDragOperation)operation; 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (WebDropData*)dropData; 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)- (void)startDragWithDropData:(const WebDropData&)dropData 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) dragOperationMask:(NSDragOperation)operationMask 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) image:(NSImage*)image 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) offset:(NSPoint)offset; 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)- (void)cancelDeferredClose; 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (void)clearWebContentsView; 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)- (void)closeTabAfterEvent; 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)- (void)viewDidBecomeFirstResponder:(NSNotification*)notification; 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)@end 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace content { 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)WebContentsViewPort* CreateWebContentsView( 71424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) WebContentsImpl* web_contents, 72424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) WebContentsViewDelegate* delegate, 73424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) RenderViewHostDelegateView** render_view_host_delegate_view) { 74424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) WebContentsViewMac* rv = new WebContentsViewMac(web_contents, delegate); 75424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) *render_view_host_delegate_view = rv; 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return rv; 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)WebContentsViewMac::WebContentsViewMac(WebContentsImpl* web_contents, 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WebContentsViewDelegate* delegate) 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : web_contents_(web_contents), 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delegate_(delegate), 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) allow_overlapping_views_(false) { 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)WebContentsViewMac::~WebContentsViewMac() { 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // This handles the case where a renderer close call was deferred 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // while the user was operating a UI control which resulted in a 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // close. In that case, the Cocoa view outlives the 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // WebContentsViewMac instance due to Cocoa retain count. 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) [cocoa_view_ cancelDeferredClose]; 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) [cocoa_view_ clearWebContentsView]; 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)gfx::NativeView WebContentsViewMac::GetNativeView() const { 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return cocoa_view_.get(); 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 98 99gfx::NativeView WebContentsViewMac::GetContentNativeView() const { 100 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView(); 101 if (!rwhv) 102 return NULL; 103 return rwhv->GetNativeView(); 104} 105 106gfx::NativeWindow WebContentsViewMac::GetTopLevelNativeWindow() const { 107 return [cocoa_view_.get() window]; 108} 109 110void WebContentsViewMac::GetContainerBounds(gfx::Rect* out) const { 111 // Convert bounds to window coordinate space. 112 NSRect bounds = 113 [cocoa_view_.get() convertRect:[cocoa_view_.get() bounds] toView:nil]; 114 115 // Convert bounds to screen coordinate space. 116 NSWindow* window = [cocoa_view_.get() window]; 117 bounds.origin = [window convertBaseToScreen:bounds.origin]; 118 119 // Flip y to account for screen flip. 120 NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; 121 bounds.origin.y = [screen frame].size.height - bounds.origin.y 122 - bounds.size.height; 123 *out = gfx::Rect(NSRectToCGRect(bounds)); 124} 125 126void WebContentsViewMac::StartDragging( 127 const WebDropData& drop_data, 128 WebDragOperationsMask allowed_operations, 129 const gfx::ImageSkia& image, 130 const gfx::Vector2d& image_offset, 131 const DragEventSourceInfo& event_info) { 132 // By allowing nested tasks, the code below also allows Close(), 133 // which would deallocate |this|. The same problem can occur while 134 // processing -sendEvent:, so Close() is deferred in that case. 135 // Drags from web content do not come via -sendEvent:, this sets the 136 // same flag -sendEvent: would. 137 base::mac::ScopedSendingEvent sending_event_scoper; 138 139 // The drag invokes a nested event loop, arrange to continue 140 // processing events. 141 MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); 142 NSDragOperation mask = static_cast<NSDragOperation>(allowed_operations); 143 NSPoint offset = NSPointFromCGPoint( 144 gfx::PointAtOffsetFromOrigin(image_offset).ToCGPoint()); 145 [cocoa_view_ startDragWithDropData:drop_data 146 dragOperationMask:mask 147 image:gfx::NSImageFromImageSkia(image) 148 offset:offset]; 149} 150 151void WebContentsViewMac::OnTabCrashed(base::TerminationStatus /* status */, 152 int /* error_code */) { 153} 154 155void WebContentsViewMac::SizeContents(const gfx::Size& size) { 156 // TODO(brettw | japhet) This is a hack and should be removed. 157 // See web_contents_view.h. 158 gfx::Rect rect(gfx::Point(), size); 159 WebContentsViewCocoa* view = cocoa_view_.get(); 160 161 NSPoint origin = [view frame].origin; 162 NSRect frame = [view flipRectToNSRect:rect]; 163 frame.origin = NSMakePoint(NSMinX(frame) + origin.x, 164 NSMinY(frame) + origin.y); 165 [view setFrame:frame]; 166} 167 168void WebContentsViewMac::Focus() { 169 NSWindow* window = [cocoa_view_.get() window]; 170 [window makeFirstResponder:GetContentNativeView()]; 171 if (![window isVisible]) 172 return; 173 [window makeKeyAndOrderFront:nil]; 174} 175 176void WebContentsViewMac::SetInitialFocus() { 177 if (web_contents_->FocusLocationBarByDefault()) 178 web_contents_->SetFocusToLocationBar(false); 179 else 180 [[cocoa_view_.get() window] makeFirstResponder:GetContentNativeView()]; 181} 182 183void WebContentsViewMac::StoreFocus() { 184 // We're explicitly being asked to store focus, so don't worry if there's 185 // already a view saved. 186 focus_tracker_.reset( 187 [[FocusTracker alloc] initWithWindow:[cocoa_view_ window]]); 188} 189 190void WebContentsViewMac::RestoreFocus() { 191 // TODO(avi): Could we be restoring a view that's no longer in the key view 192 // chain? 193 if (!(focus_tracker_.get() && 194 [focus_tracker_ restoreFocusInWindow:[cocoa_view_ window]])) { 195 // Fall back to the default focus behavior if we could not restore focus. 196 // TODO(shess): If location-bar gets focus by default, this will 197 // select-all in the field. If there was a specific selection in 198 // the field when we navigated away from it, we should restore 199 // that selection. 200 SetInitialFocus(); 201 } 202 203 focus_tracker_.reset(nil); 204} 205 206WebDropData* WebContentsViewMac::GetDropData() const { 207 return [cocoa_view_ dropData]; 208} 209 210void WebContentsViewMac::UpdateDragCursor(WebDragOperation operation) { 211 [cocoa_view_ setCurrentDragOperation: operation]; 212} 213 214void WebContentsViewMac::GotFocus() { 215 // This is only used in the views FocusManager stuff but it bleeds through 216 // all subclasses. http://crbug.com/21875 217} 218 219// This is called when the renderer asks us to take focus back (i.e., it has 220// iterated past the last focusable element on the page). 221void WebContentsViewMac::TakeFocus(bool reverse) { 222 if (reverse) { 223 [[cocoa_view_ window] selectPreviousKeyView:cocoa_view_.get()]; 224 } else { 225 [[cocoa_view_ window] selectNextKeyView:cocoa_view_.get()]; 226 } 227} 228 229void WebContentsViewMac::ShowContextMenu(const ContextMenuParams& params, 230 ContextMenuSourceType type) { 231 // Allow delegates to handle the context menu operation first. 232 if (web_contents_->GetDelegate() && 233 web_contents_->GetDelegate()->HandleContextMenu(params)) { 234 return; 235 } 236 237 if (delegate()) 238 delegate()->ShowContextMenu(params, type); 239 else 240 DLOG(ERROR) << "Cannot show context menus without a delegate."; 241} 242 243// Display a popup menu for WebKit using Cocoa widgets. 244void WebContentsViewMac::ShowPopupMenu( 245 const gfx::Rect& bounds, 246 int item_height, 247 double item_font_size, 248 int selected_item, 249 const std::vector<WebMenuItem>& items, 250 bool right_aligned, 251 bool allow_multiple_selection) { 252 PopupMenuHelper popup_menu_helper(web_contents_->GetRenderViewHost()); 253 popup_menu_helper.ShowPopupMenu(bounds, item_height, item_font_size, 254 selected_item, items, right_aligned, 255 allow_multiple_selection); 256} 257 258gfx::Rect WebContentsViewMac::GetViewBounds() const { 259 // This method is not currently used on mac. 260 NOTIMPLEMENTED(); 261 return gfx::Rect(); 262} 263 264void WebContentsViewMac::SetAllowOverlappingViews(bool overlapping) { 265 if (allow_overlapping_views_ == overlapping) 266 return; 267 268 allow_overlapping_views_ = overlapping; 269 RenderWidgetHostViewMac* view = static_cast<RenderWidgetHostViewMac*>( 270 web_contents_->GetRenderWidgetHostView()); 271 if (view) 272 view->SetAllowOverlappingViews(allow_overlapping_views_); 273} 274 275void WebContentsViewMac::CreateView( 276 const gfx::Size& initial_size, gfx::NativeView context) { 277 WebContentsViewCocoa* view = 278 [[WebContentsViewCocoa alloc] initWithWebContentsViewMac:this]; 279 cocoa_view_.reset(view); 280} 281 282RenderWidgetHostView* WebContentsViewMac::CreateViewForWidget( 283 RenderWidgetHost* render_widget_host) { 284 if (render_widget_host->GetView()) { 285 // During testing, the view will already be set up in most cases to the 286 // test view, so we don't want to clobber it with a real one. To verify that 287 // this actually is happening (and somebody isn't accidentally creating the 288 // view twice), we check for the RVH Factory, which will be set when we're 289 // making special ones (which go along with the special views). 290 DCHECK(RenderViewHostFactory::has_factory()); 291 return render_widget_host->GetView(); 292 } 293 294 RenderWidgetHostViewMac* view = static_cast<RenderWidgetHostViewMac*>( 295 RenderWidgetHostView::CreateViewForWidget(render_widget_host)); 296 if (delegate()) { 297 NSObject<RenderWidgetHostViewMacDelegate>* rw_delegate = 298 delegate()->CreateRenderWidgetHostViewDelegate(render_widget_host); 299 view->SetDelegate(rw_delegate); 300 } 301 view->SetAllowOverlappingViews(allow_overlapping_views_); 302 303 // Fancy layout comes later; for now just make it our size and resize it 304 // with us. In case there are other siblings of the content area, we want 305 // to make sure the content area is on the bottom so other things draw over 306 // it. 307 NSView* view_view = view->GetNativeView(); 308 [view_view setFrame:[cocoa_view_.get() bounds]]; 309 [view_view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; 310 // Add the new view below all other views; this also keeps it below any 311 // overlay view installed. 312 [cocoa_view_.get() addSubview:view_view 313 positioned:NSWindowBelow 314 relativeTo:nil]; 315 // For some reason known only to Cocoa, the autorecalculation of the key view 316 // loop set on the window doesn't set the next key view when the subview is 317 // added. On 10.6 things magically work fine; on 10.5 they fail 318 // <http://crbug.com/61493>. Digging into Cocoa key view loop code yielded 319 // madness; TODO(avi,rohit): look at this again and figure out what's really 320 // going on. 321 [cocoa_view_.get() setNextKeyView:view_view]; 322 return view; 323} 324 325RenderWidgetHostView* WebContentsViewMac::CreateViewForPopupWidget( 326 RenderWidgetHost* render_widget_host) { 327 return RenderWidgetHostViewPort::CreateViewForWidget(render_widget_host); 328} 329 330void WebContentsViewMac::SetPageTitle(const string16& title) { 331 // Meaningless on the Mac; widgets don't have a "title" attribute 332} 333 334 335void WebContentsViewMac::RenderViewCreated(RenderViewHost* host) { 336 // We want updates whenever the intrinsic width of the webpage changes. 337 // Put the RenderView into that mode. The preferred width is used for example 338 // when the "zoom" button in the browser window is clicked. 339 host->EnablePreferredSizeMode(); 340} 341 342void WebContentsViewMac::RenderViewSwappedIn(RenderViewHost* host) { 343} 344 345void WebContentsViewMac::SetOverscrollControllerEnabled(bool enabled) { 346} 347 348bool WebContentsViewMac::IsEventTracking() const { 349 return base::MessagePumpMac::IsHandlingSendEvent(); 350} 351 352// Arrange to call CloseTab() after we're back to the main event loop. 353// The obvious way to do this would be PostNonNestableTask(), but that 354// will fire when the event-tracking loop polls for events. So we 355// need to bounce the message via Cocoa, instead. 356void WebContentsViewMac::CloseTabAfterEventTracking() { 357 [cocoa_view_ cancelDeferredClose]; 358 [cocoa_view_ performSelector:@selector(closeTabAfterEvent) 359 withObject:nil 360 afterDelay:0.0]; 361} 362 363void WebContentsViewMac::CloseTab() { 364 web_contents_->Close(web_contents_->GetRenderViewHost()); 365} 366 367} // namespace content 368 369@implementation WebContentsViewCocoa 370 371- (id)initWithWebContentsViewMac:(WebContentsViewMac*)w { 372 self = [super initWithFrame:NSZeroRect]; 373 if (self != nil) { 374 webContentsView_ = w; 375 dragDest_.reset( 376 [[WebDragDest alloc] initWithWebContentsImpl:[self webContents]]); 377 [self registerDragTypes]; 378 379 [[NSNotificationCenter defaultCenter] 380 addObserver:self 381 selector:@selector(viewDidBecomeFirstResponder:) 382 name:kViewDidBecomeFirstResponder 383 object:nil]; 384 385 if (webContentsView_->delegate()) { 386 [dragDest_ setDragDelegate:webContentsView_->delegate()-> 387 GetDragDestDelegate()]; 388 } 389 } 390 return self; 391} 392 393- (void)dealloc { 394 // Cancel any deferred tab closes, just in case. 395 [self cancelDeferredClose]; 396 397 // This probably isn't strictly necessary, but can't hurt. 398 [self unregisterDraggedTypes]; 399 400 [[NSNotificationCenter defaultCenter] removeObserver:self]; 401 402 [super dealloc]; 403} 404 405// Registers for the view for the appropriate drag types. 406- (void)registerDragTypes { 407 NSArray* types = [NSArray arrayWithObjects: 408 ui::kChromeDragDummyPboardType, 409 kWebURLsWithTitlesPboardType, 410 NSURLPboardType, 411 NSStringPboardType, 412 NSHTMLPboardType, 413 NSRTFPboardType, 414 NSFilenamesPboardType, 415 ui::kWebCustomDataPboardType, 416 nil]; 417 [self registerForDraggedTypes:types]; 418} 419 420- (void)setCurrentDragOperation:(NSDragOperation)operation { 421 [dragDest_ setCurrentOperation:operation]; 422} 423 424- (WebDropData*)dropData { 425 return [dragDest_ currentDropData]; 426} 427 428- (WebContentsImpl*)webContents { 429 if (webContentsView_ == NULL) 430 return NULL; 431 return webContentsView_->web_contents(); 432} 433 434- (void)mouseEvent:(NSEvent*)theEvent { 435 WebContentsImpl* webContents = [self webContents]; 436 if (webContents && webContents->GetDelegate()) { 437 NSPoint location = [NSEvent mouseLocation]; 438 if ([theEvent type] == NSMouseMoved) 439 webContents->GetDelegate()->ContentsMouseEvent( 440 webContents, gfx::Point(location.x, location.y), true); 441 if ([theEvent type] == NSMouseExited) 442 webContents->GetDelegate()->ContentsMouseEvent( 443 webContents, gfx::Point(location.x, location.y), false); 444 } 445} 446 447- (void)setMouseDownCanMoveWindow:(BOOL)canMove { 448 mouseDownCanMoveWindow_ = canMove; 449} 450 451- (BOOL)mouseDownCanMoveWindow { 452 // This is needed to prevent mouseDowns from moving the window 453 // around. The default implementation returns YES only for opaque 454 // views. WebContentsViewCocoa does not draw itself in any way, but 455 // its subviews do paint their entire frames. Returning NO here 456 // saves us the effort of overriding this method in every possible 457 // subview. 458 return mouseDownCanMoveWindow_; 459} 460 461- (void)pasteboard:(NSPasteboard*)sender provideDataForType:(NSString*)type { 462 [dragSource_ lazyWriteToPasteboard:sender 463 forType:type]; 464} 465 466- (void)startDragWithDropData:(const WebDropData&)dropData 467 dragOperationMask:(NSDragOperation)operationMask 468 image:(NSImage*)image 469 offset:(NSPoint)offset { 470 dragSource_.reset([[WebDragSource alloc] 471 initWithContents:[self webContents] 472 view:self 473 dropData:&dropData 474 image:image 475 offset:offset 476 pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard] 477 dragOperationMask:operationMask]); 478 [dragSource_ startDrag]; 479} 480 481// NSDraggingSource methods 482 483// Returns what kind of drag operations are available. This is a required 484// method for NSDraggingSource. 485- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { 486 if (dragSource_.get()) 487 return [dragSource_ draggingSourceOperationMaskForLocal:isLocal]; 488 // No web drag source - this is the case for dragging a file from the 489 // downloads manager. Default to copy operation. Note: It is desirable to 490 // allow the user to either move or copy, but this requires additional 491 // plumbing to update the download item's path once its moved. 492 return NSDragOperationCopy; 493} 494 495// Called when a drag initiated in our view ends. 496- (void)draggedImage:(NSImage*)anImage 497 endedAt:(NSPoint)screenPoint 498 operation:(NSDragOperation)operation { 499 [dragSource_ endDragAt:screenPoint operation:operation]; 500 501 // Might as well throw out this object now. 502 dragSource_.reset(); 503} 504 505// Called when a drag initiated in our view moves. 506- (void)draggedImage:(NSImage*)draggedImage movedTo:(NSPoint)screenPoint { 507 [dragSource_ moveDragTo:screenPoint]; 508} 509 510// Called when we're informed where a file should be dropped. 511- (NSArray*)namesOfPromisedFilesDroppedAtDestination:(NSURL*)dropDest { 512 if (![dropDest isFileURL]) 513 return nil; 514 515 NSString* file_name = [dragSource_ dragPromisedFileTo:[dropDest path]]; 516 if (!file_name) 517 return nil; 518 519 return [NSArray arrayWithObject:file_name]; 520} 521 522// NSDraggingDestination methods 523 524- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender { 525 return [dragDest_ draggingEntered:sender view:self]; 526} 527 528- (void)draggingExited:(id<NSDraggingInfo>)sender { 529 [dragDest_ draggingExited:sender]; 530} 531 532- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender { 533 return [dragDest_ draggingUpdated:sender view:self]; 534} 535 536- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender { 537 return [dragDest_ performDragOperation:sender view:self]; 538} 539 540- (void)cancelDeferredClose { 541 SEL aSel = @selector(closeTabAfterEvent); 542 [NSObject cancelPreviousPerformRequestsWithTarget:self 543 selector:aSel 544 object:nil]; 545} 546 547- (void)clearWebContentsView { 548 webContentsView_ = NULL; 549 [dragSource_ clearWebContentsView]; 550} 551 552- (void)closeTabAfterEvent { 553 webContentsView_->CloseTab(); 554} 555 556- (void)viewDidBecomeFirstResponder:(NSNotification*)notification { 557 NSView* view = [notification object]; 558 if (![[self subviews] containsObject:view]) 559 return; 560 561 NSSelectionDirection direction = 562 [[[notification userInfo] objectForKey:kSelectionDirection] 563 unsignedIntegerValue]; 564 if (direction == NSDirectSelection) 565 return; 566 567 [self webContents]-> 568 FocusThroughTabTraversal(direction == NSSelectingPrevious); 569} 570 571@end 572